2015-10-21 3 views
5

Я разблокировал репо и изменил файл A. Теперь файл A в восходящем репо переместился в подкаталог. Я пытаюсь объединить восходящее репо на свою вилку.Git слияние перемещенных файлов

Git считает, что файл A был удален в исходном местоположении, а новый новый был создан в новом подкаталоге (это также связано с тем, что они перемещали файл вверх по течению).

Я хочу получить мои изменения в этом файле в новом месте с наименьшими возможными последствиями, w.r.t историю коммитов и прочее. Может ли кто-нибудь помочь мне с помощью способов достижения этого?

+0

У вас возникают конфликты при слиянии? Обычно Git достаточно умен, чтобы понять, что файл перемещен. Что произойдет, если вы просто запустите 'git merge origin/master' (или что бы вы ни называли свою ветвь вверх)? – knittl

ответ

5

Git всегда обнаруживает переименования «после факта», сравнивая эти два дерева (или одно дерево и индекс, для случаев, которые не включают в себя git merge). (Линус Торвальдс считает эту особенность, например, this SO question).

В любом случае git merge будет запускать внутренний diff git с включенным определением слияния и значением по умолчанию для сходства по умолчанию 50%, если вы не настроите его иначе. Аналогичным образом, git diff имеет некоторые значения по умолчанию, которые также настраиваются. Если вы запустили git diff --find-renames -M50% вручную между базой слияния и восходящим потоком, вы, вероятно, хорошо (но см. Сноску 1 о настройке).

Если git не обнаруживает переименование, вам может потребоваться настроить пороговые значения переименования и/или увеличить количество файлов, которые git должен учитывать. Первым из них является значение rename-threshold в параметрах -X (rename-threshold впервые появилось в git 1.7.4). См. the documentation.


Вы можете установить merge.renameLimit количество файлов рассматривать с точкой зрения обнаружения переименования. Если вы не установите его, текущим значением по умолчанию является 1000 файлов (но со временем значение по умолчанию изменилось). Кроме того, если вы не установите его, merge использует diff.renameLimit, поэтому вы можете установить только второе из них, и оба параметра diff и merge используют оба значения.

Способ работы по обнаружению переименования файлов немного сложный, но достаточно простой для описания на примере. Предположим, что git сравнивает фиксацию 12345 с фиксацией 67890, а в 12345 - файлы с путями A, B/C и D; но в 67890 есть пути B/gronk, B/C и D. Это означает, что путь A ушел, но появился новый путь B/gronk.Затем Git запоминает такие пути (вплоть до предельного значения переименования) и сравнивает содержимое 12345:A с содержимым 67890:B/gronk. Если файлы «достаточно схожи», git объявит, что 12345:A был переименован в 67890:B/gronk.

Я не уверен точно, как git решает, что файл 50%, или 75%, или что-то еще, похожее/другое. Я видел, что индекс подобия основан на «кусках», а не на линиях (хотя обычный выходной поток - линейно-ориентированный).

1

Для перемещения файла необходимо использовать git mv, а не только mv.

С git берет снимок содержимого, которому не важно имя файла (которое хранится в файле idx как метаданные).

Если вы просто переместите файл, git не будет «понимать», что вы хотите переместить его, и будете рассматривать его как новый файл.

Вы должны вернуть свои изменения, а затем использовать:

git mv <old path> <new path> 

Теперь в состоянии мерзавца вы увидите ход файла, а не удаление одного и создание нового.

+2

Это неверно или, по крайней мере, неполное: git обнаруживает переименования «после факта» при сравнении двух деревьев или сравнения дерева и индекса на основе флагов, предоставленных его внутреннему коду diff. Команда 'git status' всегда устанавливает« check for renames », но« git diff »и« git show »используют' -M', '--find-renames',' -no-renames' и ваши настройки конфигурации ('diff.renames' и' diff.renamelimit') для управления механизмом обнаружения переименований. Если вы уже переименовали файл, то «git rm --cached» старый путь и «git add» новый путь, вы получите тот же эффект, как если бы вы использовали 'git mv'. – torek

+0

Я не вручную переместил файл. Я пытаюсь объединить восходящее репо с моим. Он перемещается в восходящем репо. –