Как автоматически разрешать все конфликты в git rebase, «git add». - PullRequest
0 голосов
/ 06 ноября 2019

Проект, над которым я работаю, представляет собой приложение maven с родительским и дочерним модулями. Изменения в родительском модуле идут в ветку разработки. У каждого дочернего модуля есть своя ветвь, которая перебазируется из разработки, чтобы наследовать эти изменения.

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

git ls-files -z *_child | xargs -0 git update-index --skip-worktree #I do not want the child module to be touched

git rebase -X theirs development

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

git add .
git rebase --continue

Это работает, пока я не попаду в другой конфликт. Сейчас я пытаюсь использовать git rerere для записи действий по разрешению, которые я предпринял:

git config --local rerere.enabled true

Однако я все еще пытаюсь выяснить, как это на самом деле работает с перебазированием. Есть ли у вас какие-либо предложения, с помощью git rerere или какой-либо другой команды git, чтобы решить эту проблему? В идеале я хотел бы убрать git add . в целом и всегда конфликтовать по умолчанию с «их» изменениями.

1 Ответ

1 голос
/ 06 ноября 2019

Важное первое замечание: ваш git update-index здесь не очень функционален. Rebase должен будет касаться файлов, помеченных --skip-worktree, если основная операция слияния должна касаться их. Это не коснется их, если нет. Пометка файлов может может принести вам полезную ошибку во время операции выбора вишни (я не проверял это, но вы можете проверить это самостоятельно).


Повторная обработка повторяется git cherry-pick (или иногда эквивалент). Каждый вишневый кирк использует процесс слияния - то, что я люблю называть слияние как глагол или для слияния - и, как вы видите, слияния могут иметь конфликты слияния. Два отличия git cherry-pick от обычного слияния:

  1. База слияния является просто родителем коммита, выбранного вишней.
  2. Коммит, который будетв конце делается обычный коммит (без слияния).

Включение rerere будет иметь тот же эффект, что и для любого другого git merge, так как повторное использование записанных разрешений происходит в том жепуть. Это не поможет вам в вашем случае, потому что вы уже используете -X theirs, который исключает конфликт, который может разрешить rerere.

Конфликты во время слияния возникают либо из того, что я называю операции высокого уровня , для всего дерева файлов или из работы низкого уровня слияния. Я использую эти две фразы, чтобы различать два разных раздела кода в движке слияния Git. По сути, объединение выполняется двумя git diff операциями:

git diff --find-renames <base> <tip1>
git diff --find-renames <base> <tip2>

Эти разности являются внутренними по отношению к git merge, который имеет встроенный механизм различий, и могут передавать различные опции, которые труднодостичь через командную строку, но принцип тот же:

  1. Функция поиска переименования просматривает файлы, добавленные и / или удаленные, и пытается найти соответствие левой стороне (база слияниясторона) "удаленный" файл против "добавленного" файла с правой стороны. Если это так, Git решает, что этот файл был переименован .

  2. Подобное сопоставление имен файлов приводит к отображению идентичности: базовый файл с именем F B имеет новое имя F L с левой стороны и F R с правой стороны. Все три имени могут быть равными, или два или все три могут отличаться, но в любом случае, это «один и тот же» файл. Он также оставляет нам файлы, которые добавляются и / или удаляются с обеих сторон, и файлы, которые могут или не могут быть изменены с одной или обеих сторон.

  3. Теперь мы должны объединить всеменяется ... но это происходит сначала при именах файлов и уровне существования :

    • Если левая сторона удаляет файл F d и правая сторона не меняет его, это нормально. Но если левая сторона удаляет его, а правая изменяет, мы имеем конфликт удаления / изменения . (Если правая сторона удаляет его, а левая изменяет его, у нас возникает тот же конфликт, обратный.)

    • Если левая сторона переименовывает файл, а правая сторона удаляет его (илито же самое с заменой сторон), у нас конфликт переименования / удаления .

    • Если обе стороны добавляют новый файл с нуля, но с тем же именем, у нас есть добавить / добавить конфликт .

    • Если обе стороны переименуют базовый файл F B , но с двумя разными именами *F L и F R , у нас конфликт переименования / переименования .


    Git разрешает нет этих конфликтов самостоятельно. Это конфликты high level .

    Решив или не разрешив любые операции с деревьями высокого уровня, мы теперь имеем случаи, когда один и тот же файл переносился из базы в обе подсказки ветви - с помощью "тот же файл "с учетом переименований, как указано выше - но был изменен обеими сторонами. Git теперь запускает код из отдельного файла с именем ll-merge.c: низкоуровневый код слияния.

    LLСлияние позволяет пользователям определять драйверы слияния . При их использовании вся операция зависит от драйвера слияния, который просто получает данные всех трех входных файлов (базовый, левый / HEAD и правый / их). При использовании встроенных драйверов слияния разрешение конфликтов может выполняться автоматически с использованием -X extended-options: -X theirs выбирает изменение правой стороны, отбрасывая левую сторону (base-vs-HEAD) изменить. -X ours выбирает левостороннее изменение. Без этих опций Git просто объявляет конфликт, когда изменения перекрываются или примыкают.

Поскольку вы используете -X theirs и получаете конфликты, мы можем заключить, что вы должны получать высокий уровень конфликтов. Повторный код Git не записывает и не может повторно использовать эти разрешения.

Чтобы обнаружить их после прекращения слияния из-за конфликта, вы можете использовать git status или проверить индекс / промежуточную область с помощью git ls-files --stage. К сожалению, Git делает плохую (как в большинстве случаев несуществующую) работу по записи того, что на самом деле было конфликтами высокого уровня. Он печатает конфликты, поэтому, если вы фиксируете вывод, вы можете его проанализировать;или вы можете запустить собственную команду git diff --find-renames --name-status, чтобы увидеть, что видел слияние.

В общем случае слияний, git diff --find-renames проблематично, так как git merge может создать временную фиксацию, которая содержит то, что вызывает Git база виртуального слияния . Однако для cherry-pick база слияния является просто родителем коммита, выбранного в данный момент, поэтому использование этого метода может быть надежным. Вам придется написать код в любом случае.

...