Things I Learned (2020-03)

Git Undo Merge Conflict Resolve🔗

• Git

有时候,会遇到这样的情况:在处理 Git Merge Conflict 的时候,因为一些误判,导致选择了错误的修改方式。如果选择是在文本编辑器中完成的,那么可以通过撤销改动的方式回退到最原始的版本,重新选择;而如果文本编辑器的历史记录丢失或者改动是通过其他方式完成的,想要恢复到最开始的状态,就需要借助 Git 的 checkout -m 功能。

通过 git checkout -m 命令,可以将一个或多个指定的文件,回退到最开始的冲突状态。比如:

git checkout -m package.json

这个命令可以将 package.json 文件回退到最开始的冲突状态;而:

git checkout -m .

则可以将目录下所有的文件都回退到最开始的冲突状态(如果没有冲突的话保持不变)。

需要注意的几点:

  1. git checkout -m 在不同的情况下代表的含义是不同的。在解决冲突的时候表示重新创建冲突;在切分支的时候则等价于 --merge,表示使用 3-way merge 去合并两个分支都做了改动的文件(参考官方文档中的解释);
  2. 如果在处理冲突的时候做了其他的改动,在回退的时候不会保留这些改动:可以简单的认为,-m 做的事情就是将冲突文件还原到最初的状态。

Git Checkout Specific Side🔗

• Git

在进行 Git Merge 或者 Rebase 操作的时候,经常需要处理冲突。大部分时候,解决冲突需要认真观察冲突处的代码,然后手工进行选择/修改。但是在某些情况下,解决冲突只需要简单选择某一边的修改就可以了。

举个例子:假设 1.0 版本和 1.1 版本存在并行开发。在 1.0 版本完全封板之后,可能需要将 1.0 版本的改动 rebase 到 1.1 版本提交的下面。假设两个版本都有升级版本号的提交,一个升级版本号到 1.0.1,一个升级版本号到 1.1.1。此时,进行 rebase 就会造成版本号上的冲突。在 lerna 管理的项目中,这样的冲突可能会涉及很多文件。

在已知只需要选择一边的前提下,如果还要手动解决每一个文件的冲突,显然有一些机械。Git 提供了 --ours 和 --theirs 的 flag,可以用于快速的选择冲突的解决方案。

假设有一个冲突如下:

<<<<<<< HEAD
  "package": "1.0.1",
=======
  "package": "1.1.1",
>>>>>>> v1.1

如果希望选择当前的改动(假设文件名叫 package.json),可以使用如下的命令:

git checkout --ours package.json

如果希望选择对方版本的改动,则可以用:

git checkout --theirs package.json

更进一步,如果希望用同一套方案解决所有冲突的文件,可以直接用如下的命令(假设希望使用当前的改动):

git checkout --ours .

需要注意的一点是,在进行 Git Merge 和 Git Rebase 的时候,对应的“当前版本”(ours)与“对方版本”(theirs)的概念是不同的。对 Git Merge 来说,操作是将对方分支合并到当前的分支,因此“当前版本”(ours)就是当前分支;而对 Git Rebase 来说,操作是将当前分支的改动应用在对方分支代码的基础上,因此“当前版本”(ours)是对方分支。

抛开上面的概念,其实从 Git Conflict 的展示上看还是很直观的。上半部分(=======前的部分)对应的是“当前版本”(ours),下半部分是“对方版本”(theirs)。