Как объединить определенные файлы из веток Git

179

У меня есть 2 филиала git branch1 и branch2, и я хочу объединить file.py в branch2 в file.py в branch1 и только этот файл.

По сути, я просто хочу работать с file.py в branch1, но хочу воспользоваться командой слияния. Каков наилучший способ сделать это?

rwolst
источник

Ответы:

207

Когда содержание находится в file.pyот branch2 , который больше не относится к branch1 , требует сбора некоторых изменений и оставить другие. Для полного контроля выполните интерактивное слияние с помощью --patchпереключателя:

$ git checkout --patch branch2 file.py

В разделе интерактивного режима на странице git-add(1)справочника объясняются ключи, которые должны использоваться:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

Команда split особенно полезна.

ПРП
источник
3
Как мы можем использовать патч и в то же время использовать инструмент слияния? вместо ключевых вещей
Габриэль
@Gabriel Я использовал Git даже с файлами патчей и тарболлами, потому что создать репо ( git init <dir>) и, наконец, выбросить ( rm -r <dir>) так просто.
ПРП
105

Хотя само по себе это не слияние , иногда требуется все содержимое другого файла в другой ветви. Сообщение в блоге Джейсона Рудольфа предоставляет простой способ копировать файлы из одной ветви в другую. Примените технику следующим образом:

$ git checkout branch1 # ensure in branch1 is checked out and active
$ git checkout branch2 file.py

Сейчас file.pyсейчас в ветке1 .

Мэтью Тернер
источник
91
Легко, но на самом деле это не слияние . Он просто переписывается file.pyс тем, что находится в ветви 2.
Грег Хьюгилл
Что делать, если вы сливаете файл обратно из branch1 в branch2? Вы получите конфликт!
Амир
Сохраняет ли это историю фиксации?
Биз
18

Ни один из других текущих ответов на самом деле не «объединит» файлы, как если бы вы использовали команду слияния. (В лучшем случае они потребуют от вас ручного выбора различий.) Если вы действительно хотите воспользоваться преимуществами объединения с использованием информации от общего предка, вы можете выполнить процедуру, основанную на процедуре, описанной в разделе «Расширенное объединение» в git. Справочное руководство.

Для этого протокола я предполагаю, что вы хотите объединить файл 'path / to / file.txt' из origin / master в HEAD - при необходимости измените. (Вам не обязательно находиться в верхнем каталоге вашего хранилища, но это помогает.)

# Find the merge base SHA1 (the common ancestor) for the two commits:
git merge-base HEAD origin/master

# Get the contents of the files at each stage
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show HEAD:path/to/file.txt > ./file.ours.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt

# You can pre-edit any of the files (e.g. run a formatter on it), if you want.

# Merge the files
git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt

# Resolve merge conflicts in ./file.merged.txt
# Copy the merged version to the destination
# Clean up the intermediate files

git merge-file должен использовать все настройки по умолчанию для слияния для форматирования и тому подобное.

Также обратите внимание, что если ваша «наша» версия рабочей копии, и вы не хотите быть слишком осторожным, вы можете работать непосредственно с файлом:

git merge-base HEAD origin/master
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt
git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt
RM
источник
15

Все ли изменения в file.pyin branch2в их собственных коммитах отделены от изменений в других файлах? Если это так, вы можете просто cherry-pickвнести изменения:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

В противном случае, mergeне работает по отдельным путям ... вы могли бы просто создать git diffпатч file.pyизменений из branch2и git applyих к branch1:

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch

источник
8

Можно stashи stash popфайл:

git checkout branch1
git checkout branch2 file.py
git stash
git checkout branch1
git stash pop
Мартин Г
источник
Это перезаписывает branch1 / file.py содержимым branch2 / file.py вместо слияния, которое должно вызвать конфликт слияния для разрешения.
plumSemPy
2

Чтобы объединить только изменения из Branch2, оставьте file.pyдругие изменения без изменений.

git checkout -B wip branch2
git read-tree branch1
git checkout branch2 file.py
git commit -m'merging only file.py history from branch2 into branch1'
git checkout branch1
git merge wip

Слияние никогда не будет даже смотреть на любой другой файл. Вам может понадобиться '-f' оформить заказ, если деревья достаточно разные.

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

git checkout -B wip `git merge-base branch1 branch2`

в этом случае сообщение коммита, вероятно, также должно быть

git commit -m"merging only $(git rev-parse branch2):file.py into branch1"
jthill
источник
0

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

git merge <other-branch>
cp file-to-merge file-to-merge.example
git reset --hard HEAD (or HEAD^1 if no conflicts happen)
cp file-to-merge.example file-to-merge
Трак Нгуен
источник
0

То, что я сделал, немного ручное, но я:

  1. Слил ветки нормально; Отменил слияние с revert;
  2. Проверены все мои файлы HEAD~1, то есть их состояние в коммите слияния;
  3. Опроверг мои коммиты, чтобы скрыть этот хакер от истории коммитов.

Гадкий? Да. Легко вспомнить? Тоже да.

Лукас Лима
источник