Как вернуть репозиторий 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?

30 6178

30 ответов:

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

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

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

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

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

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

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

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

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 revert --no-commit 0766c053..HEAD
git commit

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

(флаг --no-commit позволяет 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 не указывает на вершину текущей ветви:

Введите описание изображения здесь


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


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

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 reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Это приведет к удалению ваших предыдущих коммитов.

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

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

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

Допустим, у вас есть следующие коммиты в текстовом файле с именем ~/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 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: удалить текущее дерево и заменить его новым

Это решение исходит из решения Свика извлечь старый коммит и сделать его новым коммитом :

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

Аналогично альтернативе #1, это воспроизводит состояние <commit> в текущей рабочей копии. Сначала нужно сделать git rm, потому что git checkout не удалит файлы, которые были добавлены после <commit>.

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

git reset HEAD~1

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

Хорошо, вернуться к предыдущему коммиту в 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 для конкретной фиксации.

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

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

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

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

git push -f ...

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

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

git back

В соответствии с man page , он также может использоваться как таковой:

# Remove the latest three commits
git back 3

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

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

Пока вы не получите требуемую фиксацию. Чтобы голова указала на это, сделайте

git reset --hard HEAD~1

Или git reset --hard HEAD~2 или еще что-нибудь.

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

git reset --hard HEAD

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

git reset <SHA>

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

git reset --hard <SHA>

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

git add -A .
git reset --hard HEAD

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

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

git stash
git stash clear

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

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

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

git reset --hard origin/master

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

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

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

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

    $ git log -n 4

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

  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

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

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

  2. Do:

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

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

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

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

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

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

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

Попробуйте выполнить сброс к нужной фиксации -

git reset <COMMIT_ID>

(для проверки COMMIT_ID используйте git log)

Это приведет к сбросу всех измененных файлов в состояние un-added.

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

git checkout .

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

Обновление

Если у вас есть один и только коммит в вашем РЕПО, попробуйте

git update-ref -d HEAD

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

Сначала нужно удалить Development из origin:

git push origin :develop (note the colon)

Тогда вам нужно получить develop к статусу, который вы хотите, позвольте мне предположить, что хэш фиксации-EFGHIJK:

git reset --hard EFGHIJK

И, наконец, нажмите кнопку снова:

git push origin develop

Если вы хотите исправить какую-то ошибку в последнем коммите, хорошей альтернативой будет использование команды git commit --amend. Если последний коммит не указан какой-либо ссылкой, это сделает трюк, так как он создает коммит с тем же родителем, что и последний коммит. Если нет ссылки на последний коммит, он будет просто отброшен, и этот коммит будет последним коммитом. Это хороший способ исправления коммитов без возврата коммитов. Однако у него есть свои ограничения.

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

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

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

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

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

git push -f

Во-первых, получить строку, которая идентифицирует фиксацию в некоторую дату, выполнив:

git rev-list -n 1 --before="2009-07-27 13:37" origin/master

Он печатает идентификатор фиксации, берет строку (например XXXX) и делает:

git checkout XXXX