Как мне вернуть Git-репозиторий к предыдущему коммиту? - PullRequest
6929 голосов
/ 06 ноября 2010

Как мне вернуться из моего текущего состояния к снимку, сделанному на определенном коммите?

Если я сделаю git log, то получу следующий вывод:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

Каквернуться к фиксации с 3 ноября, т.е. совершить 0d1d7fc?

Ответы [ 41 ]

8840 голосов
/ 06 ноября 2010

Это во многом зависит от того, что вы подразумеваете под «возвратом».

Временно переключиться на другой коммит

Если вы хотите временно вернуться к нему, дурачиться, а затем вернуться туда, где вы находитесь, все, что вам нужно сделать, это проверить желаемый коммит:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

Или, если вы хотите делать коммиты, пока вы там, продолжайте и создайте новую ветку, пока вы там:

git checkout -b old-state 0d1d7fc32

Чтобы вернуться туда, где вы были, просто проверьте ветку, на которой вы были снова. (Если вы внесли изменения, как всегда при переключении веток, вам придется обращаться с ними соответствующим образом. Вы можете сбросить их, чтобы выбросить; вы можете спрятать, оформить заказ, спрятать всплывающее окно, чтобы взять их с собой; вы можете зафиксировать если вы хотите, чтобы там была ветка.)

Жесткое удаление неопубликованных коммитов

Если, с другой стороны, вы хотите действительно избавиться от всего, что вы сделали с тех пор, есть две возможности. Во-первых, если вы не опубликовали ни одного из этих коммитов, просто выполните сброс:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

Если вы запутались, вы уже выбросили свои локальные изменения, но вы можете, по крайней мере, вернуться туда, где вы были раньше, сбросив заново.

Отменить опубликованные коммиты с новыми коммитами

С другой стороны, если вы опубликовали работу, вы, вероятно, не хотите сбрасывать ветку, поскольку это фактически переписывает историю. В этом случае вы действительно можете отменить коммиты. В Git возврат имеет очень специфическое значение: создайте коммит с обратным патчем, чтобы отменить его. Таким образом, вы не переписываете историю.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

Справочная страница git-revert фактически охватывает многое из этого в своем описании. Еще одна полезная ссылка - этот раздел git-scm.com, где обсуждается git-revert .

Если вы решили, что не хотите отменять все-таки, вы можете отменить возврат (как описано здесь) или сбросить его до возврата (см. Предыдущий раздел).

Вы также можете найти этот ответ полезным в этом случае:
Как переместить ГОЛОВУ обратно в предыдущее место? (Отдельная голова)

1474 голосов
/ 21 августа 2012

Rogue Coder?

Работаете самостоятельно и просто хотите, чтобы это работало?Следуйте приведенным ниже инструкциям, они надежно работали для меня и многих других в течение многих лет.

Работаете с другими?Git это сложно.Прочитайте комментарии под этим ответом, прежде чем делать что-то поспешное.

Возврат рабочей копии к самой последней фиксации

Чтобы вернуться к предыдущей фиксации, игнорируя любые изменения:

git reset --hard HEAD

где HEAD - последний коммит в вашей текущей ветке

Возврат рабочей копии в более старый коммит

Чтобы вернуться к коммиту, который старше самого последнего коммита:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

Кредиты переходят к аналогичному вопросу переполнения стека, Вернуть к фиксации хешем SHA в Git? .

1473 голосов
/ 12 февраля 2014

Здесь много сложных и опасных ответов, но на самом деле это просто:

git revert --no-commit 0766c053..HEAD
git commit

Это вернет все из HEAD обратно в хеш коммита, что означает, что он будет воссоздавать это состояние коммита в рабочем дереве , как если бы каждый коммит после того, как был возвращен назад. Затем вы можете зафиксировать текущее дерево, и оно создаст совершенно новый коммит, по существу эквивалентный коммиту, к которому вы «вернулись».

(Флаг --no-commit позволяет git отменить все коммиты одновременно, в противном случае вам будет предложено ввести сообщение для каждого коммита в диапазоне, засоряя вашу историю ненужными новыми коммитами.)

Это безопасный и простой способ возврата к предыдущему состоянию . История не уничтожается, поэтому ее можно использовать для коммитов, которые уже были опубликованы.

185 голосов
/ 22 октября 2013

Лучший вариант для меня и, вероятно, для других - это опция сброса Git:

git reset --hard <commidId> && git clean -f

Это был лучший вариант для меня!Это просто, быстро и эффективно!


Примечание: Как уже упоминалось в комментариях, не делайте этого, если вы делитесь своей веткой с другими людьми, у которых есть копиииз старых коммитов

Также из комментариев, если вам нужен менее «баллистический» метод, вы можете использовать

git clean -i

143 голосов
/ 06 февраля 2015

Прежде чем ответить, давайте добавим некоторый фон, объясняя, что это за HEAD.

First of all what is HEAD?

HEAD простоссылка на текущий коммит (последний) в текущей ветке.В любой момент времени может быть только один HEAD (исключая git worktree).

Содержимое HEAD хранится внутри .git/HEAD и содержит 40 байтов SHA-1текущий коммит.


detached HEAD

Если вы не используете последний коммит - это означает, что HEAD указывает напредыдущий коммит в истории называется detached HEAD.

Enter image description here

В командной строке он будетвыглядит так - SHA-1 вместо имени ветви, поскольку HEAD не указывает на вершину текущей ветви:

Enter image description here


Несколько вариантов восстановления после отсоединенной HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Это извлечет новую ветку, указывающую нажелаемый коммит.Эта команда вернется к данному коммиту.

На этом этапе вы можете создать ветку и начать работать с этого момента:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Вы также всегда можете использовать reflog.git reflog будет отображать любые изменения, которые обновили HEAD, и проверка желаемой записи reflog вернет HEAD обратно к этой фиксации.

Каждый раз, когда HEAD изменяется, будет происходитьНовая запись в reflog

git reflog
git checkout HEAD@{...}

Это вернет вас к желаемому коммиту

Enter image description here


git reset HEAD --hard <commit_id>

«Переместить» голову назад к желаемому коммиту.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

Эта схема иллюстрирует, какая команда что делает.Как видите, reset && checkout изменяет HEAD.

Enter image description here

125 голосов
/ 04 марта 2014

Если вы хотите «отменить передачу», стереть последнее сообщение о коммите и вернуть измененные файлы обратно в стадию, вы должны использовать команду:

git reset --soft HEAD~1
  • --soft указывает, что незафиксированные файлы должны быть сохранены как рабочие файлы, а не --hard, который их отбрасывает.
  • HEAD~1 - последний коммит. Если вы хотите откатить 3 коммита, вы можете использовать HEAD~3. Если вы хотите выполнить откат до определенного номера ревизии, вы также можете сделать это, используя его хэш SHA.

Это чрезвычайно полезная команда в ситуациях, когда вы совершили неправильное действие и хотите отменить последний коммит.

Источник: http://nakkaya.com/2009/09/24/git-delete-last-commit/

105 голосов
/ 29 июля 2012

Я перепробовал множество способов вернуть локальные изменения в Git, и кажется, что это работает лучше всего, если вы просто хотите вернуться к последнему состоянию фиксации.

git add . && git checkout master -f

Краткое описание:

  • Он НЕ будет создавать коммиты, как git revert.
  • НЕ ОТКЛЮЧАЕТ вашу ГОЛОВУ, как git checkout <commithashcode> делает.
  • Он отменит все ваши локальные изменения и УДАЛИТ все добавленные файлы с момента последнего коммита в ветви.
  • Он работает только с именами веток, поэтому вы можете вернуться только к последнему коммиту впереходите таким образом.

Я нашел гораздо более удобный и простой способ достижения указанных выше результатов:

git add . && git reset --hard HEAD

, где HEAD указывает на последний коммит в текущей ветке.

Это тот же код, что и предложенный boulder_ruby, но я добавил git add . до git reset --hard HEAD, чтобы стереть все новые файлы, созданные со времени последнего коммита, так как большинство людей ожидают, что я вернусь к последней версиисовершить.

100 голосов
/ 12 декабря 2014

Вы можете сделать это с помощью следующих двух команд:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Это удалит ваш предыдущий коммит Git.

Если вы хотите сохранить изменения, вы также можете использовать:

git reset --soft [previous Commit SHA id here]

Тогда он сохранит ваши изменения.

65 голосов
/ 20 июля 2017

ОК, вернуться к предыдущей фиксации в git довольно просто ...

Вернуть обратно без сохранения изменений:

git reset --hard <commit>

Возврат назад с сохранением изменений:

git reset --soft <commit>

Объясните: используя git reset, вы можете сбросить в определенное состояние, обычно это используется спередайте хеш, как вы видите выше.

Но, как вы видите, разница заключается в использовании двух флагов --soft и --hard, по умолчанию git reset с использованием флага --soft, но это хорошая практика - всегда использовать флаг, я объясняю каждый флаг:


- soft

Флаг по умолчанию, как объяснено, не требует его предоставления, не изменяет рабочее дерево, но добавляет все файлы изменений, готовые для фиксации, поэтому вы возвращаетесьв статус фиксации, который изменяется в файлах, становится неизменным.


- жесткий

Будьте осторожны с этим флагом, он сбрасывает рабочее дерево и все изменения в отслеживаемых файлах, и все исчезнет!


Я также создал изображение ниже, которое может случиться в реальной жизни, работая с git:

git reset to a commit

59 голосов
/ 13 февраля 2018

Ничто здесь не работает для меня, кроме этой точной комбинации:

git reset --hard <commit_hash>
git push origin <branch_name> --force

Ключ здесь - форсирование нажатия, никаких дополнительных сообщений о коммите / коммите и т. Д.

...