Перебазировать на исходные изменения с нетривиальными фиксациями слияния, присутствующими локально

Как разработчик php-src я недавно оказался в следующей ситуации:

A   B   C
o---o---o         version1
         \
o---o-----o---o   master
x   y     D   E

o---o---o         upstream/master
x   y   z

Итак, когда я делаю git push --dry-run upstream master version1, я получаю типичное:

! [rejected]        master -> master (fetch first)

Мой естественный ответ — перебазировать затронутую ветку и сохранить коммиты слияния:

git fetch upstream
git rebase -p upstream/master

Важно отметить, что первоначальная фиксация слияния не была тривиальной, потому что между веткой версии и мастером очень много изменений; требуется усилие, чтобы разрешить такое слияние.

Выполнение вышеуказанной операции перебазирования вызывает конфликт слияния, и мне приходится разрешать его снова; это почти точно такая же работа, которую я уже сделал.

Есть лучший способ сделать это? Или я забыл очевидный вариант перебазирования?


person Ja͢ck    schedule 02.09.2014    source источник
comment
Вам нужно перебазировать? Обычно я тоже переустанавливаю, но я также был в вашей ситуации, когда это было просто невозможно, и тогда я пошел со стандартным слиянием.   -  person musiKk    schedule 02.09.2014
comment
Конечно, я могу просто нажать D, E, M(z) вместо D', E', но я предпочитаю сохранять историю как можно более чистой :)   -  person Ja͢ck    schedule 02.09.2014
comment
Я слышу тебя. Это зависит от вашего случая. Я работал над слияниями, которые занимали часы. Моя любовь к чистой истории зашла так далеко. :)   -  person musiKk    schedule 02.09.2014


Ответы (1)


В идеале вы должны повторно использовать записанное разрешение с rerere:

В рабочем процессе, использующем относительно долгоживущие тематические ветки, разработчику иногда приходится разрешать одни и те же конфликты снова и снова, пока тематические ветки не будут либо объединены в ветку выпуска, либо отправлены и приняты вверх по течению).

Эта команда помогает разработчику в этом процессе, записывая конфликтующие результаты автоматического слияния и соответствующие результаты ручного разрешения при первоначальном ручном объединении и применяя ранее записанные ручные разрешения к соответствующим результатам автоматического слияния.

К сожалению, эта функция должна быть включена до того, как вы впервые выполните слияние:

Примечание. Чтобы активировать эту команду, необходимо установить переменную конфигурации rerere.enabled.

Насколько я знаю, нет возможности сделать что-то подобное постфактум. Я рекомендую включить rerere глобально, а затем повторить слияние:

git config --global rerere.enabled true

В будущем эта настройка может сэкономить вам много времени!

person Chris    schedule 02.09.2014
comment
Ярлык для ретроактивного включения rerere здесь должен быть просто git config rerere.enabled true; git checkout y; git merge -s ours --no-commit C; git read-tree -um HEAD D; git commit; git checkout master. - person jthill; 02.09.2014
comment
@jthill мне это не кажется простым, но если это сработает, это будет хорошим дополнением либо к этому ответу, либо к отдельному :) - person Ja͢ck; 02.09.2014
comment
Вау, я не знал о rerere или знал и забыл. Выглядит интересно. Знаете ли вы, есть ли какие-либо негативные последствия при установке rerere.enabled на true на всякий случай? - person musiKk; 02.09.2014
comment
@musiKk Не так много недостатков, ИМО. Существует небольшой каталог кэша (.git/rr-cache), которым можно разумно управлять с помощью git rerere gc. Существует вероятность повторения неудачного слияния, но я думаю, что оно того стоит. Просто имейте в виду, что теперь у вас есть кеш разрешения слияния :-). - person Chris; 02.09.2014
comment
Да. Не ответ, потому что я действительно не проверял это. Это в основном правильно, но, возможно, нужно немного обыграть. edit: стоит испортить скретч-клон. - person jthill; 02.09.2014