Check whether a Git branch has been merged

Check commit ancestry against an explicit target, distinguish squash merges from ordinary merges, and review a branch before deleting it.

Best practices
Illustration of Git branches and version history

Use git branch --merged main to list local branches whose tips are reachable from main. This answers an ancestry question: all commits reachable from the listed tip are already reachable from the target.

Inspect local and remote-tracking branches

git branch --merged main
git branch --no-merged main
git fetch origin
git branch -r --merged origin/main

Without an explicit target, --merged and --no-merged use HEAD. Supplying main avoids switching branches just to run the check. Remote-tracking refs describe the last fetched state; they are not a live query of the server.

Use an exit status in a script

git merge-base --is-ancestor feature-x main
result=$?
case "$result" in
  0) echo "feature-x is reachable from main" ;;
  1) echo "feature-x is not reachable from main" ;;
  *) echo "Could not check ancestry" >&2; exit "$result" ;;
esac

Status 1 means the ancestry test is false. Other failures, such as a misspelled ref, should not be reported as an unmerged branch.

Account for squash merges and cherry-picks

A squash merge can integrate a feature's content without making the original feature commits ancestors of main. The ancestry checks can therefore report the branch as unmerged even when its changes were accepted.

git cherry main feature-x

This compares individual patches: - marks a patch-equivalent commit upstream, and + marks one without such an equivalent. It does not generally recognize several feature commits combined into one squash commit. Review the pull request, the squash commit, and the resulting content before deciding that the branch is redundant.

Review before deleting

git branch -d feature-x checks whether the tip is merged into its configured upstream, or into HEAD if no upstream is set. That target may differ from the main you just inspected. Ancestry also says nothing about whether a branch name is still needed by a workflow or another developer.

For a verified squash integration, deletion may require -D. Preserve a backup ref if the original history matters, and confirm the branch is no longer in use before forcing deletion.

Find integration clues

git log --merges --oneline main
git log --grep='feature-x' --oneline main
git branch -r --no-merged main

Merge messages can help locate an integration date, but names are not guaranteed to appear, and fast-forward or squash integrations need not leave an ordinary merge commit. The last command lists remote-tracking branches needing review; it is not a deletion instruction.

See git-branch, git-merge-base, and git-cherry.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting