Как git справляется с изменением содержимого во время слияния, если файловая структура тем временем изменялась в отдельной ветке? - PullRequest
0 голосов
/ 08 июня 2019

Я опишу ситуацию с этим примером для простоты.

Я создал ветку git в (День 1) для своего проекта, и структура была следующей:

enter image description here

Я немедленно (все еще в День 1) изменил структуру на следующую:

enter image description here

Тем временем (День 2) файлы Class1.java и Class2.java изменились в основной ветке другим prople (объединение из другой ветви в master).

Мой вопрос: когда я объединю свою ветку с мастером (день 3) ... Git сохранит изменения, которые были внесены в Class1.java и Class2.java другими людьми на мастере, или он заменит их с теми, которые у меня есть в моей ветке?

Ответы [ 3 ]

1 голос
/ 08 июня 2019

Когда вы запускаете git merge <thing>, Git должен найти три коммитов.

Одним из трех коммитов является ваш текущий коммит.(Ваш индекс и рабочее дерево должны совпадать, и команда front end git merge обычно применяет это. Обычно неблагоразумно запускать git merge в «грязной» ситуации, хотя git stash apply делает это все время. Я рекомендуюизбегая git stash, частично из-за этого.)

Один из трех коммитов, конечно, коммит, который вы называете с помощью аргумента <thing>:

git merge theirbranch

выбираеткоммит в конце их ветви как второй из двух коммитов для слияния.

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

Предположим, что ваша ветвь и их ветвь имеют очень простую дивергентную структуру:

          o--...--o   <-- yourbranch (HEAD)
         /
...--o--*
         \
          o--...--o   <-- theirbranch

Базой слияния этой структуры является просто commit*.

В сложных установках Git по-прежнему находит базу слияния самостоятельно: база слияния является лучшим общим предком двух коммитов с ветвлением-кончиком, которые должны быть объединены.Однако перед слиянием вы можете провести расследование:

git merge-base --all theirbranch

сообщит вам, какие коммиты являются базой (ами) слияния.В идеале есть только один;когда их два или более, у Git есть проблема, которую Git решит, но (а) это довольно редко и (б) он немного мешает остальной части этого описания, так что давайте просто пока проигнорируем проблему.: -)

Найдя только одну базу слияния, Git теперь делает это:

  • git diff --find-renames <em>base</em> <em>your-commit</em>, чтобы увидеть, что вы изменили;
  • git diff --find-renames <em>base</em> <em>their-commit</em>, чтобы увидетьчто они изменили.

То есть Git запускает git diff дважды , используя то же самое (общий, общий) базовый коммит.

Учитывая ситуацию, которую вы описали выше, либо вы переименовали некоторые файлы, либо они переименовали некоторые файлы - либо, возможно, вы оба переименовали некоторые файлы.Опция --find-renames указывает git diff на обнаружение этих переименований.(В данном случае это вы переименовывали файлы.)

Поиск переименования не идеален, но в большинстве случаев он делает именно то, что нужно.Git обнаруживает, кто из вас переименовал какие файлы.Это позволяет Git идентифицировать базовый файл слияния (который должен быть folder1/src/Class1.java) с переименованным файлом folder2/src/Class1.java.Git помнит, что переименование также произошло.

В diff для их изменений Git идентифицирует исходный файл folder1/src/Class1.java с неотименованным folder1/src/Class1.java в их последнем коммите.

Поскольку эти изменения взяты из идентичных исходных файлов, Git теперь объединяет ваши изменения с их изменениями.Он пытается применить те же самые изменения - включая переименование - к базовому файлу.Таким образом, Git получает версию базового коммита folder1/src/Class1.java, объединяет ваши изменения и их изменения - которые могут или не могут конфликтовать - и помещает результат в ваш индекс и рабочее дерево как folder2/src/Class1.java, принимая (одиночное) переименование.

Все это объединение завершается неудачей, если Git не может идентифицировать исходные файлы base-commit с переименованными файлами.Таким образом, вы можете запустить тот же git diff --find-renames, возможно, с --name-status, чтобы пропустить просмотр реальных различий и просто посмотреть, что совпадает.Если правильные вещи совпадают, git merge сделает правильные вещи.

Если буровая установкаht вещи не совпадают, вы можете попробовать настроить «порог переименования» Git, указанный как число --find-renames=<em>num</em>.Число является пределом для индекса сходства Git .Когда Git сравнивает два коммита, такие как база слияния и ваш текущий коммит, если у базы слияния есть файл d1/d2/file.ext, а у вашего коммита нет, а у вашего коммита d3/d4/other.ext, которого нет у базы, Git сравниваетсодержимое двух файлов.Затем он вычисляет индекс сходства.Это, примерно, количество файла , которое было перенесено без изменений; максимально равно 100%, и, если ни одна из частей файла не совпадает, становится равным 0%.По умолчанию выполняется сопряжение файлов, которые по крайней мере на 50% похожи.Если один источник соответствует пяти адресатам, Git примет соединение с наивысшим индексом сходства, если оно соответствует пороговому значению.

Команда git merge принимает тот же параметр, но записывает его -X find-renames=<em>number</em>.

Если существует несколько баз слияний

Если git merge-base --all дает вам более одной базы слияний, вот как Git решает эту проблему:

  • -s recursive (по умолчанию): Git сначала объединяет базы слияний, выполняя на них git merge, более или менее.Результирующий коммит становится базой слияния.
  • -s resolve: Git выбирает одну из баз слияния случайно (очевидно) и использует ее.

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

0 голосов
/ 08 июня 2019

Сохранит ли git изменения, внесенные в Class1.java и Class2.java другими людьми на master, или заменит их теми, что есть в моей ветке?

Да, операция слияния в Git обычно замечает, что вы переименовали некоторые файлы (вы переместили их в другой каталог - это операция переименования).Изменения, внесенные другими пользователями в исходное местоположение, тем временем переносятся.

Однако это работает только до тех пор, пока вы не используете пути folder1/src/Class*.java на своей стороне, а другая сторона также не вводит Folder2/src/Class*.java до того, как произойдет слияние, потому что это победит обнаружение переименования Git.

0 голосов
/ 08 июня 2019

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

https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...