git merge-base Command: Find Common Ancestor in CI
git merge-base finds the commit where two branches diverged, their best common ancestor.
Change-aware CI needs to diff a PR against the point it branched from, not against the tip of the target branch. merge-base computes exactly that fork point.
Common flags
<a> <b>- print the best common ancestor of two commits--fork-point <ref>- find where the current branch forked, using reflog data--is-ancestor <a> <b>- exit zero if A is an ancestor of B (a test, no output)--all- print all best common ancestors when several exist--octopus- common ancestor for more than two commits
Example
# Diff a PR against the point it diverged from main
BASE="$(git merge-base origin/main HEAD)"
git diff --name-only "${BASE}...HEAD"In CI
Computing the merge-base is the correct way to scope a PR diff; using origin/main directly includes unrelated commits merged after the branch was cut. This requires enough history to reach the fork point, so use fetch-depth: 0 (or a deepened fetch) on PR builds.
Using this in CI
CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # history, tags, and git describe all need this
- run: |
git rev-parse --is-shallow-repository # expect false
git rev-parse --abbrev-ref HEAD # prints HEAD when detachedKey takeaways
- git merge-base finds the true PR fork point for accurate changed-files diffs.
- --is-ancestor is a clean boolean test for "is this commit reachable".
- It needs history back to the divergence, so PR builds want fetch-depth 0.