我试图理解为什么git会为两个分支之间的合并产生一个带有唯一SHA1的提交而没有冲突。存储没有冲突的信息真的值得修改历史的杂乱吗?
答案 0 :(得分:7)
简短的回答是提交记录了工作目录的特定状态,合并将创建一个与父项不匹配的状态,因此需要新的提交,而不是仅仅移动分支指针。但是,为了进一步阐述,有助于准确理解合并两个分支的含义。
使用git merge
这两种最常见的方式是:a)将本地分支赶上远程分支,b)实际将两个独立的分支合并在一起。
在第一种情况下,你有这样的事情:
A--B--C--D--E--F--G
^ ^
| +-- origin/master
+-- master
在这种情况下,git merge origin/master
只是将master
的指针移动到新位置。这就是所谓的“快进”合并,并且通常不会导致新的提交(尽管如果您有理由可以明确请求一个)。
另一方面,如果您有这样的事情:
A--B--C--D--E--F--G <-- branch1
\
J--K--L--M--N <-- branch2
并且您在branch2
并想要在branch1
中合并,只需移动您的branch2
指针就没有意义了。如果您刚刚将branch2
移至指向G
,则会失去J
到N
所做的更改。在这种情况下,git merge
必须创建一个新的提交,其中生成的工作树看起来像是您复制了C
(G
和N
的合并基础,其中您可以通过运行git merge-base branch1 branch2
)查看,然后应用D
到G
以及J
到N
中的所有更改。即使这导致没有冲突(两个分支修改了不同的文件集或至少只是文件的不同区域),生成的工作目录状态也不匹配G
或N
,所以需要新的提交。因此git
将创建一个新的提交,其中包含一个工作目录,其中包含应用两个分支的更改的结果,并将该提交标记为同时将G
和N
作为父项。 / p>
因此,它并不是“存储没有冲突的信息”,而是存储项目的新的独特状态。当然,您可以使用git log
,git diff
等查看该提交,并查看是否存在冲突,但这并不是新提交的原因。
答案 1 :(得分:3)
合并提交的要点是在生成的HEAD的父级中包含两个不同的提交树。
有三种方法可以执行合并:
为您合并的每件事创建一个包含单独父级的合并提交 这意味着您合并的分支的所有原始提交仍将在您的历史记录中显示为单独的并行轨道。
创建一个虚假的合并提交,其中只有一个父级包含所有合并的更改 这会导致更简单的历史记录(没有单独的树),但它会丢失合并分支的所有提交 这是一个坏主意。
为合并后的更改创建新的提交,这些更改将原始分支作为其父项
这会产生线性历史,两组提交散布在一起
这是git rebase
的作用。
答案 2 :(得分:1)
存储没有冲突的信息是否真的值得修改历史更加混乱?
你需要git rebase
,这样做。考虑使用rebase进行合并并避免合并提交的一种简单方法是“假装工作首先发生而不是并行发生。”
在git让你觉得优雅之前,Rebase对于“玩”很危险,但它确实解决了你所直观的问题。通常,当“原始”提交历史记录对您没有意义时,将使用rebase。在合并的情况下,当您认为其中一个父历史不相关且不应该真正发生时(它“重写历史记录”)时使用它。在一些重大合并的情况下,你真的做想要两个历史;在其他人,你没有。我省略了一个更全面的解释,因为你可以在网上找到很多,有些比其他更好。