Git之深入解析Rerere重用記錄的解決方案
了解了管理或者維護 Git 倉庫、實現(xiàn)代碼控制所需的大多數(shù)日常命令和工作流程,嘗試跟了蹤和提交文件的基本操作,并且掌握了暫存區(qū)和輕量級地分支及合并的威力。如果想進一步對 Git 深入學習,可以學習一些 Git 更加強大的功能,這些功能可能并不會在日常操作中使用,但在某些時候可能還是會起到一定的關鍵性作用。
如果還不清楚 Git 的基礎使用流程、分支的管理、托管服務器的技術以及分布式工作流程等相關的技術和能力,請參考博客:
Git之深入解析Git的安裝流程與初次運行Git前的環(huán)境配置;
Git之深入解析本地倉庫的基本操作·倉庫的獲取更新和提交歷史的查看撤銷以及標簽別名的使用;
Git之深入解析Git的殺手級特性·分支管理與變基的開發(fā)工作流以及遠程分支的跟蹤;
Git之深入解析如何運行自己的Git倉庫托管服務器;
Git之深入解析如何使用Git的分布式工作流程與如何管理多人開發(fā)貢獻的項目。
git rerere 功能是一個隱藏的功能,正如它的名字“重用記錄的解決方案(reuse recorded resolution)”所示,它允許 Git 記住解決一個塊沖突的方法,這樣在下一次看到相同沖突時,Git 可以為我們自動地解決它。
在幾種情形下這個功能會非常有用,在文檔中提到的一個例子是想要保證一個長期分支會干凈地合并,但是又不想要一串中間的合并提交弄亂提交歷史,將 rerere 功能開啟后,可以試著偶爾合并,解決沖突,然后退出合并。 如果持續(xù)這樣做,那么最終的合并會很容易,因為 rerere 可以自動做所有的事情。
可以將同樣的策略用在維持一個變基的分支時,這樣就不用每次解決同樣的變基沖突了,或者將一個分支合并并修復了一堆沖突后想要用變基來替代合并,可能并不想要再次解決相同的沖突。
另一個 rerere 的應用場景是:當偶爾將一堆正在改進的主題分支合并到一個可測試的頭時,就像 Git 項目自身經(jīng)常做的。如果測試失敗,可以倒回合并之前然后在去除導致測試失敗的那個主題分支后重做合并,而不用再次重新解決所有的沖突。
要啟用 rerere 功能,只需運行以下配置選項即可:
$ git config --global rerere.enabled true
1
也可以通過在特定的倉庫中創(chuàng)建 .git/rr-cache 目錄來開啟它,但是設置選項更干凈并且可以應用到全局。
現(xiàn)在來看一個簡單的例子,類似之前的那個,假設有一個名為 hello.rb 的文件如下:
#! /usr/bin/env ruby def hello puts 'hello world' end
1
2
3
4
5
在一個分支中修改單詞 “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.
1
2
3
4
5
現(xiàn)在會注意到那個新行 Recorded preimage for FILE,除此之外它應該看起來就像一個普通的合并沖突。在這個時候,rerere 可以告訴我們幾件事,和往常一樣,在這個時候可以運行 git status 來查看所有沖突的內(nèi)容:
$ git status # On branch master # Unmerged paths: # (use "git reset HEAD
1
2
3
4
5
6
7
8
然而,git rerere 也會通過 git rerere status 告訴我們它記錄的合并前狀態(tài):
$ git rerere status hello.rb
1
2
并且 git rerere diff 將會顯示解決方案的當前狀態(tài),開始解決前與解決后的樣子:
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
同樣(這并不是真的與 rerere 有關系),可以使用 git ls-files -u 來查看沖突文件的之前、左邊與右邊版本:
$ git ls-files -u 100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb 100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb 100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
1
2
3
4
現(xiàn)在可以通過改為 puts ‘hola mundo’ 來解決它,可以再次運行 git rerere diff 命令來查看 rerere 將會記住的內(nèi)容:
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
所以從本質(zhì)上說,當 Git 看到一個 hello.rb 文件的一個塊沖突中有 “hello mundo” 在一邊與 “hola world” 在另一邊,它會將其解決為 “hola mundo”。現(xiàn)在可以將它標記為已解決并提交它:
$ git add hello.rb $ git commit Recorded resolution for 'hello.rb'. [master 68e16e5] Merge branch 'i18n'
1
2
3
4
可以看到它 “Recorded resolution for FILE”。現(xiàn)在,讓我們撤消那個合并然后將它變基到 master 分支頂部來替代它,可以通過使用之前在 git reset 來回滾分支:
$ git reset --hard HEAD^ HEAD is now at ad63f15 i18n the hello
1
2
我們的合并被撤消了,現(xiàn)在讓我們變基主題分支:
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
現(xiàn)在,正像我們期望的一樣,得到了相同的合并沖突,但是看一下 Resolved FILE using previous resolution 這行,如果我們看這個文件,會發(fā)現(xiàn)它已經(jīng)被解決了,而且在它里面沒有合并沖突標記。
#! /usr/bin/env ruby def hello puts 'hola mundo' end
1
2
3
4
5
同樣,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
1
2
3
4
5
6
7
8
9
10
11
12
13
也可以通過 git checkout 命令重新恢復到?jīng)_突時候的文件狀態(tài):
$ git checkout --conflict=merge hello.rb $ cat hello.rb #! /usr/bin/env ruby def hello <<<<<<< ours puts 'hola world' ======= puts 'hello mundo' >>>>>>> theirs end
1
2
3
4
5
6
7
8
9
10
11
在Git之深入解析高級合并中,看到這個的一個例子,然而現(xiàn)在,通過運行 git rerere 來重新解決它:
$ git rerere Resolved 'hello.rb' using previous resolution. $ cat hello.rb #! /usr/bin/env ruby def hello puts 'hola mundo' end
1
2
3
4
5
6
7
8
我們通過 rerere 緩存的解決方案來自動重新解決了文件沖突,現(xiàn)在可以添加并繼續(xù)變基來完成它:
$ git add hello.rb $ git rebase --continue Applying: i18n one word
1
2
3
所以,如果做了很多次重新合并,或者想要一個主題分支始終與 master 分支保持最新但卻不想要一大堆合并, 或者經(jīng)常變基,打開 rerere 功能可以幫助我們變得更美好。
Git
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。