Skip to content

merge-base Git Command Guide

The git merge-base command finds the best common ancestor(s) between two or more commits to use in a three-way merge. It identifies the most appropriate merge base for resolving conflicts and understanding development history relationships.

Terminal window
git merge-base [-a | --all] <commit> <commit>...
git merge-base [-a | --all] --octopus <commit>...
git merge-base --is-ancestor <commit> <commit>
git merge-base --independent <commit>...
git merge-base --fork-point <ref> [<commit>]
ModeDescription
<commit> <commit>Find best common ancestor between two commits
--allShow all merge bases, not just the best one
--octopusCompute merge base for octopus merge (multiple branches)
ModeDescription
--is-ancestor <commit> <commit>Test if first commit is ancestor of second
--independent <commit>...Find minimal set of commits with no common ancestors
--fork-point <ref> [<commit>]Find commit where branch forked from reference
ParameterDescription
<commit>Commit SHA, branch name, or tag reference
<ref>Reference point (usually branch or remote)
Terminal window
# Find merge base between two commits
git merge-base main feature-branch
# Find merge base between HEAD and specific commit
git merge-base HEAD abc123
# Find merge base between two branch refs
git merge-base origin/main develop
Terminal window
# Show all merge bases (not just best one)
git merge-base --all main feature1 feature2
# Octopus merge base for three branches
git merge-base --octopus main feature1 feature2 feature3
Terminal window
# Test if commit is ancestor of another
git merge-base --is-ancestor main HEAD && echo "main is ancestor"
# Find independent commits (no common ancestors)
git merge-base --independent HEAD~5 HEAD~3 HEAD~1
Terminal window
# Find where current branch forked from main
git merge-base --fork-point main
# Find fork point for specific branch
git merge-base --fork-point main feature-branch
Terminal window
# Diamond merge pattern
git merge-base HEAD^1 HEAD^2 # Find base of merge commit
# Cross-branch comparison
git merge-base release/v1 release/v2
# Release branching strategy
git merge-base --all develop release/v1 release/v2
Terminal window
# Before merging, find appropriate merge base
BASE=$(git merge-base HEAD MERGE_HEAD)
echo "Using merge base: $BASE"
# Check what files changed since merge base
git diff --name-only $BASE
# Three-way diff for conflict analysis
git diff $BASE HEAD MERGE_HEAD -- file-with-conflict.txt
Terminal window
# Find common base between two releases
git merge-base --all v1.0 v2.0
# Determine hotfix merge strategy
HOTFIX_BASE=$(git merge-base production hotfix-123)
git log $HOTFIX_BASE..hotfix-123 # Changes in hotfix
#!/bin/bash
# Determine appropriate merge strategy
source_branch="$1"
target_branch="${2:-main}"
# Find merge base
merge_base=$(git merge-base "$target_branch" "$source_branch")
if [ $? -ne 0 ]; then
echo "Branches have no common history - force merge required"
exit 1
fi
# Check if fast-forward is possible
if git merge-base --is-ancestor "$source_branch" "$target_branch"; then
echo "Fast-forward merge possible"
git merge --ff-only "$source_branch"
elif git merge-base --is-ancestor "$target_branch" "$source_branch"; then
echo "Already up to date"
exit 0
else
echo "Three-way merge required with base: $merge_base"
git merge --no-ff "$source_branch"
fi
Terminal window
# Analyze branch relationships in repository
analyze_branches() {
local branch1="$1"
local branch2="$2"
merge_base=$(git merge-base "$branch1" "$branch2" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "=== Branch Analysis: $branch1 vs $branch2 ==="
echo "Merge base: $merge_base"
# Check relationships
if git merge-base --is-ancestor "$merge_base" "$branch1" 2>/dev/null; then
echo "$branch1 contains merge base"
fi
if git merge-base --is-ancestor "$merge_base" "$branch2" 2>/dev/null; then
echo "$branch2 contains merge base"
fi
# Count commits from merge base
commits1=$(git rev-list --count "$merge_base..$branch1")
commits2=$(git rev-list --count "$merge_base..$branch2")
echo "Commits since merge-base:"
echo " $branch1: $commits1"
echo " $branch2: $commits2"
# Divergence analysis
if [ "$commits1" -eq 0 ] && [ "$commits2" -eq 0 ]; then
echo "Branches are identical"
elif [ "$commits1" -eq 0 ]; then
echo "$branch1 can fast-forward to $branch2"
elif [ "$commits2" -eq 0 ]; then
echo "$branch2 can fast-forward to $branch1"
else
echo "Branches have diverged - $((commits1 + commits2)) total commits"
fi
else
echo "Branches have no common history"
fi
}
# Usage
analyze_branches main feature-x
analyze_branches develop release/v1
Terminal window
# Pre-merge validation in CI
validate_merge() {
local source_commit="$1"
local target_branch="$2"
# Find merge base
merge_base=$(git merge-base "$target_branch" "$source_commit")
if [ $? -ne 0 ]; then
echo "ERROR: No common history - merge not possible"
exit 1
fi
echo "Merge base: $merge_base"
# Test merge without committing
if git merge-tree "$merge_base" "$target_branch" "$source_commit" >/dev/null 2>&1; then
echo "✓ Clean merge possible"
return 0
else
echo "⚠ Conflicts detected - manual resolution needed"
# Show conflicting files
git merge-tree "$merge_base" "$target_branch" "$source_commit" |
grep "^<<<<<<<\|^=======\|^>>>>>>>" -B1 -A1 | head -10
return 1
fi
}
# Usage in CI
if validate_merge "${CI_MERGE_REQUEST_TARGET_BRANCH}" "${CI_COMMIT_SHA}"; then
echo "Merge validation passed"
else
echo "Merge validation failed"
exit 1
fi
A - B - C (main branch)
\
D - E (feature branch)
Merge base: B (best common ancestor)
A - B - E - F
| \ /
| X
| / \
C - D - Y - G
Merge bases: [B, D] (both are equally good)
Use --all to see all merge bases
H (merge commit)
/|\
C -- D | F -- G
/ | \
A -- B E I
|
J -- K
Merge base: A (common ancestor for 3-way octopus merge)
Terminal window
# Check repository state
git log --oneline --all --graph | head -20
# Verify commit exists
git cat-file -t "$COMMIT_HASH"
# Check for disconnected histories
git log --oneline "$BRANCH1" "$BRANCH2" --not $(git merge-base --all "$BRANCH1" "$BRANCH2") | head -5
Terminal window
# Show all merge bases
git merge-base --all branch1 branch2
# Choose appropriate one based on context
# Usually the oldest (first) one is preferred
bases=( $(git merge-base --all branch1 branch2) )
echo "Best merge base: ${bases[0]}"
Terminal window
# Debug fork point detection
git log --oneline --decorate --graph --all | grep -A5 -B5 "$(git merge-base --fork-point main)"
# Manual fork point identification
git log --oneline main..feature | tail -1
Terminal window
# Cache merge-base results for repeated operations
MERGE_BASE_CACHE="/tmp/merge-base-$RANDOM"
git merge-base main feature > "$MERGE_BASE_CACHE"
# Use cached result
base_commit=$(cat "$MERGE_BASE_CACHE")
Terminal window
# Before merge, understand conflict sources
CONFLICT_BASE=$(git merge-base HEAD MERGE_HEAD)
echo "Conflicts originate from changes after: $CONFLICT_BASE"
# Show what changed in each branch
git log --oneline $CONFLICT_BASE..HEAD | head -5 # Our changes
git log --oneline $CONFLICT_BASE..MERGE_HEAD | head -5 # Their changes
# Analyze specific file conflict
git diff $CONFLICT_BASE HEAD -- conflicted-file.txt # Our changes
git diff $CONFLICT_BASE MERGE_HEAD -- conflicted-file.txt # Their changes
Terminal window
# Determine if rebase or merge strategy is better
source_branch="feature-abc"
target_branch="main"
base=$(git merge-base "$target_branch" "$source_branch")
source_commits=$(git rev-list --count "$base..$source_branch")
target_commits=$(git rev-list --count "$base..$target_branch")
if [ "$target_commits" -gt 0 ]; then
echo "Branches diverged - consider merge instead of rebase"
echo "Rebase would create $target_commits merge commits"
else
echo "Rebase safe - no divergence detected"
git rebase "$target_branch" "$source_branch"
fi
#!/bin/bash
# Manage patch series with merge-base tracking
# Track patch application status
find patches/ -name "*.patch" | while read patch_file; do
patch_id=$(basename "$patch_file" .patch)
# Check if patch is already applied
if git log --grep="$patch_id" --oneline >/dev/null; then
echo "✓ Patch $patch_id already applied"
continue
fi
# Test patch application
if git apply --check "$patch_file" 2>/dev/null; then
echo "Applying patch: $patch_id"
git am "$patch_file"
# Record merge-base for future reference
applied_base=$(git merge-base HEAD HEAD~1)
git notes add -m "Patch: $patch_id, Base: $applied_base" HEAD
else
echo "✗ Patch $patch_id has conflicts - manual intervention needed"
fi
done

How merge-base handles criss-cross merges?

Section titled “How merge-base handles criss-cross merges?”

Returns all equally good merge bases with —all option. Algorithm finds minimal set of commits with no better common ancestors available.

What’s the difference between merge-base and git log —merges?

Section titled “What’s the difference between merge-base and git log —merges?”

git log —merges shows merge commits; git merge-base finds the common ancestor commit used for creating those merges, enabling analysis before merging.

Can merge-base work with tags and remotes?

Section titled “Can merge-base work with tags and remotes?”

Fully supports refs: git merge-base v1.0 v2.0, git merge-base origin/main HEAD. Works with any commit-ish reference in Git.

How do I find the merge-base of an octopus merge?

Section titled “How do I find the merge-base of an octopus merge?”

Use git merge-base —octopus branch1 branch2 branch3 when more than two branches converge, calculating the common ancestor for complex multi-branch scenarios.

What’s the performance impact of merge-base?

Section titled “What’s the performance impact of merge-base?”

Very fast operation - traverses commit graph similar to git log —graph. Performance scales with repository depth, typically sub-second for reasonable history sizes.

Can merge-base detect if branches have diverged?

Section titled “Can merge-base detect if branches have diverged?”

Yes, compare results: same merge-base means branches haven’t diverged. Different commits from merge-base indicate divergence requiring merge resolution.

Pre-rebase analysis: git merge-base topic main shows what commits will be replayed. Post-rebase verification ensures rebase maintains correct history relationships.

What’s the relationship between merge-base and three-way diff?

Section titled “What’s the relationship between merge-base and three-way diff?”

Git uses merge-base as third point in three-way diff/merge: git diff BASE HEAD MERGE_HEAD shows changes from common ancestor to each branch tip.

Can merge-base work with rewritten history?

Section titled “Can merge-base work with rewritten history?”

Works with current commit graph. After rebase, merge bases change because commit relationships change. Use git merge-base —fork-point to find original branch point in rewritten history.

How do I handle multiple merge-bases in scripts?

Section titled “How do I handle multiple merge-bases in scripts?”

Use git merge-base —all and select first result (—all output is ordered by preference). For automation, first merge-base is usually most appropriate.

What’s the difference between git merge-base and git show-branch —merge-base?

Section titled “What’s the difference between git merge-base and git show-branch —merge-base?”

git show-branch —merge-base shows merge base for current branches; git merge-base provides programmatic interface for any commits and more advanced options like —octopus.

Applications of the git merge-base command

Section titled “Applications of the git merge-base command”
  1. Merge Conflict Analysis: Understand conflict origins by identifying common ancestor and branch changes
  2. Branch Relationship Analysis: Determine how branches relate and what merging strategy to use
  3. Automated Merge Decision Making: Enable scripts to choose fast-forward vs three-way merge strategies
  4. Release Management: Track where releases branched from and what changes they contain
  5. Conflict Prevention: Test potential merges before execution using merge-tree with merge-base
  6. Development Workflow Optimization: Automate rebase vs merge decisions based on branch divergence