git: Find the oldest commit of `mine` which does not exist in `theirs`
I’d like to be able to find the longest path in my git-graph which does not exist upstream. One end of that path is obviously HEAD, so that’s easy. The other end is my oldest commit which does not exist upstream. I don’t know how to find this.
[otherguy] H--I--J / \ [master] A--B--C--M1--D--E--M2--F--G \ \ \ [mine] H---I--M3---J---K---M4--M--HEAD
I want a command which will point me to H (or B), given
master. Note that a simple
git merge-base master HEAD gives me F.
2 Solutions collect form web for “git: Find the oldest commit of `mine` which does not exist in `theirs`”
This should work reasonably:
git rev-list --topo-order --reverse mine ^master | head -1
Tested with a replica of your setup, it prints the commit you marked as “H”. I am not 100% convinced that it finds the “farthest” path in all possible cases, or that such a concept is even well-defined, so you might want to test it on cases that matter to you before relying on it.
(Note that the
-1 option one would usually specify to limit
git rev-list output does not combine well with
head -1 is needed.)
git rev-list mine ^masterrequests the commits reachable from
mine, but not from
master. In your case we are requesting all commits starting with
HEAD, excluding those reachable from
G, which gives a list of commits
(M, M4, K, J, M3, I, H), of which we choose the last one.
--topo-orderis needed to ensure topological ordering of commits (that a commit always appears before its parent), rather than chronological ordering, which is the default. We also specify
--reversebecause we need the last one.
commit1 ^commit2can also be spelled
commit2..commit1, which is the preferred syntax when
commit1is a descendant of
commit2. In this case
masterhave diverged, so it’s clearer to spell out what we want. Multiple exclusions, such as
git log branch1 ^branch2 ^branch3, are also allowed. This applies to all git commands that take ranges, and is documented in the
This is mostly equivalent to the question »Which commits are reachable from (my) HEAD, but not from master?« To answer that question, use the commit range
master..HEAD. You want the oldest commit from this list, so pipe the output through tail:
git rev-list master..HEAD|tail -n1.
If your commit timestamps are not ordered chronologically, you might have to specify the
--topo-order option to rev-list.