【问题标题】:GIT: how to force a merge commit to an ancestorGIT:如何强制合并提交给祖先
【发布时间】:2011-10-12 00:54:28
【问题描述】:

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

 A(master)---B(branch "topic")
  • “master”分支的 HEAD 是提交 A
  • 分支“主题”的 HEAD 是提交 B
  • 提交 A 是提交 B 的父级

我想在“主题”分支中创建一个合并提交 C(它将 A 和 B 作为父级)。 (我知道这看起来很奇怪,而且合并提交是空的。)

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

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

感谢您的回答!


初始状态:

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

【问题讨论】:

  • 你为什么要这样做?这没有意义。可以在 master 上创建一个新的提交,并合并到 topic 中(这也很有意义)。
  • 这是合并祖先提交的一个可能用例:假设分支包含我们现在想要恢复的文件的一些更改(例如,它是某种下游分支)。做一个简单的git revert 会使git blame 在该属性之后将所有恢复的行归因于恢复提交,但是将它们归因于上游会更有帮助。进行还原提交并将其标记为与上游的合并可以实现这一点。
  • 好问题。这是一个示例,说明您为什么要这样做,每个人都在问“为什么”。我有一个 gh-pages 分支,它构建了文档,以及仅在该分支上签入的 dist/prod 文件,用于部署。我的dev 分支在master 之前,我合并了dev -&gt; gh-pages 并重建,然后部署。但后来我意识到我失败了,因为我希望部署我的主构建,而不是我的开发构建。所以我checkout gh-pages 并尝试了merge --no-commit master,但它警告“已经是最新的。”在这种情况下强制下游(空)合并会很有帮助。
  • 刚刚遇到这个问题,master刚刚合并到主题中,当主题合并到master中时我想要另一个提交......但是遇到了这个问题。这对于需要知道要遵循哪个合并祖先的工具很重要。此外,当 git log --graph 在主题分支的右侧或中间显示您的主节点时,它也无济于事。

标签: git merge commit


【解决方案1】:

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)

有关此操作的详细信息 - 阅读完整答案:)


我完全同意其他人的观点,因为它对我来说毫无意义,但如果你真的想要它 - 可以使用如下所述的低级管道命令。

首先,您应该知道父提交的 sha1。我想 B 有评论“从主题改变”,A 有评论“从主人改变”,我们目前在 B(主题分支)。

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

那么你应该知道提交 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

所以它是867f31c455a371756ec353b54d755f51d98d62c4。最后你应该执行git-commit-tree 命令:

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

请注意,我使用管道重定向,因为git-commit-treestdin 流中获取提交评论。第一个参数是我们用git cat-file 得到的树的sha1,另外两个是我们用git log 得到的提交的sha1。

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

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

就是这样。你有你想要的。

【讨论】:

  • 谢谢, git commit-tree 是我所缺少的。我同意如果它导致那种低级 GIT 命令,我必须重新考虑我们的工作流程......
  • @Stefan 如果从 master 完成 - 它会在 master 分支中创建合并提交,这不是 OP 想要的。如果我从主题执行git merge master --no-ff - git 回复“已经是最新的。”
  • 哦,对了,对不起。应该更仔细地阅读,OP想要以相反的方式合并。在那种情况下,我会使用(在主题分支上):cur=$(git rev-parse HEAD); git reset master; git merge --no-ff $cur -m 'merge master into topic'
  • 我建议交换父节点的顺序,将分支作为第一个父节点,将主节点作为第二个父节点。如果git merge 不拒绝运行,这就是它会做的事情。
【解决方案2】:

反向合并应该可以:

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

【讨论】:

    【解决方案3】:

    只有在 mastertopic 之间存在差异时才有意义进行合并提交 - 如果它们已经分歧。在你的情况下,没有什么可以合并 - topic 已经拥有 master 的所有提交,所以 git 不允许你创建一个什么都不做的合并。

    如果您在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.
    

    导致...

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

    【讨论】:

    • 感谢您的回答。我知道要求一个空提交看起来很奇怪,但它适合我们的开发工作流程(这可能是坏的,这是另一个问题)。 GIT 允许空提交,所以我想 GIT 在这里应该不是问题......
    【解决方案4】:

    现在你在 topic 分支上,因为它是 master 的直接后代,与 master 合并没有意义,因为 topic 包含 master 的所有更改。但是,master 没有主题的任何更改。

    如果你签出 master 然后将 topic in 合并到 master,master 应该快进并更新它的 HEAD。

    【讨论】:

    • 这就是我所做的。但是,我不得不重置主分支,因为我不希望它的 HEAD 移动(尽管我希望“主题”的 HEAD 移动)。有没有更简单的方法来实现这一点?
    • 哦,不。我误解了你的问题。虽然我没有答案,但我也不明白你为什么要这样做。也许告诉会有所帮助?
    • 我知道要求一个空提交看起来很奇怪,但它适合我们的开发工作流程(这可能是坏的,这是另一个问题)。 GIT 允许空提交,所以我猜这里 GIT 应该不是问题。
    【解决方案5】:

    这个问题没有官方解决方案,有解决方法。检查master 的提交,以便您处于分离的HEAD 状态。然后提交一个空提交。然后检查您的 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-25
      • 2010-12-21
      相关资源
      最近更新 更多