git merge命令:解决冲突,重新放置压扁差异,合并策略
在这篇文章中,我们将介绍git merge方法。从如何合并到解决冲突,合并提交的特点,合并策略,与rebase和squash的区别,以及git merge命令的其他选项。
1. 如何合并一个分支
git merge命令是用来将一个分支合并到另一个分支。
在git branch post中,我提到分支名称是该分支的最后一次提交。
同样的道理,合并分支最终会创建一个新的提交,其中包含两个分支最后一次提交的所有修改、
你也可以把它看成是对运行git merge命令的工作分支的一次新提交。
git merge命令总是在创建该分支的地方执行合并提交。
例如,如果你要从 main分支合并 feature-a分支,你会使用这样的命令
$ git switch main
switched to branch 'main'
$ git merge feature-a
Merge made by the 'ort' strategy在上面的例子中,你可以看到我们使用了merge-ort策略,这是Git最新的默认合并策略,于2022年改变。
1.1. ort策略
在进入下一节之前,让我们先来看看Git最新的合并算法,ort策略。
ort是 "Ostensibly Recursive's Twin "的缩写,意味着它是为了取代旧的默认算法,recursive策略而创建的。
与 recursive策略相比,据说它可以减少冲突并照顾到重命名的文件。
它基本上是基于三向合并算法,比较三个来源的变化:两个分支的同一祖先提交、两个分支的最新提交和两个分支的最新提交,然后执行一个
合并。在合并两个分支时,我们主要使用ort策略,因为它比之前使用的resolve和recursive策略表现更好。
其他值得了解的策略是用于合并两个或多个分支的octopus策略,或者用于合并到子目录的subtree策略。
现在,让我们先熟悉一下这些名称。
这些策略可以用-s或--strategy选项来指定,如下所示。
$ git merge -s recursive feature-a2. How to resolve a merge conflict## 2. 如何解决合并冲突
当两个不同分支上的同一文件中的同一行内容不同时,就会发生合并冲突。 为了保存数据,除非你在策略中给它一个选项,否则Git绝不会任意删除某些东西。相反,它将暂停合并,给我们一个选择。
让我们看看这个动作。
首先,我们修改了1.md文件,在main和develop两个分支中的内容不同。
然后,当我们进入main分支并试图合并develop分支时,我们得到一个合并冲突。

如果你对git commit命令的-a选项感到陌生,请参阅git commit post。
此时,Git 会在有冲突的文件内容中添加诸如 <<<<<<< HEAD, =======, >>>>>>> branch-name 的符号,让你知道到底有什么需要修正的。
让我们打开1.md文件。

这是在Neovim编辑器中打开的1.md文件。我们只需要在这部分保留我们想要的东西,删除Git添加的符号,然后继续提交。
在一个支持Git的编辑器中,合并就更容易了,比如VSCode。高亮显示很直观,按下上面四句话的按钮<<<<<<< HEAD就会自动删除排除的内容和Git的符号。

修改完内容后,像正常提交一样用git commit命令完成合并。

3. 与rebase的区别
git merge和git rebase命令有一些共同点:它们都是合并两个分支和解决合并冲突的方法。
然而,它们的工作方式还是有区别的,了解它们很重要,这样你就可以根据自己的需要选择正确的命令。
git merge命令创建一个新的合并提交,将两个分支的最后一个提交作为其父分支,如上图所示。
结果,提交历史中出现了两个分支一起对应的提交。
feature-a、feature-b等路径在主路径上来来回回,称为 main分支。
git rebase命令将两个分支合并,这样提交历史中就没有死角了。
这比你想象的要简单。让我们看一下下面的图片。

假设你想把feature-a分支合并到main分支,该分支从一个共同的祖先提交A中分化出来,git rebase命令会创建一个新的提交,其改动与feature-a中的提交相同。
在图中,这些是C和D的提交。
这两个提交被附加到B,即main分支的最后一个提交。
这样就形成了一个提交历史,但结果是,feature-a分支的所有修改都可以合并到main分支。
历史记录也更简单,因为我们不需要创建一个新的合并提交。
然而,我们不容易一眼看出C和D两个提交是来自不同分支的合并提交,还是之前在main分支的提交。
所以从历史的角度来看,你正在失去信息。
出于这个原因,你应该在适当的情况下使用merge和rebase,这取决于你的团队所采取的方向。
关于git rebase命令的更多信息,见本帖。
4. 与Squash的区别
Squash是Git中的一个概念,将多个提交压缩成一个。
它并不作为一个单独的命令存在,但可以作为合并或重构命令的一个选项使用。
当git merge命令使用--squash选项时,它被称为squash合并。
让我们看看下面的图片来理解squash merge。

在当前提交的 8c12中,main和 develop两个分支被分割。
我试着在main分支上进行squash合并,结果顺利通过。
下面的 git status命令的结果显示,develop分支的所有提交都在 main分支上进行了缓存。

如果你检查提交后的历史,你会发现develop分支仍未被合并,但它的改动已经被登记为main的新提交。
这就是挤压式合并的作用。
在重建过程中也可以使用squash选项,不同的是,develop分支的历史不会像上面那样留下。
我们将在rebase帖子中再次介绍这个问题。
5. 最后的想法
我认为合并冲突是Git初学者最先卡住的事情之一。 然而,合并和解决合并冲突是Git协作的核心,所以理解和掌握它们很重要。 我希望这篇文章能帮助你入门。
