Как вернуть Git-репозиторий к предыдущему коммиту

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

Если я сделаю 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?

40 ответов

Решение

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

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

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

# 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 man-страница действительно описывает многое из этого в своем описании. Еще одна полезная ссылка - это раздел git-scm.com, где обсуждается git-revert.

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

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

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

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

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

(The --no-commit флаг позволяет 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?,

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

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

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


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

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

git clean -i

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

First of all what is HEAD?

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

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


detached HEAD

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

Введите описание здесь

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

Введите описание здесь


Несколько вариантов того, как восстановить систему с отключенной 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 вернуться к этому коммиту.

Каждый раз, когда ГОЛОВКА изменяется, в reflog

git reflog
git checkout HEAD@{...}

Это вернет вас к желаемой фиксации

Введите описание здесь


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.
  • Примечание: ( начиная с Git 2.7) вы также можете использовать git rebase --no-autostash также.

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

Введите описание здесь

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

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

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

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

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

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

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

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

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

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

Лучший способ:

git reset --hard <commidId> && git push --force

Это приведет к сбросу ветки на конкретную фиксацию, а затем загрузит удаленный сервер с теми же коммитами, что и в локальном (это полностью исключит команды после этой конкретной фиксации)

Будьте осторожны с --force flag удаляет все последующие коммиты после выбранной фиксации без возможности их восстановления.

Я перепробовал множество способов вернуть локальные изменения в 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 стереть все новые файлы, созданные с момента последнего коммита, так как большинство людей ожидают, что вернутся к последнему коммиту.

Хорошо, вернуться к предыдущему коммиту в git довольно просто...

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

git reset --hard <commit>

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

git reset --soft <commit>

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

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


--мягкий

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


--жесткий

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


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

Git сбрасывается на коммит

Предполагая, что вы говорите о мастере и о соответствующей ветке (при этом речь может идти о любой рабочей ветке, которая вас интересует):

# Revert local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Revert remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

Я нашел ответ в сообщении в блоге Удалить удаленное Git-репо для конкретного коммита.

Дополнительные альтернативы решениям Jefromi

Решения Jefromi, безусловно, самые лучшие, и вам обязательно стоит их использовать. Однако для полноты картины я также хотел показать эти другие альтернативные решения, которые также могут быть использованы для отмены фиксации (в том смысле, что вы создаете новую фиксацию, которая отменяет изменения в предыдущей фиксации, как git revert делает).

Чтобы быть ясным, эти альтернативы не лучший способ отменить коммиты, решения Джефроми, но я просто хочу отметить, что вы можете также использовать эти другие методы для достижения того же, что и git revert,

Альтернатива 1: жесткий и мягкий сброс

Это очень немного измененная версия решения Чарльза Бейли " Вернуть коммит с помощью хэша SHA в Git"?:

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

# Commit the changes
git commit -m "Revert to <commit>"

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

Альтернатива 2: удалить текущее дерево и заменить новым

Это решение взято из решения svick Checkout old commit и делает его новым коммитом:

git rm -r .
git checkout <commit> .
git commit

Подобно альтернативе № 1, это воспроизводит состояние <commit> в текущей рабочей копии. Надо делать git rm во-первых, потому что git checkout не будет удалять файлы, которые были добавлены с <commit>,

Скажем, у вас есть следующие коммиты в текстовом файле с именем ~/commits-to-revert.txt (Я использовал git log --pretty=oneline чтобы получить их)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

Создайте сценарий оболочки Bash, чтобы вернуть каждый из них:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

Это вернет все обратно к предыдущему состоянию, включая создание файлов и каталогов, а также удаление, зафиксирует его в вашей ветви, и вы сохраните историю, но вы вернули ее обратно в ту же файловую структуру. Почему у Git нет git revert --to <hash> вне меня.

Внимание! Эта команда может привести к потере истории коммитов, если пользователь ошибочно добавил неверный коммит. Всегда имейте дополнительную резервную копию вашего git где-нибудь еще на всякий случай, если вы делаете ошибки, чем вы немного безопаснее.:)

У меня была похожая проблема, и я хотел вернуться к предыдущей фиксации. В моем случае меня не интересовали новые коммиты, поэтому я использовал Hard,

Вот как я это сделал:

git reset --hard CommitId && git clean -f

Это вернется в локальный репозиторий, здесь после использования git push -f обновит удаленный репозиторий.

git push -f

Вот гораздо более простой способ вернуться к предыдущему коммиту (и иметь его в незафиксированном состоянии, чтобы делать с ним что угодно):

git reset HEAD~1

Таким образом, нет необходимости в фиксации идентификаторов и так далее:)

Вы можете выполнить все эти начальные шаги самостоятельно и вернуться к git repo.

  1. Извлеките последнюю версию вашего хранилища из Bitbucket, используяgit pull --all команда.

  2. Запустите команду git log с -n 4 на вашем терминале. Число после -n определяет количество коммитов в журнале, начиная с самого последнего коммита в вашей локальной истории.

    $ git log -n 4

  3. Сбросьте заголовок истории вашего репозитория, используя git reset --hard HEAD~N где N - количество коммитов, которые вы хотите вернуть назад. В следующем примере заголовок будет возвращен на один коммит до последнего коммита в истории репозитория:

  4. Нажмите изменения в git repo, используя git push --force заставить толкнуть изменения.

Если вы хотите git-репозиторий для предыдущего коммита

git pull --all
git reset --hard HEAD~1
git push --force

Revert - команда для отката коммитов.

git revert <commit1> <commit2> 

Образец:

git revert 2h3h23233

Он способен принимать дальность от головы, как показано ниже. Здесь 1 говорит "отменить последний коммит".

git revert HEAD~1..HEAD

а затем сделать git push

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

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

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

Существует команда (не входит в состав ядра Git, но она входит в пакет git-extras) специально для возврата и установки старых коммитов:

git back

Для справочной страницы, он также может быть использован как таковой:

# Remove the latest three commits
git back 3

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

git push -f ...

И не только git push,

Попробуйте сбросить до желаемой фиксации -

git reset <COMMIT_ID>

(чтобы проверить использование COMMIT_ID git log)

Это вернет все измененные файлы в состояние без добавления.

Теперь вы можете checkout все не добавленные файлы

git checkout .

Проверьте git log чтобы проверить ваши изменения.

ОБНОВИТЬ

Если у вас есть один-единственный коммит в репо, попробуйте

git update-ref -d HEAD

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

  1. Скопируйте весь каталог и назовите его как-нибудь еще, например, "мой проект - копия".

  2. Делать:

    git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

Затем у вас есть две версии в вашей системе... вы можете просматривать, копировать или изменять файлы, представляющие интерес, или что-то еще из предыдущего коммита. Вы можете полностью удалить файлы в разделе "Мой проект - копия", если решили, что новая работа никуда не денется...

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

Git - блестящее творение, но вы не можете просто "поднять его на лету": также люди, которые слишком часто пытаются объяснить это, предполагают, что они уже знакомы с другими VCS [системами контроля версий] и слишком глубоко копаются, и совершать другие преступления, такие как использование взаимозаменяемых терминов для "проверки" - способами, которые иногда кажутся почти рассчитанными, чтобы запутать новичка.

Чтобы избавить себя от стресса, вы должны прочитать книгу о Git - я бы порекомендовал "Контроль версий с помощью Git". И если вы можете доверять мне (или, скорее, моим шрамам), когда я говорю "должен", из этого следует, что вы можете сделать это СЕЙЧАС. Большая часть сложности Git происходит от ветвления и последующего повторного использования. Но из твоего вопроса нет причин, почему люди должны ослеплять тебя наукой.

Особенно, если, например, это отчаянная ситуация, и вы новичок в Git!

PS: Еще одна мысль: (сейчас) на самом деле довольно просто хранить Git-репозиторий ("repo") в каталоге, отличном от каталога с рабочими файлами. Это будет означать, что вам не нужно будет копировать весь репозиторий Git, используя вышеуказанное быстрое и грязное решение. Смотрите ответ Фрайера, используя --separate-git-dir здесь. Тем не менее, будьте осторожны: если у вас есть репозиторий "отдельный каталог", который вы не копируете, и вы выполняете полный сброс, все версии, следующие за фиксацией сброса, будут потеряны навсегда, если у вас нет, как вы абсолютно должны, регулярно создавайте резервные копии вашего хранилища, желательно в облаке (например, Google Drive) среди других мест.

Выберите необходимый коммит и проверьте его

git show HEAD
git show HEAD~1
git show HEAD~2 

пока вы не получите необходимый коммит. Чтобы ГОЛОВА указала на это, сделайте

git reset --hard HEAD~1

или же git reset --hard HEAD~2 или что угодно.

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

  1. Emtpy рабочее дерево *.

     git rm -r --cached . && git clean -f -d
    
  2. Приведите рабочее дерево в желаемое состояние **.

     git checkout 0d1d7fc3 .
    
  3. Создайте возвратную фиксацию.

     git add --all && git commit -m "revert to 0d1d7fc3"
    

Сначала я подумал, что ответ Яринса будет лучшим, но он не работает для коммитов слияния. Это решение делает.

Кроме того, он не удаляет ничего (перемещенное или перемещенное вверх) из истории. Он производит одну чистую фиксацию, которая представляет состояние, к которому мы хотим вернуться.


* удалив неотслеживаемые, но не игнорируемые файлы (те, которые указаны в .gitignore) из рабочего дерева. Рабочее дерево пусто, за исключением проигнорированных файлов, которые мы хотели сохранить (если не указано иное-x вариант для clean)

** Когда указан путь (здесь: .), checkout оставляет HEAD в покое.

Возврат к самой последней фиксации и игнорирование всех локальных изменений:

git reset --hard HEAD

Это еще один способ прямого сброса на недавний коммит

git stash
git stash clear

Он напрямую удаляет все изменения, которые вы внесли с момента последнего коммита.

PS: у него есть небольшая проблема; он также удаляет все недавно сохраненные вами тайники. Что, я думаю, в большинстве случаев не должно иметь значения.

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

git add -A .
git reset --hard HEAD

Просто git reset --hard HEAD избавится от модификаций, но не избавится от "новых" файлов. В их случае они случайно перетащили важную папку куда-то случайно, и все эти файлы были обработаны Git как новые. reset --hard не исправить это. Запустив git add -A . заранее, он явно отслеживал их всех с помощью git, чтобы сбросить их при перезагрузке.

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

git reset <SHA>

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

git reset --hard <SHA>

Я полагаю, что некоторые люди могут прийти к этому вопросу, желая знать, как откатить совершенные изменения, которые они сделали в своем мастере - то есть выбросить все и вернуться к origin / master, и в этом случае сделать это:

git reset --hard origin/master

https://superuser.com/questions/273172/how-to-reset-master-to-origin-master

Поскольку ваши коммиты передаются удаленно, вам нужно их удалить. Позвольте мне предположить, что ваша ветвь развивается, и она отталкивается от происхождения.

Сначала нужно удалить развернуть из источника:

git push origin :develop (note the colon)

Затем вам нужно довести до нужного вам состояния, позвольте мне предположить, что хеш коммита - EFGHIJK:

git reset --hard EFGHIJK

Наконец, нажмите развиваться снова:

git push origin develop
Другие вопросы по тегам