How can I tell if one commit is a descendant of another commit?
From Git 1.8.0, this is supported as an option to merge-base
:
git merge-base --is-ancestor <maybe-ancestor-commit> <descendant-commit>
From the man page:
--is-ancestor
Check if the first is an ancestor of the second , and exit with status 0 if true, or with status 1 if not. Errors are signaled by a non-zero status that is not 1.
For example:
git merge-base --is-ancestor origin/master master; echo $?
If you want to check this programmatically (e.g. in script), you can check if git merge-base A B
is equal to git rev-parse --verify A
(then A is reachable from B), or if it is git rev-parse --verify B
(then B is reachable from A). git rev-parse
is here needed to convert from commit name to commit SHA-1 / commit id.
Using git rev-list
like in VonC answer is also possibility.
Edit: in modern Git there is explicit support for this query in the form of git merge-base --is-ancestor
.
If one of commits you are asking about is a branch tip, then git branch --contains <commit>
or git branch --merged <commit>
might be better non-programmatic solution.
This kind of operations relies on the notion of range of revisions detailed in the SO question: "Difference in ‘git log origin/master’ vs ‘git log origin/master..’".
git rev-list
should be able to walk back from a commit, up until another if reachable.
So I would try:
git rev-list --boundary 85e54e2408..0815fcf18a
0815fcf18a19441c1c26fc3495c4047cf59a06b9
8a1658147a460a0230fb1990f0bc61130ab624b2
-85e54e240836e6efb46978e4a1780f0b45516b20
(Boundary commits are prefixed with -
)
If the last commit displayed is the same than the first commit in the git rev-list
command, then it is a commit reachable from the second commit.
If the first commit is not reachable from the second, git rev-list
should return nothing.
git rev-list --boundary A..B
would finish by A
, if A
is reachable from B
.
It is the same as:
git rev-list --boundary B --not A
,with B
a positive reference, and A
a negative reference.
It will starts at B
and walks back through the graph until it encounters a revision that is reachable from A
.
I would argue that if A
is directly reachable from B
, it will encounter (and display, because of the --boundary
option) A
itself.