git commit --amend не создаёт новый коммит - заменяет
последний. Точнее, создаёт новый коммит с обновлённым содержимым
и двигает ветку на него. Старый коммит остаётся в
.git/objects/ как dangling.
Что можно делать
Поправить сообщение
git commit --amend -m "новый текст сообщения"
# или без -m откроется редактор с текущим сообщением
git commit --amend
Добавить забытый файл
git add forgot.js
git commit --amend --no-edit
# --no-edit оставит старое сообщение, файл подмешается в коммит
Поправить содержимое
Если только что закоммитил и заметил баг - поправь файл,
застейджи, --amend. Получишь правильный коммит вместо
«фикс предыдущего коммита» отдельным коммитом.
Что физически происходит
- Берётся текущий индекс (включая новые правки, если есть).
- Создаётся новый commit-объект:
- tree: из текущего индекса
- parent: тот же, что был у старого коммита (не текущий коммит!)
- author/committer/message: из старого + правки
- Текущая ветка двигается на новый SHA.
- Старый коммит становится dangling.
Старый коммит ещё месяц виден в reflog. Если ошибся в amend -
можно восстановить через git reflog.
Когда нельзя
Если коммит уже запушен и кто-то его подтянул - amend ломает историю. У тебя локально один SHA, у других - другой. Обычный push откажет:
! [rejected] feature -> feature (non-fast-forward)
Варианты:
- Force-push через
--force-with-lease. Безопасно только для feature-ветки, которую кроме тебя никто не смотрит. - Не amend'ить, сделать новый коммит. Правильно для
main/master/общих веток.
Правило: amend разрешён до первого push. После push - только на личных ветках и только с force-with-lease.
Подводные камни
- Author-date.
--amendоставляет author-date старым, но committer-date обновляет.git log --pretty=fullerпокажет обе.- Подписи (GPG). Если коммит был подписан - после
--amendподпись слетит. Повторноgit commit --amend -S.
- Подписи (GPG). Если коммит был подписан - после
- Время.
git logсортирует по committer-date по умолчанию. После amend коммит «всплывает» наверх, даже если author-date старый.