Есть ли способ "мягкого возврата" старого коммита?
Есть ли способ вернуть старый коммит без изменения файлов в рабочем каталоге? Я сделал коммит некоторое время назад, но код, который я зафиксировал, не был готов, и я хочу, чтобы эти изменения оставались в моем рабочем каталоге как незафиксированные изменения, чтобы я мог продолжить работу над ними сейчас. Я посмотрел в команду возврата, но это меняет рабочий каталог. Я думал о проверке старой ревизии, обнулении головы 1 и сохранении изменений, но у меня уже есть изменения. Я просто хочу, чтобы это было так, как будто я никогда не делал этот коммит еще тогда, но я хочу, чтобы изменения в файлах остались.
6 ответов
Короткий ответ - нет".
Чем дольше ответ: git revert
- как и все операции слияния, в том числе git cherry-pick
, git rebase
и конечно git merge
само по себе - изменяет изменяемое рабочее дерево, используя индекс. Вы можете зафиксировать или спрятать вашу текущую работу, или получить второе дерево работы (с другим клоном, или используя git worktree
если у вас Git версии 2.5 или выше).
Ты можешь использовать git revert -n
, что позволяет рабочему дереву быть грязным, но я бы не советовал это здесь.
То, как я справлюсь с этим, это сделать коммит сейчас:
$ git add ...
$ git commit -m 'temporary commit, do not push'
Затем сделайте желаемый возврат как обычный коммит:
$ git revert <hash>
Тогда используйте git rebase -i
поменять местами порядок нового возврата и временного принятия:
$ git rebase -i HEAD~2 # and edit the two "pick" lines
затем используйте git reset --soft HEAD^
(или же HEAD~1
тоже самое) или git reset --mixed HEAD^
снять временную фиксацию В этот момент вы находитесь в том же состоянии (в основном), в котором находились до того, как сделали временный коммит.
(В основном) имеет отношение к состоянию индекса: если вы используете git reset --soft
, всех тех git add
сейчас действуют. Если вы используете git reset --mixed
ни один из тех git add
сейчас действуют.
Только для экспертов
Если до того, как вы начнете что-либо из этого, у вас уже есть какое-то тщательно подготовленное состояние, например git add -p
- что вы хотите сохранить, это требует выполнения двух коммитов, и git stash
до возврата, с git stash apply --index
потом проще. Это потому что git stash
фактически делает два коммита, и git stash apply --index
извлекает и применяет эти два коммита отдельно к индексу и рабочему дереву. (Затем git stash drop
тайник, если все прошло хорошо.)
В зависимости от того, насколько вам удобно git stash
Вы можете даже заменить всю последовательность выше на git stash && git revert <hash> && git stash pop
сделать это как однострочник. добавлять --index
восстановить отдельное состояние индекса. (Обратите внимание, что если вы опечатка --index
и ваша версия Git недостаточно современна, чтобы обнаружить ошибку, это объединит два отдельных коммита и сбросит тайник. Вот почему я люблю использовать git stash apply
вместо git stash pop
Вот.)
Если во время этого процесса что-то пойдет не так, вам необходимо точно знать, что произошло, и что с этим делать, поэтому заголовок "только для экспертов" над этой частью.
Вы можете сделать что-то вроде
git revert hash_of_your_commit
git reset HEAD^
После этого вы пришли с неустановленными изменениями вашего отмененного коммита.
У меня обычно работает эта команда:
git revert --no-commit <commit>
Отличный вариант, использоватьgit apply
, что является безопасной операцией и не редактирует локальную историю git.
Это мягко вернет конкретную фиксацию
git show COMMIT_HASH | git apply -R
Как это работает
Используяgit show
, мы получаем diff из определенного коммита. Затемgit apply -R
отменяет эти изменения и применяет их к текущему репо (без фиксации)
Другой способ сделать это - установить плохой $EDITOR, например:
EDITOR=nope git revert <hash>
он выйдет при попытке отредактировать сообщение о коммите, но уже внес изменения