git помечает все содержимое исходного файла cpp как конфликтующее, в то время как большая часть содержимого идентична - PullRequest
0 голосов
/ 25 апреля 2020

После этой проблемы у меня теперь есть два локальных репо git на моей машине windows, которые я хочу объединить. Когда я использую инструмент WinMerge для сравнения файлов в репозиториях, различия показываются в общих чертах. Но когда git пытается объединить весь файл, он помечается как конфликтующий.

Один важный момент заключается в том, что существуют другие файлы, которые идентичны и правильно обрабатываются. Другой момент заключается в том, что проблема не имеет ничего общего с core.autocrlf по двум причинам: 1 - я проверил как с истинными, так и с ложными настройками 2 - WinMerge не показывает разницы с опцией игнорирования окончания строки

Как вы предлагаете мы расследуем это дело?

[править] Я обновил git, но это было бесполезно.

Ответы [ 2 ]

3 голосов
/ 25 апреля 2020

Когда Git выполняет нормальное слияние, оно учитывает ровно три точки: две головы, которые вы объединяете, и базу слияния, которая обычно является ближайшим общим предком. Если вы объединяете несвязанные истории, этот общий предок - пустое дерево; то есть состояние без файлов.

Слияние принимает сумму результата применения различий между базой слияния и каждой головкой.

Если при слиянии файл идентичен с обеих сторон (то есть, BLOB-объект имеет одинаковый идентификатор объекта), тогда результатом объединения будет просто принять этот BLOB-объект в качестве значения для этого файла во время объединения. Обе стороны имеют одинаковые изменения, поэтому нет смысла делать какой-либо причудливый анализ. Это объясняет, почему идентичные файлы в этом случае работают нормально.

Однако в случае, когда файлы не идентичны, и у вас есть несвязанные истории, Git считает это конфликтом добавления / добавления: это одна сторона добавила некоторый набор линий, а другая сторона добавила другой набор линий. Может случиться так, что многие из этих строк являются общими, но логически конфликт заключается в том, что добавляются два разных набора строк, поэтому конфликтует весь файл.

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

0 голосов
/ 26 апреля 2020

WinMerge реализует то, что люди иногда называют «двусторонним слиянием». Это неправильно, так как двустороннее «слияние» - это вовсе не слияние: это просто diff, за которым следует управляемое применение этого diff. См. Почему трехстороннее слияние выгоднее двухстороннего слияния?

В WinMerge также реализовано трехстороннее слияние. Git only реализует трехстороннее объединение в своих алгоритмах объединения (git merge и git merge-file). То есть должен быть общим базовым файлом.

Поэтому вам придется использовать что-то отличное от Git, чтобы выполнить слияние на уровне файлов, или придумать общую базу file:

  • Вам не нужен общий предок commit (как в ответе bk2204 ), но иметь его намного проще, потому что Git сам тогда сделает всю работу. Общий базовый файл происходит из общего базового коммита слияния.
  • Вам нужно нужен общий базовый файл , однако, если вы хотите использовать Git tools.

Другими словами, если хотите, вы можете:

  • Начать объединение, используя git merge --allow-unrelated-histories.
  • Let Git stop с сообщениями о CONFLICT (add/add).
  • Для каждого результата слияния, находящегося в этом конфликтующем состоянии:
    • Выберите два или три файла. Два найденных Git легко получить. Поиск или создание общей базы слияния - ваша собственная проблема; Git не имеет ответа для вас здесь.
    • Используйте любой инструмент по вашему выбору для получения результата слияния. Это может быть git merge-file, WinMerge или что угодно.
    • Скажите Git: этот результат слияния является правильным результатом слияния . Git примет все, что вы дадите, в качестве правильного результата слияния.
  • Теперь, когда вы разрешили все конфликты, завершите sh слияние.

Относительно легко, например, с использованием сценариев bash, автоматизировать часть "для каждого конфликтующего файла". git status сообщает вам, какие файлы находятся в UU (не объединенном) состоянии, так что вы получаете набор файлов имен . Затем вы можете использовать git ls-files --stage <name> для каждого имени файла, чтобы убедиться, что для этого имени действительно есть индексная запись в слот-2 и слот-3, и нет записи в слот-1, т. Е. Что это конфликт «добавить / добавить». , Затем вы можете использовать довольно неудобный для пользователя вариант git checkout-index, чтобы получить два конфликтующих входных файла во временные файлы.

Фактически, git mergetool выполняет все вышеперечисленное для вас, а затем запускает любой произвольный Команда на ваш выбор. Если есть возможность запустить WinMerge для этих файлов непосредственно из git mergetool, это может быть способом справиться с этим.

Другими словами, git mergetool делает "для каждого конфликтующего слияния, получите три файла с Git "часть работы. Поскольку Git не нашел общий файл базы слияния, git mergetool предоставляет пустой файл в качестве базы слияния для выбранного вами инструмента. Вы можете, зная (или проверяя), что этот файл пуст, просто выбросить файл и выполнить «двустороннее слияние» - действительно управляемое приложение diff - для получения правильного результата.

(у меня есть не знаю, как запустить сам WinMerge, будь то инструмент слияния, вызванный из git mergetool или любым другим способом. Так что эту часть вам нужно будет найти или выяснить самостоятельно.)

...