Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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.

like image 469
bukzor Avatar asked Oct 25 '25 09:10

bukzor


1 Answers

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.

like image 63
user4815162342 Avatar answered Oct 27 '25 22:10

user4815162342