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.
Diagram
[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 HEAD and master. Note that a simple git merge-base master HEAD gives me F.
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 --reverse, so head -1 is needed.)
UPDATE:
Some explanation:
git rev-list mine ^master requests 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-order is 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 --reverse because we need the last one.
commit1 ^commit2 can also be spelled commit2..commit1, which is the preferred syntax when commit1 is a descendant of commit2. In this case mine and master have 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 git rev-parse manual.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With