Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GIT: how to force a merge commit to an ancestor

Tags:

git

merge

commit

In GIT, I have two branches and two commits:

 A(master)---B(branch "topic")
  • the HEAD of the branch 'master' is commit A
  • the HEAD of the branch 'topic' is commit B
  • commit A is the parent of commit B

I would like to create a merge commit C in the "topic" branch (it would have A and B as parents). (I know that this seems odd, and that the merge commit would be empty.)

 A(master)---B---C (branch "topic")
  \-------------/

I managed to create this merge commit in a too complex way (see below). Is there any easier way to create this merge commit?

Thanks for your answers!


Initial state:

$ git init plop
Initialized empty Git repository in /tmp/plop/.git/
$ cd plop/
$ git commit -m "Initial commit (commit A)"  --allow-empty
[master (root-commit) a687d4e] Initial commit (commit A)
$ git checkout -b topic
Switched to a new branch 'topic'
$ git commit -m "Some work on my topic branch (commit B)" --allow-empty
[topic d4d1c71] Some work on my topic branch (commit B)
$ #OK, we now reached the initial state

Some tries:

$ git merge master #Does not work
Already up-to-date.
$ git merge --no-ff -s ours master #Does not work
Already up-to-date.

Is there an easier way to achieve the following?

$ #Let's try another way (too complex!)
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff topic
Already up-to-date!
Merge made by recursive.
$ git checkout topic
Switched to branch 'topic'
$ git merge master
Updating d4d1c71..641e7ae
Fast-forward
$ git checkout master
Switched to branch 'master'
$ git reset --hard HEAD^1
HEAD is now at a687d4e Initial commit
$ git checkout topic
Switched to branch 'topic'
$ git log #This is what I wanted to reach
commit 641e7aeb614d9b49796e8f11abd3a0290ac08b40
Merge: a687d4e d4d1c71
Author: xxx <yyy.zzz>
Date:   Sat Jul 23 12:52:41 2011 +0200

    Merge branch 'topic'

commit d4d1c71c87b94335c8852ab7675cbb663965ef7d
Author: xxx <yyy.zzz>
Date:   Sat Jul 23 12:50:11 2011 +0200

    Some work on my topic branch (commit B)

commit a687d4eb88b9f6d661122a5766dd632dd462fbaa
Author: xxx <yyy.zzz>
Date:   Sat Jul 23 12:49:52 2011 +0200

    Initial commit (commit A)
like image 903
OLU Avatar asked Jul 24 '11 13:07

OLU


People also ask

How do you force a merge abortion?

Use git-reset or git merge --abort to cancel a merge that had conflicts. Please note that all the changes will be reset, and this operation cannot be reverted, so make sure to commit or git-stash all your changes before you start a merge.

Does merging create a new commit?

Merging your branch into master is the most common way to do this. Git creates a new commit (M) that is referred to as a merge commit that results from combining the changes from your feature branch and master from the point where the two branches diverged.


1 Answers

UPD: Cleaner way to do same thing without messing with sha1 directly:

$ echo "merge commit" | git commit-tree topic^{tree} -p master -p topic
4201b6abae6bb06f929ea00fbc35019679d55535

$ git merge 4201b6abae6bb06f929ea00fbc35019679d55535
Updating b826a8e..4201b6a
Fast-forward

Or even one-line command:

$ git merge $(echo "merge commit" | git commit-tree topic^{tree} -p master -p topic)

For details of what that's doing - read entire answer :)


I'm totally agree with others in that it has no sense for me, but if you really want it - it is possible with low-level plumbing commands as described below.

First of all, you should know sha1 of your parent commits. I suppose B has comment 'change from topic', A has comment 'change from master' and we're currently at B (topic branch).

$ git log --format=oneline -2
b826a8e93ac8da0de5bfb5b70d5f4e7c352a01fa change from topic
8b7653a529fb3ce964fda79bfd57e645441ad893 change from master

Then you should know sha1 of concrete tree object of commit B:

$ git cat-file -p topic
tree 867f31c455a371756ec353b54d755f51d98d62c4
parent 8b7653a529fb3ce964fda79bfd57e645441ad893
author ivan-danilov <[email protected]> 1311518908 +0300
committer ivan-danilov <[email protected]> 1311518908 +0300

change from topic

So it is 867f31c455a371756ec353b54d755f51d98d62c4. And finally you should execute git-commit-tree command:

$ echo "merge commit" | git commit-tree 867f31c455a371756ec353b54d755f51d98d62c4 -p b826a8e93ac8da0de5bfb5b70d5f4e7c352a01fa -p 8b7653a529fb3ce964fda79bfd57e645441ad893
4201b6abae6bb06f929ea00fbc35019679d55535

Note that I used pipeline redirection as git-commit-tree takes commit comment from stdin stream. First param is tree's sha1 we got with git cat-file and two others are commits' sha1 we got with git log.

Output from command is the sha1 of newly created merge commit. Now you want to fast-forward topic branch to it:

$ git merge 4201b6abae6bb06f929ea00fbc35019679d55535
Updating b826a8e..4201b6a
Fast-forward

That's all. You have what you wanted.

like image 104
Ivan Danilov Avatar answered Sep 19 '22 21:09

Ivan Danilov