最好用一个例子来解释:
git init
touch a # create the file "a"
git add a && git commit -m "a"
git checkout -b test # create and checkout the branch "test"
touch t
git add t && git commit -m "t"
git checkout master
touch b
git add b && git commit -m "b"
git checkout test
git merge master # when I do the merge the editor pops up asking for a commit message with something like "merge with master" as the default, and this commit is the problem
现在问题是,我希望“test”的提交历史记录有三个提交,这些提交在这里由它们的消息表示(与git log
的顺序相同):
- b
- t
- 一个
但我得到了:
- 与主人合并 - t
- b
- 一个
有趣的是,[ b ]和[与主合并]提交与之前的提交具有相同的 diff 。更有趣的是, HEAD^
实际上指向 [t] 的“test”HEAD^^
指向<在“测试”中强> [a]
我想知道为什么会发生这种情况以及如何避免[与主合并]提交。 另请参阅Update-2。
我应该注意,如果我不在分支“test”上执行[ t ]提交,这将不会发生,即:我将在合并后的历史记录中获得两次提交:[ a ]和[ b ]。
似乎我无法使用--ff-only
选项并获得错误“无法快进”。但为什么会这样(因为没有冲突)?这已在“ckruczek”的评论中得到解决。
我猜这个问题自最初发布以来已经发生了一些变化: 提交[与主合并]和[ b ]都在其中包含创建的“b”,那么它是如何存在的呢?在序列中“播放这些提交”时没有错误?
答案 0 :(得分:4)
合并提交应该在分支上发生。
gitk
提供了比git log
更好的提交可视化。
合并两个分支时,它们在git log
历史记录中的显示顺序无关紧要;重要的是他们来自两个不同的分支。
在您进行合并之前,这里是gitk的屏幕截图:
当您创建提交&#34; t&#34;时,您将从master创建分支分支,其将继续使用名称 test 。如果您在测试分支中,则现在将在提交之后添加未来提交&#34; t&#34;。
同时,主分支在&#34; a&#34;之上有另一个提交,即提交&#34; b&#34;。当你进行合并时,git做的是它将 test 的所有提交压缩成一个并在&#34; b&#34;之上进行提交,这被称为合并提交,有两个父母 - 每个分支一个。您可以在gitk
中观察它们。
这是合并后的屏幕截图:
提交&#34; b&#34;和&#34; t&#34;没有任何共同之处,因此合并提交可以安全地创建在&#34; b&#34;之上,没有任何冲突。
所有这一切,你想要的是线性历史。如果是这样,在 test 分支中,执行 rebase 而不是合并:
$ git checkout test #making sure we're in 'test' branch
$ git rebase master
在rebase之后,历史看起来像这样:
完全相同的事情;只是它是线性的。
如果你不做&#34; t&#34;提交,然后测试分支指向提交&#34; a&#34;并且 test 中没有任何内容 master ,因此快进合并会发生。这意味着 test 分支指针只是更新为指向与较新的 master 分支相同的提交。
回应OP的最新评论
您在代码中执行的操作已经签出 test 并将 master 合并到其中,这通常与您何时执行相反实践中的合并,因为主分支是主要分支。在那种情况下,我会这样做:
$ git checkout master
$ git merge test
看起来像这样:
这里, master 分支现在指向合并提交,合并提交包含&#34; b&#34;在它。
如果要还原此提交,请执行以下操作:
$ git revert <merge commit id>
没有工作 - 因为合并是在两个分支之间。您必须指定要与合并一起使用的父编号。要恢复&#34; b&#34;中的更改,您必须说&#34;我想恢复主要主分支&#34;,如:
$ git revert -m 1 <merge commit id>
将恢复提交&#34; b&#34;。指定2将恢复测试分支,并提交&#34; t&#34;。
答案 1 :(得分:1)
这是图git merge
命令之前的图形:
* 355aaea b <-------- master is here
* | 4bfc6f1 t <-------- test is here
|/
* fd7cb2e a
如您所见,您的命令创建了与test
不同的分支master
。
这是git log --graph
之后git merge
显示的内容:
$ git log --graph
* be820db Merge branch 'master' into test
|\
| * 355aaea b
* | 4bfc6f1 t
|/
* fd7cb2e a
分支master
仍指向355aaea
(合并仅影响当前分支),test
已移至新提交(be820db
)。
合并不同的分支需要创建一个具有两个父项的新提交(be820db
):4bfc6f1
(当前由t
指向)和355aaea
(当前指向)在master
)。 4bfc6f1
是第一个父级,因为当test
命令出现时git merge
是当前分支。其他父项是git merge
命令中指定的分支,按命令行中指定的顺序排列。
只有当前分支是您要分支的合并的祖先时才可以进行快速转发。例如,给定存储库的当前状态,以下命令会产生“快进”合并:
$ git branch new fd7cb2e
$ git checkout new
$ git merge test
“快进”合并是可能的,因为合并的分支(test
)包含不在当前分支(new
)中的提交,但当前分支不包含不是的提交在合并的分支中。在这种情况下,不需要新的提交,因为它不会产生任何新的提示。 “快进”表示当前分支向前移动,直到达到合并提交为止。