Branching is one of Git's most powerful features. It allows you to diverge from the main line of development and work on features, fixes, or experiments in isolation. When your work is ready, you can merge it back into the main branch. This lesson will teach you how to effectively use branches to manage your development workflow.
By the end of this lesson, you will:
A branch is simply a movable pointer to a commit. The default branch is typically called main
(previously master
). When you create a new branch, you're creating a new pointer to the current commit.
main: A---B---C
\
feature: D---E
# Create a new branch
git branch feature-branch
# Create and switch to new branch
git checkout -b feature-branch
# New way (Git 2.23+)
git switch -c feature-branch
Command | Description | Example |
---|---|---|
git branch |
List branches | git branch |
git branch <name> |
Create branch | git branch feature-auth |
git checkout -b <name> |
Create & switch | git checkout -b fix-bug |
git switch -c <name> |
Create & switch (new) | git switch -c feature-api |
git branch -d <name> |
Delete branch | git branch -d old-feature |
git branch -m <new> |
Rename branch | git branch -m new-name |
# List local branches
git branch
# List all branches (local and remote)
git branch -a
# List remote branches
git branch -r
# Show branches with last commit
git branch -v
# Show merged/unmerged branches
git branch --merged
git branch --no-merged
# Switch to existing branch
git checkout branch-name
# New way (Git 2.23+)
git switch branch-name
# Switch to previous branch
git checkout -
git switch -
# Rename current branch
git branch -m new-name
# Rename any branch
git branch -m old-name new-name
# Rename on remote
git push origin --delete old-name
git push origin -u new-name
# Delete local branch (safe - prevents deleting unmerged branches)
git branch -d branch-name
# Force delete local branch
git branch -D branch-name
# Delete remote branch
git push origin --delete branch-name
# Switch to target branch
git checkout main
# Merge feature branch
git merge feature-branch
When there are no divergent commits, Git simply moves the pointer forward.
Before merge:
main: A---B
\
feature: C---D
After fast-forward merge:
main: A---B---C---D
Force fast-forward only:
git merge --ff-only feature-branch
When branches have diverged, Git creates a merge commit.
Before merge:
main: A---B---E
\
feature: C---D
After three-way merge:
main: A---B---E---M
\ /
feature: C---D
Force merge commit even if fast-forward is possible:
git merge --no-ff feature-branch
Combines all commits from a branch into a single commit.
git merge --squash feature-branch
git commit -m "Add feature"
Conflicts happen when:
When a conflict occurs, Git marks the file:
<<<<<<< HEAD
Current branch content
=======
Incoming branch content
>>>>>>> feature-branch
git status
git add resolved-file.txt
git commit
If things go wrong:
git merge --abort
:bulb: :bulb: Pro Tips for Merge Conflict Resolution
- Use a merge tool: Tools like VS Code, Beyond Compare, or P4Merge provide visual diff interfaces
- Communicate with team: Check with the author of conflicting changes before resolving
- Test thoroughly: Always run tests after resolving conflicts
- Keep commits small: Smaller, focused commits lead to easier conflict resolution
- Pull frequently: Regular syncing reduces the likelihood of complex conflicts
Scenario: Two developers working on the same API endpoint Problem: Both modified the authentication logic differently Solution:
Apply specific commits from one branch to another:
# Apply single commit
git cherry-pick commit-hash
# Apply multiple commits
git cherry-pick commit1 commit2
# Apply range of commits
git cherry-pick start-commit..end-commit
Reapply commits on top of another base:
# Rebase current branch onto main
git rebase main
# Interactive rebase
git rebase -i HEAD~3
:warning: Warning: Never rebase commits that have been pushed to a public repository!
# Recursive (default)
git merge -s recursive branch-name
# Ours (keep our version)
git merge -s ours branch-name
# Theirs option (prefer their changes in conflicts)
git merge -X theirs branch-name
Popular for projects with scheduled releases.
main (production)
|
develop (integration)
|
+-- feature/user-auth
+-- feature/payment-api
|
release/1.0.0
|
hotfix/security-patch
When to use:
Implementation:
# Start a new feature
git checkout develop
git checkout -b feature/new-feature
# Finish feature
git checkout develop
git merge --no-ff feature/new-feature
git branch -d feature/new-feature
# Create release
git checkout -b release/1.0.0 develop
# Finish release
git checkout main
git merge --no-ff release/1.0.0
git tag -a v1.0.0 -m "Version 1.0.0"
git checkout develop
git merge --no-ff release/1.0.0
Simplified workflow for continuous deployment.
main (always deployable)
|
+-- feature/add-search
+-- fix/navigation-bug
+-- update/documentation
When to use:
Implementation:
# Create feature branch
git checkout -b feature/add-search
# Work and commit
git add .
git commit -m "Add search functionality"
# Push and create PR
git push origin feature/add-search
# Create pull request on GitHub
# After review and merge
git checkout main
git pull origin main
git branch -d feature/add-search
Environment-based branching strategy.
main (development)
|
+-- feature branches
|
pre-production
|
production
When to use:
Minimal branching with feature flags.
main (trunk)
|
+-- short-lived feature branches (<1 day)
When to use:
:bulb: :bulb: Choosing the Right Strategy
- Small teams/startups: GitHub Flow
- Enterprise with releases: Git Flow
- Multiple environments: GitLab Flow
- Continuous deployment: Trunk-Based Development
feature/add-user-authentication
bugfix/fix-login-error
hotfix/security-patch
release/v2.0.0
chore/update-dependencies
docs/api-documentation
refactor/optimize-database-queries
# Update feature branch with latest main
git checkout feature-branch
git merge main
# or
git rebase main
# Automate with git aliases
git config --global alias.update '!git fetch origin && git merge origin/main'
type(scope): subject
body (optional)
footer (optional)
Configure on GitHub:
# Example branch protection settings
main:
- Require pull request reviews (2 approvals)
- Dismiss stale PR approvals on new commits
- Require status checks (CI/CD)
- Require branches to be up to date
- Include administrators
- Restrict who can push
Daily Workflow:
# Start of day
git checkout main
git pull origin main
# Start new work
git checkout -b feature/JIRA-123-new-feature
# During development
git add -p # Stage changes interactively
git commit -m "feat: add user validation"
# Before creating PR
git fetch origin
git rebase origin/main
git push origin feature/JIRA-123-new-feature
Code Review Workflow:
Pair Programming Workflow:
# Developer A starts feature
git checkout -b feature/shared-feature
git push -u origin feature/shared-feature
# Developer B joins
git fetch origin
git checkout feature/shared-feature
# Taking turns
git pull --rebase # Before starting work
git add -p # Stage changes
git commit # Commit with co-author
git push # Share changes
# Co-author in commit message
git commit -m "Add feature X
Co-authored-by: Name <email@example.com>"
git checkout -b feature/new-feature
# Make changes
git add .
git commit -m "Add new feature"
git fetch origin
git merge origin/main
git push -u origin feature/new-feature
Create pull request on GitHub
After merge, clean up
git checkout main
git pull
git branch -d feature/new-feature
# Text-based graph
git log --graph --oneline --all
# Pretty graph
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all
# Simplified view
git log --oneline --graph --decorate
Issue 1: "Cannot delete branch"
error: The branch 'feature-x' is not fully merged.
Solution:
# Check what's not merged
git log feature-x ^main
# Force delete if you're sure
git branch -D feature-x
Prevention: Always merge or rebase before deleting branches
Issue 2: "Your branch has diverged"
Your branch and 'origin/main' have diverged,
and have 3 and 2 different commits each, respectively.
Solution:
# Option 1: Merge (preserves history)
git pull origin main
# Option 2: Rebase (linear history)
git pull --rebase origin main
Prevention: Pull before pushing, communicate with team
Issue 3: "Detached HEAD state"
You are in 'detached HEAD' state...
Solution:
# Create a new branch from current state
git checkout -b recovery-branch
# Or return to a branch
git checkout main
Prevention: Always work on branches, not commits
Issue 4: Complex merge conflicts Solution:
# Use merge tool
git mergetool
# Or manually resolve with three-way diff
git checkout --conflict=diff3 file.txt
# See common ancestor version
git show :1:file.txt # Common ancestor
git show :2:file.txt # Our version
git show :3:file.txt # Their version
Issue 5: Accidentally merged wrong branch Solution:
# Undo merge (if not pushed)
git reset --hard HEAD~1
# Revert merge (if pushed)
git revert -m 1 <merge-commit-hash>
# Find lost commits
git reflog
# Recover specific commit
git checkout <commit-hash>
git checkout -b recovery-branch
# Alternative: cherry-pick lost commit
git cherry-pick <commit-hash>
# Interactive rebase to fix commits
git rebase -i HEAD~5
# Options in interactive rebase:
# pick = use commit
# reword = change commit message
# edit = amend commit
# squash = combine with previous
# fixup = combine, discard message
# drop = remove commit
Branching and merging are essential skills for collaborative development. You've learned:
Challenge: Simulate a real-world feature development workflow
Requirements:
Starter Template:
# Initialize project
mkdir feature-branch-exercise
cd feature-branch-exercise
git init
# Create initial files
echo "# My App" > README.md
echo "console.log('Hello World');" > app.js
git add .
git commit -m "Initial commit"
# Your task: Add a new feature following GitHub Flow
# 1. Create feature branch for adding user authentication
# 2. Make changes in feature branch
# 3. Create another branch for updating README
# 4. Merge both branches handling any conflicts
# Step 1: Create feature branch
git checkout -b feature/user-authentication
# Step 2: Add authentication
echo "function authenticate(user, pass) {
// Authentication logic
return true;
}" >> app.js
git add app.js
git commit -m "Add user authentication function"
# Step 3: Create documentation branch
git checkout main
git checkout -b update/readme-auth-docs
# Step 4: Update README
echo "## Authentication
This app now supports user authentication." >> README.md
git add README.md
git commit -m "Document authentication feature"
# Step 5: Merge documentation first
git checkout main
git merge update/readme-auth-docs
# Step 6: Merge feature (might have conflicts)
git merge feature/user-authentication
# Step 7: Clean up
git branch -d feature/user-authentication
git branch -d update/readme-auth-docs
# Step 8: View your work
git log --oneline --graph --all
Key Learning Points:
Now that you understand branching and merging, you're ready to learn about collaboration workflows using pull requests and code reviews!