简体   繁体   English

GIT:如何强制合并提交到祖先

[英]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")
  • the HEAD of the branch 'master' is commit A 分支'master'的HEAD是提交A.
  • the HEAD of the branch 'topic' is commit B 分支'主题'的HEAD是提交B.
  • commit A is the parent of commit B commit A是提交B的父级

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-treestdin流中获取提交注释。 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. 只有在mastertopic之间存在差异时才进行合并提交才有意义 - 如果它们有分歧的话。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM