git revert
Создание нового коммита, отменяющего изменения указанного коммита
Описание
git revert создаёт новый коммит, который является «обратным» (инверсным) к указанному коммиту. В отличие от git reset, который удаляет коммиты из истории, git revert сохраняет всю историю нетронутой и добавляет новую запись об отмене. Это делает его безопасным для использования в общих (опубликованных) ветках.
Команда применяет «обратный diff» указанного коммита: если коммит добавил строку — revert её удалит, если удалил — добавит обратно. Если с момента отменяемого коммита прошло много изменений, могут возникнуть конфликты слияния, которые нужно разрешить вручную.
Основные сценарии использования: откат неудачного деплоя на production-ветке, отмена коммита, который был уже слит в main и отправлен на remote, удаление фичи, которая вызвала проблемы, без переписывания публичной истории.
Синтаксис
Флаги и опции
| Флаг | Описание |
|---|---|
--no-edit |
Не открывать редактор для сообщения коммита — использовать автоматически сгенерированное сообщение «Revert "..."» |
-n, --no-commit |
Применить изменения и добавить в индекс, но не создавать коммит. Позволяет собрать несколько revert-ов в один коммит. |
-m <N> |
При отмене merge-коммита: указать номер родителя (1 = ветка-получатель, 2 = вливаемая ветка), изменения которого нужно сохранить |
--continue |
Продолжить процесс revert после разрешения конфликтов и git add |
--abort |
Отменить процесс revert и вернуть рабочий каталог в исходное состояние |
--quit |
Прервать revert, оставив рабочий каталог как есть (без отката) |
-e, --edit |
Открыть редактор для сообщения revert-коммита (включено по умолчанию) |
-S, --gpg-sign |
GPG-подписать создаваемый revert-коммит |
--signoff |
Добавить строку Signed-off-by в сообщение revert-коммита |
--strategy |
Указать стратегию слияния при разрешении конфликтов (ort, recursive) |
Паттерны использования
Откат последнего коммита на production
# Безопасная отмена опубликованного коммита git revert HEAD --no-edit # Или с кастомным сообщением git revert HEAD # В редакторе: "revert: rollback broken deploy #247" git push origin main
Откат конкретного коммита из середины истории
# Найти коммит с багом git log --oneline # Отменить конкретный коммит git revert abc1234 # Могут возникнуть конфликты — разрешить и: git add . git revert --continue
Отмена нескольких коммитов одним коммитом
# Отменить последние 3 коммита одним revert-коммитом git revert --no-commit HEAD~3..HEAD # Все изменения собраны в индексе git status # Создать один итоговый коммит git commit -m "revert: remove feature X (caused regression)"
Откат merge-коммита
# -m 1: оставить состояние главной ветки (main), # отменить всё, что пришло из feature-ветки git revert -m 1 <хеш-merge-коммита> # -m 2 означало бы: оставить feature, отменить main # (используется очень редко)
revert vs reset: когда что использовать
# revert: коммит уже опубликован на remote # история должна быть сохранена git revert HEAD git push origin main # reset: коммит ещё локальный # можно переписать историю git reset --soft HEAD~1 git push origin main # НЕ нужен force-push
Восстановление после revert (re-apply)
# Если нужно "вернуть обратно отменённую фичу" # revert of revert: git revert <хеш-revert-коммита> # Или cherry-pick оригинального коммита git cherry-pick <хеш-оригинального-коммита>
Советы и подводные камни
git revert вместо git reset. Revert не переписывает историю, поэтому не вызывает проблем при git pull у других.
Revert "<исходное сообщение коммита>". Флаг --no-edit позволяет принять его без открытия редактора — удобно в скриптах или при массовом откате через --no-commit.
git revert -m 1 <merge-коммит>, если попытаться снова влить ту же feature-ветку — Git посчитает, что эти изменения уже в истории и ничего не добавит. Придётся сначала revert-нуть revert-коммит, и только потом делать повторный merge.