Git 🌙
Chapters ▾ 2nd Edition

7.9 Mga Git na Kasangkapan - Ang Rerere

Ang Rerere

Ang git rerere na pag-andar ay maliit na nakatagong tampok. Ang ibig sabihin ng pangalan ay “reuse recorded resolution” at, bilang nagpapahiwatig na pangalan, pinapayagan ka nitong hilingan ang Git na tandaan kung paano mo nalutas ang isang malaking naputol na pagsasalungat kaya sa susunod na makakita ito ng parehong pagkasalungat, ang Git ay maaaring malutas ito para sa iyo ng awtomatiko.

Mayroong mga bilang ng mga sitwasyon na kung saan ang pag-andar nito ay maaari talagang magaling. Isa sa mga halimbawa na nabanggit sa dokumentasyon ay kapag gusto mo na tiyakin ang isang matagal na paksa na branch ay ganap na pagsasama nang malinis, ngunit ayaw mong magkakaroon ng isang grupo ng intermediate merge na mga commit na nag-clutter pataas sa iyong kasaysayan ng commit. Sa rerere na pinagana, maaari kang magtangka sa minsang na-merge, lutasin ang mga pagkasalungat, pagkatapos ay i-atras ang pag-merge. Kung gagawin mo ito nang paulit-ulit, pagkatapos ay ang huling merge ay dapat na madali dahil sa rerere ay maaari lamang gawin ang lahat para sa iyo ng awtomatiko.

Ang parehong taktika ay maaaring gamitin kung gusto mong itago ang isang branch na naka-rebase rebased kaya hindi mo kailangang harapin ang parehong pag-rebase sa mga sumasalungat sa bawat oras na ginawa mo ito. O kung gusto mong kumuha ng isang branch na nai-merge mo at nag-ayos ng maraming mga pagkakasalugat at pagkatapos ay magpasya na i-rebase ito sa halip — malamang na hindi mo kailanganin gawin muli ang parehong mga pagkakasalungat muli.

Isa pang application sa rerere na kung saan ikaw ay mag merge ng maraming nagbabago na paksang mga branch magkasama sa isang pagsubok sa ulo pangminsan-minsan, bilang ang Git na proyekto sa kanyang sarili ay madalas na ginagawa. Kung ang pagsubok ay nabigo, maaari mong i-rewind ang mga merge at gawin muli sila ng walang paksa sa branch na ginawa mong pagsubok na walang nareresulba na mga pagsasalungat muli.

Para mapagana ang rerere na pag-andar, kailangan mo lang na patakbuhin ang config na setting na ito:

$ git config --global rerere.enabled true

Maaari mo ring buksan ito sa pamamagitan ng paglikha ng .git/rr-cache na direktoryo sa isang tiyak na repositoryo, ngunit ang config na setting ay mas malinaw at nagpapagana sa pag-andar sa buong mundo para sa iyo.

Ngayon tingnan natin ang isang simpleng halimbawa, katulad sa ating nakaraang isa. Sabihin natin na meron tayong isang file na pinangalanang hello.rb na ganito ang hitsura:

#! /usr/bin/env ruby

def hello
  puts 'hello world'
end

Sa isang branch ay binago natin ang salitang “hello” sa “hola”, pagkatapos sa ibang branch ay binago natin ang “world” sa “mundo”, tulad ng dati.

rerere1

Kapag na-merge natin ang dalawang mga branch na magkasama, makakuha tayo ng merge na nagkasalungat:

$ 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.

Dapat mong mapansin ang bagong linya na Recorded preimage for FILE doon. Kung hindi man dapat itong magmukha na katulad ng isang normal na merge na pagkakasalungat. Sa puntong ito, ang rerere ay maaaring sabihin natin ang ilang mga bagay. Karaniwan, maaari mong patakbuhin ang git status sa puntong ito upang tingnan ang lahat na nagkasalungat:

$ 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
#

Gayunpaman, ang git rerere ay magsasabi din sa iyo kung ano ang natala na pre-merge na estado para sa git rerere status:

$ git rerere status
hello.rb

At ang git rerere diff ay nagpapakita sa kasalukuyang estado sa resolusyon — kung ano ang iyong sinimulan sa paglutas at ano ang iyong nalutas na ito.

$ 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

Gayundin (at ito ay hindi talagang may kaugnayan sa rerere), maaari mong gamitin ang git ls-files -u para tingnan ang nagkasalungat na mga file at ang bago, kaliwa at kanan na mga bersyon:

$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1	hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2	hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3	hello.rb

Ngayon ay maaari mong malutas ito sa pagtulas na ito lang ang puts 'hola mundo' at maaari mong patakbuhin ang git rerere diff muli upang tingnan kung anong rerere ay maalala:

$ 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

Kaya talagang sabi, kapag ang Git ay nakakita ng maraming pagkakasalungat sa isang hello.rb na file na mayroong “hello mundo” sa ibang panig at ang “hola world” ay sa kabila, ito ay maglulutas sa “hola mundo”.

Ngayon ay markahan natin ito bilang nalutas at na-commit ito:

$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'

Maaari mong makita itong "Recorded resolution for FILE".

rerere2

Ngayon, i-undo natin ang na-merge at pagkatapos i-rebase ito sa itaas sa ating master branch sa halip. Maaari nating ilipat ang ating branch pabalik sa pamamagitan ng pagagamit ng git reset tulad ng nakita natin sa Ang Reset Demystified.

$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello

Ang ating merge ay hindi natapos. Ngayon i-rebase natin ang paksa na branch.

$ 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

Ngayon, nakuha na namin ang parehong marge na pagkakasalungat tulad ng inaasahan, ngunit tingnan ang Resolved FILE using previous resolution na linya. Kung titingnan namin ang file, makikita namin na ito ay nalutas na, walang nagkakasalungat na mga marka nito.

#! /usr/bin/env ruby

def hello
  puts 'hola mundo'
end

Gayundin, ang git diff ay nagpapakita sa iyo kung papaano ito awtomatikong nalutas:

$ 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
rerere3

Maaari ka ding lumikha sa nagkasalungat na file na estado gamit ang 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

Nakita namin ang halimbawa nito sa Advanced na Pag-merge. Para sa ngayon bagaman, muling lutasin ito sa pamamagitan ng pagpapatakbo ng git rerere muli:

$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby

def hello
  puts 'hola mundo'
end

Meron kaming nalutas na file na awtomatikong gumagamit ng rerere na cached na resolusyon. Maaari mo na ngayong idagdag at ipagpatuloy ang pag-rebase upang tapusin ito.

$ git add hello.rb
$ git rebase --continue
Applying: i18n one word

Kaya, kung ikaw ay maraming gagawin na mga pag-remerge, o nais na panatilihin ang isang paksa na branch na bagong-bago sa maraming mga merge, o madalas mong i-rebase, maaari mong i-on ang rerere upang tulungan ang iyong buhay nang kaunti.

scroll-to-top