[英]GIT: how to force a merge commit to an ancestor
In GIT, I have two branches and two commits: 在GIT中,我有两个分支和两个提交:
A(master)---B(branch "topic")
I would like to create a merge commit C in the "topic" branch (it would have A and B as parents). 我想在“topic”分支中创建一个合并提交C(它将A和B作为父级)。 (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)
UPD : Cleaner way to do same thing without messing with sha1 directly: UPD :更干净的方式做同样的事情而不直接搞乱sha1:
$ 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. 首先,您应该知道父提交的sha1。 I suppose B has comment 'change from topic', A has comment 'change from master' and we're currently at B (topic branch). 我想B有评论'从主题改变',A有评论'从主人改变',我们现在在B(主题分支)。
$ 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: 然后你应该知道提交B的具体树对象的sha1:
$ git cat-file -p topic
tree 867f31c455a371756ec353b54d755f51d98d62c4
parent 8b7653a529fb3ce964fda79bfd57e645441ad893
author ivan-danilov <email@gmail.com> 1311518908 +0300
committer ivan-danilov <email@gmail.com> 1311518908 +0300
change from topic
So it is 867f31c455a371756ec353b54d755f51d98d62c4
. 所以它是867f31c455a371756ec353b54d755f51d98d62c4
。 And finally you should execute git-commit-tree
command: 最后你应该执行git-commit-tree
命令:
$ 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. 请注意,我使用了管道重定向,因为git-commit-tree
从stdin
流中获取提交注释。 First param is tree's sha1 we got with git cat-file
and two others are commits' sha1 we got with git log
. 第一个参数是我们用git cat-file
得到的树的sha1,另外两个是我们用git log
得到的sha1。
Output from command is the sha1 of newly created merge commit. 命令输出是新创建的合并提交的sha1。 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. 你有你想要的。
Merging the other way around should work: 合并相反的方法应该有效:
git branch tmp master # tmp points to A
git checkout tmp
git merge --no-ff -m 'odd merge' topic # merge B+A ==> C
git checkout topic
git reset --hard tmp # topic now points to C
git branch -d tmp
It only makes sense to make a merge commit if there's a difference between master
and topic
- if they have diverged. 只有在master
和topic
之间存在差异时才进行合并提交才有意义 - 如果它们有分歧的话。 In your case, there's nothing to merge - topic
already has all of master
's commits, so git won't allow you to create a merge that does nothing. 在你的情况下,没有什么可以合并 - topic
已经拥有所有master
的提交,所以git将不允许你创建一个什么都不做的合并。
It works fine if you have a commit in master
that's not in topic
: 如果你在master
中的提交不在topic
,它可以正常工作:
$ git init plop
Initialized empty Git repository in C:/Temp/plop/.git/
$ cd plop
$ git commit -m "Initial commit (commit A)" --allow-empty
[master (root-commit) b6e2e91] Initial commit (commit A)
$ git commit -m "master-only commit (commit C)" --allow-empty
[master 67b491e] master-only commit (commit C)
$ git checkout HEAD~ -b topic
Switched to a new branch 'topic'
$ git commit -m "Some work on my topic branch (commit B)" --allow-empty
[topic 2251f13] Some work on my topic branch (commit B)
$ git merge master
Already up-to-date!
Merge made by recursive.
Resulting in... 导致...
* 592ad46 Merge branch 'master' into topic
|\
| * 67b491e master-only commit (commit C)
* | 2251f13 Some work on my topic branch (commit B)
|/
* b6e2e91 Initial commit (commit A)
There is no official solution to this problem, there is a workaround. 这个问题没有正式的解决方案,有一个解决方法。 Check out the commit that master
is on, so that you are in detached HEAD state. 检查master
所在的提交,以便您处于分离的HEAD状态。 Then commit an empty commit. 然后提交一个空提交。 Then check out your topic
branch and merge in that empty commit. 然后检查您的topic
分支并合并该空提交。
$ git checkout 9123456 # (the latest commit on master)
Note: checking out '9123456'.
You are in 'detached HEAD' state...
$ git commit --allow-empty -m 'empty commit'
[detached HEAD 9123457] empty commit
$ git checkout topic
Warning: you are leaving 1 commit behind ... 9123457 empty commit
Switched to branch 'topic'
$ git merge 9123457
Right now you're on the topic branch, and since it's a direct descendant of master, merging with master makes no sense as topic contains all the changes master has. 现在你在主题分支上,因为它是master的直接后代,与master合并没有任何意义,因为topic包含master拥有的所有更改。 However, master has none of the changes topic has. 但是,master没有任何更改主题。
If you checkout master and then merge topic in to master, master should fast forward and update its HEAD. 如果您签出master然后将主题合并到 master,master应该快进并更新其HEAD。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.