Git
Chapters ▾ 2nd Edition

7.9 Orodja Git - Rerere

Rerere

Funkcionalnost git rerere je nekoliko skrita značilnost. Ime izhaja iz »reuse recorded resolution« (»ponovno uporabi posneto rešitev«) in vam, kot že samo ime nakazuje, omogoča, da si Git zapomni, kako ste rešili konflikt med kosi, tako da vam lahko prihodnjič pomaga in konflikt reši avtomatično.

Obstaja več scenarijev, kjer je ta funkcionalnost zelo priročna. Eden izmed primerov, ki ga omenjajo v dokumentaciji, je, ko želite zagotoviti, ali se bo dolgotrajna tematska veja na koncu gladko združila brez konfliktov, vendar pa v svoji zgodovini ne želite imeti veliko vmesnih potrditev združitev. Z vklopljenim rerere lahko občasno poskusite združiti, rešite konflikte, nato pa izstopite iz združitve. Če to počnete neprestano, bi morala biti končna združitev enostavna, saj lahko rerere vse naredi za vas avtomatično.

Enako taktiko lahko uporabite, če želite ohraniti vejo ponovno bazirano, da se vam ne bo treba ukvarjati z istimi konflikti pri vsakem ponovnem baziranju. Ali pa, če želite vzeti vejo, ki ste jo združili in rešili veliko konfliktov, in se odločite, da jo boste raje ponovno bazirali — verjetno vam ni treba znova reševati vseh istih konfliktov.

Druga uporaba rerere je, ko združujete več tematskih vej, ki se razvijajo, skupaj v testno glavo, kar uporablja občasno tudi sam projekt Git. Če testi niso uspešni, lahko izbrišete združitve in jih ponovno izvedete brez tiste tematske veje, ki je naredila težave, ne da bi se morali ponovno spopasti s konflikti.

Za vklop funkcionalnosti rerere morate samo nastaviti to nastavitev konfiguracije:

$ git config --global rerere.enabled true

To lahko omogočite tudi tako, da v določenem repozitoriju ustvarite direktorij .git/rr-cache, vendar je nastavitev konfiguracije bolj jasna in vam omogoča, da to funkcionalnost omogočite globalno.

Zdaj si poglejmo preprost primer podoben prejšnjemu. Recimo, da imamo datoteko z imenom hello.rb, ki je videti tako:

#! /usr/bin/env ruby

def hello
  puts 'hello world'
end

V eni veji spremenimo besedo »hello« v »hola«, nato pa v drugi veji spremenimo »world« v »mundo«, tako kot prej.

Dve veji spreminjata isti del iste datoteke na različen način
Slika 160. Dve veji spreminjata isti del iste datoteke na različen način

Ko združimo dve veji skupaj, bomo dobili konflikt združevanja:

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

Opaziti bi morali novo vrstico Recorded preimage for FILE. Sicer bi morala biti videti enako kot običajen konflikt med združevanjem. V tem trenutku nam lahko rerere pove nekaj stvari. Običajno bi zdaj zagnali ukaz git status, da bi videli, kaj vse je povzročilo konflikt:

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

Z git rerere status pa vam bo git rerere tudi povedal, kaj je posnel v stanje pred-združevanja:

$ git rerere status
hello.rb

Z ukazom git rerere diff lahko prikažete trenutno stanje reševanja — s čim ste začeli, da bi rešili konflikt, in s čim ste ga rešili.

$ 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

Prav tako (in to ni povezano z rerere) lahko uporabite ukaz git ls-files -u, da vidite datoteke, ki so povzročile konflikt, in predhodno, leve in desne različice:

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

Sedaj lahko konflikt rešite tako, da spremenite vsebino datoteke na puts 'hola mundo', in nato lahko znova zaženete ukaz git rerere diff, da vidite, kaj si bo rerere zapomnil:

$ 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

To pomeni, da bo Git ob zaznavi konflikta med kosom kode v datoteki hello.rb, kjer je na eni strani »hello mundo« in na drugi strani »hola world«, konflikt rešil s »hola mundo«.

Sedaj lahko označimo konflikt kot rešen in ga potrdimo:

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

Vidite lahko, da se prikaže sporočilo »Recorded resolution for FILE«, kar pomeni, da je bila rešitev konflikta uspešno posneta.

Uspešno posneta rešitev za datoteko
Slika 161. Uspešno posneta rešitev za datoteko

Zdaj pa razveljavimo to združitev in namesto tega ponovno bazirajmo na vrh naše veje master. To lahko storimo z ukazom git reset, kot smo videli v razdelku Demistifikacija ponastavitve.

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

Naša združitev je razveljavljena. Sedaj ponovno bazirajmo tematsko vejo.

$ 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

Sedaj smo dobili enak konflikt združevanja, kot smo pričakovali, vendar oglejte si vrstico Resolved FILE using previous resolution. Če si ogledamo datoteko, bomo videli, da je bila že rešena in da v njej ni označb konfliktov združevanja.

#! /usr/bin/env ruby

def hello
  puts 'hola mundo'
end

Tudi git diff vam bo prikazal, kako je bilo avtomatično ponovno rešeno:

$ 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
Avtomatsko rešen konflikt združevanja z uporabo prejšnje rešitve
Slika 162. Avtomatsko rešen konflikt združevanja z uporabo prejšnje rešitve

Z git checkout lahko tudi ponovno kreirate stanje konfliktne datoteke:

$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby

def hello
<<<<<<< ours
  puts 'hola world'
=======
  puts 'hello mundo'
>>>>>>> theirs
end

V razdelku Napredno združevanje smo videli primer tega. Za zdaj pa ga ponovno rešimo samo z ukazom git rerere:

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

def hello
  puts 'hola mundo'
end

Datoteko smo ponovno rešili samodejno s pomočjo predpomnjenja rešitve rerere. Sedaj lahko dodate in nadaljujete ponovno baziranje, da ga dokončate.

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

Če torej pogosto ponovno združujete veje, ali želite imeti tematsko vejo posodobljeno z vejo master brez veliko združevanj, ali pogosto ponovno bazirate, lahko vklopite rerere in si tako olajšajte življenje.

scroll-to-top