Почему тот же конфликт возникает снова, когда я использую git rebase?

Я прочитал соответствующие вопросы о git merge и git rebase на SO, но я до сих пор не могу полностью понять, что происходит под капотом.

Вот наша ситуация ветвления:

MASTER------------------------
        \        \
         \        \----Feature B---
          \                        \
           \-----Feature A----------\---Feature A+B

У нас есть 2 ветки функций, которые происходят от мастера в разное время, теперь мы хотим объединить 2 ветки. Мы хотим следовать практике first rebase then merge, но когда мы перебазируем компонент A в компонент B, возникают конфликты. Это ожидаемо, потому что обе функции (и главная) имеют изменения в одних и тех же областях. Но странно то, что тот же самый конфликт продолжает появляться после git rebase --continue. Это сводит нас с ума, поэтому мы прерываем перебазирование и используем git merge. Оказывается, конфликты на самом деле легко разрешаются.

Мой вопрос двоякий:

  1. Подходит ли git rebase для нашей ситуации? Или rebase подходит только для внесения нескольких (1 или 2) изменений?
  2. Что происходит под капотом, из-за чего один и тот же конфликт возникает снова и снова? Насколько я понимаю, rebase разрешать конфликты по одному, но сравнивая какой коммит с чем?

Соответствующие сообщения на SO:


person NeoWang    schedule 14.07.2015    source источник
comment
Вы уверены, что это тот же конфликт (тот же файл, те же строки, те же изменения), или тот же файл + те же строки, но новые изменения в них, или это просто один и тот же файл но конфликтующие диапазоны строк разные?   -  person quetzalcoatl    schedule 14.07.2015
comment
гм.. и извините за такой простой вопрос - после того, как конфликт впервые возник и после того, как вы его исправили, вы не забыли сделать git add conflicted.file ? если нет, git не заметит исправление коммита, и git rebase --continue переподнимет файл как еще не разрешенный   -  person quetzalcoatl    schedule 14.07.2015
comment
Это не совсем один и тот же конфликт, но, безусловно, они связаны с одними и теми же линиями, и я уверен, что не так много изменений (как повторяющиеся конфликты), которые затрагивают эту область. И мы делаем add conflicted.file перед git rebase continue.   -  person NeoWang    schedule 14.07.2015
comment
возможный дубликат Git rebase --preserve-merges не работает   -  person jub0bs    schedule 14.07.2015
comment
Что касается 2., вы, вероятно, захотите активировать rerere.   -  person jub0bs    schedule 14.07.2015


Ответы (1)


Подходит ли rebase для вашей ситуации?

Основываясь на том факте, что Feature A и Feature B кажутся общими ветвями, я бы сказал нет.

Перебазирование — это способ объединения ветвей без коммитов слияния (т. е. коммитов, у которых есть два или более родителей), что делает его линейным. Его лучше всего использовать для объединения локальных веток, то есть веток, которые существуют только в вашем локальном репозитории и не были опубликованы для других людей. Почему? Как минимум по двум причинам:

  1. Перебазирование изменяет идентификаторы коммитов (т. е. SHA-1 хэшей их метаданных). Это означает, что как только вы отправите перебазированные коммиты в общую ветку, они будут отображаться как совершенно новые коммиты для всех, кто извлечет их из своего локального репозитория, даже если они все еще содержат такие же изменения. Теперь, если кто-то тем временем добавил новые коммиты поверх старых, им придется их переместить. Это создает ненужную путаницу.

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

Что происходит под капотом?

Просто обычное слияние. Разница в том, что git rebase объединяет одну фиксацию за раз поверх предыдущей, начиная с общего родителя. git merge объединяет два коммита — со всем их набором изменений — как одну операцию, поэтому вам нужно разрешать конфликты только один раз.

Обновление: разрешение повторяющихся конфликтов

Как отметил @Jubobs в комментариях, в Git есть автоматизированное решение для разрешения конфликтов, возникающих несколько раз: git rerere или "повторно использовать записанное разрешение".

После включения rerere в файле конфигурации (rerere.enabled true) каждый раз, когда возникает конфликт слияния, Git будет записывать состояние конфликтующих файлов до и после их слияния. В следующий раз, когда возникнет такой же конфликт — конфликт, включающий одинаковые строки с обеих сторон слияния, — Git автоматически применит то же разрешение, которое было записано ранее. Это также сообщит вам об этом в выводе слияния:

КОНФЛИКТ (содержимое): конфликт слияния в 'somefile'
Устранен 'somefile' с использованием предыдущего разрешения.

Здесь вы можете найти более подробную информацию о том, как разрешать конфликты с помощью git rerere.

person Enrico Campidoglio    schedule 14.07.2015
comment
Я думаю, что в вашем ответе должно быть упомянуто rerere. - person jub0bs; 14.07.2015
comment
Просто примечание: некоторые сторонники перебазирования сочтут тот факт, что все изменения разрешения конфликтов содержатся в одном коммите слияния, очень плохая вещь. Кто-то может возразить, что лучше видеть отдельные разрешения конфликтов в виде последовательности коммитов, а не один большой шар разрешенных изменений в одном коммите. - person ely; 23.08.2017