修改合并分支后如何修改合并?

时间:2017-12-24 16:20:29

标签: git

我习惯使用--amend --no-edit在分支或主服务器上添加一些小的更改(如拼写错误或格式化)到上次提交。

然而,今天我第一次遇到一个小问题 在将该分支与master合并后,我在分支上修改了一个提交。

                  * branch (X+) (amended)   (this is a chronological view
                  |                          since in fact there is
                  |                           only one commit here)
* master (X) <=>  * branch (X) (merged)
|                 |
|                /
|               /
+--------------/
|

那么我怎样才能在合并后的主人身上带来变化(+)?

我尝试了其他一些合并,但这带来了一些奇怪的合并提交 由于原始更改(X)并不复杂,我只需要重置一些提交并一次性提交它们。

那么我怎样才能在合并的主人身上带来变化(+)? 因为我的机会较少,而且无法进行硬重置

非常感谢。

1 个答案:

答案 0 :(得分:1)

你说(根据评论)你跑了:

git checkout master
git merge branch

(按此顺序)。假设这有效,有两种主要可能性:你有一个快进(实际上并不是合并),或者你有一个真正的合并。我假设您有一个真正的合并,其中Git必须在两个分支提示之间找到合并基础提交。这是因为在#34;之前有提交的情况。两个分支上的合并基础(合并基础本身同时在两个分支上,而&#34;提前#34;提交仅在一个或另一个上):

...--o--o--*--M1--M2   <-- master
            \
             B1--B2--B3   <-- branch

此处,我使用Mn来标记当前仅包含在master分支中的提交,而不是Git的原始哈希ID,而Bn标记当前仅在名为branch的分支上的提交。

通过运行git checkout master,您告诉Git将M2作为当前提交。名称master此时标识此特定提交,特殊名称HEAD(全部为大写)现在&#34;附加到&#34; master

...--o--o--*--M1--M2   <-- master (HEAD)
            \
             B1--B2--B3   <-- branch

然后,git merge branch找到提交B3,这是branch此时标识的提交。然后Git自己定位 merge base 提交。在这里,提交*,因为那是&#34;最近的&#34;提交 masterbranch **。 (请注意,git diff --find-renames <hash-of-*> <hash-of-M2> # what happened on master? git diff --find-renames <hash-of-*> <hash-of-B3> # what happened on branch? 之前的所有提交也都在两个分支上。)

Git将合并基础M2与两个提示提交进行比较,即运行相当于:

*

然后Git将这两组更改结合起来:无论通过向前推进到B3而改变了什么,Git都适用于*;通过前往git add而改变的任何内容,Git 也适用于git commit。如果在这些更改集中的某处,存在重叠更改,Git会尝试找出如何正确组合它们。这可能会导致合并冲突(如果Git无法解决),或者不会(如果Git认为可以)。

通常情况下,合并进展顺利,在这种情况下,Git会将合并后的结果写入工作树(您可以看到它们)和Git的索引 (Git使用它来进行每次新提交)。即使合并失败,Git仍会将所有内容写入索引和工作树,它只使用索引的额外功能,并在工作树中保留组合的冲突文件,以便您手动进行排序。您执行此排序,M2结果以解决索引冲突,并手动运行B3而不是让Git自动执行。无论哪种方式,最后,您或Git都会从结果中进行新的提交。

新提交的特殊之处在于它有两个父项。第一个父项是当前提交 - 在这种情况下,提交...--o--o--*--M1--M2----M3 \ / B1--B2--B3 <-- branch - 第二个父项是另一个提交,这里是HEAD

master

然后Git做了与任何新提交,合并或不合并一样的事情:它将提交的哈希ID写入当前分支名称,即...--o--o--*--M1--M2----M3 <-- master (HEAD) \ / B1--B2--B3 <-- branch 所附加的名称。所以现在我们知道git checkout branch 本身发生了什么,也可以把它画出来:

branch

然后你做了一些其他的工作。现在让我们假设这并没有改变任何这些提交,因此上面的图片仍然有效。最后,你跑了:

HEAD

使名称branch指向的提交成为当前提交,并将...--o--o--*--M1--M2----M3 <-- master \ / B1--B2--B3 <-- branch (HEAD) 附加到git commit --amend --no-edit

--amend

然后你运行了有问题的命令:

B4

对于正常的,没有 - B3提交,Git在这里要做的就是立即获取索引中的任何内容,从它进行新的提交 - 调用提交{{1} - 并将新提交的当前提交(branch)作为其父项,然后将名称B4指向...--o--o--*--M1--M2----M3 <-- master \ / B1--B2--B3--B4 <-- branch (HEAD) 。结果如下:

--amend

但是,B4的作用是更改 Git创建新提交B4的方式。 Git仍然使用索引中的任何内容,但不是让B3的父级为B4,而是使B3的父级成为B3 {1}}的父母是/。由于B2是一个普通提交,只有一个父级,即B4,因此Git将B2作为其父级...--o--o--*--M1--M2----M3 <-- master \ / B1--B2--B3 \ B4

...--o--o--*--M1--M2----M3   <-- master
            \          /
             B1--B2--B3
                   \
                    B4   <-- branch (HEAD)

- 然后,为了完成提交,Git执行它始终做的事情:它将新提交的哈希ID写入当前分支,为您提供:

M3

这是您遇到的问题,但您可以做什么呢?

做什么关于这个更复杂,取决于你想要的结果。

您所做的合并提交B3仍存在于您的存储库中。合并提交会挂起以提交git push。如果您尚未发布此提交 - 即,未通过运行git fetch将其提供给其他人,或者让他们通过M3向您的计算机运送您那么你就是只有存储库,它有这个提交M3。这意味着您可以放弃 git checkout master git reset --hard HEAD~1

git reset

master将名称HEAD~1移动到指向您指定的提交。在这里,名称M3表示查找当前提交,然后查找其第一个父级,并执行第一次父级查找。提交M2的第一个父级是提交master,这样就会使名称M2指向提交...--o--o--*--M1--M2 <-- master (HEAD) \ `---. B1--B2--B3--M3 \ B4 <-- branch

M3

我们无法找到任何名称 M3。效果就好像你从未做过M3一样。由于提交B3也是您可以找到提交B3的唯一方法,因此假装...--o--o--*--M1--M2 <-- master (HEAD) \ B1--B2--B4 <-- branch 的副作用也已消失。所以我们现在可以把它画成:

M3

现在你正在重复合并。

如果您不希望重复合并,或者您已将合并提交{{1}}推送到另一个Git存储库,那么您的选项会更改,但我赢了&#39;在这里进一步详细说明,因为这已经足够长了。