Merge的进阶用法和冲突处理

9/14/2022

# 一、进阶用法

# 1. squash

squash是压碎的意思。

在merge另一个分支X的时候,如果觉得其无用的提交太多,可以尝试使用squash,把那个分支历史提交压缩后再提交。

更直观一些,可以如下操作:

  • 假如当前分支 master 的commitId是a。
  • 从当前分支创建了另一个分支 dev
  • 在dev上做了三次提交,commitId 分别是 b c d
  • 此时切换到master分支
  • 执行 git merge --squash dev

git 会把 dev 分支上所有的改动提取出来,并做了一次 git add 操作。但它不会自动提交,需要我们手动发起提交。

其实实际开发环境中,进行 merge --squash的操作很少,这个适用于:

  • 想丢弃某个分支的提交记录(可能提交太多且无用),另外新建一个分支替代它
  • 想丢弃某个分支,又想留住其代码

# 2.Fast-Forward

看如下的操作步骤:

  1. 假如当前分支 master 的commitId是a。
  2. 从当前分支创建了另一个分支 dev
  3. 在dev上做了三次提交,commitId 分别是 b c d
  4. 此时切换到master分支(前4步都一样)
  5. 执行 git merge dev 的操作

这个时候master分支是什么样子?

  • 默认情况下(ff模式),master的提交树会是一条线,看上去和dev的分支一样。
  • no-ff 模式下,会在master创建一个新的提交,明显可见的有其他分支合并进来。

因为fast-forward 模式只是更新了一下master的指针。而no-ff模式下,是创建了一个新的提交。

Git默认是 ff 模式,然而并不是每次都能使用 fast-forward。

如果从 commitId-a 创建dev分支后,master又做了1次或多次提交,那再merge dev分支的时候,就无法使用 fast-forward ,只能新建一个提交了。

# 二、merge冲突处理

# 1.直接放弃

无论是执行 pull 还是 merge其他分支,如果merge遇到冲突,我们感觉肯定解决不了的,git提供了一个放弃 merge的指令:

git merge --abort

# 2.中途放弃

比放弃更痛苦的是花了很长时间,解决了很多冲突,才发现自己还是解决不了。这个时候 abort 可能已经不好用了。

这时候最好的办法就是,先提它一版,再reset

git add .
git commit -m xxx
git reset --hard HEAD~1

中间不要断,一气呵成,就回到最初的起点

# 3.手动解决冲突

如果下定决心解决冲突,有个比较传统的办法就是手动解决冲突,一共分三步:

  • 看明白冲突
  • 编辑代码解决冲突
  • git add 解决完冲突的文件,然后git commit

# step1看明白冲突

<<<<<<< HEAD
aaa
=======
bbb
>>>>>>> a9ie876y654r43efgu876tghji87yhj

一般冲突都这个样子,中间一串等号是分隔符。往上的是当前我们分支的内容(HEAD),往下是我们要合并过来的分支的内容(一串commitId)

# step2手动解决冲突

要把不相干的内容都删掉,包括分隔符和 commitId 和 HEAD 标记位。

# step3 提交

如果确定冲突解决完了,就把解决完的文件执行一下 git add。到最后执行一个 git commit 即可。

最后的commit 建议不要加-m参数。git会跳出一个界面,附带它自动生成的备注,包含了合并信息,在提交记录中很容易看出来。

如果我们添加了-m,自己指定了注释,往往不如自动的清除,它明确标出了从哪里merge到哪里。

不要觉得最后打开的注释面板很恐怖,其实就是打开了一个vim编辑器,而且提交的时候,以#开头的文本都不会记录到备注中。

# 4.一键解决冲突

这里一定要推荐 jetBrain 系列从2020 版开始推出的魔术棒,可以一键解决90%的冲突。

首先当合并出现冲突的时候,点击 Resolve,然后点击merge,进入合并界面

image-20220315220327370

然后就可以看到弹出对话框上有一个魔术棒。点击一下,即可自动解决90%的冲突。

image-20220315220410972

如果魔术棒不可用,或者点了之后还是有冲突,剩下的就只能手动解决了。