Я сейчас пытаюсь выполнить довольно мощный маневр слияния git. Одна из проблем, с которой я столкнулся, заключается в том, что я внес некоторые изменения в некоторый код в своей ветке, но мой коллега переместил этот код в новый файл в своей ветке. Когда я это сделал git merge my_branch his_branch
, git не заметил, что код в новом файле был таким же, как и в старом, и поэтому никаких моих изменений там нет.
Какой самый простой способ снова применить мои изменения к коду в новых файлах? У меня не будет слишком много проблем с выяснением, какие коммиты нужно повторно применить (я могу просто использовать git log --stat
). Но, насколько я могу судить, нет никакого способа заставить git повторно применить изменения к новым файлам. Самое простое, что я вижу прямо сейчас, - это повторно применить изменения вручную, что не похоже на хорошую идею.
Я знаю, что git распознает капли, а не файлы, поэтому наверняка должен быть способ сказать ему: «применить это точное изменение кода из этого коммита, за исключением того, где оно было, а где оно сейчас находится в этом новом файле».
--rename-threshold
возможность настроить необходимое количество сходства.Ответы:
У меня была аналогичная проблема, и я решил ее, переместив свою работу в соответствие с организацией целевого файла.
Скажем, вы изменили
original.txt
свою ветку (local
ветку), ноoriginal.txt
, скажем, основная ветка была скопирована в другуюcopy.txt
. Эта копия была сделана в коммите, который мы называем коммитомCP
.Вы хотите применить к новому файлу все ваши локальные изменения, коммиты
A
иB
ниже, которые были сделаны .original.txt
copy.txt
Создайте одноразовую ветку
move
в начальной точке ваших изменений с помощьюgit branch move X
. Другими словами, поместитеmove
ветку в точку фиксацииX
, ту, что перед коммитами, которые вы хотите объединить; скорее всего, это тот коммит, из которого вы вышли для реализации своих изменений. Как написал ниже пользователь @digory doo , вы можете самиgit merge-base master local
найтиX
.В этой ветке введите следующую команду переименования:
Это переименовывает файл. Обратите внимание, что
copy.txt
на данный момент в вашем дереве еще не было.Зафиксируйте свое изменение (мы называем это фиксацией
MV
).Теперь вы можете перебазировать свою работу поверх
move
:Это должно работать без проблем, и ваши изменения будут применены
copy.txt
в вашем локальном филиале.Теперь вы не обязательно хотите или должны иметь фиксацию
MV
в истории вашей основной ветки, потому что операция перемещения может привести к конфликту с операцией копирования при фиксацииCP
в основной ветке.Вам нужно только снова переустановить свою работу, отказавшись от операции перемещения, как показано ниже:
... где
CP
коммит, которыйcopy.txt
был введен в другой ветке. Это перебазирует все измененияcopy.txt
поверхCP
коммита. Теперь вашаlocal
ветка такая же, как если бы вы всегда изменяли,copy.txt
а не изменялиoriginal.txt
, и вы можете продолжить слияние с другими.Важно, чтобы изменения применялись
CP
или иначеcopy.txt
не существовало бы, и изменения применялись бы сноваoriginal.txt
.Надеюсь, это понятно. Этот ответ приходит с опозданием, но может быть полезен кому-то другому.
источник
patch
(что также потенциально требует большого объема работы), и поэтому я подумал, что было бы интересно показать его. Также обратите внимание, что в моем случае я потратил больше времени на то, чтобы написать ответ, чем на то, чтобы применить изменения. На каком этапе вы бы рекомендовали использовать слияние? и почему? Единственное различие, которое я вижу, заключается в том, что путем перебазирования я делаю временную фиксацию, которая позже отбрасывается (фиксацияMV
), что невозможно только при слияниях.Вы всегда можете использовать
git diff
(илиgit format-patch
) для создания патча, затем вручную отредактировать имена файлов в патче и применить его с помощьюgit apply
(илиgit am
).Если не считать этого, единственный способ, которым это будет работать автоматически, - это если обнаружение переименования git сможет определить, что старый и новый файлы - это одно и то же - что, похоже, на самом деле не в вашем случае, а просто их кусок. Это правда, что git использует большие двоичные объекты, а не файлы, но большой двоичный объект - это просто содержимое всего файла без прикрепленных файлов и метаданных. Таким образом, если у вас есть фрагмент кода, перемещенный между двумя файлами, на самом деле это не один и тот же blob - остальное содержимое blob-объекта отличается, просто общий фрагмент.
источник
git format-patch
работать коммит. Если я это сделаюgit format-patch SHA1
, он создаст целую кучу файлов патчей для всей истории. Но, думаю,git show SHA1 > diff.patch
тоже сработает.-1
опцию. Обычный режим работы для format-patch - это диапазон ревизий, напримерorigin/master..master
, так что вы можете легко подготовить серию исправлений.git apply
иgit am
слишком разборчивы, потому что хотят одинаковые номера строк. Но в настоящее время я успешно используюpatch
команду UNIX .Вот решение слияния при обнаружении конфликта слияния с переименованием и редактированием и его разрешение с помощью mergetool, распознающего правильные 3 исходных файла слияния.
После сбоя слияния из-за «удаленного файла», который, как вы понимаете, был переименован и отредактирован:
Прохождение:
Создайте файл .txt:
Создайте ветку, в которой вы будете редактировать позже:
Создайте переименование и отредактируйте на мастере:
Переключитесь на ветку и отредактируйте там тоже:
Попытка слить мастер:
Обратите внимание, что конфликт трудно разрешить, и файлы были переименованы. Прервать, имитировать переименование:
Попробуйте слить еще раз:
Большой! Слияние приводит к «нормальному» конфликту, который можно разрешить с помощью mergetool:
источник
B.txt -> C.txt
иA.txt -> B.txt
с мерзавца мв и мерзавцем не может автоматически соответствовать конфликты слияния правильно (получал конфликты слияния между старымB.txt
и новымB.txt
). При использовании этого метода конфликты слияния теперь возникают между правильными файлами.