ChatGPT解决这个技术问题 Extra ChatGPT

Git: Find the most recent common ancestor of two branches

How to find the most recent common ancestor of two Git branches?

Define most recent: real world time, number of commits, other metric?
Relevant (criss-cross merges): stackoverflow.com/questions/26370185/…
@YakovL I believe no because of branching and because you can set arbitrary commit dates on your commit objects: that date itself is likely not what you want.
@CiroSantilli新疆改造中心996ICU六四事件 it seems to me that can only be different if before the last common commit in the tree there's a commit that has an older timestamp. Can you provide a less trivial example?

M
Mark Amery

You are looking for git merge-base. Usage:

$ git merge-base branch2 branch3
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

Note that this finds the most recent common ancestor... which I believe is what the questioner wants, so +1. Just noting it, in case anyone comes here trying to find the oldest common ancestor (as I did) -- for which, see also: stackoverflow.com/questions/1527234/…
@funroll: Or the shorthand for that: git log master...HEAD
@lindes would the oldest common ancestor not be the initial commit?
@ThorbjørnRavnAndersen, yes, I suppose that's so... The difficulty in description comes with the fact that git uses a Directed Acyclic Graph, and yet it's often thought of as a tree, which it technically is not. To be more careful in my wording, I was talking about the case where you want the parent of the first instance of the "branches" diverging... since they may have multiple points where they re-merged and re-split, this is the "oldest" of these, but not truly the oldest ancestor, which is (I think) always the initial commit.
While this question is strictly about finding a common ancestor of two branches, anyone wanting the common ancestor of three or more branches should note that they need to pass the --octopus flag to get the right result. The obvious-but-wrong git merge-base branch1 branch2 branch3 will give you a commit, but, as described in the Discussion section in the docs, it isn't necessarily a common ancestor of all three branches.
C
Ciro Santilli Путлер Капут 六四事

git diff master...feature

shows all the new commits of your current (possibly multi-commit) feature branch.

man git-diff documents that:

git diff A...B

is the same as:

git diff $(git merge-base A B) B

but the ... is easier to type and remember.

As mentioned by Dave, the special case of HEAD can be omitted. So:

git diff master...HEAD

is the same as:

git diff master...

which is enough if the current branch is feature.

Finally, remember that order matters! Doing git diff feature...master will show changes that are on master not on feature.

I wish more git commands would support that syntax, but I don't think they do. And some even have different semantics for ...: What are the differences between double-dot ".." and triple-dot "..." in Git commit ranges?


Or just git diff master... in the special case of diffing to HEAD
the "..." didn't work for me in powershell, funny it worked in git console maybe the repo wasn't complete, git diff $(git merge-base A B) B did and since I am a bit new to git I was a bit sceptical that this might merge the branches :)
wow. quite amazing. and if the branch you want doesn't exist in your local repo because you never checked it out, you can simply do git diff origin/branchname...
so what is the difference between git diff branchA..branchB and git diff branchA...branchB ?
@BharatPahalwani, after I read your comment, if searched on google, found this one to be the third. matthew-brett.github.io/pydagogue/git_diff_dots.html what did you try before asking this in comments?
A
Asclepius

As noted in a prior answer, although git merge-base works,

$ git merge-base myfeature develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

If myfeature is the current branch, as is common, you can use --fork-point:

$ git merge-base --fork-point develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

This argument works only in sufficiently recent versions of git. Unfortunately it doesn't always work, however, and it is not clear why. Please refer to the limitations noted toward the end of this answer.

For full commit info, consider:

$ git log -1 $(git merge-base --fork-point develop) 

I have git version 2.14.1.windows.1. Running git merge-base --fork-point branch2 with a branch (with its own commits) that I know has forked from the current branch doesn't yield any result, whereas git merge-base branch1 branch2 correctly shows the fork point. What could be the problem?
@ADTC Checkout branch2 and then run git merge-base --fork-point branch1.
@ADTC Use a graphical commit viewer, e.g. gitk, etc. to see what the tree looks like. Maybe you will get your answer.
I see nothing odd about the tree as I view it graphically. I can trace the paths and find the common ancestor which matches the result of git merge-base branch1 branch2. But what's odd is that --fork-point gives nothing either way. Have you confirmed it works for you as intended?
I get the same that @ADTC. The command 'git log -1 $(git merge-base --fork-point anotherBranch)' doesn't show any result using git version 2.16.2.windows.1.
M
Martin G

With gitk you can view the two branches graphically:

gitk branch1 branch2

And then it's easy to find the common ancestor in the history of the two branches.


Not everything can be done visually in every case. There are reasons why things may need to be automated programmatically.