Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як Git визначає перейменування файлів, якщо він їх не зберігає?

У коміті немає запису «файл перейменовано». Tree лише містить ім'я й хеш: у старому дереві є big.txt, у новому - big2.txt. Перейменування Git обчислює заново щоразу, коли показує diff, log чи виконує злиття.

Алгоритм:

  1. знайти пари «видалений файл» і «доданий файл»;
  2. точні збіги - однаковий хеш blob-а: це перейменування зі 100% схожістю (R100). Перевіряється дешево;
  3. для решти - оцінити схожість вмісту кожної пари і вважати перейменуванням, якщо вона вища за поріг. Поріг за замовчуванням - 50%.
git diff -M HEAD~1 --name-status
# R100	big.txt	big2.txt
# R087	app/Helpers.php	app/Support/Helpers.php

git diff -M80% HEAD~1          # суворіший поріг
git diff -C HEAD~1             # шукати ще й копії
git diff --no-renames HEAD~1   # показати як видалення + додавання

Чому git mv нічого не гарантує: він лише видаляє й додає файл в індексі. Якщо в тому самому коміті файл перейменовано і суттєво змінено, схожість опуститься нижче порогу - і Git покаже видалення одного файлу й створення іншого. Звідси практика: перейменування окремим комітом, зміни вмісту - наступним.

Де це впливає на роботу:

  • git log --follow file стежить за історією файлу через перейменування - але лише для одного файлу й саме евристикою;
  • git blame знаходить рядки, переміщені з інших файлів, з -C;
  • злиття: якщо в одній гілці файл перейменовано, а в іншій змінено, стратегія ort знаходить перейменування і застосовує зміни до нового імені. Невдале визначення дає конфлікт «deleted by us / modified by them»;
  • ліміт кандидатів: порівняння - квадратична задача. Якщо видалених і доданих файлів забагато, Git пропускає неточне визначення (diff.renameLimit, merge.renameLimit) і попереджає про це. Після масового переміщення файлів зручно підняти ліміт.

Плюс підходу: перейменування «знаходиться» навіть якщо його зробили без git mv - просто через IDE чи mv - і навіть ретроспективно для старої історії, коли алгоритм покращується з новими версіями Git.

Докладніше в документації: gitdiffcore

Схожі питання