Как я могу отменить git reset --hard HEAD ~ 1?

Можно ли отменить изменения, вызванные следующей командой? Если да, то как?

git reset --hard HEAD~1

Ответ 1

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

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... [email protected]{0}: reset --hard HEAD^: updating HEAD
f6e5064... [email protected]{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

В примере показано, что файл2 был удален из жесткого reset, но был вставлен на место, когда я reset через reflog.

Ответ 2

Что вы хотите сделать, так это указать sha1 комманды, которую вы хотите восстановить. Вы можете получить sha1, изучив reflog (git reflog), а затем сделав

git reset --hard <sha1 of desired commit>

Но не ждите слишком долго... через несколько недель git в конечном итоге увидит, что commit как unreferenced и удаляет все капли.

Ответ 3

Ответ скрыт в подробном ответе выше, вы можете просто сделать:

$> git reset --hard [email protected]{1}

(Смотрите вывод git reflog show)

Ответ 4

Его можно восстановить, если Git не собрал мусор.

Получить обзор оборванных коммитов с помощью fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Восстановите оборванную фиксацию с помощью rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Ответ 5

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

Я знаю, что это не совсем правильный ответ, но он спас мне полдня, поэтому, надеюсь, он сделает то же самое для кого-то еще!

Ответ 6

насколько я знаю, --hard будет отбрасывать незафиксированные изменения. Поскольку они не отслеживаются git. но вы можете отменить discarded commit.

$ git reflog

будут перечислены:

b0d059c [email protected]{0}: reset: moving to HEAD~1
4bac331 [email protected]{1}: commit: added level introduction....
....

где 4bac331 - discarded commit.

Теперь просто переместите голову в команду commit:

$ git reset --hard 4bac331

Ответ 7

Пример случая IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <[email protected]>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

Ответ 8

В большинстве случаев да.

В зависимости от состояния вашего репозитория, когда вы запускали команду, эффекты git reset --hard могут варьироваться от тривиального до отмены, в принципе невозможного.

Ниже я перечислил ряд различных возможных сценариев и способы их восстановления.

Все мои изменения были совершены, но теперь коммиты исчезли!

Эта ситуация обычно возникает, когда вы запускаете git reset с аргументом, как в git reset --hard HEAD~. Не беспокойтесь, это легко восстановить!

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

git reset --hard @{1}

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

Если, однако, вы внесли другие изменения в свою ветку с reset, однострочный надстрочный файл не будет работать. Вместо этого вы должны запустить git reflog <branchname>, чтобы просмотреть список всех последних изменений, внесенных в вашу ветку (включая сбрасывания). Этот список будет выглядеть примерно так:

7c169bd [email protected]{0}: reset: moving to HEAD~
3ae5027 [email protected]{1}: commit: Changed file2
7c169bd [email protected]{2}: commit: Some change
5eb37ca [email protected]{3}: commit (initial): Initial commit

Найдите операцию в этом списке, которую вы хотите "отменить". В приведенном выше примере это будет первая строка, в которой говорится "reset: переход к HEAD ~". Затем скопируйте представление фиксации до (ниже) этой операции. В нашем случае это будет [email protected]{1} (или 3ae5027, они оба представляют одно и то же commit), и запустите git reset --hard <commit> в reset вашу текущую ветку обратно на эту фиксацию.

Я выполнил свои изменения с помощью git add, но никогда не совершал. Теперь мои изменения ушли!

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

Подробнее об этом см. в разделе Отменить git reset --hard с незафиксированными файлами в промежуточной области.

У меня были изменения в файлах в моем рабочем каталоге, которые я никогда не выполнял с git add и никогда не совершал. Теперь мои изменения ушли!

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

- жесткий

Сбрасывает индекс и рабочее дерево. Любые изменения в отслеживаемых файлах в рабочем дереве с <commit> отбрасываются.

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

Ответ 9

Если у вас еще нет мусора, собравшего ваш репозиторий (например, используя git repack -d или git gc, но обратите внимание, что сборка мусора также может произойти автоматически), тогда ваша фиксация все еще существует - она ​​больше не доступна через HEAD.

Вы можете попытаться найти свою фиксацию, просмотрев вывод git fsck --lost-found.

В более новых версиях Git есть что-то, называемое "reflog", которое является журналом всех изменений, внесенных в ref (в отличие от изменений, внесенных в содержимое репозитория). Так, например, каждый раз, когда вы переключаете HEAD (т.е. Каждый раз, когда вы делаете git checkout для переключения ветвей), которые будут регистрироваться. И, конечно же, ваш git reset также управлял HEAD, поэтому он также записывался в журнал. Вы можете получить доступ к старым состояниям ваших ссылок таким же образом, что вы можете получить доступ к более старым состояниям вашего репозитория, используя знак @ вместо ~, например git reset [email protected]{1}.

Мне потребовалось некоторое время, чтобы понять, какая разница между HEAD @{1} и HEAD ~ 1, так что вот небольшое объяснение:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show [email protected]{1} # => Three
git reflog

Итак, HEAD~1 означает "перейти к фиксации до фиксации, которую HEAD в настоящее время указывает на", а [email protected]{1} означает "перейти к фиксации, на которую указал HEAD, прежде чем он указал на то, где он сейчас указывает на".

Это легко позволит вам найти потерянную фиксацию и восстановить ее.

Ответ 10

Прежде чем ответить, давайте добавим некоторую предысторию, объясняющую, что это 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

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

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

git reflog
git checkout [email protected]{...}

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

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 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.


git revert <sha-1>

"Отменить" указанный диапазон фиксации или фиксации.
Команда сброса "отменит" любые изменения, сделанные в данном коммите.
Новый коммит с патчем отмены будет зафиксирован, в то время как оригинальный коммит останется в истории.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

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

enter image description here

Ответ 11

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

Когда вы делаете "git add" или перемещаете что-либо из левого верхнего левого в нижнее левое в git gui, содержимое файла хранится в блобе, а содержимое файла можно восстановить из этого blob,

Таким образом, можно восстановить файл, даже если он не был зафиксирован, но он должен быть добавлен.

git init  
echo hello >> test.txt  
git add test.txt  

Теперь blob создается, но на него ссылается индекс, поэтому он не будет указан с git fsck, пока мы reset. Итак, мы reset...

git reset --hard  
git fsck  

вы получите свисающий blob ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

предоставит вам содержимое файла "привет" назад

Чтобы найти неучтенные коммиты, я нашел подсказку где-то, предлагая это.

gitk --all $(git log -g --pretty=format:%h)  

У меня есть инструмент в git gui, и это очень удобно.

Ответ 12

Я только что сделал жесткий reset в неправильном проекте. То, что спасло мою жизнь, было местной историей Eclipse. Сообщается, что у IntelliJ Idea тоже есть один, и поэтому ваш редактор может проверить:

Ответ 13

git reflog

  • Найдите свой коммит в списке, затем скопируйте и вставьте его в эту команду:

git cherry-pick <the sha>

Ответ 14

Сделал крошечный script, чтобы немного легче найти комманду, которую вы ищете:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Да, его можно сделать намного красивее с awk или чем-то вроде этого, но это просто, и я просто нуждался в нем. Может спасти кого-то еще 30 секунд.

Ответ 15

Если вы используете IDE JetBrains (на основе IntelliJ), вы можете восстановить даже свои незафиксированные изменения с помощью функции "Локальная история".

Щелкните правой кнопкой мыши каталог верхнего уровня в дереве файлов, найдите "Локальная история" в контекстном меню и выберите "Показать историю". Откроется окно, в котором можно найти последние изменения, и как только вы найдете ревизию, к которой хотите вернуться, щелкните ее правой кнопкой мыши и нажмите "Вернуть".