Получение Git для просмотра переименованных и отредактированных файлов

Вопросы о переименовании файлов в Git имеют спросил, но я не могу решить решение моей конкретной проблемы.

Я переместил и отредактировал несколько файлов (я не использовал git mv - к сожалению, сейчас слишком поздно для этого). Теперь я хочу так, когда мой коллега вытащит из моего репозитория, внеся свои собственные изменения в те же файлы (без их перемещения), он успешно объединяет мои изменения с ним в новом месте файла. Чтобы успешно объединиться, Git явно должен знать, что это одни и те же файлы.

Является ли Git достаточно умным, чтобы справиться с этим самостоятельно? Кажется, трудно поверить. И если да, то как я могу быть уверен, что конкретный ход файла будет поднят на Git - даже если содержимое изменилось?

Ответ 1

Git фактически не отслеживает переименования в репозитории, он использует эвристику diff, чтобы определить, переименован ли файл в другой. То есть, если вы git mv файл и затем полностью замените его, он не считается переименованием, и вам не нужно использовать git mv для обнаружения переименований.

Например:

% mv d.txt e.txt
% git rm d.txt
rm 'd.txt'
% git add e.txt
% git commit -m"rename without git mv"
[master f70ae76] rename without git mv
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename d.txt => e.txt (100%)
% git diff --summary --find-renames HEAD~1 HEAD
 rename d.txt => e.txt (100%)

Аналогично, git mv не означает, что файл будет переименован, он все равно будет использовать алгоритм diff:

% git mv e.txt f.txt
% echo "Completely replacing f.txt" > f.txt
% git add f.txt
% git commit -m"git mv doesn't help here"
[master 068d19c] git mv doesn't help here
 2 files changed, 1 insertion(+), 14 deletions(-)
 delete mode 100644 e.txt
 create mode 100644 f.txt
% git diff --summary --find-renames HEAD~1 HEAD
 delete mode 100644 e.txt
 create mode 100644 f.txt

Ответ 2

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

Обратите внимание, что логически git сохраняет только дерево, как оно существовало в каждой ревизии: оно не хранит информацию отслеживания изменений, внесенных между версиями.

Если вы хотите увидеть, что обнаружено, вы можете использовать переключатель -M (--find-renames) в git diff для отображения переименований. Этот переключатель также включает эвристику, которая полезна, если у вас есть фиксация, которая не вызывает их.

Этот эвристический подход является хорошей причиной (если вам нужен другой), чтобы сохранить мелкие и автономные комманды, поскольку это облегчает работу git.

Ответ 3

git diff не собирал, что я переименовал файлы и изменил их содержимое. Мой сценарий состоял в том, что у меня были файлы A, B, C и вставлен новый B, поэтому старый B теперь был C, а старый C теперь D. git diff говорил мне, что B и C теперь совершенно разные!

Решение, которое я использовал, было утомительным и ручным, но выполнило эту работу.

  • Переименовал файлы, насколько мог. То есть B в Bnew, от C до B, от D до C.
  • Был ли diff, чтобы не проверять ошибок.
  • Согласен с этим.
  • Используется git mv, чтобы вернуть файлы к новым именам. B - C, C - D.
  • Согласен с этим.
  • Другой переименовал и перенял их как новые файлы. То есть Bnew to B.