Skip to content

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.

Terminal window
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)
OptionDescription
--no-commitPerform merge but don’t create commit
--no-editAccept auto-generated merge message
--editEdit merge message before committing
--no-verifySkip pre-commit and commit-msg hooks
--no-ffCreate merge commit even for fast-forward
--ffAllow fast-forward merges
--no-ffDisable fast-forward merges
--ff-onlyOnly allow fast-forward merges
OptionDescription
-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
OptionDescription
-m <message>Use commit message
-F <file>Read message from file
--log[=<n>]Include merge description
--no-logDon’t include merge description
OptionDescription
--squashMerge but don’t create merge commit
--allow-unrelated-historiesAllow merging unrelated histories
--rerere-autoupdateUpdate index with reused conflict resolutions
--no-rerere-autoupdateDon’t update index with reused resolutions
-S[<keyid>]GPG-sign merge commit
--into-name <branch>Use name for merge result instead of current branch
OptionDescription
-n, --no-statDon’t show diffstat
--statShow diffstat at end
--compact-summaryShow compact summary instead of full diff
-q, --quietQuiet operation
-v, --verboseVerbose operation
OptionDescription
--continueContinue after conflict resolution
--abortAbort merge and return to pre-merge state
--quitStop merge but keep state (since Git 2.41)
ParameterDescription
<commit>...Commits to merge into current branch
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
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
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
Terminal window
# Merge feature branch into main
git checkout main
git merge feature-branch
# Merge with custom message
git merge -m "Add new login feature" feature-login
# Merge multiple branches (octopus merge)
git merge -m "Merge three features" feature-1 feature-2 feature-3
Terminal window
# Allow fast-forward (default)
git merge feature-branch
# Force merge commit
git merge --no-ff feature-branch
# Only allow fast-forward
git merge --ff-only feature-branch
Terminal window
# Start merge
git merge feature-branch
# If conflicts occur, resolve them:
# Edit conflicted files
# Add resolved files
git add resolved-file.txt
# Continue merge
git merge --continue
# Or abort merge
git merge --abort
Terminal window
# Merge three feature branches simultaneously
git 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 branches
Terminal window
# Merge subdirectory from another repository
git remote add other-repo https://github.com/other/repo.git
git merge -s subtree other-repo/main
# With subdirectory prefix
git merge -s subtree -Xsubtree=vendor/library other-repo/vendor/library
Terminal window
# Accept all changes from other branch (ours)
git merge -s ours -m "Accept all changes" other-branch
# Resolve conflicts by choosing our version
git merge -X ours conflict-resolution-branch
# Resolve conflicts by choosing their version
git merge -X theirs theirs-take-precedence
Terminal window
# Standard three-way recursive merge
git merge -s recursive feature-branch
# Handle renames
git merge -X find-renames feature-branch
# Ignore whitespace differences
git merge -X ignore-space-change feature-branch
# Ignore all whitespace
git merge -X ignore-all-space feature-branch
Terminal window
# Faster but less capable merge
git merge -s resolve simple-feature
# Good for large repositories or simple merges
# Doesn't handle rename conflicts
Terminal window
# Automatic when merging >2 branches
git merge feature1 feature2 feature3
# Manual octopus strategy
git merge -s octopus parallel-feature1 parallel-feature2
Terminal window
# Record merge but ignore other branch content
git merge -s ours -m "Mark merge point" legacy-branch
# Useful for marking integration points without code changes
Terminal window
# Import external project as subdirectory
git merge -s subtree external-project/master
# Strategy for managing subproject imports
git merge -X subtree=lib/third-party third-party-lib/feature
Terminal window
# Check conflict status
git status
# View conflict markers in files
cat conflicted-file.txt
# Resolve conflicts manually
# Edit conflicted-file.txt
# Remove conflict markers
# Save changes
# Stage resolved file
git add conflicted-file.txt
# Continue merge
git merge --continue
# Or abort if problems
git merge --abort
Terminal window
# Configure merge tool
git config merge.tool vscode
git config mergetool.vscode.cmd "code --wait $MERGED"
# Launch mergetool during merge
git mergetool
# Check resolved files
git status
# Complete merge
git merge --continue
Terminal window
# Use previous conflict solutions
git config rerere.enabled true
git merge --rerere-autoupdate feature-branch
# Accept resolved conflicts from previous merges
# Git remembers and auto-applies previous resolutions
#!/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"
Terminal window
# Merge release branch back to main
create_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"
Terminal window
# Handle stacked feature branches
merge_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 branches
merge_stacked_branches "main" \
"auth/feature-login" \
"auth/feature-registration" \
"auth/feature-password-reset"
Terminal window
# Structured merge with branch naming
merge_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"
Terminal window
# Pre-merge conflict check
check_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 merge
if check_for_conflicts "feature-x"; then
git merge --no-ff "feature-x"
fi
Terminal window
# Controlled release integration
stabilize_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_release
Terminal window
# Check merge status
git status
# See what branches are being merged
git log --oneline --graph HEAD~10..
# Abort merge
git merge --abort
# Reset to pre-merge state
git reset --hard ORIG_HEAD
Terminal window
# When octopus merge fails
git status
# Check which heads are conflicting
cat .git/MERGE_HEAD
# Individual branch merging
for head in $(cat .git/MERGE_HEAD); do
echo "Merging $(git show --no-patch --format=%s $head)"
# Handle each merge individually
done
Terminal window
# Allow unrelated histories
git merge --allow-unrelated-histories unrelated-branch
# Check if histories are related
git merge-base HEAD other-branch >/dev/null 2>&1 || echo "Unrelated"
Terminal window
# Optimize for large repos
git config merge.renameLimit 999999
git config diff.renameLimit 999999
# Use content-aware rename detection
git merge -X find-renames=50 -X rename-threshold=50 large-feature-branch
Terminal window
# Check repository state
git status
ls -la .git/
# Handle locked files
rm -f .git/index.lock
rm -f .git/MERGE_HEAD
rm -f .git/MERGE_MSG
# Reset index if needed
git reset --merge
Terminal window
# Comprehensive feature merge workflow
integrate_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
}
# Usage
integrate_feature "feature/user-notifications" "develop"
Terminal window
# Controlled release merge process
perform_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"
Terminal window
# Handle merges in distributed team workflow
coordinated_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_merge

What’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.

Use merge to preserve complete histories and show collaboration. Use rebase for clean linear history on personal branches. Never rebase shared branches.

Edit conflicted files to remove conflict markers, choose correct version of changes, stage resolved files with git add, then git merge —continue.

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.

git merge —abort cancels merge and returns to pre-merge state. Only works after conflicts occur.

Fast-forward moves branch pointer without merge commit (linear history). Three-way merge creates merge commit with two parents.

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.

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.

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.

Scripts should run git merge, check for conflicts with git status —porcelain, use automated resolution tools, or mark build as failed.

  1. Feature Branch Integration: Combine feature development branches back into main development line
  2. Release Management: Merge release branches into production with proper tracking and approvals
  3. Collaborative Development: Enable team members to integrate their work while preserving contribution history
  4. Version Control Strategies: Support various Git workflows including Gitflow, GitHub Flow, and trunk-based development
  5. Conflict Resolution: Provide robust mechanisms for handling conflicting changes between branches
  6. Continuous Integration: Enable automated merging and deployment processes in CI/CD pipelines