Команда Git Rerere — автоматизируйте решения для устранения конфликтов слияния


rerere — сокращение от «reuse recorded resolution» (повторное использование сохраненных разрешений конфликтов). С помощью этой команды Git запоминает, каким образом был разрешен конфликт, чтобы при возникновении подобного, разрешить его автоматически.

Рассмотрим сценарии, в которых может пригодиться эта функциональность.

Сценарии

  • Допустим, у вас есть ветка темы, которую вы объединяете с главной для поддержания актуального состояния. При этом необходимо избежать засорения истории множеством промежуточных коммитов. С помощью rerere можно периодически выполнять слияние, разрешать конфликты, а затем прерывать слияние. При завершении ветки темы можно выполнить финальное слияние, а rerere разрешит все проблемы автоматически.
  • Допустим, вы объединяете множество изменений ветки темы с тестовой веткой. При возникновении ошибки в тестовой ветке можно отменить слияние, исправить ошибку и выполнить повторное слияние без повторного разрешения конфликтов.
  • Как это работает

    Для запуска rerere введите следующую команду:

    $ git config --global rerere.enabled true

    Допустим, у нас есть файл с именем script.sh со следующим содержимым:

    #!/bin/bash # My first script echo "Hello World!"

    В главной ветке изменяем слово «Hello» на «Hola», а в ветке темы — «World» на «Git»:

    При объединении двух ветвей возникает конфликт слияния:

    $ git merge topic Auto-merging script.sh CONFLICT (content): Merge conflict in script.sh Recorded preimage for 'script.sh' Automatic merge failed; fix conflicts and then commit the result.

    Это обычный конфликт слияния, но с дополнительным оператором «Recorded preimage for ‘script.sh'» (сохранение пред-образа для ‘script.sh’). При запуске git rerere status вместо git status можно выяснить, записан ли pre-merge-статус или пред-образ:

    $ git rerere statusscript.sh

    Ниже показана информация, полученная с помощью git rerere diff и git diff:

    Rerere сохраняет запись решения в папке .git/rr-cache. Заглянув в репозиторий, вы обнаружите файл preimage:

    $ tree .git/rr-cache .git/rr-cache └── 54db390f1318184c7fb941c7c688546bdec9590a └── preimage

    Запись исправления путем разрешения конфликта

    Попробуем разрешить этот конфликт, объединив «Hola» в главной ветке и «Git» в ветке темы. В результате получаем «Hola Git». Запустите rerere diff еще раз, чтобы проверить сохраненную информацию:

    $ git rerere diff --- a/script.sh +++ b/script.sh @@ -1,8 +1,4 @@ #!/bin/bash # My first script -<<<<<<< -echo "Hello Git!" -======= -echo "Hola World!" ->>>>>>> +echo "Hola Git!"

    Чтобы rerere запомнил разрешение конфликта, подготовьте файл и зафиксируйте изменение:

    $ git add script.sh $ git commit Recorded resolution for 'script.sh'. [master d0e6d1b] Merge branch 'topic'

    rerere сохранил разрешение для ‘script.sh’ или пост-образ. Представим изменение с помощью диаграммы:

    Это исправление теперь находится в postimage:

    tree .git/rr-cache .git/rr-cache └── 54db390f1318184c7fb941c7c688546bdec9590a ├── postimage └── preimage Содержимое предобраза и постобраза.

    Таким образом, мы выполнили запись разрешения с помощью git rerere.

    Для каждого файла, содержащего конфликт, git создает новую директорию с хешем, в которой будут находиться «пред-образ» и «пост-образ».

    • Когда rerere видит конфликт, он создает «пред-образ», содержимое которого такое же, как при запуске команды git diff.
    • Соответственно, «пост-образ» — это то, как выглядит файл после разрешения конфликта.

    Как работает rerere:

    Когда rerere видит конфликт для script.sh, он просматривает соответствующую директорию rr-cache, находит «пред-образ», который соответствует конфликту, и изменяет файл в рабочей директории для соответствия «пост-образу».

    Воспроизведение конфликта для автоматического разрешения

    Проверим, решится ли конфликт автоматически. Отменяем слияние, а затем перемещаем ветку темы поверх главной с помощью команды git reset -—hard HEAD^:

    $ git reset --hard HEAD^ HEAD is now at ca1bf2b Change Hello to Hola

    Затем извлекаем ветку темы и перемещаем ее:

    $ git checkout topic Switched to branch 'topic' $ git rebase master First, rewinding head to replay your work on top of it... Applying: Change World to Git Using index info to reconstruct a base tree... M script.sh Falling back to patching base and 3-way merge... Auto-merging script.sh CONFLICT (content): Merge conflict in script.sh Resolved 'script.sh' using previous resolution. error: Failed to merge in the changes. Patch failed at 0001 Change World to Git

    Возникает тот же конфликт, однако появляется строка Resolved ‘script.sh’ using previous resolution (Разрешение ‘script.sh’ с помощью предыдущего разрешения). Заглянув в файл, мы обнаружим, что проблема уже решена:

    $ cat script.sh #!/bin/bash # My first script echo "Hola Git!"

    git diff также показывает, как проблема была решена автоматически:

    $ git diff diff --cc script.sh index 46e4937,3108049..0000000 --- a/script.sh +++ b/script.sh @@@ -1,4 -1,4 +1,4 @@@ #!/bin/bash # My first script - echo "Hola World!" -echo "Hello Git!" ++echo "Hola Git!" Процесс перемещения

    Добавив следующий код, мы завершаем процесс перемещения:

    $ git add script.sh $ git rebase --continue Applying: Change World to Git

    Еще одна настройка

    Несмотря на то, что rerere автоматически разрешает конфликт, исправленные файлы остаются в состоянии unstaged. Это означает, что git add <file> необходимо выполнить вручную.

    Чтобы rerere автоматически индексировал исправленные файлы, нужно воспользоваться следующей командой:

    $ git config --global rerere.autoupdate true

    Теперь rerere автоматически исправляет и индексирует файлы.

    git rebase master First, rewinding head to replay your work on top of it... Applying: Change text to Hello Git Using index info to reconstruct a base tree... M script.sh Falling back to patching base and 3-way merge... Auto-merging script.sh CONFLICT (content): Merge conflict in script.sh Staged 'script.sh' using previous resolution. error: Failed to merge in the changes. Patch failed at 0001 Change World to Git

    Продолжите перемещение для завершения:

    $ git rebase --continue Applying: Change World to Git

    Заключение

    Если вы выполняете множество повторных слияний, хотите поддерживать актуальность ветки темы с главной веткой или часто выполняете перемещение, то воспользуйтесь rerere. Просто включите его с помощью git config --global rerere.enabled true и предоставьте Git всю оставшуюся работу.


    Перевод статьи Minh Pham: The Git Rerere Command — Automate Solutions to Fix Merge Conflicts


    Поделиться статьей:


    Вернуться к статьям

    Комментарии

      Ничего не найдено.