Git помогает понять конфликты слияния

Я получаю конфликты в файлах, которые я не изменял. Конфликты файлов с одной строкой изменяются при слиянии. Я начинаю разбираться с тем, что может произойти, но все еще неспособным решить проблему.

Вот структура ветки.

  • мастер
    • current_iteration
      • mapr_autoinit

Мастер довольно старый и не имел изменений от current_iteration в течение некоторого времени. Однако у мастера были изменения, которые непосредственно его применяли, переустанавливая другие базы непосредственно на master. Так что технически мастер и current_iteration расходились. Мы последовательно разветвляемся и помещаем current_iteration. Проблема, которую я вижу, заключается в том, что когда я делаю слияние с current_iteration обратно в свою ветку. Я получаю больше конфликтов, чем должно происходить, основываясь на изменениях current_iteration. Я могу сделать git diff/git применительно к current_iteration, и он применяется чисто.

Когда я запускаю git show-branch --merge-base на mapr-autoinit, я вижу, что фиксация была фактически фиксацией на мастер-месяцев назад. Однако, когда я проверяю git merge-base current_iteration mapr_autoninit я вижу, что версия очень недавняя и, скорее всего, не будет иметь конфликтов.

Из того, что я видел в течение последних нескольких дней, кажется логичным, что если я объединю master в current_iteration, зафиксируйте, а затем объедините current_iteration обратно в master. Вероятно, это должно привести к тому, что моя ветвь merge-base укажет на более новую версию.

Также возможно, что я мог бы остановить отслеживание мастера. Я попытался использовать git config --unset branch.master.merge; git config --unset branch.master.remote git config --unset branch.master.merge; git config --unset branch.master.remote чтобы остановить мастер отслеживания, но это не решило мою проблему.

Является ли это проблемой, когда master и current_iteration расходились и слияние пытались согласовать слияние путем повторного воспроизведения всего журнала?

Также здесь более подробно. Сейчас я задаю новый вопрос, который гораздо более конкретный. Я обновляю как действительный ответ, так и удаляю старшего в зависимости от того, какой из них является предпочтительным.

Git merge приводит к необоснованным конфликтам

Ответ 1

Я никогда не обнаружил, что вывод git show-branch очень полезен сам, и я не уверен, как он предназначен для использования, и как другие могут успешно использовать его.

Также возможно, что я мог бы остановить отслеживание мастера...

Это не имеет значения. Важно иметь фактический граф фиксации. Верхняя часть любой ветки не зависит от графика фиксации.

Является ли это проблемой, когда master и current_iteration расходились и слияние пытались согласовать слияние путем повторного воспроизведения всего журнала?

Нет. Что важно после того, как поиск слияния основан только на том, что фиксация базы слияния, то есть плюс два кончика ответвления. Все между ними не имеет значения.

Однако, когда я проверяю git merge-base current_iteration mapr_autoinit я вижу, что версия очень недавняя и, скорее всего, не будет иметь конфликтов.

Обычно это способ начать работу, поскольку git merge-base проверяет граф фиксации и использует его для вычисления фиксации базы слияния. Обратите внимание, что git merge по умолчанию запускает эквивалент git merge-base --all. Если это создает более одной базы слияния (более одного идентификатора хеширования), у вас есть особая ситуация. Предположим, что вы этого пока не делаете, но это хорошая идея, чтобы проверить.

Обнаружив, что это объединение слияния, вы можете посмотреть выход git log (см. Последний раздел) и посмотреть, как база слияния относится к двум подсказкам ветки. Git не заботится об этом - ну, это не совсем верно: после того, как Git нашел базу слияния (что зависит от этого), Git перестает заботиться об этом, но вам может показаться полезным.

Найдя (единственную) базу слияния current_iteration и mapr_autoinit (и предположив, что вы находитесь в одном из этих двух ветвей), вот что делает Git:

git diff --find-renames <merge-base-hash> current_iteration > /tmp/1
git diff --find-renames <merge-base-hash> mapr_autoinit > /tmp/2

Я перенаправил их в /tmp файлы здесь, чтобы упростить просмотр несколько раз и бок о бок или что-то еще, в зависимости от ваших зрителей файлов. Поскольку я не знаю, в каком направлении вы сливаетесь - от чего, до чего-то я просто пронумеровал два файла, вместо того, чтобы называть их "наши" и "их". Обратите внимание, что шаг слияния изменений в значительной степени симметричен. Для каждого изменения каждого файла есть четыре возможности:

  • Вы коснулись линий, и они этого не сделали: Git принимает ваши изменения.
  • Они коснулись линий, а вы этого не сделали: Гит принимает их изменения.
  • Вы и они коснулись линий, но вы сделали одно и то же изменение: Git берет одну копию изменения.
  • Вы и они коснулись строк, но внесли разные изменения: Git объявляет конфликт слияния и помещает оба набора изменений в файл дерева работ. Если вы установите merge.conflictStyle в diff3 настоятельно рекомендую это: Git включает также версию слияния, чтобы показать вам, с чего вы и с чего начали, и сделали конфликтующие изменения.

Просмотр результатов с маркерами слияния конфликтов и базовой версией, включенной с помощью параметра merge.conflictStyle установленным в diff3, обычно является достаточным. (В частности, иногда появляются случаи, когда Git имеет неправильные изменения и думает, что они конфликтуют, когда на самом деле изменения относятся к другим регионам, которые не конфликтуют.) Если нет, это может помочь просмотреть граф фиксации.

Подробнее о графе фиксации

Что-то, что работает, но может быть трудно понять, 1 - выход git log --graph. Полезно включить --decorate --oneline, и для этого конкретного случая вам нужно будет указать имена текущей ветки 2 и ветки, которую вы собираетесь объединить. Например, если вы mapr_autoinit и собираетесь запустить git merge master, вы можете запустить:

git log --graph --decorate --oneline mapr_autoinit master

Git сделает все возможное, чтобы рисовать в искусстве ASCII с дополнительным дополнительным цветом, добавленным в помощь, графом фиксации. Конечно, результат зависит от того, что на графике. Вот фрагмент из репозитория Git для ядра Linux:

* 1ffaddd029c8 (HEAD -> master, tag: v4.18-rc8, origin/master, origin/HEAD) Linux 4.18-rc8
*   a8c199208cd6 Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
|\  
| * 1b3a62643660 x86/boot/compressed/64: Validate trampoline placement against E820
* |   2f3672cbf9da Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
|\ \  
| * | 0a0e0829f990 nohz: Fix missing tick reprogram when interrupting an inline softirq
| * | 80d20d35af1e nohz: Fix local_timer_softirq_pending()
* | |   0cdf6d4607df Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Его можно использовать для отслеживания того, что произошло после основания слияния. Есть еще инструменты:

git log --graph --decorate --oneline --boundary mapr_autoinit...master

например, покажет вам то, что не слилось (коммиты отмечены *), плюс (из-за --boundary) граничные коммиты, которые объединены (--boundary o), но не углубляясь в график, чем это.

Для очень простых случаев иногда полезно также графы, которые не ужасаются с внутренним добавлением ветки и повторного слияния --left-right к синтаксису с тремя точками. В сложных случаях, с большим количеством внутренних ветвей и сливаться действиями вниз с каждой ногой, --first-parent иногда полезно, и --simplify-by-decoration иногда полезно.


1 Несмотря на это, это все равно стоит изучить. Если вы предпочитаете, используйте графический интерфейс или подобное, что привлекает граф более красиво, но имейте в виду, что, по крайней мере, некоторые графические интерфейсы Git, похоже, рисуют неправильные графики (coughvariouscoughwebservicescore).

2 Вы всегда можете просто использовать имя HEAD, заглавными буквами, вместо имени текущей ветки. Все строчные буквы работают на файловых системах, не учитывающих регистр, в Windows и MacOS, например, но это нехорошо вникать в эту привычку. Одинокий at-sign @ означает HEAD в любом современном Git, хотя, если вы предпочитаете, используйте это вместо написания HEAD. Обратите внимание, что при использовании двух или трех точечных синтаксисов (A..B и A...B), опускание одного имени целиком также означает HEAD: HEAD..B, @..B и ..B - три ..B для то же самое.