How to get commit where merged branch forked from
Asked Answered
W

3

13
o---1---o---o---o---o     master
     \         /
      o---o---2           feature

Is it possible to get commit 1 without using reflog ? Using git 2.4.2

I tried:

git merge-base master feature
git merge-base feature master
returns: commit 2 
git merge-base --fork-point master feature
git merge-base --fork-point feature master
returns nothing ( exit code 1 )

Not duplicates:

Weakly answered 31/5, 2015 at 17:17 Comment(0)
W
11

Found my answer as a subset from this question: ( backporting was in fact also my usecase ! ) https://mcmap.net/q/48580/-how-to-git-backport-rebase-cherry-pick-an-already-merged-branch

[alias]
    oldest-ancestor = !bash -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' -

I am somewhat baffled that this is not part of git as default. You would at least expect that this would be the behavior of the --fork-point option for merge-base. If anyone knows a better/default alternative. Please put it in the comments or as a separate answer !

Weakly answered 31/5, 2015 at 21:49 Comment(7)
Yeah, I don't understand why --fork-point would rely on the reflog when you can get the same information from the commit graph.Clarkson
As with the other answer, if we needed code that works with all edge cases, we'd need a special case for $1 == $2. Looks correct otherwise. Could be made slightly shorter with diff -U 1.Clarkson
@Daniel Hey Daniel, You seem to grok this command really well, would you mind providing a breakdown as to how it works ? I can't say I fully understand the bash and git magic going on there...Jarman
Yeah it's clever but hard to decipher! It lists the full history (newest to oldest) of both commits, then uses diff to find all commits which aren't shared. So the last line would be the first non-shared commit, except that -U 1 causes diff to append an extra line of "context" at the end, which will be the last shared commit before the branches diverged. The <(...) syntax is process substitution.Clarkson
Note that by default rev-list orders commits based on when they were authored, whereas we want commits ordered based on when they became reachable. The two dates can differ for commits which were merged in from another branch -- I might have just merged an old commit. Using --first-parent is one way to take care of that -- we'll just see the merge commit, but not look at any of the commits that were merged in. It also speeds things up a bit.Clarkson
Hello. I've found that your solution couldn't bypass intermediate merge. I will create a separate question at stackoverflow.Unbrace
#49310639Unbrace
L
3

As you noticed, git merge-base will not help you. The reason for this is that feature is part of master’s history and it could be fast-forwarded to master.

If this is your specific setup though, that you have merged feature into master, and the feature branch still points to the commit before the merge, then you can just get all the commits that are included in master but not included in feature and take the last one; the merge base you are looking for is its parent. You can do that by specifying the range feature..master:

git show $(git rev-list feature..master | tail -1)~1

This will show you the merge base commit “1” in your graph.

Ladyship answered 31/5, 2015 at 22:25 Comment(3)
This seems like a good approach, although if you need 100% correctness, watch out for the edge case where the feature branch was just forked and master hasn't had any new commits since.Clarkson
Another minor issue is that rev-list is chronological by default. The oldest commit could have been merged into master much later than it was authored. I would use --first-parent so that we only see commits directly on master.Clarkson
One final caveat is that if master is merged into the feature branch, rev-list will consider those master commits reachable from the feature branch and this won't find the original fork point. I don't think there's a way to tell rev-list to exclude just the commits on the first-parent path of feature.Clarkson
A
2

I think the following does what you are looking for:

git merge-base --fork-point master
Alcinia answered 14/10, 2020 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.