git diff - самая часто используемая команда расследования. Знаешь
четыре её режима - и понимаешь, в какой зоне Git что.
Четыре основных режима
git diff # working tree vs index (что не застейджил)
git diff --staged # index vs HEAD (что войдёт в следующий коммит)
git diff HEAD # working tree vs HEAD (сумма обоих)
git diff <A> <B> # коммит A vs коммит B
Это четыре зоны Git и пары между ними (см. главу 5 книги).
Частые сценарии
# Что я ещё не застейджил
git diff
# Что войдёт в следующий коммит
git diff --staged
# синоним: git diff --cached
# Всё, что отличается от последнего коммита
git diff HEAD
# Что изменилось между релизами
git diff v1.0 v1.1
git diff v1.0..v1.1 # эквивалентно
# Только в каталоге
git diff -- src/auth/
git diff HEAD -- "**/*.py"
# Между двумя ветками
git diff main feature # all differences between tips
git diff main...feature # only what feature added relative to merge-base
Разница между git diff A B и git diff A...B тонкая:
A B- diff между вершинами. «Если приложить B к A - какие изменения».A...B- diff от общего предка до B. «Что добавил B, игнорируя параллельные изменения в A».
Для code review удобнее A...B: чистая картина «что сделала
feature», без шума из main.
Полезные опции
git diff --stat # сводка: файлы и числа строк
git diff --shortstat # одна итоговая строка
git diff --name-only # только список изменённых файлов
git diff --name-status # список + статус (A/M/D/R)
git diff -w # игнорировать whitespace
git diff --word-diff # диф по словам, не по строкам
git diff --word-diff=color # с цветным выделением
git diff -M # детект переименований (rename)
git diff -C # детект копирований (copy)
git diff -B # break-rewrite: расщепить
# сильно изменённый файл на delete+add
git diff --find-renames=50% # порог похожести для переименования
git diff -p # full patch (по умолчанию)
git diff -U10 # 10 строк контекста (по умолчанию 3)
git diff -U0 # без контекста, только сами правки
Pickaxe и поиск по содержимому
Не совсем git diff, но рядом - git log -S и -G:
git log -S "magicConstant" --oneline # коммиты, изменившие
# количество вхождений строки
git log -G "TODO\(.*\)" --oneline # коммиты с diff'ом, матчащим regex
См. log.
Сравнение между файлами без репозитория
git diff --no-index a.txt b.txt
Полезно как универсальный diff с цветами и фильтрами, даже когда файлы не в Git.
Подводные камни
git diffбез аргументов не показывает застейдженное. Если кажется, что нет изменений, а ты что-то стейджил -git diff --staged.- Бинарные файлы показываются как
Binary files differ. Чтобы увидеть имена ---statили--name-only. Чтобы заставить показать как текст ---text. - Файлы с другой кодировкой (windows-1251, и т.п.) могут
отображаться кракозябрами. Решение -
.gitattributesсdiff=cp1251(для русских файлов) или конвертация при diff'е. - Длинные строки в JSON / minified JS показываются одной
строкой - нечитаемо.
--word-diffиногда помогает. - Diff большого файла медленный.
--statбыстрее всех.