Git筆記(33) Rerere
1. 重用記錄的解決方案
git rerere
功能是一個隱藏的功能
正如它的名字“重用記錄的解決方案(reuse recorded resolution)”所示
它允許讓 Git 記住解決一個塊衝突的方法, 這樣在下一次看到相同衝突時,Git 可以爲你自動地解決它
要啓用 rerere
功能,只需運行以下配置選項即可:
$ git config --global rerere.enabled true
你也可以通過在特定的倉庫中創建 .git/rr-cache
目錄來開啓它
但是設置選項更乾淨並且可以應用到全局
2. 乾淨的合併和變基
想要保證一個長期分支會乾淨地合併
但是又不想要一串中間的合併提交弄亂你的提交歷史
將 rerere
功能開啓後,可以試着偶爾合併,解決衝突,然後退出合併
如果你持續這樣做,那麼最終的合併會很容易,因爲 rerere
可以爲自動做所有的事情
可以將同樣的策略用在維持一個變基的分支時
這樣就不用每次解決同樣的變基衝突了
或者你將一個分支合併並修復了一堆衝突後想要用變基來替代合併
可能並不想要再次解決相同的衝突
當偶爾將一堆正在改進的主題分支合併到一個可測試的頭時
如果測試失敗,可以倒回合併之前
然後在去除導致測試失敗的那個主題分支後重做合併
而不用再次重新解決所有的衝突
3. 舉例
假設有一個名爲 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
同樣可以使用 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 add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
可以看到它 “Recorded resolution for FILE
”
現在如果想撤消那個合併然後將它變基到 master 分支頂部來替代它
可以通過使用之前在 Git筆記(31) 重置揭密 看到的 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
puts 'hello mundo'
end
在 Git筆記(32) 高級合併 中已看過這個例子
然而現在,通過運行 git rerere
來重新解決它:
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
通過 rerere
緩存的解決方案來自動重新解決了文件衝突
現在可以添加並繼續變基來完成它
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
所以,如果做了很多次重新合併
或者想要一個主題分支始終與你的 master
分支保持最新但卻不想要一大堆合併, 或者經常變基
打開 rerere
功能可以幫助你的工作
參考: git
以上內容,均根據git官網介紹刪減、添加和修改組成
相關推薦:
Git筆記(32) 高級合併
Git筆記(31) 重置揭密
Git筆記(30) 重寫歷史
Git筆記(29) 搜索
Git筆記(28) 簽署工作
謝謝