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

GIT:如何强制将合并提交给祖先,git,merge,commit,Git,Merge,Commit,在GIT中,我有两个分支和两个提交: A(master)---B(branch "topic") 分支“主”的负责人是提交人 分支“topic”的头是commit B 提交A是提交B的父级 我想在“topic”分支中创建一个合并提交C(它将a和B作为父级)。(我知道这看起来很奇怪,合并提交将是空的。) 我设法以一种过于复杂的方式创建了这个合并提交(见下文)。有没有更简单的方法来创建此合并提交 谢谢你的回答 初始状态: $ git init plop Initialized empty

在GIT中,我有两个分支和两个提交:

 A(master)---B(branch "topic")
  • 分支“主”的负责人是提交人
  • 分支“topic”的头是commit B
  • 提交A是提交B的父级
我想在“topic”分支中创建一个合并提交C(它将a和B作为父级)。(我知道这看起来很奇怪,合并提交将是空的。)

我设法以一种过于复杂的方式创建了这个合并提交(见下文)。有没有更简单的方法来创建此合并提交

谢谢你的回答


初始状态:

$ 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

一些尝试:

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

有没有更简单的方法来实现以下目标

$ #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)
让我们试试另一种方法(太复杂了!) $git签出主机 切换到“主”分支 $git合并--无ff主题 已经是最新的了! 通过递归进行合并。 $git签出主题 切换到“主题”分支 $git合并主机 更新d4d1c71..641e7ae 快进 $git签出主机 切换到“主”分支 $git重置--硬头^1 HEAD现在处于a687d4e初始提交状态 $git签出主题 切换到“主题”分支 $git log#这是我想要达到的目标 提交641e7aeb614d9b49796e8f11abd3a0290ac08b40 合并:a687d4e d4d1c71 作者:xxx 日期:星期六2011年7月23日12:52:41+0200 合并分支“主题” 提交d4d1c71c87b94335c8852ab7675cbb663965ef7d 作者:xxx 日期:星期六2011年7月23日12:50:11+0200 关于我的主题分支的一些工作(提交B) 提交A687D4EB88B9F6D66112A5766DD632DD462FBAA 作者:xxx 日期:星期六2011年7月23日12:49:52+0200 初始提交(提交A)
现在您在主题分支上,因为它是master的直接后代,所以与master合并没有意义,因为主题包含master所做的所有更改。但是,master没有主题所做的任何更改


如果您签出master,然后将主题合并到master中,那么master应该快进并更新其头部。

只有当
master
topic
之间存在差异时,才有意义进行合并提交-如果它们存在分歧。在您的情况下,没有要合并的内容-
topic
已经有了所有
master
的提交,所以git不允许您创建一个不做任何事情的合并

如果您在
master
中有一个commit,而该commit不在
主题中,则可以正常工作:

$ 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.
导致

*   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)

UPD:在不直接干扰sha1的情况下做同样事情的更干净方法:

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

$ git merge 4201b6abae6bb06f929ea00fbc35019679d55535
Updating b826a8e..4201b6a
Fast-forward
甚至一行命令:

$ git merge $(echo "merge commit" | git commit-tree topic^{tree} -p master -p topic)
有关这项工作的详细信息,请阅读完整答案:)


我完全同意其他人的看法,因为这对我来说毫无意义,但如果您真的需要它,可以使用下面描述的低级管道命令

首先,你应该知道你父母的承诺。我想B有“主题变更”的注释,A有“主控变更”的注释,我们现在在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
注意,我使用管道重定向作为
git提交树
stdin
流中获取提交注释。第一个参数是tree的sha1,我们使用
git cat file
获得,另外两个参数是commissions的sha1,我们使用
git log
获得

命令的输出是新创建的合并提交的sha1。现在,您要将主题分支快进到它:

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

就这些。你得到了你想要的。

用另一种方式合并应该可以:

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

这个问题没有正式的解决办法,有一个变通办法。检查
master
处于启用状态的提交,以使您处于分离头部的状态。然后提交一个空的提交。然后检查您的
主题
分支并合并到该空提交中

$ 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

这就是我所做的。但是,我必须重置主分支,因为我不希望它的头移动(尽管我希望“topic”的头移动)。有更简单的方法吗?哦,不,我误解了你的问题。虽然我没有答案,但我也不明白你为什么要这么做。也许告诉会有帮助吗?我知道要求一个空的提交看起来很奇怪,但它适合我们的开发工作流程(whis可能被破坏了,这是另一个问题)。GIT允许空提交,所以我想GIT在这里应该不是问题。谢谢你的回答。我知道需要一个空提交看起来很奇怪,但它适合我们的开发工作流程(这可能是坏的,这是另一个问题)。GIT允许空提交,所以我想GIT在这里不应该是个问题……为什么要这样做?这没有道理。在
master
上创建一个新的提交,该提交将合并到
topic
中是可能的(这也是有意义的)。下面是一个合并到祖先提交中的可能用例:假设分支包含我们现在要还原的文件的一些更改(例如,它是某种下游分支)。执行一个简单的
git revert
会使
git在该属性之后将所有还原的行都归为revert提交,但是将它们归为上游会更有帮助。进行一次恢复提交并将其标记为与上游的合并可以实现这一点。好问题。下面是一个你为什么要这样做的例子,每个人都会问“为什么”。我有一个
gh-pages
分支,它构建了文档,以及仅在该分支上签入的dist/prod文件,用于部署。我的
dev
分支位于
master
之前,我合并了
dev->gh页面
并重建,然后部署。但后来我意识到我失败了,因为我想部署我的主构建,而不是我的开发构建。所以我
签出了gh页面
并尝试了
合并--没有提交主机
,但它会提醒“已经是最新的”。在这种情况下,强制下游(空)合并会很有帮助。遇到这个问题,主机刚刚合并到主题中,我希望在
$ git merge 4201b6abae6bb06f929ea00fbc35019679d55535
Updating b826a8e..4201b6a
Fast-forward
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
$ 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