-
A1. 附录 A:Git 在其他环境中的使用
- A1.1 图形界面
- A1.2 Git 在 Visual Studio 中的使用
- A1.3 Git 在 Visual Studio Code 中的使用
- A1.4 Git 在 IntelliJ/PyCharm/WebStorm/PhpStorm/RubyMine 中的使用
- A1.5 Git 在 Sublime Text 中的使用
- A1.6 Git 在 Bash 中的使用
- A1.7 Git 在 Zsh 中的使用
- A1.8 Git 在 PowerShell 中的使用
- A1.9 总结
-
A2. 附录 B:在应用程序中嵌入 Git
-
A3. 附录 C:Git 命令
7.9 Git 工具 - Rerere
Rerere
git rerere
功能有点像隐藏特性。这个名称代表“重用已记录的解决方案”,顾名思义,它允许你让 Git 记住你如何解决代码块冲突,以便下次遇到相同的冲突时,Git 可以自动为你解决。
在许多情况下,此功能可能非常方便。文档中提到的一个示例是,当你想确保一个长期存在的主题分支最终能够干净地合并,但又不想让一堆中间合并提交弄乱你的提交历史时。启用 rerere
后,你可以尝试偶尔合并,解决冲突,然后撤消合并。如果你持续这样做,那么最终的合并应该会很容易,因为 rerere
可以自动为你完成所有操作。
如果要保持分支的变基状态,这样每次变基时都不必处理相同的冲突,也可以使用相同的策略。或者,如果你想获取一个你已经合并并修复了许多冲突的分支,然后决定对其进行变基,你可能不必再次处理所有相同的冲突。
rerere
的另一个应用场景是,你偶尔将许多不断发展的主题分支合并到可测试的头部,就像 Git 项目本身经常做的那样。如果测试失败,你可以倒回合并并重新执行合并,而无需再次解决冲突,同时排除导致测试失败的主题分支。
要启用 rerere
功能,只需运行以下配置设置即可
$ git config --global rerere.enabled true
你也可以通过在特定仓库中创建 .git/rr-cache
目录来启用它,但配置设置更清晰,并且可以为你全局启用此功能。
现在让我们看一个简单的示例,类似于我们之前的示例。假设我们有一个名为 hello.rb
的文件,其内容如下
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
在一个分支中,我们将“hello”更改为“hola”,然后在另一个分支中,我们将“world”更改为“mundo”,就像之前一样。
当我们将这两个分支合并在一起时,我们会遇到合并冲突
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
你应该注意到那里出现了一行新内容 Recorded preimage for FILE
。否则,它应该看起来与正常的合并冲突完全一样。此时,rerere
可以告诉我们一些事情。通常,你可能会在此时运行 git status
以查看所有冲突的内容
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
但是,git rerere
还会使用 git rerere status
告诉你它已记录了合并前的状态
$ git rerere status
hello.rb
而 git rerere diff
将显示解决冲突的当前状态,即你开始解决冲突时的状态以及你解决后的状态。
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
此外(这与 rerere
关系不大),你可以使用 git ls-files -u
查看冲突的文件以及之前、左侧和右侧的版本
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
现在你可以将其解决为 puts 'hola mundo'
,然后再次运行 git rerere diff
以查看 rerere 将记住的内容
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
所以基本上是说,当 Git 在 hello.rb
文件中看到一个代码块冲突,其中一侧是“hello mundo”,另一侧是“hola world”时,它会将其解决为“hola mundo”。
现在我们可以将其标记为已解决并提交
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
你可以看到它“Recorded resolution for FILE”。
现在,让我们撤消该合并,然后将其变基到我们的 master
分支之上。我们可以使用 git reset
将我们的分支移回,就像我们在 重置详解 中看到的那样。
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
我们的合并已撤消。现在让我们将主题分支变基。
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
现在,我们得到了预期的合并冲突,但是请查看Resolved FILE using previous resolution
这一行。如果我们查看该文件,会发现它已经被解决,其中不再存在合并冲突标记。
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
此外,git diff
会向你展示它是如何被自动重新解决的。
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
你也可以使用git checkout
重新创建冲突文件的状态。
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
我们在高级合并中看到了一个这样的例子。不过现在,让我们通过再次运行git rerere
来重新解决它。
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
我们已经使用rerere
缓存的解决方案自动重新解决了该文件。你现在可以添加并继续rebase以完成它。
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
所以,如果你经常进行重新合并,或者想要在不进行大量合并的情况下使主题分支与你的master
分支保持最新,或者你经常进行rebase操作,你可以开启rerere
来简化你的工作。