# Отмена действий в Git ## Отмена изменений до `git add` Вернуть состояние файла к последнему коммиту. ```sh git restore ``` ## Отмена изменений после `git add` до `git commit` Если нежелательные изменения уже проиндексированы, т. е. выполнена команда `git add`. ```sh # Отменяет git add git restore --staged # Возвращает к исходному состоянию git restore ``` Можно и одной командой. ```sh git reset --hard ``` ## Отмена коммитов до `git push` ### Изменение последнего коммита Часто нужно что-то добавить/исправить/удалить в последнем коммите, в том числе сообщение коммита. ```sh # Добавляем/исправляем/удаляем # Индексируем изменения (git add) git commit -m "New message" --amend ``` Можно без `-m` и сообщения, если не хотим его менять, тогда надо будет просто закрыть открывшийся редактор, либо добавить флаг `--no-edit`, чтобы `Git` даже и не предлагал изменять сообщение. ```sh # Добавляем/исправляем/удаляем # Индексируем изменения (git add) git commit --amend --no-edit ``` !!! warning "Коммит не должен быть запушен!" Команда `git commit --amend` изменяет историю репозитория, не нужно использовать её, если последний коммит уже оказался на сервере (была выполнена команда `git push`). ### Удаление последних коммитов Можно полностью удалить коммит из истории репозитория с помощью `git reset`. ```sh # Можно добавить --hard, чтобы откатить изменения и вернуть рабочий каталог # к состоянию, в котором он был на предыдущем коммите git reset HEAD~1 ``` После такого удаления можно делать `git push`, не опасаясь, что кто-нибудь ещё сможет получить доступ к данным коммита, его следы могут остаться лишь в локальной копии репозитория. !!! warning "Коммит не должен быть запушен!" Команда `git reset` изменяет историю репозитория, не нужно использовать её, если последний коммит уже оказался на сервере (была выполнена команда `git push`). ??? info "Подробнее про `git reset`" Команда `git reset ` просто перемещает текущую ветку и `HEAD` на указанный коммит. Соответственно, вместо `HEAD~1` (указатель на предыдущий коммит) можно указать любой другой коммит в текущей ветке, например, `HEAD~3` - позволит отменить последние 3 коммита. Разумеется можно указать хэш коммита, к которому нужно откатиться. Параметр `--hard` говорит о том, что нужно сбросить и индекс и рабочий каталог до состояния указанного коммита. Есть и другие варианты: `--soft` - оставить изменения в индексе и рабочем каталоге, `--mixed` (значение по умолчанию) - сбросить индекс, но не трогать рабочий каталог. ??? info "Как восстановить коммиты, удалённые с помощью `git reset`" `Git` ведёт локальный журнал всех операций, так что хэш коммита ещё можно восстановить. ```sh git reflog ``` Зная хэш коммита, можно вернуть состояние ветки к нему с помощью того же `git reset`. ```sh git reset ``` Или, например, вынести его в отдельную ветку. ```sh git checkout git checkout -b branch-with-restored-commit ``` ## Отмена коммитов после `git push` ### Отмена изменений последнего коммита Если коммит уже оказался в удалённом репозитории, то самый простой вариант - просто сделать новый коммит, который будет отменять изменения предыдущего. ```sh git revert HEAD ``` Можно указать диапазон коммитов, которые нужно отменить, или перечислить их хэши. ```sh # Создаст коммит с отменой изменений последних трёх коммитов git revert HEAD~3..HEAD ``` После `git revert` можно спокойно делать `git push`, не опасаясь, что возникнут какие-либо конфликты с удалённым репозиторием. !!! warning "Изменения сохраняются в репозитории" Никакие данные ни из локального, ни из удалённого репозитория не удаляются, все коммиты остаются в истории той же самой ветки. `git revert` не подходит, если нужно полностью удалить нежелательные изменения (например, конфиденциальные данные) из локального и удалённого репозитория. ### Удаление последних коммитов из удалённого репозитория Переписывать историю удалённого репозитория можно если над репозиторием работает один человек, либо, если на сервер была отправлена конфиденциальная информация, которую непременно нужно удалить, в других случаях лучше использовать `git revert`. Для отмены коммитов можно использовать методы, описанные в предыдущем разделе, а затем перезаписать историю удалённого репозитория. ```sh git push --force ``` ## Полезные ссылки - GitHowTo [12](https://githowto.com/ru/undoing_local_changes), [13](https://githowto.com/ru/undoing_staged_changes), [14](https://githowto.com/ru/undoing_committed_changes), [15](https://githowto.com/ru/removing_commits_from_a_branch). - [Отмена нескольких коммитов](https://stackoverflow.com/questions/1463340/how-can-i-revert-multiple-git-commits#answer-1470452). - [Удаление запушенного коммита](https://stackoverflow.com/questions/3293531/how-to-permanently-remove-few-commits-from-remote-branch#answer-41726152).