MarkdownとBullet Journal

いわゆるプログラマーのつぶやき

【Git】リカバリーメモ

目的

色々とリカバリーするコマンドをまとめた

stashを誤って削除した際の復元方法

stashはpopコマンドやdropコマンドで削除出来るが、誤って必要なstashを削除しても復元できる(有効期限あり)

$ # stash復元方法
$ # ①シェル画面をバックスクロールしてstashをdrop/popした行に移動
$ ----
$ git stash pop
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   a.sh

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (1a4ccf68abd1ed3512085ac18bb85c4ce8c8fd46) →②copy
$ ----
$ # ③cherry-pickコマンドを実行
$ git cherry-pick -n -m1 1a4ccf68abd1ed3512085ac18bb85c4ce8c8fd46 ←paste
$

staging後にcommitを忘れて reset --hard して消え去ったfileの復元方法

一般的には諦める様なケースだが、Gitはstagingしたfileで破棄されたものを特殊なfolderに全て保管しており復元出来る(有効期限あり)。下記の手段で複数表示されるblobを順に調べて見つけて復活させる。

$ # ロストしたstagingファイルの復元方法
$ git fsck --lost-found # - ①サーチコマンド
Checking object directories: 100% (256/256), done.
dangling blob c073eade7db14753c55098e310a9d309eeb95064
dangling blob 4a1d9a6867f9713af79a63b2b02365d4aceae39f
dangling commit 722e8fd66cde5691f77af8340523c0d71f6b7cdb
dangling commit 73a25b0e21edaeae91eb2900fac6f42971aa8e85
dangling commit 74fccf1afbb327ed6c760d41ffd5978cde594013
dangling blob 753bd569bc1d5b08fe969b8e1c167b664a319bdd
dangling blob 79350d80be3503537651aa8b58d7f0109d8b4881 # - ②どれかcopy

$ git cat-file -p 79350d80be3503537651aa8b58d7f0109d8b4881  # - ③中身を確認
----②③を繰り返す
$ git unpack-file 79350d80be3503537651aa8b58d7f0109d8b4881 # - ④見つかったらunpack
.merge_file_a03280                       # - ⑤候補ファイルがリネームされて復活
$ mv .merge_file_a03280 piyo.sh  # - ⑥元の名前でリネーム
$

参考: http://git-scm.com/docs/git-fsck

stagingを重ねて失った数回前にstagingしたfileの復元方法

Gitはstaging毎にfileをblob objectで全て保管しているので、これも復元しようと思えば出来る。commit前ならば、git resetしてから上の手順の様にgit fsck --lost-foundコマンドでblob(file)を順に確認する方法が使える。

commit後は下記手順で可能だが、対象のblob(file)を手動で探すのは大変なのでblobを更新時間順にソートするシェルスクリプトの活用が望ましい

$ # 重ねたstagingファイルの復元方法
$ du .git/objects # ←①object一覧を出す
----
12      .git/objects/7c   # - ②候補を見つける(手作業では大変)
----
42524   .git/objects/pack
42625   .git/objects

$ cd .git/objects/7c   # - ③そのフォルダに移動して対象blobのSHA1をcopy
$ ls
3197b4421d92bd6fad81eddd241a6c9dcd421d   # - ④これにfolder名の7cを先頭に加える

$ git cat-file -p 7c3197b4421d92bd6fad81eddd241a6c9dcd421d  # - ⑤中身を確認
$ git unpack-file 7c3197b4421d92bd6fad81eddd241a6c9dcd421d # - ⑥OKならunpack
.merge_file_a11580  
$ mv .merge_file_a11580 hoge.sh  # ⑦元の名前にリネーム
$

最新commitの軽微な修正

git commit --amendコマンドを用いればcommitメッセージの修正やファイル追加など、新たなcommitを作らずに修正出来る(但しcommit IDは更新されてcommit履歴が変わるので公開したcommitには使用しないこと)。内容的にはgit reset --soft HEAD^を使う感覚と同じ(commit IDが更新される点も)

$ # -- a.shファイルを追加してcommit
$
$ touch a.sh      # -- 追加ファイル作成
$ git add a.sh    # -- staging
$ git commit -m "a.shファイルを追加"   # -- message作成してcommit
$
$ # -- 上のcommitにb.shを追加修正する
$
$ touch b.sh      # -- 追加ファイル作成とstaging
$ git add b.sh    # -- commit messageのみ修正の場合はこの2行は不要
$ git commit --amend m "a.shとb.shファイルを追加"  # messageも修正して再度commit
$ # -- commitが修正された(commit IDは更新)

過去commitの修正

  • git resetコマンド: -不要commitの削除

  • git rebaseコマンド:

    • ブランチ繋ぎ変え
    • 過去の複数commitを一つに集約
    • commit並び替え

以下git rebaseの解説記事

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E6%AD%B4%E5%8F%B2%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88:tittle

  • git cherry-pickコマンド:

    • 欲しいcommitを単体または連続で現在のブランチのHEADにコピー
  • git rebasegit cherry-pickの組み合わせ:

    • 過去のcommitに別のcommitを挿入

失ったcommitの復活

get resetを用いた作業などでcommit消失時の復活方法

  • git reflogで失った消失commitを見つけてSHA1をメモ
  • git cherrry-pick SHA1で消失commitを最新HEADにコピー(消失commit数が1個程度の時)
  • ③あるいはgit checkout SHA1でcommit消失群の先頭へ移動してから$ git branch New-Branchで新しいブランチを作るとそこにcommit消失群が復活する(消失commit数が数個以上ある場合に最適)