Git
Chapters ▾ 2nd Edition

7.9 Гит алати - Rerere

Rerere

git rerere функционалност је донекле скривена могућност. Име значи reuse recorded resolution (поново искористи сачувано решење) и као што име наводи, дозвољава вам да од програма Гит затражите да запамти начин на који сте разрешили комад конфликта, тако да кад следећи пут наиђе на исти конфликт буде у могућности да га уместо вас аутоматски разреши.

Постоји већи број ситуација у којима је ова функционалност заиста корисна. Један од примера поменут у документацији је када хоћете обезбедити да се у будућности дуговечна тематска грана чисто споји, али не желите у међувремену гомилу комитова спајања. Када је rerere укључено можете повремено да покренуте спајање, разрешите конфликте, па затим откажете спајање. Ако то радите редовно, онда би коначно спајање требало да прође глатко јер rerere може аутоматски да одради све уместо вас.

Иста ова тактика може да се употреби ако грану желите да одржавате ребазираном тако да се не морате суочавати са истим конфликтима ребазирања сваки пут када то радите. Или ако имате грану коју сте спојили и исправили гомилу конфликата, па онда одлучите да уместо спајања урадите ребазирање – највероватније нећете морати да поново решавате све исте конфликте.

Још једна ситуација се дешава када повремено спајате гомилу тематских грана које се развијају у главу која може да се тестира, као што то често чини сам пројекат Гит. Ако тестови не прођу, можете да премотате уназад спајања и одрадите их поново без тематске гране због које тестови нису успешни, а да нема потребе за поновним решавањем конфликата.

Ако желите да укључите rerere функционалност, једноставно извршите следеће конфигурационо подешавање:

$ git config --global rerere.enabled true

Други начин на који је такође можете укључити је да креирате .git/rr-cache директоријум у одређеном репозиторијуму, али је конфигурационо подешавање чистије и може да се обави глобално.

Хајде да сада погледамо прости пример, сличан претходном. Рецимо да имамо фајл који изгледа овако:

#! /usr/bin/env ruby

def hello
  puts 'hello world'
end

У једној грани изменимо реч „hello” у „hola”, па затим у другој грани променимо „world” у „mundo”, као и раније.

rerere1

Када спојимо две гране, доћи ће до конфликта спајања:

$ 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 ФАЈЛ. Иначе би требало да изгледа као обичан конфликт спајања. У овом тренутку, 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) употребити и 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' и можете поново да извршите команду 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

Ово у суштини каже, када програм Гит наиђе на комад конфликта у фајлу 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 ФАЈЛ).

rerere2

Хајде да сада поништимо то спајање па да уместо њега извршимо ребазирање на врх наше master гране. Грану можемо вратити уназад користећи 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 ФАЈЛ using previous resolution (Решен ФАЈЛ употребом ранијег решења). Ако погледамо у фајл, видећемо да је већ разрешен, у њему нема маркера конфликта.

$ cat hello.rb
#! /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
rerere3

Командом 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

Пример за ово смо видели у Напредно спајање. Међутим, за сада, хајде да га још једном поново разрешимо употребом команде 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 да вам макар мало олакша живот.