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

发布于 2024-11-26 03:46:35 字数 2024 浏览 2 评论 0原文

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

 A(master)---B(branch "topic")
  • 分支“master”的HEAD是提交A
  • 分支“topic”的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)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

知足的幸福 2024-12-03 03:46:35

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 protected]> 1311518908 +0300
committer ivan-danilov <[email protected]> 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

仅此而已。你有你想要的了。

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.

深海夜未眠 2024-12-03 03:46:35

反过来合并应该可以:

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

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
少钕鈤記 2024-12-03 03:46:35

仅当 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)

It only makes sense to make a merge commit if there's a difference between master and topic - if they have diverged. 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.

It works fine if you have a commit in master that's not in 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)
独夜无伴 2024-12-03 03:46:35

现在您位于主题分支上,并且由于它是 master 的直接后代,因此与 master 合并没有任何意义,因为 topic 包含 master 的所有更改。然而,master 没有对主题进行任何更改。

如果您签出 master,然后将主题合并到 master,master 应该快进并更新其 HEAD。

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. However, master has none of the changes topic has.

If you checkout master and then merge topic in to master, master should fast forward and update its HEAD.

椒妓 2024-12-03 03:46:35

这个问题没有官方解决方案,有一个解决方法。检查 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

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. Then commit an empty commit. Then check out your topic branch and merge in that empty commit.

$ 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文