Отмена действий гит
All checks were successful
Build MkDocs / build-and-deploy (push) Successful in 3s

This commit is contained in:
2025-01-19 01:02:42 +03:00
parent fa1d8dad61
commit 607ee6297c

134
docs/git/undo.md Normal file
View File

@@ -0,0 +1,134 @@
# Отмена действий в Git
## Отмена изменений до `git add`
Вернуть состояние файла к последнему коммиту.
```sh
git restore <path-to-dir-or-file>
```
## Отмена изменений после `git add` до `git commit`
Если нежелательные изменения уже проиндексированы, т. е. выполнена команда `git add`.
```sh
# Отменяет git add
git restore --staged <path-to-dir-or-file>
# Возвращает к исходному состоянию
git restore <path-to-dir-or-file>
```
Можно и одной командой.
```sh
git reset --hard <path-to-dir-or-file>
```
## Отмена коммитов до `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 <commit>` просто перемещает текущую ветку и `HEAD` на указанный коммит. Соответственно, вместо `HEAD~1` (указатель на предыдущий коммит) можно указать любой другой коммит в текущей ветке, например, `HEAD~3` - позволит отменить последние 3 коммита. Разумеется можно указать хэш коммита, к которому нужно откатиться.
Параметр `--hard` говорит о том, что нужно сбросить и индекс и рабочий каталог до состояния указанного коммита. Есть и другие варианты: `--soft` - оставить изменения в индексе и рабочем каталоге, `--mixed` (значение по умолчанию) - сбросить индекс, но не трогать рабочий каталог.
??? info "Как восстановить коммиты, удалённые с помощью `git reset`"
`Git` ведёт локальный журнал всех операций, так что хэш коммита ещё можно восстановить.
```sh
git reflog
```
Зная хэш коммита, можно вернуть состояние ветки к нему с помощью того же `git reset`.
```sh
git reset <commit-hash>
```
Или, например, вынести его в отдельную ветку.
```sh
git checkout <commit-hash>
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).