4

I tried to get ancestor of my branch with git merge-base command on merged branch.

When I try git merge-base develop branch1 it shows sha YYY instead of XXX

* `develop`
|
* merge branch1 into develop
|\
| * `branch1` <- HEAD sha YYY
|/
* sha XXX

Everything works fine when I fire the same command on not merged branch (diagram bellow)

* `develop`
|
|
| * `branch1` <- HEAD sha YYY
|/
* sha XXX

The only way I get this commit id is by git log --oneline --boundary develop...branch1 It shows me a list of commits but I need only one.

milczi
  • 7,064
  • 2
  • 27
  • 22
  • 1
    git [merge-base](https://git-scm.com/docs/git-merge-base) is behaving as intended. It's job is to find the most recent commit that's an ancestor of both arguments. In this case, YYY is an ancestor of both `branch1` and `develop` (since the branch has been merged in). Maybe you're not asking the right question... What are you trying to do? – mkasberg Feb 14 '18 at 19:35
  • I have to make bash script which copy all commits from `branch1` to another branch. If my branch was not merged then I picked my common commit with `git merge-base develop branch1_copy`. Then using `git rebase --onto another_branch SHA-XXX branch1_copy` put that copy in another place. – milczi Feb 14 '18 at 21:00

1 Answers1

7

That's because the merge base after the merge is YYY:

* `develop`
|
* merge branch1 into develop
|\
| * `branch1` <- HEAD sha YYY
|/
* sha XXX

is a vertical version of this same horizontal drawing:

X---M--D   <-- develop
 \ /
  Y   <-- branch1

The merge base of any two commits, such as Y and D, is the nearest commit reachable from both commits.

Y reaches itself in zero steps; D reaches M and then Y in two steps; so Y is a nearby common ancestor.

While X is also a common ancestor, it is clearly more distant: Y reaches X in one step, and D reaches X in two or three steps, either D-M-X or D-M-Y-X. So D-to-X is no further than D-to-Y (min path is 2 steps either way), but Y-to-Y is clearly shorter than Y-to-X.

This means that Y is the best common ancestor, and hence is the merge base.

torek
  • 448,244
  • 59
  • 642
  • 775
  • OK. Thanks for explanation. Could you tell me is there any possibility to get SHA of X commit in this situation ? – milczi Feb 14 '18 at 23:18
  • 1
    @milczi: just start from `Y`'s ancestor: `git merge-base develop branch1^` for instance. – torek Feb 14 '18 at 23:58
  • It works on the branch with only one commit. I have to count somehow this commits. "I have to make bash script which copy all commits from branch1 to another branch. If my branch was not merged then I picked my common commit with git merge-base develop branch1_copy. Then using git rebase --onto another_branch SHA-XXX branch1_copy put that copy in another place." – milczi Feb 15 '18 at 07:22
  • The phrase *all commits from (some) branch* is ill-defined in Git. Commits are, at least potentially, on *many* branches simultaneously. It's up to you to define which commits you want to copy. (I assume that's why you are looking at merge bases, but they are not the only way to make this decision; see also set difference, for instance.) Note that it rarely makes sense to copy a merge commit. – torek Feb 15 '18 at 16:20
  • There should be a `--first-parent` option. – Dávid Horváth Aug 05 '22 at 08:04
  • @DávidHorváth: there is for `git log` and `git rev-list`, and similar logic (sometimes using the same name) has been added to various Git commands over the years. But there isn't for `git merge-base`. – torek Aug 05 '22 at 15:04