Если я чему-то научился за 15 с лишним лет программирования, так это тому, что ошибки - обычное дело, и я делаю их много. Это в равной степени относится и к инструментам управления версиями. Независимо от того, случайно ли вы зафиксировали изменения или только что осознали, что ваш предыдущий зафиксированный код - это не то, что вам нужно, часто вам нужно отменить предыдущую фиксацию в Git.
В этой статье я покажу несколько способов отменить ваши коммиты в зависимости от вашего варианта использования. Это сложная тема (что справедливо для многих тем Git в целом), поэтому убедитесь, что вы следуете инструкциям, которые лучше всего соответствуют вашим потребностям.
Удалить неопубликованные коммиты
Если вы еще не опубликовали свои коммиты в удаленном репозитории, таком
как GitHub, вы можете удалить предыдущие коммиты с помощью команды
reset
.
Хотя это эффективное решение, оно опасно, поскольку вы переписываете
историю и оставляете «удаленные» коммиты без ссылок или «сиротскими».
Единственный способ найти и восстановить эти коммиты без git reflog
.
Команда reset
имеет три различных варианта, два из которых мы опишем
здесь:
$ git reset --hard <hash-or-ref>
Используя параметр --hard
, все возвращается к указанной фиксации.
Сюда входят указатели ссылок на историю фиксации, промежуточный индекс и
ваш рабочий каталог.
Это означает, что, используя только эту команду, вы не только вернетесь
к предыдущей фиксации, но и потеряете все рабочие изменения в процессе.
Чтобы не потерять какие-либо рабочие изменения, вы можете использовать
команды stash
и stash pop
:
$ git stash
$ git reset --hard <hash-or-ref>
$ git stash pop
Команда stash
сохраняет ваши рабочие изменения (без каких-либо
коммитов или изменений в дереве), а затем stash pop
возвращает их.
Другой вариант, который вы можете рассмотреть, - это опция --soft
Этот
параметр работает почти так же, как git reset --hard <hash-or-ref>
,
но влияет только на историю коммитов, а не на ваш рабочий каталог или
промежуточный индекс.
$ git reset --soft <hash-or-ref>
Так что, если у вас есть незафиксированные изменения, которые вы хотите сохранить, то это, вероятно, тот вариант, который вам нужен.
Удаление опубликованных коммитов
Допустим, вы зафиксировали свой код, а затем отправили его в удаленный
репозиторий. На этом этапе настоятельно рекомендуется не
использовать что-то вроде git reset
так как вы будете переписывать
историю.
Вместо этого рекомендуется использовать команду revert
. Эта команда
работает, отменяя изменения, которые были внесены в указанную фиксацию,
создавая новую фиксацию, а не удаляя предыдущие фиксации. Это идеально
подходит для опубликованных изменений, поскольку тогда сохраняется
истинная история репо. Вот команда:
$ git revert <hash-or-ref>
Допустим, в вашем репо есть текстовый файл со следующим содержимым:
This is my sample text
А затем вы меняете его на:
This is my awesome sample text
История ваших коммитов может выглядеть примерно так:
$ git log --pretty=oneline
676ec97a9cb2cebbb5c77904bbc61ced05b86f52 Added 'awesome' to text
735c5b43bf4b5b7107a9cc3f6614a3890e2889f6 Initial commit
Если мы решим, что больше не хотим использовать "awesome" в нашем
тексте, но не хотим удалять 676ec
, мы можем использовать revert
чтобы отменить это изменение:
$ git revert 676ec
[master f68e546] Revert "Added 'awesome' to text"
1 file changed, 1 insertion(+), 1 deletion(-)
После того, как нам будет предложено ввести сообщение о фиксации, мы теперь можем видеть в нашей истории фиксации, что на самом деле есть новая фиксация:
$ git log --pretty=oneline
f68e546ac2ae240f22b2676b5aec499aab27f1ca Revert "Added 'awesome' to text"
676ec97a9cb2cebbb5c77904bbc61ced05b86f52 Added 'awesome' to text
735c5b43bf4b5b7107a9cc3f6614a3890e2889f6 Initial commit
В результате первая и третья фиксации представляют одно и то же состояние проекта. Фиксация была отменена, и история не была потеряна.
Обратите внимание, что есть несколько других способов использования этой команды, например, если вы хотите отменить 2 фиксации, вы можете использовать:
$ git revert HEAD~2
Или, если вы хотите отменить многие прерывистые коммиты, вы указываете их индивидуально:
$ git revert 676ec 735c5
Временно проверить предыдущую фиксацию
Под «откатом фиксации» вы можете иметь в виду, что вы временно хотите вернуться к предыдущему состоянию в вашем репо, но без внесения каких-либо фактических изменений в дерево. В этом случае вы, вероятно, просто захотите проверить фиксацию, что позволит вам вернуться к мастеру или любому другому состоянию, когда вы закончите:
$ git checkout <hash-or-ref>
Это изменит ваш рабочий каталог на содержимое этого коммита, а также на место, на которое указывает HEAD, ни одно из которых не является необратимым. Любые изменения, которые вы здесь вносите, можно либо зафиксировать в ветке, либо спрятать для дальнейшего использования.