Как повторить разрешение конфликта слияния после работы с несвязанными коммитами, которые были перед ним с rebase -ir?
Для простого примера, скажем, у нас есть репозиторий, в котором в файл была добавлена неправильная строка a
,
$ git init
Initialized empty Git repository in /someplace/.git/
$ echo "a1\nb2" > a
$ echo b1 > b
$ git add .
$ git commit -m init
[master (root-commit) 917f3b9] init
2 files changed, 3 insertions(+)
create mode 100644 a
create mode 100644 b
Филиал master
затем разветвляется новая ветка f
,
$ git branch f
В master
Затем мы добавляем еще одну строку в неправильный файл.
$ echo b3 >> a
$ git commit -am 'added b3 to a'
[master e44bc9f] added b3 to a
1 file changed, 1 insertion(+)
В ветке f
мы делаем что-то не связанное, совершаем это,
$ git checkout f
$ echo c1 > c
$ git add .
$ git commit -m "added c"
1 label onto
[f 7cb63b2] added c
1 file changed, 1 insertion(+)
create mode 100644 c
затем мы перемещаем строку, неправильно помещенную в файл a, в файл b.
$ echo b2 >> b
$ sed -i '/b2/d' a
$ git commit -am "moved b2 to where it really belongs"
[f 32cee76] moved b2 to where it really belongs
2 files changed, 1 insertion(+), 1 deletion(-)
Затем мы пытаемся объединить master
в f
но столкнулись с конфликтом, который master
добавил еще одну неправильную строку f
убрал первый.
$ git merge master
Auto-merging a
CONFLICT (content): Merge conflict in a
Automatic merge failed; fix conflicts and then commit the result.
$ cat a
a1
<<<<<<< HEAD
=======
b2
b3
>>>>>>> master
Чтобы разрешить конфликт, мы перемещаем вторую неправильную строку в правильный файл и фиксируем слияние.
$ echo b3 >> b
$ sed -i '/HEAD/,$d' a
$ git commit -a --no-edit
[f 28d8543] Merge branch 'master' into f
Затем мы осознаем обязательство о c
не должно быть в этой ветке, поэтому мы "удаляем" его rebase -ir
и встречаются с тем же конфликтом, что и раньше.
$ git rebase -ir $(git merge-base master @) # remove the commit about c
Auto-merging a
CONFLICT (content): Merge conflict in a
Could not apply 28d8543... onto # Merge branch 'master' into f
$ cat a
a1
<<<<<<< HEAD
=======
b2
b3
>>>>>>> refs/rewritten/onto
Итак, какое самое простое, наиболее эффективное и универсальное решение здесь, чтобы переделать предыдущую резолюцию с учетом того, что было добавлено в b
который не появляется в конфликте?
2 ответа
Существует утилита git для записи разрешения конфликта, чтобы вы могли воспроизвести его позже. Это называется git rerere
,
Это действительно предназначено для конкретного случая использования - и поскольку этот вариант использования основан на предположениях, с которыми я не согласен, я почти никогда не использую git rerere
,
Я бы также сказал, что при хорошем рабочем процессе сценарий, который вы описываете, должен быть нечастым, если вообще не существующим, поэтому я лично не стал бы использовать rerere
записывать каждое разрешение конфликта только на случай, если он понадобится мне позже.
Но... так как вы задали этот вопрос, git rerere
это, вероятно, "ответ".
Наилучшее решение, которое до сих пор приходит на ум (это на самом деле не так уж и хорошо), - отказаться от git и сделать патч для разрешения конфликта слияния:
$ cp -a . ../$(basename $PWD)~
$ echo b3 >> b
$ sed -i '/HEAD/,$d' a
$ diff -ru ../$(basename $PWD)~ .
diff -ru ../t~/a ./a
--- ../t~/a 2019-03-08 12:54:34.701197573 -0800
+++ ./a 2019-03-08 12:54:56.761197321 -0800
@@ -1,6 +1 @@
a1
-<<<<<<< HEAD
-=======
-b2
-b3
->>>>>>> refs/rewritten/onto
diff -ru ../t~/b ./b
--- ../t~/b 2019-03-08 12:54:34.701197573 -0800
+++ ./b 2019-03-08 12:54:54.044530686 -0800
@@ -1,2 +1,3 @@
b1
b2
+b3
Я могу сохранить этот патч где-нибудь и применить его всякий раз, когда мне нужно решить это снова. Проблема с этим заключается в управлении этими исправлениями и наличии дисциплины, чтобы либо предвидеть, когда мне нужно будет повторить разрешение конфликта, либо всегда вносить исправления в каждое разрешение конфликта.
Я бы предпочел решение, которое использует git для управления этим, хотя.
git rerere
или сделать патч refs/rewritten/onto
необходимо, потому что в Git 2.23 refs/rewritten/onto
будет удален в частном случае, когда git rebase -ir
прервано.
"git rebase --abort
"раньше уходил refs/rewritten/
при заключении " git rebase -r
", что было исправлено.
См. Commit d559f50, commit 37e9ee5, commit d3fce47, commit 7372eae (14 мая 2019 г.) от Филиппа Вуда (phillipwood
).
(Слияние Junio C Hamano -gitster
- в коммите 88f95e4, 09 июл 2019)
rebase --abort/--quit
: cleanuprefs/rewritten
когда
rebase -r
заканчивает, удаляет все ссылки подrefs/rewritten
что он создал.
Однако, если пользователь прерывает работу или выходит из нее, ссылки на перебазирование не удаляются. Это может вызвать проблемы при будущих перестановках.Например, я недавно хотел объединить обновленную версию ветки темы в ветку интеграции, поэтому запустил
rebase -ir
и удалил выбор и метку для ветки темы из списка задач, чтобыmerge -C <old-merge> topic
подцепил бы новую версию темы.
К сожалениюrefs/rewritten/topic
уже существовал из предыдущей перебазировки, которая была прервана, поэтому перебазирование просто использовало старую тему, а не новую.Изменена логика неинтерактивного случая выхода, чтобы
buf
всегда свободен.