GIT: создать объединенную версию файла из двух веток - PullRequest
0 голосов
/ 04 мая 2019

Я не хотел бы создавать объединенную версию файла из двух веток с 3-way, но я не знаю как.

Ответы [ 3 ]

1 голос
/ 04 мая 2019

Из текущей ветки создайте новую ветку:

git checkout -b new_branch

После слияния с другой веткой:

git merge old_branch

1 голос
/ 04 мая 2019

Создать новую ветку

git branch new_branch

git checkout new_branch

git merge old_branch1

git merge old_branch2

new_branch теперь содержит объединенную версию, а old_branch1 и old_branch2 содержат предыдущие версии.

0 голосов
/ 04 мая 2019

Помните, что слияние - это объединение работы. Я думаю, это поможет, если, например, вы думаете об этом как, например:

Алиса выполнила некоторую работунад своими файлами, и Боб поработал над своими файлами, и теперь Алиса, Боб или, может быть, даже какая-то третья персона Кэрол хочет объединить эти две линии работы.1011 * Git обычно работает с целыми коммитами одновременно, а не с отдельными файлами.Если вы запустите git merge, вы объедините коммиты , а не файлы .То есть вы можете git checkout последний коммит Алисы, затем запустить git merge Bob, и Git найдет, с чего начали Алиса и Боб, посмотреть, что они сделали с всеми файлами, и объединить все этого.

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

Три операции ввода слияния на уровне файлов:

  • Версия файла --ours.Если бы вы набрали git checkout Alice (чтобы попасть в филиал Алиса), это была бы последняя Алиса.

  • Версия файла --theirs.Если бы вы запустили git merge Bob (для слияния из ветви Боба), это было бы последним Бобом.

  • Базовая версия файла слияния.Это версия файла, с которой начинали Алиса и Боб.Это сложная часть: какую версию файла сделал Алиса и Боб оба начинают с?

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

             o--o--A   <-- alice
            /
...--o--o--*
            \
             o--o--B   <-- bob

Алиса и Боб оба начали с коммита *.С тех пор Алиса сделала три коммита на ее ветви, а Боб сделал три коммита на его .Я пометил последний Алис как коммит A, а последний Боб как коммит B, хотя, конечно, оба из них - и даже коммит * - имеют некоторые большие уродливые хеш-идентификаторы в качестве своих настоящих имен.

Commit * находится на обеих ветвях, и поскольку это shared commit и commit - это постоянные снимки только для чтения всех файлов,очевидно, что Алиса и Боб в то время имели одинаковое содержимое в каждом файле.Поэтому команда git merge будет принимать каждый файл из коммита * и сравнивать каждый такой файл с каждым файлом в коммите A.Что бы здесь ни изменилось, Алиса изменилась.Затем Git будет сравнивать каждый файл с * с каждым файлом в коммите B.Что бы здесь ни изменилось, Боб изменился.

Теперь команда git merge будет изменяться для каждого файла, который изменяется в A или B по сравнению с *, объединить изменения в каждом файле.То есть, если Алиса и Боб оба изменили README.md, Git объединит изменения.Если Алиса изменила alice.txt, а Боб - нет, Git просто примет изменения Алисы.Если Боб изменил blue.py, а Алиса - нет, Git просто примет изменения Боба.

Объединив все эти изменения - при условии, что это объединяет все работы - Git применит объединенные изменения к тому, что было в *,Полученные файлы теперь пригодны для нового коммита.Новый коммит - коммит слияния , который является особенным только потому, что у него два родителя вместо обычного: вместо запоминания мой родитель коммит A или мой родителькоммит B , новый коммит запоминает оба:

             o--o--A
            /       \
...--o--o--*         M
            \       /
             o--o--B

Новый комmmit M переходит на ту ветку, которую вы проверили прямо сейчас. Если это ветвь alice, результат:

             o--o--A
            /       \
...--o--o--*         M   <-- alice (HEAD)
            \       /
             o--o--B   <-- bob

Если вы начнете с создания новой ветви - например, carol - что также указывает на фиксацию A сначала:

             o--o--A   <-- alice, carol (HEAD)
            /
...--o--o--*
            \
             o--o--B   <-- bob

затем новый коммит M меняет имя carol, указывая на M:

             o--o--A   <-- alice
            /       \
...--o--o--*         M   <-- carol (HEAD)
            \       /
             o--o--B   <-- bob

Помните, что все файлы в M являются результатом объединения всех изменений. Сложнее было найти изменения , потому что коммиты - это моментальные снимки, и хитрость для этого заключалась в том, чтобы найти моментальный снимок *, базу слияния. Git сравнил снимок * со снимком A:

git diff --find-renames <hash-of-*> <hash-of-A>    # what Alice changed

и повторил это для снимка B:

git diff --find-renames <hash-of-*> <hash-of-B>    # what Bob changed

Затем слияние объединило эти изменения для всех файлов в трех снимках, чтобы создать коммит слияния M, который переходит в текущую ветвь: ту, к которой прикреплен HEAD.

Заключение № 1

Чтобы объединить все файлы в A и B, не затрагивая другие ветви, вы можете создать ветвь new , указывающую либо на коммит A, либо на коммит B, затем запустите git merge с любым именем или идентификатором хэша, который указывает другой из двух коммитов. Если слияние завершится успешно, ваш новый коммит слияния M будет указывать на A и B и будет исключительно в вашей новой ветви.

Чтобы объединить все файлы в A и B во время помещения нового коммита слияния в ветвь alice (текущий коммит A) или bob (текущий коммит B), выберите нужный ветвь и запустите git merge с именем другой ветки. Если слияние выполнится успешно, ваш новый коммит слияния M будет указывать на A и B, как и в другом случае, но на этот раз коммит слияния будет, скорее, на alice или bob чем в новой ветке, которую вы не создали.

Заключение № 2

Если вы действительно, действительно, хотите объединить один файл из коммитов A и B, вы не можете использовать git merge для этого: он делает слишком много; он объединяет все файлы. Существует команда Git, которая может объединить один файл:

git merge-file

сделает работу. Но для этого нужны три входных файла. Требуется базовая версия файла слияния, изменения которого вы хотите объединить. Найдите базовую версию слияния плюс две другие версии, которые вы хотите объединить. Поместите их в три файла, например, file.base, file.mine и file.theirs. Затем запустите:

git merge-file file.mine file.base file.theirs

Git будет сравнивать file.base с file.mine, чтобы увидеть, что вы изменили, и сравнить file.base с file.theirs, чтобы увидеть, что они изменились. Затем он попытается объединить эти два изменения, применив объединенные изменения к file.base и записав результат в file.mine.

Это, конечно, именно то, что git merge делает для каждого файла. Просто git merge находит три файла для вас и автоматизирует всю эту работу.

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