Як злити зміни в один файл, а не об'єднувати коміти?


382

У мене є дві гілки (A і B), і я хочу об'єднати один файл із гілки A з відповідним єдиним файлом із відділення B.


2
Тут уже обговорювали stackoverflow.com/questions/449541/…
позитрон

27
Більшість відповідей на цю іншу публікацію стосуються того, як вибіркове об'єднання комітетів , а не файлів . Це робить обрану відповідь неправильною. Питання залишається без відповіді.


Ця відповідь - це шлях, ІМО. git diff branch_name > patch git apply patch. stackoverflow.com/a/9473543/1091853
blamb

Відповіді:


630

Я зіткнувся з тією ж проблемою. Якщо бути точним, у мене є дві гілки 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варіант. В іншому випадку ви отримаєте "Без змін". повідомлення.


10
Це працює лише в тому випадку, якщо ви хочете оновити файл. Що робити, якщо я хочу додати новий файл із гілки B до гілки A?
Умаїр А.

25
@UmairAshraf вам слід додати новий файл з B до A, видаливши опцію --patch.
bbak

9
Гммм ... коли я спробую це, я отримую повідомлення "немає змін", але явно є зміни. Гаразд, мені потрібно було знаходитись у папці, де був відповідний файл. Редагувати: Це, можливо, може бути моїм улюбленим рішенням проблеми, яку я бачив у
stackoverflow

2
Мені довелося скористатися, git checkout --patch B -- fщоб це налагодити.
користувач545424

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

Скопіюйте ша1 хеш злиття:

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

І там ви повинні його мати. Здійсніть свій результат.


3
Отже, ми повинні зробити все це просто для об'єднання одного файлу? Чи не було б просто простіше скопіювати та вставити файл в іншу гілку
Робін,

1
@Robin, мабуть, ні, оскільки об'єднання зберігає зміни у файлі, які відрізняються між гілками A і B. Копіювання файлу замінить будь-які додаткові відмінності між вашою робочою гілкою A і тим, що ви хотіли внести з B, які можуть не містити ці записи / правки. наприклад, підозрюваний Aвідхилився від Bпочатку іншими способами. Копіювання замінить ці відмінності.
блам

13

Для цього використовується внутрішній дифтол 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: ARGUMENT DISAMBIGUATION кажуть: "використовувати, git checkout -- <pathspec>якщо ви хочете вивести ці шляхи з індексу". Це тому, що ви могли мати і гілку, і файл / шлях з тим самим іменем. У таких випадках, замість того, щоб просити вас роз'єднати, чи слід перевіряти гілку чи шлях, коли вони існують, обидва git вирішать перевірити гілку за замовчуванням. Однак, якщо --передує, git замість цього буде перевіряти файл / шлях.
SherylHohman

8

Цей підхід я вважав простим і корисним: як "об'єднати" конкретні файли з іншої гілки

Як виявляється, ми намагаємося надто наполегливо. Наш хороший друг git checkout - це правильний інструмент для роботи.

git checkout source_branch <paths>...

Ми можемо просто надати git checkout назву гілки функції A та шляхи до конкретних файлів, які ми хочемо додати до нашої гілки.

Будь ласка, прочитайте всю статтю для більшого розуміння


2
Це перезаписує файли, їх не
Алекс G

Для вас це, можливо, залежить, що ви робите і чого намагаєтесь досягти. Ідея тут - відділення B - вилка A, ви змінюєте 4 файли в B, але хочете об'єднати лише 2 з B в A. Регулярне злиття об'єднало б усі 4, тут ви можете вибрати. Це може виглядати так, як вони були відмінені, оскільки B містить істотно новіші файли. Вам потрібно підтвердити свій досвід деякими доказами.
Pawel Cioch

Я згоден, що це перезаписується. я думаю, ти мав на увазі використання -pпараметра в цій команді. Потім, на жаль, перезаписує будь-які частини у вашому файлі робочих дерев, які раніше були відхилені від гілки, з якої ви перевіряєтесь, до зміни виправлення, на жаль.
блам

Ну ідея була з 2009 року, швидше за все, нова версія git поводиться інакше і потребує -p або що-небудь інше, але ще тоді, коли я публікував це, це працювало для мене, але, можливо, я знову не переймався тим, як файли перекриваються, як остання версія була те, що мені потрібно
Pawel Cioch


3

Наступна команда (1) порівняє файл правильної гілки, щоб майстер (2) інтерактивно запитав вас, які модифікації застосувати.

git checkout - майстер патчу


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

Якщо В є поточною галуззю:

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

Зауважте, що це стосується лише змін до локального файлу. Після цього вам потрібно буде взяти на себе зобов’язання.


Для мене це генерує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

це створить виправлення для файлу.

Застосувати виправлення на цільовому відділенні_old

git am blahblah.patch


Чи можете ви легко заглянути в пластир для додаткової безпеки?
XavierStuvw
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.