Как объединить изменения в один файл, а не объединить коммиты?

383

У меня есть две ветви (A и B), и я хочу объединить один файл из ветви A с соответствующим одним файлом из ветви B.

Isuru
источник
2
Уже обсуждалось здесь stackoverflow.com/questions/449541/…
позитрон
27
Большинство ответов на этот пост посвящено тому, как выборочно объединять коммиты , а не файлы . Это делает выбранный ответ неверным. Вопрос остается без ответа.
Этот ответ - путь, ИМО. git diff branch_name > patch git apply patch, stackoverflow.com/a/9473543/1091853
блам

Ответы:

631

Я столкнулся с той же проблемой. Если быть точным, у меня есть две ветви Aи Bс одними и теми же файлами, но с другим интерфейсом программирования в некоторых файлах. Теперь методы файла f, который не зависит от различий интерфейса в двух ветвях, были изменены в ветке B, но это изменение важно для обеих ветвей. Таким образом, мне нужно просто объединить файл fфилиала Bв файл fфилиала A.

Простая команда уже решила проблему для меня, если я предполагаю, что все изменения зафиксированы в обеих ветках Aи B:

git checkout A

git checkout --patch B f

Первая команда переключается в ветку A, в которую я хочу объединить Bверсию файла f. Вторая команда исправляет файл fс fиз HEADиз B. Вы можете даже принять / отменить отдельные части патча. Вместо того, Bчтобы указать здесь любой коммит, это не обязательно должно быть HEAD.

Сообщество редактирование : Если файл fна Bне существует на Aеще, то опустит --patchвариант. В противном случае вы получите «Без изменений». сообщение.

Loup
источник
10
Это работает только если вы хотите обновить файл. Что, если я хочу добавить новый файл из ветви B в ветку A?
Умайр А.
25
@UmairAshraf вы сможете добавить новый файл из B в A, удалив опцию --patch.
bbak
9
Хммм ... когда я пытаюсь это сделать, я получаю сообщение "без изменений", но изменения явно есть. ОК, мне нужно было находиться в папке, где находился соответствующий файл. Редактировать: это вполне может быть моим любимым решением проблемы, которую я видел в stackoverflow :-D
bot_bot
2
Я должен был использовать, git checkout --patch B -- fчтобы заставить это работать.
user545424
8
Просто добавьте, что если у вас есть несколько изменений (блоков) в файле, и вы хотите разместить их все , вы можете нажать aво время интерактивной фазы, вместо того, чтобы нажимать yкаждый раз. Или используйте git checkout B -- fкоманду вместо.
Дмитрий Гончар
17

Вот что я делаю в этих ситуациях. Это клудж, но он прекрасно работает для меня.

  1. Создайте другую ветку на основе вашей рабочей ветки.
  2. git pull / git объединить ревизию (SHA1), которая содержит файл, который вы хотите скопировать. Таким образом, это объединит все ваши изменения, но мы используем эту ветку только для получения одного файла.
  3. Устраните любые конфликты и т. Д. Исследуйте ваш файл.
  4. Оформите свою рабочую ветку
  5. Оформить заказ на файл, принятый из вашего слияния.
  6. Передай это.

Я попытался исправить, и моя ситуация была слишком уродлива для этого. Короче, это будет выглядеть так:

Рабочая ветвь: Экспериментальная ветвь: B (содержит файл file.txt, в котором есть изменения, которые я хочу добавить.)

git checkout A

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

git checkout -b tempAB

Слить B в tempAB

git merge B

Скопируйте sha1-хеш слияния:

git log

commit 8dad944210dfb901695975886737dc35614fa94e
Merge: ea3aec1 0f76e61
Author: matthewe <matthewe@matthewe.com>
Date:   Wed Oct 3 15:13:24 2012 -0700

Merge branch 'B' into tempAB

Оформите свою рабочую ветку:

git checkout A

Оформите ваш исправленный файл:

git checkout 7e65b5a52e5f8b1979d75dffbbe4f7ee7dad5017 file.txt

И там у вас должно быть это. Зафиксируйте свой результат.

eggmatters
источник
3
Таким образом, мы должны сделать все это, чтобы объединить один файл? Не было бы проще скопировать и вставить файл в другую ветку
Робин
1
@Robin, вероятно, нет, потому что слияние сохраняет изменения в файле, которые отличаются между ветвями A и B. Копирование файла перезапишет любые дополнительные различия между вашей рабочей веткой A и тем, что вы хотели получить из B, который может не содержать эти записи / правки. например, подозреваемый Aотклонился от Bначала другими способами. Копирование переопределит эти различия.
Буб
14

Это использует внутренний diff-инструмент git. Может быть, немного работы, но прямо вперед.

#First checkout the branch you want to merge into
git checkout <branch_to_merge_into>

#Then checkout the file from the branch you want to merge from
git checkout <branch_to_merge_from> -- <file> 

#Then you have to unstage that file to be able to use difftool
git reset HEAD <file> 

#Now use difftool to chose which lines to keep. Click on the mergebutton in difftool
git difftool

#Save the file in difftool and you should be done.
Микаэль Келлгрен
источник
1
Чтобы пояснить использование --(пустая метка аргумента), в git checkout docs: ARGUMENT DISAMBIGUATION говорят: «используйте, git checkout -- <pathspec>если вы хотите извлекать эти пути из индекса». Это потому, что вы можете иметь как ветку, так и файл / путь с одним и тем же именем. В таких случаях вместо того, чтобы просить вас устранить неоднозначность, следует ли извлекать ветку или путь, если оба существуют, git по умолчанию выберет извлечение ветки. Однако, если --предшествует, git извлечет файл / путь вместо этого.
SherylHohman
8

Я нашел этот подход простым и полезным: как «объединить» определенные файлы из другой ветки

Оказывается, мы слишком стараемся. Наш хороший друг Git Checkout является правильным инструментом для работы.

git checkout source_branch <paths>...

Мы можем просто дать git checkout имя ветви функции A и пути к конкретным файлам, которые мы хотим добавить в нашу основную ветку.

Пожалуйста, прочитайте всю статью для большего понимания

Павел Cioch
источник
2
Это переписывает файлы, но не объединяет их
Alex G
Для вас это может зависеть от того, что вы делаете и чего пытаетесь достичь. Идея здесь в том, что ветвь B является ветвью A, вы изменяете 4 файла в B, но хотите объединить только 2 из B в A. Обычное объединение объединит все 4, здесь вы можете выбрать. Это может выглядеть так, как будто они были переопределены, потому что B содержит существенно более новые файлы. Вы должны подтвердить свой опыт некоторыми доказательствами.
Павел Cioch
Я согласен, что это перезаписывает. Я думаю, что вы имели в виду использование -pопции в этой команде. Который затем перезаписывает любые части в вашем файле рабочего дерева, которые ранее были отклонены от ветви, из которой вы извлекаете, к сожалению, до изменения патча.
Буб
Ну, идея была с 2009 года, скорее всего, новая версия git ведет себя по-другому и требует -p или чего-то еще, но когда я публиковал его, это работало для меня, но опять же, возможно, мне было все равно, что файлы были переопределены, так как последняя версия была то, что мне было нужно
Pawel Cioch
3

Следующая команда (1) сравнит файл правильной ветки, чтобы master (2) в интерактивном режиме запросил, какие изменения применить.

git checkout --patch master

user1854182
источник
0

Мое редактирование было отклонено, поэтому я прилагаю, как обрабатывать слияния изменений из удаленной ветви здесь.

Если вам нужно сделать это после неправильного слияния, вы можете сделать что-то вроде этого:

# If you did a git pull and it broke something, do this first
# Find the one before the merge, copy the SHA1
git reflog
git reset --hard <sha1>

# Get remote updates but DONT auto merge it
git fetch github 

# Checkout to your mainline so your branch is correct.
git checkout develop 

# Make a new branch where you'll be applying matches
git checkout -b manual-merge-github-develop

# Apply your patches
git checkout --patch github/develop path/to/file
...

# Merge changes back in
git checkout develop
git merge manual-merge-github-develop # optionally add --no-ff

# You'll probably have to
git push -f # make sure you know what you're doing.
Суп
источник
0

Предполагая, что B является текущей ветвью:

$ git diff A <file-path> > patch.tmp
$ git apply patch.tmp -R

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

jbirkel
источник
Для меня это создаетerror: <file-path>: already exists in working directory
kontur
Вы должны указать конкретный файл или путь к файлу в текущем каталоге. Я используюgit diff Branch_A <file-path, filename> -- hash_commit > file_name.temp
Р.Чацири
0

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

например.

git show B:src/common/store.ts > /tmp/store.ts (где B - имя ветви / коммит / тег)

meld src/common/store.ts /tmp/store.ts

Салями
источник
0

Я сделаю это как

git format-patch branch_old..branch_new file

это произведет патч для файла.

Примените патч к цели branch_old

git am blahblah.patch

Новичек
источник
Можете ли вы легко заглянуть в патч для дополнительной безопасности?
XavierStuvw