merge Git Command Guide
The git merge command incorporates changes from named commits into the current branch since the time their histories diverged. It creates a new merge commit that preserves the complete history of both branches and provides conflict resolution when changes overlap.
git merge Syntax:
Section titled “git merge Syntax:”git merge [-n] [--stat] [--compact-summary] [--no-commit] [--squash] [--[no-]edit] [--no-verify] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]] [--[no-]allow-unrelated-histories] [--[no-]rerere-autoupdate] [-m <msg>] [-F <file>] [--into-name <branch>] [<commit>...]git merge (--continue | --abort | --quit)Merge Control Options:
Section titled “Merge Control Options:”| Option | Description |
|---|---|
--no-commit | Perform merge but don’t create commit |
--no-edit | Accept auto-generated merge message |
--edit | Edit merge message before committing |
--no-verify | Skip pre-commit and commit-msg hooks |
--no-ff | Create merge commit even for fast-forward |
--ff | Allow fast-forward merges |
--no-ff | Disable fast-forward merges |
--ff-only | Only allow fast-forward merges |
Merge Strategy Options:
Section titled “Merge Strategy Options:”| Option | Description |
|---|---|
-s <strategy> | Use specified merge strategy |
-X <option> | Pass option to merge strategy |
--strategy=<strategy> | Strategy: resolve, recursive, octopus, ours, subtree |
--strategy-option=<opt> | Pass option to strategy |
Commit Message Options:
Section titled “Commit Message Options:”| Option | Description |
|---|---|
-m <message> | Use commit message |
-F <file> | Read message from file |
--log[=<n>] | Include merge description |
--no-log | Don’t include merge description |
Advanced Options:
Section titled “Advanced Options:”| Option | Description |
|---|---|
--squash | Merge but don’t create merge commit |
--allow-unrelated-histories | Allow merging unrelated histories |
--rerere-autoupdate | Update index with reused conflict resolutions |
--no-rerere-autoupdate | Don’t update index with reused resolutions |
-S[<keyid>] | GPG-sign merge commit |
--into-name <branch> | Use name for merge result instead of current branch |
Output Control Options:
Section titled “Output Control Options:”| Option | Description |
|---|---|
-n, --no-stat | Don’t show diffstat |
--stat | Show diffstat at end |
--compact-summary | Show compact summary instead of full diff |
-q, --quiet | Quiet operation |
-v, --verbose | Verbose operation |
Conflict Resolution:
Section titled “Conflict Resolution:”| Option | Description |
|---|---|
--continue | Continue after conflict resolution |
--abort | Abort merge and return to pre-merge state |
--quit | Stop merge but keep state (since Git 2.41) |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<commit>... | Commits to merge into current branch |
Understanding Merge Types:
Section titled “Understanding Merge Types:”Fast-Forward Merge:
Section titled “Fast-Forward Merge:”Before: A---B---C (main) \ D (feature)
After: A---B---C---D (main)- Current branch pointer moves forward
- No merge commit created
- Linear history preserved
Three-Way Merge:
Section titled “Three-Way Merge:”Before: A---B---C (main) \ D---E (feature)
After: A---B---C---F (main) \ / D---E- Creates merge commit with two parents
- Preserves both branch histories
- Shows where branches diverged and merged
Squash Merge:
Section titled “Squash Merge:”Before: A---B---C---D (main) \ E---F (feature)
After: A---B---C---G (main)- Combines feature commits into single commit
- Doesn’t preserve individual commits
- Feature branch history lost
Basic Merge Examples:
Section titled “Basic Merge Examples:”Merge a Feature Branch:
Section titled “Merge a Feature Branch:”# Merge feature branch into maingit checkout maingit merge feature-branch
# Merge with custom messagegit merge -m "Add new login feature" feature-login
# Merge multiple branches (octopus merge)git merge -m "Merge three features" feature-1 feature-2 feature-3Fast-Forward vs Non-Fast-Forward:
Section titled “Fast-Forward vs Non-Fast-Forward:”# Allow fast-forward (default)git merge feature-branch
# Force merge commitgit merge --no-ff feature-branch
# Only allow fast-forwardgit merge --ff-only feature-branchMerge with Conflicts:
Section titled “Merge with Conflicts:”# Start mergegit merge feature-branch
# If conflicts occur, resolve them:# Edit conflicted files# Add resolved filesgit add resolved-file.txt
# Continue mergegit merge --continue
# Or abort mergegit merge --abortAdvanced Merge Scenarios:
Section titled “Advanced Merge Scenarios:”Octopus Merge (Multiple Branches):
Section titled “Octopus Merge (Multiple Branches):”# Merge three feature branches simultaneouslygit merge -m "Integrate multiple features" \ feature-auth feature-api feature-ui
# Octopus merge creates single merge commit with multiple parents# Useful for combining independent feature branchesSubtree Merging:
Section titled “Subtree Merging:”# Merge subdirectory from another repositorygit remote add other-repo https://github.com/other/repo.gitgit merge -s subtree other-repo/main
# With subdirectory prefixgit merge -s subtree -Xsubtree=vendor/library other-repo/vendor/libraryOurs/Theirs Strategies:
Section titled “Ours/Theirs Strategies:”# Accept all changes from other branch (ours)git merge -s ours -m "Accept all changes" other-branch
# Resolve conflicts by choosing our versiongit merge -X ours conflict-resolution-branch
# Resolve conflicts by choosing their versiongit merge -X theirs theirs-take-precedenceMerge Strategies Explained:
Section titled “Merge Strategies Explained:”Recursive Strategy (Default):
Section titled “Recursive Strategy (Default):”# Standard three-way recursive mergegit merge -s recursive feature-branch
# Handle renamesgit merge -X find-renames feature-branch
# Ignore whitespace differencesgit merge -X ignore-space-change feature-branch
# Ignore all whitespacegit merge -X ignore-all-space feature-branchResolve Strategy:
Section titled “Resolve Strategy:”# Faster but less capable mergegit merge -s resolve simple-feature
# Good for large repositories or simple merges# Doesn't handle rename conflictsOctopus Strategy:
Section titled “Octopus Strategy:”# Automatic when merging >2 branchesgit merge feature1 feature2 feature3
# Manual octopus strategygit merge -s octopus parallel-feature1 parallel-feature2Ours Strategy:
Section titled “Ours Strategy:”# Record merge but ignore other branch contentgit merge -s ours -m "Mark merge point" legacy-branch
# Useful for marking integration points without code changesSubtree Strategy:
Section titled “Subtree Strategy:”# Import external project as subdirectorygit merge -s subtree external-project/master
# Strategy for managing subproject importsgit merge -X subtree=lib/third-party third-party-lib/featureConflict Resolution Workflow:
Section titled “Conflict Resolution Workflow:”Resolving Merge Conflicts:
Section titled “Resolving Merge Conflicts:”# Check conflict statusgit status
# View conflict markers in filescat conflicted-file.txt
# Resolve conflicts manually# Edit conflicted-file.txt# Remove conflict markers# Save changes
# Stage resolved filegit add conflicted-file.txt
# Continue mergegit merge --continue
# Or abort if problemsgit merge --abortUsing Mergetool for Conflicts:
Section titled “Using Mergetool for Conflicts:”# Configure merge toolgit config merge.tool vscodegit config mergetool.vscode.cmd "code --wait $MERGED"
# Launch mergetool during mergegit mergetool
# Check resolved filesgit status
# Complete mergegit merge --continueAutomated Conflict Resolution:
Section titled “Automated Conflict Resolution:”# Use previous conflict solutionsgit config rerere.enabled truegit merge --rerere-autoupdate feature-branch
# Accept resolved conflicts from previous merges# Git remembers and auto-applies previous resolutionsIntegration with Development Workflows:
Section titled “Integration with Development Workflows:”Pull Request / Merge Request Integration:
Section titled “Pull Request / Merge Request Integration:”#!/bin/bash# PR merge workflow
merge_pr() { local pr_branch="$1" local target_branch="${2:-main}" local pr_title="$3"
# Switch to target branch git checkout "$target_branch" git pull origin "$target_branch"
# Merge PR with full information git merge "$pr_branch" \ --no-ff \ -m "Merge pull request: $pr_title
This merge incorporates changes from $pr_branch into $target_branch.PR includes [list changes or link to PR]"
if [ $? -ne 0 ]; then echo "Merge failed. Please resolve conflicts and run:" echo "git merge --continue" return 1 fi
# Push merged changes git push origin "$target_branch" echo "PR successfully merged to $target_branch"}
merge_pr "feature/authentication" "develop" "Add user authentication"Release Branch Management:
Section titled “Release Branch Management:”# Merge release branch back to maincreate_release() { local version="$1" local release_branch="release/v$version"
# Create release branch from develop git checkout -b "$release_branch" develop
# Perform release testing and finalization # ... testing steps ...
# Merge back to main with version tag git checkout main git pull origin main
git merge --no-ff "$release_branch" \ -m "Release v$version"
# Create version tag git tag -a "v$version" -m "Release version $version" \ -m "Merged features: [list major features]" \ -m "Bug fixes: [list critical fixes]"
# Merge to develop for continued development git checkout develop git merge main
# Clean up release branch git branch -d "$release_branch"
# Push changes git push origin main develop --tags}
create_release "3.2.1"Stacked Branch Workflows:
Section titled “Stacked Branch Workflows:”# Handle stacked feature branchesmerge_stacked_branches() { local base_branch="${1:-main}" local feature_branches=("${@:2}")
git checkout "$base_branch" git pull origin "$base_branch"
for branch in "${feature_branches[@]}"; do echo "Merging $branch..."
if git merge --no-ff -m "Merge $branch" "$branch"; then echo "✓ Successfully merged $branch"
# Optional: delete merged branch # git branch -d "$branch"
else echo "✗ Failed to merge $branch" echo "Resolve conflicts and run: git merge --continue" return 1 fi done
echo "All branches merged successfully" git push origin "$base_branch"}
# Merge stacked PR branchesmerge_stacked_branches "main" \ "auth/feature-login" \ "auth/feature-registration" \ "auth/feature-password-reset"Merge Best Practices and Patterns:
Section titled “Merge Best Practices and Patterns:”Branch Naming Convention Integration:
Section titled “Branch Naming Convention Integration:”# Structured merge with branch namingmerge_feature_branch() { local feature_branch="$1" local branch_type
# Extract branch type from name if [[ "$feature_branch" == feature/* ]]; then branch_type="New feature" elif [[ "$feature_branch" == bugfix/* ]]; then branch_type="Bug fix" elif [[ "$feature_branch" == hotfix/* ]]; then branch_type="Hotfix" fi
# Perform merge with structured message git merge --no-ff "$feature_branch" \ -m "$branch_type: ${feature_branch#*/}" \ -m "" \ -m "Merged from: $feature_branch" \ -m "Original PR: [link to PR if applicable]"
# Tag the merge for traceability git tag "merge/${feature_branch//\//-}-$(date +%Y%m%d)"}
merge_feature_branch "feature/user-dashboard"Conflict Prediction and Prevention:
Section titled “Conflict Prediction and Prevention:”# Pre-merge conflict checkcheck_for_conflicts() { local source_branch="$1" local target_branch="${2:-main}"
echo "Checking for potential conflicts between $source_branch and $target_branch"
# Check for modified files common_files=$(git diff --name-only "$target_branch..$source_branch" "$target_branch")
if [ -z "$common_files" ]; then echo "✓ No conflicts expected" return 0 fi
echo "Files changed in both branches:" echo "$common_files"
# Test actual merge if git merge-tree "$target_branch" "$source_branch" >/dev/null 2>&1; then echo "✓ Clean merge possible" return 0 else echo "⚠ Conflicts detected in merge" return 1 fi}
# Use before actual mergeif check_for_conflicts "feature-x"; then git merge --no-ff "feature-x"fiRelease Stabilization Patterns:
Section titled “Release Stabilization Patterns:”# Controlled release integrationstabilize_release() { local stabilization_branch="stabilization/v$(date +%Y.%m)" local release_branches=("release/sprint-21" "release/sprint-22" "hotfix/critical-bug")
# Create stabilization branch git checkout -b "$stabilization_branch" main
for release_branch in "${release_branches[@]}"; do echo "Integrating $release_branch..."
git merge --no-ff "$release_branch" \ -m "Integrate $release_branch into stabilization" \ -m "" \ -m "Included changes:" -m "$(git log --oneline "$stabilization_branch..$release_branch")"
if [ $? -ne 0 ]; then echo "Failed to integrate $release_branch" return 1 fi done
# Perform stabilization testing echo "Stabilization branch ready for testing: $stabilization_branch"}
stabilize_releaseTroubleshooting Common Merge Issues:
Section titled “Troubleshooting Common Merge Issues:”Failed Auto-merge:
Section titled “Failed Auto-merge:”# Check merge statusgit status
# See what branches are being mergedgit log --oneline --graph HEAD~10..
# Abort mergegit merge --abort
# Reset to pre-merge stategit reset --hard ORIG_HEADMultiple Merge Heads:
Section titled “Multiple Merge Heads:”# When octopus merge failsgit status
# Check which heads are conflictingcat .git/MERGE_HEAD
# Individual branch mergingfor head in $(cat .git/MERGE_HEAD); do echo "Merging $(git show --no-patch --format=%s $head)" # Handle each merge individuallydoneUnrelated Histories:
Section titled “Unrelated Histories:”# Allow unrelated historiesgit merge --allow-unrelated-histories unrelated-branch
# Check if histories are relatedgit merge-base HEAD other-branch >/dev/null 2>&1 || echo "Unrelated"Large Repository Merges:
Section titled “Large Repository Merges:”# Optimize for large reposgit config merge.renameLimit 999999git config diff.renameLimit 999999
# Use content-aware rename detectiongit merge -X find-renames=50 -X rename-threshold=50 large-feature-branchPermission and Access Issues:
Section titled “Permission and Access Issues:”# Check repository stategit statusls -la .git/
# Handle locked filesrm -f .git/index.lockrm -f .git/MERGE_HEADrm -f .git/MERGE_MSG
# Reset index if neededgit reset --mergeReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Feature Branch Integration:
Section titled “Feature Branch Integration:”# Comprehensive feature merge workflowintegrate_feature() { local feature_branch="$1" local base_branch="${2:-develop}"
echo "Integrating feature: $feature_branch into $base_branch"
# Validation git checkout "$base_branch" git pull origin "$base_branch"
# Check if feature branch exists and is up to date if ! git rev-parse --verify "$feature_branch" >/dev/null 2>&1; then echo "Error: Feature branch $feature_branch does not exist" return 1 fi
# Check for conflicts ahead of time if git merge-tree "$base_branch" "$feature_branch" >/dev/null 2>&1; then echo "✓ No conflicts detected" else echo "⚠ Conflicts may occur - proceeding with caution" fi
# Perform the merge if git merge --no-ff -m "Integrate feature: $feature_branch" \ -m "" \ -m "Feature branch: $feature_branch" \ -m "Commits integrated: $(git rev-list --count "$base_branch..$feature_branch")" \ "$feature_branch"; then
echo "✓ Feature successfully integrated"
# Optional: Delete feature branch if git branch -d "$feature_branch" 2>/dev/null; then echo "✓ Feature branch cleaned up" fi
# Push changes git push origin "$base_branch"
else echo "✗ Merge failed" echo "Resolve conflicts and run: git merge --continue" echo "Or abort with: git merge --abort" return 1 fi}
# Usageintegrate_feature "feature/user-notifications" "develop"Enterprise Release Management:
Section titled “Enterprise Release Management:”# Controlled release merge processperform_release_merge() { local release_version="$1" local release_branch="release/$release_version" local staging_branch="staging" local production_branch="main"
echo "=== Release Merge Process: v$release_version ==="
# Validate release branch if ! git rev-parse --verify "$release_branch" >/dev/null 2>&1; then echo "Error: Release branch $release_branch does not exist" return 1 fi
# Step 1: Merge to staging echo "Step 1: Merging to staging environment" git checkout "$staging_branch" git pull origin "$staging_branch"
git merge --no-ff "$release_branch" \ -m "Deploy v$release_version to staging" \ -m "Release branch: $release_branch" \ -m "Approved by: [approval info]" \ -m "Testing checklist: [link to test results]"
if [ $? -ne 0 ]; then echo "Staging merge failed" return 1 fi
# Run staging tests echo "Running staging tests..." if ! ./run-staging-tests.sh; then echo "Staging tests failed" git merge --abort 2>/dev/null || git reset --hard ORIG_HEAD return 1 fi
# Step 2: Merge to production (manual approval usually) echo "Step 2: Ready for production deployment" echo "To merge to production, run:" echo "git checkout $production_branch" echo "git merge --no-ff $staging_branch -m 'Release v$release_version to production'" echo "git tag -a v$release_version_production -m 'Production release v$release_version'"
echo "Release v$release_version successfully deployed to staging"}
perform_release_merge "3.2.1"Distributed Team Collaboration:
Section titled “Distributed Team Collaboration:”# Handle merges in distributed team workflowcoordinated_team_merge() { local feature_branches=("auth", "api", "frontend", "testing") local integration_branch="ready-for-merge"
# Create clean integration branch git checkout -b "$integration_branch" main
for feature in "${feature_branches[@]}"; do feature_branch="feature/$feature"
echo "Integrating $feature..."
# Check if feature is ready (has approval) if ! git log --grep="Reviewed-by:" --oneline "$feature_branch" | head -1 >/dev/null; then echo "⚠ $feature_branch not reviewed yet" continue fi
# Perform integration merge git merge --no-edit "$feature_branch" \ -m "Integrate $feature"
if [ $? -ne 0 ]; then echo "✗ Integration failed for $feature" echo "Resolve and continue with: git merge --continue" return 1 fi
echo "✓ $feature integrated successfully" done
echo "All features integrated into $integration_branch" echo "Ready for final review and merge to main"
# Create integration notes git notes add -m "Integrated features: ${feature_branches[*]}" \ -m "Integration branch: $integration_branch" \ -m "Integrated by: $(git config user.name)"}
coordinated_team_mergeWhat’s the difference between git merge and git pull?
Section titled “What’s the difference between git merge and git pull?”git pull fetches and merges in one operation. git merge only performs the merge. Use merge for manual control, pull for automated updates.
When should I use merge vs rebase?
Section titled “When should I use merge vs rebase?”Use merge to preserve complete histories and show collaboration. Use rebase for clean linear history on personal branches. Never rebase shared branches.
How do I resolve merge conflicts?
Section titled “How do I resolve merge conflicts?”Edit conflicted files to remove conflict markers, choose correct version of changes, stage resolved files with git add, then git merge —continue.
What does —no-ff do?
Section titled “What does —no-ff do?”Forces creation of merge commit even when fast-forward possible. Preserves branch history and shows intentional merges.
Can I use git merge on uncommitted changes?
Section titled “Can I use git merge on uncommitted changes?”No, working directory must be clean. Commit or stash changes first, then merge.
How do I abort a merge?
Section titled “How do I abort a merge?”git merge —abort cancels merge and returns to pre-merge state. Only works after conflicts occur.
What’s fast-forward vs three-way merge?
Section titled “What’s fast-forward vs three-way merge?”Fast-forward moves branch pointer without merge commit (linear history). Three-way merge creates merge commit with two parents.
Can I merge from multiple branches?
Section titled “Can I merge from multiple branches?”Yes, octopus merge allows >2 branches: git merge branch1 branch2 branch3 creates multi-parent merge commit.
What’s the difference between squash and merge?
Section titled “What’s the difference between squash and merge?”Merge preserves all commits and creates merge commit. Squash combines all commits into single commit on target branch.
How do I sign merge commits?
Section titled “How do I sign merge commits?”Use -S option: git merge -S branch-name requires GPG key setup.
What does —allow-unrelated-histories do?
Section titled “What does —allow-unrelated-histories do?”Allows merging repositories with no shared history. Use with care as it may cause unexpected conflicts.
How do I handle large merges with many files?
Section titled “How do I handle large merges with many files?”Increase git limits: git config merge.renameLimit 999999, git config diff.renameLimit 999999. Consider splitting large merges.
Can I preview a merge before doing it?
Section titled “Can I preview a merge before doing it?”Use git merge-tree base-branch feature-branch to simulate merge and check for conflicts without modifying repository.
What’s the relationship between merge and merge-base?
Section titled “What’s the relationship between merge and merge-base?”git merge-base finds common ancestor for three-way merge. Git merge uses merge-base internally when creating merge commits.
How do I handle merge conflicts in CI/CD?
Section titled “How do I handle merge conflicts in CI/CD?”Scripts should run git merge, check for conflicts with git status —porcelain, use automated resolution tools, or mark build as failed.
Applications of the git merge command
Section titled “Applications of the git merge command”- Feature Branch Integration: Combine feature development branches back into main development line
- Release Management: Merge release branches into production with proper tracking and approvals
- Collaborative Development: Enable team members to integrate their work while preserving contribution history
- Version Control Strategies: Support various Git workflows including Gitflow, GitHub Flow, and trunk-based development
- Conflict Resolution: Provide robust mechanisms for handling conflicting changes between branches
- Continuous Integration: Enable automated merging and deployment processes in CI/CD pipelines