A comprehensive guide for working on shared projects with Git, focusing on proper branching, pulling, merging, and conflict resolution.
- The Basic Workflow
- Initial Setup
- Daily Workflow Step-by-Step
- Understanding Branches
- Handling Merge Conflicts
- Best Practices
- Common Scenarios
- Troubleshooting
Here's the golden rule for collaborative Git work:
1. Create a branch for your work
2. Make your changes on that branch
3. Pull the latest changes from remote
4. Merge remote changes into YOUR branch (solve conflicts here)
5. Push your branch to remote
6. Create a Pull Request (PR) / Merge Request (MR)
7. After review, merge into main branch
Why this workflow?
- ✅ Keeps the main branch stable and working
- ✅ Allows you to work without breaking others' code
- ✅ Conflicts happen on YOUR branch, not the main branch
- ✅ Easy to review and test changes before merging
# Clone the project to your local machine
git clone https://github.com/username/project-name.git
# Navigate into the project folder
cd project-name# Set your name and email (if not already set)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Verify your configuration
git config --list# See what branch you're on (usually 'main' or 'master')
git branch
# See the remote repository URL
git remote -v
# Check the status of your working directory
git statusLet's walk through a complete work session from start to finish.
Before creating a new branch, always make sure your main branch is up to date.
# Switch to the main branch
git checkout main
# Pull the latest changes from remote
git pull origin mainWhat this does:
git checkout main→ Switches you to the main branchgit pull origin main→ Downloads and merges the latest changes from the remote repository
Never work directly on the main branch! Always create a feature branch.
# Create and switch to a new branch in one command
git checkout -b feature/my-new-feature
# Alternative: Create branch then switch to it
git branch feature/my-new-feature
git checkout feature/my-new-featureBranch naming conventions:
feature/add-login-page→ New featuresbugfix/fix-null-pointer→ Bug fixeshotfix/security-patch→ Urgent fixesdocs/update-readme→ Documentation updates
Now you can work on your code! Edit files, add features, fix bugs, etc.
# Check what files you've changed
git status
# See the specific changes you've made
git diffOnce you've made some progress, save your work with commits.
# Stage specific files
git add filename.py
# Or stage all changed files
git add .
# Commit with a descriptive message
git commit -m "Add user authentication feature"Good commit messages:
- ✅ "Add login form validation"
- ✅ "Fix null pointer exception in user service"
- ✅ "Update API documentation for /users endpoint"
Bad commit messages:
- ❌ "fixed stuff"
- ❌ "changes"
- ❌ "asdf"
This is crucial! Before pushing your work, get the latest changes from your teammate.
# First, switch to main and update it
git checkout main
git pull origin main
# Switch back to your branch
git checkout feature/my-new-featureThis is where you handle conflicts on your branch, not on main!
# Merge the latest main branch into your feature branch
git merge mainPossible outcomes:
A) No conflicts (Automatic merge):
Auto-merging file.py
Merge made by the 'recursive' strategy.
✅ Great! Git merged everything automatically.
B) Merge conflicts:
Auto-merging file.py
CONFLICT (content): Merge conflict in file.py
Automatic merge failed; fix conflicts and then commit the result.
When Git can't automatically merge, you'll see conflict markers in your files.
Example conflict in app.py:
def calculate_total(price, tax):
<<<<<<< HEAD
# Your changes
return price * (1 + tax)
=======
# Changes from main branch
return price + (price * tax)
>>>>>>> mainHow to resolve:
-
Open the conflicted file in your editor
-
Look for conflict markers:
<<<<<<< HEAD→ Your changes start here=======→ Separator between changes>>>>>>> main→ Changes from main branch end here
-
Decide which changes to keep:
- Keep yours
- Keep theirs
- Keep both (combine them)
- Write something completely new
-
Remove the conflict markers and edit to your final version:
def calculate_total(price, tax):
# Combined version - best of both
result = price + (price * tax)
return result- Mark as resolved:
# Stage the resolved file
git add app.py
# Check status to see if all conflicts are resolved
git status
# Complete the merge with a commit
git commit -m "Merge main into feature/my-new-feature, resolved conflicts"Now your branch is ready to share with your teammate!
# Push your branch to the remote repository
git push origin feature/my-new-feature
# If this is the first time pushing this branch, you might need:
git push -u origin feature/my-new-featureWhat this does:
- Uploads your branch to GitHub/GitLab/Bitbucket
- Makes it available for your teammate to review
- The
-uflag sets up tracking (only needed first time)
On GitHub/GitLab/Bitbucket web interface:
- Go to your repository's website
- Click "Pull Requests" or "Merge Requests"
- Click "New Pull Request"
- Select:
- Base branch:
main(where you want to merge TO) - Compare branch:
feature/my-new-feature(your branch)
- Base branch:
- Add a title and description
- Request review from your teammate
- Click "Create Pull Request"
Your teammate will:
- Review your code
- Leave comments/suggestions
- Approve or request changes
If your teammate requests changes:
# Make the requested changes to your files
# Stage and commit the changes
git add .
git commit -m "Address review feedback: improve error handling"
# Push the new commits to your branch
git push origin feature/my-new-featureThe Pull Request will automatically update with your new commits!
Once approved, merge your branch into main (usually done via the web interface):
- Click "Merge Pull Request" on GitHub/GitLab
- Choose merge type (usually "Merge commit" or "Squash and merge")
- Confirm the merge
- Delete the feature branch (optional but recommended)
Or via command line:
# Switch to main
git checkout main
# Pull the latest (your merged changes)
git pull origin main
# Delete your local feature branch (it's merged now)
git branch -d feature/my-new-feature
# Delete the remote feature branch
git push origin --delete feature/my-new-featureThink of branches as parallel universes for your code:
main: A --- B --- C --- F --- G
\ /
feature branch: D --- E ---
- main: The stable, production-ready code
- feature branch: Your experimental/development work
- A, B, C: Commits on main before you branched off
- D, E: Your commits on the feature branch
- F: Changes your teammate made on main while you worked
- G: The merge commit bringing your work back to main
# List all local branches (* shows current branch)
git branch
# List all branches including remote
git branch -a
# See branch history as a graph
git log --oneline --graph --all# Switch to an existing branch
git checkout branch-name
# Create and switch to a new branch
git checkout -b new-branch-name
# Switch using the newer 'switch' command (Git 2.23+)
git switch branch-name
git switch -c new-branch-name1. Content Conflict (most common) Both you and your teammate edited the same lines in the same file.
2. Delete/Modify Conflict You modified a file that your teammate deleted (or vice versa).
3. Rename Conflict Both of you renamed the same file to different names.
Step-by-step process:
-
Don't panic! Conflicts are normal in collaboration.
-
Check which files have conflicts:
git statusLook for files marked as "both modified"
-
Open conflicted files and look for conflict markers
-
Understand both changes:
- Read your changes carefully
- Read your teammate's changes
- Understand the intent of both
-
Decide on the resolution:
- Talk to your teammate if unclear
- Test the combined code
- Make sure functionality isn't broken
-
Edit the file to the correct final state
-
Remove ALL conflict markers (
<<<<<<<,=======,>>>>>>>) -
Test your code to ensure it works
-
Stage the resolved files:
git add resolved-file.py- Complete the merge:
git commit -m "Resolve merge conflicts"Original file (before changes):
def greet(name):
return "Hello, " + nameYour change (on feature branch):
def greet(name):
return f"Hello, {name}!" # Using f-stringTeammate's change (on main):
def greet(name):
return "Hi there, " + name # Changed greetingAfter merge attempt:
def greet(name):
<<<<<<< HEAD
return f"Hello, {name}!" # Using f-string
=======
return "Hi there, " + name # Changed greeting
>>>>>>> mainYour resolution (combining both improvements):
def greet(name):
return f"Hi there, {name}!" # Using f-string AND new greetingVisual merge tools make conflicts easier to handle:
# Configure a merge tool (VS Code, for example)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'
# Use the merge tool
git mergetoolPopular merge tools:
- VS Code (built-in Git support)
- GitKraken (visual Git client)
- Beyond Compare
- Meld
- P4Merge
- KDiff3
# Make small, focused commits
git commit -m "Add email validation"
git commit -m "Add password strength checker"
git commit -m "Add login form styling"
# Don't wait days to push
git push origin feature/login-systemBenefits:
- Easier to track changes
- Easier to revert if something breaks
- Your work is backed up remotely
Always update your branch before pushing:
# Daily routine:
git checkout main
git pull origin main
git checkout your-feature-branch
git merge main
# Resolve any conflicts
git push origin your-feature-branch# Good branch names
git checkout -b feature/user-authentication
git checkout -b bugfix/login-redirect-loop
git checkout -b docs/api-documentation
# Bad branch names
git checkout -b test
git checkout -b fixes
git checkout -b my-branchFormat:
<type>: <short description>
<detailed description if needed>
Examples:
git commit -m "feat: Add password reset functionality"
git commit -m "fix: Resolve null pointer in user service"
git commit -m "docs: Update README with setup instructions"
git commit -m "refactor: Simplify authentication logic"Types:
feat: New featurefix: Bug fixdocs: Documentationstyle: Formatting (no code change)refactor: Code restructuringtest: Adding testschore: Maintenance tasks
- Create a branch for a specific task
- Merge it within a few days
- Delete the branch after merging
- Don't let branches live for weeks
- Before starting: "I'm working on the login feature"
- During work: "I'm modifying the User model"
- Before big changes: "I need to refactor the database layer"
- When stuck: "I'm getting a conflict in auth.py, can we discuss?"
# You're on main and made changes (but haven't committed)
git status # Shows modified files
# Create a new branch with your changes
git checkout -b feature/my-work
# Now your changes are on the new branch!
git add .
git commit -m "Add my work"# You committed to main instead of a feature branch
git log # See your commits
# Create a new branch from current state
git branch feature/my-work
# Reset main to remote state (this removes your commits from main)
git checkout main
git reset --hard origin/main
# Switch to your feature branch (your commits are here)
git checkout feature/my-work# You're on your feature branch and ready to push
# But first, update with their changes
git checkout main
git pull origin main
git checkout feature/your-branch
git merge main
# Resolve conflicts if any
git push origin feature/your-branch# Your PR is open, but main has new commits
git checkout main
git pull origin main
git checkout feature/your-branch
git merge main
# Resolve conflicts
git push origin feature/your-branch
# The PR automatically updates!# Discard all uncommitted changes
git checkout .
# Or reset to last commit
git reset --hard HEAD
# Discard changes to a specific file
git checkout filename.py# See commits on main that you don't have
git fetch origin
git log HEAD..origin/main
# See the actual changes
git diff main origin/main
# See commits in a nicer format
git log --oneline --graph origin/mainSolution:
# Push your commits
git push origin your-branch-nameSolution:
# Pull the latest changes
git pull origin mainSolution:
# Allow merging unrelated histories (rare, usually on first merge)
git pull origin main --allow-unrelated-historiesSolution:
# Someone pushed before you, pull first
git pull origin your-branch-name
# Resolve any conflicts
git push origin your-branch-nameSolution:
# Your local branch and remote branch have different commits
# Option 1: Merge remote changes into local
git pull origin your-branch-name
# Option 2: Rebase your changes on top of remote (cleaner history)
git pull --rebase origin your-branch-nameSolution:
# Keep changes, just undo commit
git reset --soft HEAD~1
# Discard changes and commit completely
git reset --hard HEAD~1
# Already pushed? Create a new commit that reverses it
git revert HEADSolution:
# Abort the merge and start over
git merge --abort
# Go back to state before merge
git checkout your-branch-name
# Talk to your teammate about the conflicts
# Consider pair programming the merge# Setup
git clone <url> # Clone a repository
git config --global user.name "Name" # Set your name
git config --global user.email "email" # Set your email
# Daily workflow
git status # Check current state
git pull origin main # Update main branch
git checkout -b feature/name # Create new branch
git add . # Stage all changes
git commit -m "message" # Commit changes
git push origin branch-name # Push to remote
# Branching
git branch # List local branches
git branch -a # List all branches
git checkout branch-name # Switch branches
git branch -d branch-name # Delete local branch
# Merging
git merge branch-name # Merge branch into current
git merge --abort # Abort a merge
# Viewing changes
git diff # See unstaged changes
git log # View commit history
git log --oneline --graph # Pretty commit history
# Undoing
git checkout . # Discard all changes
git reset --hard HEAD # Reset to last commit
git revert HEAD # Create commit that undoes last commitThe golden workflow:
- ✅ Always work on a feature branch, never on main
- ✅ Pull latest changes before starting work
- ✅ Commit often with clear messages
- ✅ Merge main into YOUR branch to resolve conflicts
- ✅ Push your branch and create a Pull Request
- ✅ After merging, delete the feature branch and start fresh
Remember:
- Conflicts are normal and expected
- Communicate with your teammate
- When in doubt, ask before forcing changes
- Your local repository is safe to experiment in
- You can always abort a merge with
git merge --abort
Good luck with your collaborative project! 🚀