次のコマンドによる変更を元に戻すことはできますか?もしそうなら、どのように?
git reset --hard HEAD~1
パット・ノッツは正しいです。数日以内であれば、コミットを取り戻すことができます。gitは、新しいBLOBを削除するように明示的に指示しない限り、約1か月後にのみガベージコレクションを収集します。
$ 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
この例では、ハードリセットの結果としてfile2が削除されましたが、reflogを介してリセットすると元の場所に戻されたことがわかります。
あなたがしたいことは、復元したいコミットのsha1を指定することです。reflog ( git reflog
) を調べてから実行することで、sha1 を取得できます。
git reset --hard <sha1 of desired commit>
しかし、あまり長く待たないでください... 数週間後、git は最終的にそのコミットが参照されていないと見なし、すべてのブロブを削除します。
答えは上記の詳細な応答に隠されています。簡単に実行できます。
$> git reset --hard HEAD@{1}
( git reflog showの出力を参照)
Git がまだガベージ コレクションを行っていない場合は、回復することができます。
でダングリング コミットの概要を取得しますfsck
。
$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
リベースを使用してダングリング コミットを回復します。
$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
私の知る限り、--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
If you're really lucky, like I was, you can go back into your text editor and hit 'undo'.
I know that's not really a proper answer, but it saved me half a day's work so hopefully it'll do the same for someone else!
コマンドを実行したときのリポジトリの状態に応じて、影響は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: moving to HEAD~」と書かれています。次に、その操作の前(下)のコミットの表現をコピーします。私たちの場合、それはmaster@{1}
(または3ae5027
、両方とも同じコミットを表します) でありgit reset --hard <commit>
、現在のブランチをそのコミットにリセットするために実行されます。
git add
コミットしませんでした。これで私の変更はなくなりました!これは、回復するのが少し難しいです。gitには追加したファイルのコピーがありますが、これらのコピーは特定のコミットに関連付けられていないため、一度にすべての変更を復元することはできません。代わりに、git のデータベースで個々のファイルを見つけて、手動で復元する必要があります。を使用してこれを行うことができますgit fsck
。
詳細については、ステージング領域にあるコミットされていないファイルで git reset --hard を元に戻すを参照してください。
git add
ことも、コミットしたこともない変更がありました。これで私の変更はなくなりました!ええとああ。こんなことを言いたくないのですが、あなたはおそらく運が悪いのでしょう。git は、追加またはコミットしていない変更を保存しませんgit reset
。
- 難しい
インデックスと作業ツリーをリセットします。それ以降の作業ツリー内の追跡対象ファイルへの変更はすべて
<commit>
破棄されます。
ある種のディスク リカバリ ユーティリティまたは専門的なデータ リカバリ サービスを使用して変更をリカバリできる可能性はありますが、現時点では、おそらくその価値よりも面倒なことです。
$ 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.
リポジトリのガベージ コレクションをまだ行っていない場合 (たとえば、git repack -d
またはを使用しますgit gc
が、ガベージ コレクションも自動的に行われる可能性があることに注意してください)、コミットはまだそこにあり、HEAD からは到達できません。
の出力を調べることで、コミットを見つけることができますgit fsck --lost-found
。
Git の新しいバージョンには、「reflog」と呼ばれるものがあります。これは、(リポジトリの内容に加えられた変更とは対照的に) ref に加えられたすべての変更のログです。したがって、たとえば、HEAD を切り替えるたびに (つまり、git checkout
ブランチを切り替えるために a を実行するたびに) ログに記録されます。そしてもちろん、あなた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 が現在指している場所を指す前に、HEAD が指しているコミットに移動する」ことを意味します。
これにより、失われたコミットを簡単に見つけて回復できます。
探しているコミットを見つけやすくするために、小さなスクリプトを作成しました。
git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'
はい、 awk などを使用してかなりきれいにすることができますが、それは単純であり、私はそれが必要でした. 他の誰かを 30 秒節約できるかもしれません。
git reflog
最後の HEAD 6a56624 (HEAD -> master) HEAD@{0}: リセット: HEAD~3 に移動 1a9bf73 HEAD@{1}: コミット: モデルに変更を追加 バイナリを生成
これは私の命を救った:
https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c
基本的に、次を実行する必要があります。
for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done
次に、ファイルを正しい構造に再編成するために手動で苦労します。
要点:git reset --hard
仕組みを完全に 100% 理解していない場合は使用しないでください。使用しないことをお勧めします。