Git - Merging
Merging combines changes from different branches into one. It's how parallel development streams come together in Git, and understanding merging is essential for effective collaboration.
What is Merging?
Merging integrates changes from one branch into another. There are two main types:
Before merge:
main: A---B---C
\
feature: D---E
After merge:
main: A---B---C---D---E ← main moves forward
Before merge:
main: A---B---C---F
\
feature: D---E
After merge:
main: A---B---C---F---G ← G is merge commit
\ /
feature: D---E---/
Basic Merge Commands
Simple Merge
# Switch to target branch (usually main)
git switch main
# Merge feature branch
git merge feature-branch
Updating a1b2c3d..b2c3d4e
Fast-forward
feature.js | 25 +++++++++++++++++++++++++
README.md | 3 +++
2 files changed, 28 insertions(+)
Merge made by the 'ort' strategy.
feature.js | 25 +++++++++++++++++++++++++
README.md | 3 +++
2 files changed, 28 insertions(+)
Fast-Forward Merges
When the current branch hasn't diverged from the feature branch, Git can simply move the branch pointer forward:
Enabling/Disabling Fast-Forward
# Allow fast-forward (default)
git merge feature-branch
# Force merge commit even if fast-forward possible
git merge --no-ff feature-branch
# Only merge if fast-forward possible
git merge --ff-only feature-branch
When to Use --no-ff
- Preserve branch history visually
- Group related commits together
- Make it easy to revert entire features
- Follow team merge policies
Three-Way Merges
When branches have diverged, Git performs a three-way merge using:
- Base commit: Common ancestor of both branches
- Ours: Current branch's latest commit
- Theirs: Feature branch's latest commit
Merge Commit Messages
# Merge with custom message
git merge feature-branch -m "Merge feature: Add user authentication"
# Edit merge message in editor
git merge feature-branch # Opens editor for message
Merge branch 'feature-login' into main
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
Merge Conflicts
Conflicts occur when the same lines are modified in both branches. Git cannot automatically resolve these:
Conflict Example
Auto-merging config.js
CONFLICT (content): Merge conflict in config.js
Automatic merge failed; fix conflicts and then commit the result.
git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add ..." to mark resolution)
both modified: config.js
no changes added to commit (use "git add" or "git commit -a")
Conflict Markers
const config = {
database: {
<<<<<<< HEAD
host: 'localhost',
port: 5432
=======
host: 'production-db.example.com',
port: 3306
>>>>>>> feature-database
}
};
Conflict markers explained:
<<<<<<< HEAD
: Start of current branch's version=======
: Separator between versions>>>>>>> feature-database
: End of merging branch's version
Resolving Conflicts
# 1. Edit the conflicted file
nano config.js # Remove markers, choose/combine content
# 2. Stage the resolved file
git add config.js
# 3. Complete the merge
git commit # Uses default merge message
const config = {
database: {
host: process.env.NODE_ENV === 'production'
? 'production-db.example.com'
: 'localhost',
port: process.env.NODE_ENV === 'production' ? 3306 : 5432
}
};
Merge Tools
Built-in Merge Tool
# Launch merge tool
git mergetool
Configure External Tools
# Configure VS Code as merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# Configure vimdiff
git config --global merge.tool vimdiff
# Configure Beyond Compare
git config --global merge.tool bc3
git config --global mergetool.bc3.cmd "bcompare \$LOCAL \$REMOTE \$BASE \$MERGED"
Aborting Merges
# Abort merge and return to pre-merge state
git merge --abort
# Reset to before merge (more drastic)
git reset --hard HEAD~1
git reset --hard
will lose uncommitted changes. Use git merge --abort
when possible.
Advanced Merge Strategies
Merge Strategies
# Use specific merge strategy
git merge -s ort feature-branch # Default strategy
git merge -s resolve feature-branch # Three-way merge only
git merge -s octopus branch1 branch2 branch3 # Multiple branches
Strategy Options
# Favor our changes during conflicts
git merge -X ours feature-branch
# Favor their changes during conflicts
git merge -X theirs feature-branch
# Ignore whitespace changes
git merge -X ignore-space-change feature-branch
Squash Merging
Squash merging combines all commits from the feature branch into a single commit:
# Squash merge (doesn't create merge commit)
git merge --squash feature-branch
# Review changes
git diff --staged
# Commit the squashed changes
git commit -m "Add user authentication feature
- Add login form component
- Implement password validation
- Add session management
- Update user interface"
main: A---B---C
\
feature: D---E---F---G
main: A---B---C---H ← H contains all changes from D,E,F,G
\
feature: D---E---F---G ← Branch still exists
Merge Workflows
Feature Branch Workflow
# 1. Update main branch
git switch main
git pull origin main
# 2. Switch to feature branch
git switch feature-user-auth
# 3. Rebase on latest main (optional)
git rebase main
# 4. Switch back to main
git switch main
# 5. Merge feature
git merge --no-ff feature-user-auth
# 6. Push merged changes
git push origin main
# 7. Delete feature branch
git branch -d feature-user-auth
git push origin --delete feature-user-auth
Release Branch Workflow
# Merge release branch to main
git switch main
git merge --no-ff release/v1.2.0
# Tag the release
git tag -a v1.2.0 -m "Release version 1.2.0"
# Merge back to develop
git switch develop
git merge --no-ff release/v1.2.0
# Clean up
git branch -d release/v1.2.0
Merge History and Analysis
Viewing Merge History
# Show merge commits only
git log --merges --oneline
# Show first parent only (main line of development)
git log --first-parent --oneline
# Show graph with merge visualization
git log --graph --oneline --all
Finding Merge Information
# Show what branches were merged
git show --format=fuller merge-commit-hash
# Find merge that introduced a commit
git log --merges --ancestry-path commit-hash..HEAD
# Show merge conflicts that were resolved
git show merge-commit-hash
Troubleshooting Merge Issues
Large Number of Conflicts
# See all conflicted files
git diff --name-only --diff-filter=U
# Check merge progress
git status
# Use merge tool for each conflict
git mergetool
Merge Commit Problems
# Undo last merge (if not pushed)
git reset --hard HEAD~1
# Revert merge commit (safe for pushed changes)
git revert -m 1 merge-commit-hash
Best Practices
Before Merging
- ✅ Update your main branch
- ✅ Test your feature branch thoroughly
- ✅ Consider rebasing feature branch on main
- ✅ Review all changes one final time
Merge Strategies by Project Type
# Preserve contribution history
git merge --no-ff contributor-branch
# Squash small features
git merge --squash small-feature
# Regular merge for significant features
git merge --no-ff major-feature
Merge Configuration
# Default merge behavior
git config --global merge.ff false # Always create merge commits
# Default merge tool
git config --global merge.tool vscode
# Keep backup files from merge tool
git config --global mergetool.keepBackup false
# Show common ancestor in conflict markers
git config --global merge.conflictstyle diff3
Summary
You now understand Git merging:
- ✅ Fast-forward vs three-way merges
- ✅ Merge conflicts and resolution techniques
- ✅ Merge tools for easier conflict resolution
- ✅ Squash merging for clean history
- ✅ Different merge strategies and options
- ✅ Workflow patterns for different scenarios
- ✅ Troubleshooting and undoing merges
Next Steps
Now that you understand merging, let's explore more advanced branching techniques: