Skip to content
Git Basics: Check Whether a Branch Contains an Ancestor

Git Basics: Check Whether a Branch Contains an Ancestor

October 28, 2026

Before assuming a branch includes a particular base, ask Git about ancestry. A diverged fixture shows why a common ancestor and a branch tip are different concepts.

Prepare a scratch directory

Tested on Linux with Git 2.52.0 and GNU Bash 5.2.37. You need Bash, a text editor, the named runtime, and standard mktemp, rm, and rmdir utilities. The examples use only controlled local data; generated fixture directories are cleaned automatically.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as demonstrate-merge-base.sh:

#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
fixture_dir="$(mktemp -d)"
trap 'rm -rf -- "$fixture_dir"' EXIT
export GIT_CONFIG_NOSYSTEM=1
export GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author'
export GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_AUTHOR_DATE='2026-10-28T00:00:00+00:00'
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git init -q -b main "$fixture_dir/repo"
cd -- "$fixture_dir/repo"
git config commit.gpgsign false
git config core.hooksPath /dev/null
printf 'base\n' > shared.txt
git add shared.txt
git commit -qm 'Shared base'
git tag base
git switch -qc feature
printf 'feature\n' > feature.txt
git add feature.txt
git commit -qm 'Feature work'
git switch -q main
printf 'main\n' > main.txt
git add main.txt
git commit -qm 'Main work'
common="$(git merge-base main feature)"
test "$common" = "$(git rev-parse base)"
printf 'Common ancestor: '
git show -s --format=%s "$common"
if git merge-base --is-ancestor base feature; then
    printf 'Feature contains base: yes\n'
fi
if git merge-base --is-ancestor main feature; then
    printf 'Feature contains main: yes\n'
else
    status=$?
    test "$status" -eq 1
    printf 'Feature contains main: no\n'
fi

Run it:

bash demonstrate-merge-base.sh

Observed output:

Common ancestor: Shared base
Feature contains base: yes
Feature contains main: no

Read the result

Both tips descend from the tagged base. The feature branch contains that ancestor but not the independent main commit. --is-ancestor returns status zero for yes and one for no; other failures must not be treated as a normal negative answer.

Apply it carefully

Ancestry is a graph property, not proof of equivalent file contents or successful tests. Complex histories can have several best merge bases; use --all when that distinction matters. Fetch current refs before using an ancestry check for remote release decisions. Run this script from an ordinary shell with no repository-selection variables such as GIT_DIR or GIT_WORK_TREE set. All commits and cleanup stay inside the newly created temporary fixture.

The official reference describes the behavior and options. These checks cover the fixture above rather than every input or platform.

Clean up

Remove the saved source, return to the starting directory, then remove the empty practice directory:

rm -- demonstrate-merge-base.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents rather than deleting unknown files.

Acknowledgements

This post was created with assistance from AI.

Last updated on