Вопрос

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

git reset --hard HEAD~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... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

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

$ cat file2
added new file

В примере видно, что файл2 был удален в результате аппаратного сброса, но был возвращен на место при сбросе через рефлог.

Другие советы

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

git reset --hard <sha1 of desired commit>

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

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

$> git reset --hard HEAD@{1}

(См. вывод git reflog показать)

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

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

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Восстановите висячий коммит с помощью rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

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

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

Пример случая 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's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
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.

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

$ git reflog

будут списки:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

где 4bac331 это discarded commit.

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

$ git reset --hard 4bac331

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

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

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

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

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

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

git reset --hard @{1}

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

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

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

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

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

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

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

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

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

--жесткий

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

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

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

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

В более новых версиях Git есть так называемый «журнал обновлений», который представляет собой журнал всех изменений, внесенных в ссылки (в отличие от изменений, внесенных в содержимое репозитория).Так, например, каждый раз, когда вы переключаете HEAD (т.каждый раз, когда ты делаешь git checkout для переключения ветвей), которые будут зарегистрированы.И, конечно же, ваш git reset также манипулировал HEAD, поэтому он также был зарегистрирован.Вы можете получить доступ к более старым состояниям ваших ссылок аналогично тому, как вы можете получить доступ к старым состояниям вашего репозитория, используя @ знак вместо ~, нравиться git reset HEAD@{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 HEAD@{1} # => Three
git reflog

Так, HEAD~1 означает «перейти к коммиту перед коммитом, на который в данный момент указывает HEAD», а HEAD@{1} означает «перейти к коммиту, на который указывал HEAD до того, как он указал на то место, на которое он указывает в данный момент».

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

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

Когда вы выполняете «git add» или перемещаете что-либо из верхнего левого угла в нижний левый в git gui, содержимое файла сохраняется в BLOB-объекте, и содержимое файла можно восстановить из этого BLOB-объекта.

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

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

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

git reset --hard  
git fsck  

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

git show ce01362  

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

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

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

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

Прежде чем ответить, давайте добавим немного предыстории и объясним, что это такое. 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 и проверка желаемой записи в рефлоге установит 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.
  • Примечание:(Начиная с 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

Я только что сделал полный сброс неправильного проекта.Что спасло мне жизнь, так это местная история Эклипса.Говорят, что у IntelliJ Idea он тоже есть, и ваш редактор тоже, стоит проверить:

  1. Раздел справки Eclipse по местной истории
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

Сделал крошечный скрипт, чтобы было немного проще найти нужный коммит:

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top