如何交换Git提交的两个父母的顺序?

Fli*_*imm 18 git

合并提交是至少有两个父级的提交.这些父母按特定顺序排列.

如果我当前在分支上master,并且我在分支中合并feature,我创建一个新的提交,其第一个父是提交master,第二个提交是提交feature.这个顺序通过跑步特别明显git log --first-parent.

*   The merge commit
|\
| * The commit from `feature`
* | The commit from `master`
Run Code Online (Sandbox Code Playgroud)

说我现在认识到的顺序是南辕北辙:我打算到分支合并masterfeature运行git checkout feature; git merge master.我想交换合并提交的父级的顺序,但我不想经历再次解决所有合并冲突的麻烦.我怎样才能做到这一点?

*   The merge commit
|\
* | The commit from `feature`
| * The commit from `master`
Run Code Online (Sandbox Code Playgroud)

Jar*_*ubb 25

Actualy,我最近学到了一个非常酷的命令,可以完全按照你的意愿行事:

git commit-tree -p HEAD^2 -p HEAD^1 -m "Commit message" "HEAD^{tree}" 
Run Code Online (Sandbox Code Playgroud)

这将基于当前HEAD创建一个新提交,但假设它的父母是HEAD ^ 2,HEAD ^ 1(注意这是相反的顺序).

git-commit-tree将新版本打印为输出,因此您可以将它与git-reset-hard结合使用:

git reset --hard $(git commit-tree -p HEAD^2 -p HEAD^1 -m "New commit message" "HEAD^{tree}")
Run Code Online (Sandbox Code Playgroud)

  • 我认为你应该使用`--soft` - 或者至少省略`--hard`.没有内容取决于父母的顺序,这只是一个祖先的问题.机上内容的变化仍然很好,没有理由重置那些. (3认同)

Sas*_*olf 7

一种方法是模拟合并.那我们怎么做呢?

让我们假设你有类似下面的提交图:

* (master) Merge branch 'feature'
|\
| * (feature) feature commit
* | master commit
. .
. .
. .
Run Code Online (Sandbox Code Playgroud)

保持变化

我们要合并masterfeature,但我们希望保持的变化,所以首先我们切换到master,从中我们"手动"更新我们的头在参考点feature,而不是改变工作树.

git checkout master
git symbolic-ref HEAD refs/heads/feature
Run Code Online (Sandbox Code Playgroud)

symbolic-ref命令类似git checkout feature但不触及工作树.所以所有变化都master保持不变.

撤消旧合并

现在我们对工作树中的合并进行了所有更改.所以我们继续通过重置"撤消"合并master.如果您不愿意将引用丢失到合并提交中,则可以创建临时标记或分支.

(如果你想保留提交信息,现在是将它复制到某处保存的好时机.)

# Optional
git tag tmp master

git branch -f master master^
Run Code Online (Sandbox Code Playgroud)

现在,您的提交树应该像合并之前一样.

假合并

这是hacky部分.我们想欺骗git相信我们目前正在合并.我们可以通过MERGE_HEAD.git包含我们要合并的提交的哈希的文件夹中手动创建文件来实现此目的.
所以我们这样做:

git rev-parse master > .git/MERGE_HEAD
Run Code Online (Sandbox Code Playgroud)

如果你正在使用git bash,git现在会告诉你它正在合并的过程中.

要完成合并,我们必须这样做commit.

git commit
# Enter your commit message
Run Code Online (Sandbox Code Playgroud)

它已经完成了.我们重新创建了合并提交但是使用了交换父项.所以你提交历史现在应该是这样的:

* (feature) Merge branch 'master'
|\
| * (master) master commit
* | feature commit
. .
. .
. .
Run Code Online (Sandbox Code Playgroud)

如果您需要任何进一步的信息,请不要犹豫.


Tij*_*men 7

受这个答案的启发,我想出了这个:

git replace -g HEAD HEAD^2 HEAD^1 && 
git commit --amend && 
git replace -d HEAD@{1}
Run Code Online (Sandbox Code Playgroud)

第一个命令在称为替换引用的东西中切换两个父级,但仅将其存储在本地,人们称之为 hack

第二个命令创建一个新的提交。

第三个命令删除旧的替换引用,因此它不会弄乱取决于该提交的其他提交。