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-a
2. 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协作的核心,所以理解和掌握它们很重要。 我希望这篇文章能帮助你入门。
