Как разбить файл на наш и свой на конфликт - PullRequest
0 голосов
/ 11 ноября 2018

У меня есть способ получить 2 копии файла, где первый будет иметь удаленный контент, а второй - с локальным контентом

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

TL; DR

Подумайте об использовании git mergetool (хотя я сам никогда так не делаю) или git show (я иногда так делаю). Также рассмотрите возможность установки merge.conflictStyle в diff3, которая заставляет Git писать, в конфликтующую копию рабочего дерева, базовую версию , а также левую и правую версии. Я обнаружил, что с этим включенным мне почти никогда не нужно , чтобы видеть два входа. (Но только почти никогда.)

Long (МОГ)

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

Давайте кратко, но подробно рассмотрим, как git merge работает при возникновении конфликтов. Чтобы возникли конфликты, мы должны были сделать что-то вроде этого:

$ git checkout ours
Switched to branch 'ours'
$ git merge theirs

Git рассмотрит график фиксации и обнаружит, что ours и theirs разошлись, но имеют общую базу слияния commit: 1

          o--...--L   <-- ours (HEAD)
         /
...--o--B
         \
          o--...--R   <-- theirs

Коммит L - это левая сторона или локальная или --ours фиксация. Коммит R - это правая сторона или удаленный или --theirs коммит. Совершите B здесь база слияния. Затем Git фактически выполнил две команды git diff, одну, чтобы узнать, что мы изменили с момента объединения базы:

git diff --find-renames <hash-of-B> <hash-of-L>   # what we changed
git diff --find-renames <hash-of-B> <hash-of-R>   # what they changed

Слияние затем попыталось объединить эти два набора изменений, используя содержимое, связанное с коммитом B , в качестве основы для объединенных изменений. Однако мы изменили какой-то файл, они изменили тот же файл, и наши изменения столкнулись с их изменениями, и мы получили конфликт слияния.

На этом этапе Git поместил все три копии файла в указатель с ненулевым промежуточным слотом чисел:

  • Этап 1 содержит базу слияния: файл B: P , где B - базовый коммит, а P - путь к файлу (как в любом случае мы нашли в этом коммите - мы могли бы переименовать файл!).
  • Этап 2 содержит нашу версию файла: файл L: P .
  • Этап 3 содержит свою версию файла: файл R: P .

Рабочее дерево содержит попытку Git объединить два набора изменений с маркерами конфликта. Обратите внимание, что эта версия отличается от любой из трех версий ввода! Некоторые части слияния могут быть уже разрешены. Стиль по умолчанию для конфликтующих изменений - merge, который показывает только левый ( B -vs- L ) и правый ( B -vs- R ) меняет без отображения раздела, который был в B . Во многих случаях этого достаточно, но когда изменения являются чисто удалениями, часто очень полезно знать, какие строки в B удаляются / удаляются, и это не то, что вы можете просто вывести. При установке стиля конфликта на diff3 Git также записывает кодовую секцию B , между двумя секциями изменений.


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

Извлечение трех версий

  • Вы можете извлечь любую из трех версий, используя git checkout-index, хотя эту команду немного затруднит:

    git checkout-index --all -- path/to/file
    

    Это записывает все три в файлы со странными временными именами, которые вы затем должны переименовать. (Есть несколько вариантов этой темы, но все они немного раздражают.)

  • Вы можете использовать git mergetool, который автоматически извлекает все три версии, а затем вызывает выбранную вами команду инструмента слияния для всех из них.

  • Или вы можете вручную извлечь один или оба файла. Метод из ответа DogEata будет работать, но если у вас нет проблем с окончанием строки, этот путь будет короче:

    git show :1:path/to/file > path/to/file.base
    git show :2:path/to/file > path/to/file.ours
    git show :3:path/to/file > path/to/file.theirs
    

    При этом используется команда git show вместе с синтаксисом gitrevisions для доступа к индексным копиям, их отображения в стандартном выводе и перенаправления вывода в новые файлы.

Обратите внимание, что git add записывает в нулевой слот

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

git add path/to/file

чтобы скопировать файл обратно в индекс, взяв копию рабочего дерева нормального формата и сжав в специальный формат Git-only, который входит в индекс.

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

Если вы используете git mergetool, команда git mergetool может автоматически запустить для вас git add, скрывая дополнительный шаг. Некоторые люди считают это особенно удобным.

0 голосов
/ 11 ноября 2018

Я не думаю, что есть опция git, чтобы хранить обе версии файла в двух копиях.

Но вы можете легко достичь этой цели с помощью следующих команд:

git merge the_branch
git checkout --theirs -- path/to/file ; mv path/to/file path/to/file.theirs
git checkout --ours -- path/to/file ; mv path/to/file path/to/file.ours
git checkout -m -- path/to/file

В итоге у вас есть три файла:

  • file.theirs, с их версией;
  • file.ours, с вашей версией;
  • file, с отметками версий и конфликтов.
...