Из того, что я узнал, git может обрабатывать переименования / перемещения файлов, когда вы фиксируете переименование / перемещение в одном коммите и вносите изменения в другой коммит.
Что ж, да, но также нет.
Ключ в том, что Git не сохраняет изменений . Git хранит снимков . Другими словами, каждый коммит имеет полную и полную копию вашего исходного кода. Если вы переименуете группу файлов, не внося никаких других изменений и сделав новый снимок, старый снимок будет иметь содержимое под старыми именами, а новый снимок будет иметь то же самое содержимое, но под новым набором. из names .
Если вы переименуете и измените файлы , старый снимок будет иметь старое содержимое под старыми именами, а новый снимок будет содержать новое содержимое под новые имена.
Что Git делает с git log --follow
и git diff --find-renames
, делает два снимка - скажем, «до» и «после» интересного события, причем интересным событием в этом случае является переименуйте - и сравните их. Внутренне зафиксированные файлы хранятся как пары (или, точнее, утраивает):
$ git ls-tree -r HEAD
[snippage]
100644 blob 41b718c29e1b9fc2981d7d14a3d25e69c31a3030 version.c
100644 blob 7c62e80577154d79bec050424945eb500d262a0f version.h
100644 blob 069ee94a4d79422ea659a7ebe3923662f0626afa versioncmp.c
100644 blob bb010f7a2b3c1090bc9c62f613cede7bbda86e97 walker.c
[snippage]
Здесь blob
фактически является текстовым представлением части mode
(100644
всегда является объектом BLOB-объекта), поэтому каждая из этих строк является результатом чтение записи tree , в которой хранится это имя-и-ха sh -ID.
Идентификатор ha sh идентификатора содержимого каждого файла основан исключительно на данных файла, отсутствует в файле name . Например, если имя файла было walker.c
или funny.name
, при условии, что content одинаково, ha sh ID также будет одинаковым.
Итак, с учетом снимка с левой и правой стороны - до и после - если га sh идентификаторов совпадают, содержимое также совпадает. Это делает его очень быстрым для git diff --find-renames
до поиска переименований: мы просто выстраиваем все совпадающие идентификаторы ha sh, а имена слева переименовываются в имена, которые находятся на правильно.
Если файлы были слегка изменены , этот трюк быстрого переименования не работает. Теперь Git должен фактически извлечь все левые файлы и все правые файлы и сравнить их. В отличие от быстрого трюка «посмотрите на ha sh ID», на самом деле это очень сложно (это O (n 2 ) в количестве файлов, которые нужно объединить в пару). Git сначала сделает все возможное, чтобы спарить все левые и правые файлы, которые он может, без проверки их содержимого, чтобы список «возможно переименованных» файлов был как можно меньшим, а затем только смотреть на те файлы, которые не в паре.
Итак, Git может обрабатывать обе ситуации - до тех пор, пока содержимое не изменилось слишком , так что Детектор сходства может сжечь много процессорного времени для сопоставления файлов по индексу сходства, но для поиска совпадения по переименованию требуется намного меньше вычислительной мощности, если событие, через которое git diff
передает два коммита, просто событие переименования. Это означает, что все идентификаторы ha sh совпадают, а код быстрого совпадения выполняет всю работу.
Но как это работает, когда вы объединяетесь в sh слияние вашей PR-ветви?
Это не так.
Squa sh слияния инструменты . Используйте их, когда они уместны. Используйте другие инструменты, когда слияния squa sh не подходят.
(Помните, squa sh -merge означает run git merge
, но затем фиксируйте результат как обычный коммит , а не как коммит слияния. Из командной строки git merge --squash
действует так, как если бы вы также включали опцию --no-commit
каждый раз, поэтому вы должны сами запускать команду git commit
. GitHub clicky "squa * 1112 Кнопка * and merge "не использует команды командной строки, поэтому она немного отличается, но окончательный набор коммитов, который вы получаете, такой же, как если бы вы сделали все это в командной строке.)