rcmdnk's blog

まんがでわかる 復縁方法 〜 また元カレと恋をする 〜

Gitはバージョン管理システムなのでソースコードなどで 古い記述を残さないで消してしまっても後から簡単に見ることが出来るので 余計な記述をどんどん消していく事ができます。

一方消したファイルも履歴に残っていますが、 いざ探そうと思うとちょっと面倒だったりするので とりあえず残しておこう、とか思う事もあるかもしれません。

そんなことをせずにレポジトリを綺麗にしておくためにも、 過去に削除したファイルを簡単に検索、復元させられる様にしておこう、 という話し。

過去に削除したファイルの検索

git log --diff-filter=D --summary

をすることで過去に削除したファイルを検索できます。

$ git log --diff-filter=D --summary
commit b318eb6b0875cffcc6e7c6c4990d5ef90177ad40
Author: rcmdnk <[email protected]>
Date:   Thu Jun 12 18:03:06 2014 +0900

    removed .mailto

 delete mode 100644 .mailto

commit 7be0877bc3d8510fed4252e1dbc3d8074e2d4c11
Author: rcmdnk <[email protected]>
Date:   Fri May 23 13:11:47 2014 +0900

    removed unnecessary screen files

 delete mode 100644 .screen/.hostForScreen
 delete mode 100644 .screen/.hostForScreen-e

基本的にはlogを見るわけですが、 --diff-filter=Dを使えば何かを削除したcommitのみを取ってこれます。

さらに--summaryrmaddなどをした時のファイル一覧が出るので 上みたいな感じに表示されて実際に削除されたファイルを見ることが出来ます。

過去に削除したファイルを復元する

git checkout <commit>^ -- <file_name>

これで削除したファイルを取ってこれます。 上の.mailtoを復元したいなら、

$ git checkout b318eb6b0875cffcc6e7c6c4990d5ef90177ad40^ -- .mailto

commit番号の後ろに^を付けるのを忘れないように。 ^を付けると1つ前のcommitを意味する様になります。

b318....mailtoを削除したcommitなのでそれより1つ前のファイルが有る所からでないと取ってこれません。

--はそれ以降はオプション出ないことを知らせる引数で最後にファイル名を書きます。

.gitconfigにaliasを書いて簡単に検索、復元出来る様にする

コマンドを覚えて確認して復元して、ということでも良いですが、 Gitにはせっかくalias機能があるのでそれを使います。

[alias]
  deleted = log --diff-filter=D --summary
  restore = "!f () {\
    if [ \"$#\" -eq 0 ];then \
      echo 'usage: git restore <file_name> [file_name_2 [file_name_3 [...]]]';\
      return 1;\
    fi;\
    ret=0;\
    for f in \"$@\";do \
      if [ -a \"$(git rev-parse --show-toplevel)/$f\" ];then \
        printf \"\\e[31m$f exists\\n\\e[m\";\
        ret=2;\
        continue;\
      fi;\
      c=$(git rev-list -n 1 HEAD -- \"$f\");\
      if [ -n \"$c\" ];then \
        git checkout \"$c\"^ -- \"$f\";\
        echo \"$f\" has been restored;\
      else \
        printf \"\\e[31m$f is not in the log\\n\\e[m\";\
        ret=2;\
      fi;\
    done;\
    return $ret;\
  };f"

こんな感じでdeletedrestoreという2つのエイリアスを~/.gitconfigの中に書いておきます。 エイリアスに関して詳しくは下のポストで。

deletedの方は単に上で紹介したコマンドをそのままエイリアス化しただけです。

restoreの方はまずは

[ -a "$(git rev-parse --show-toplevel)/<file_name>" ]

でレポジトリにファイルが存在しているかどうかを確認しています。

git rev-parse --show-toplevel

は現在いるレポジトリのトップディレクトリ(ルートディレクトリ)の絶対パスを返します。

restoreではレポジトリのどこに居ようがトップディレクトリからのパスでファイルを指定することにしています。

ファイルがある場合にはそれについてはスキップ。

その次は

git rev-list -n 1 HEAD -- <file_name>

によってそのファイルに関する最後のcommitを取ってきています。 これは削除されたファイルに関しては削除された時のcommit番号が返って来る事になります。

もし過去にもcommitしたことが無いファイルだとこれは空文字を返しますが、 終了ステータスは0で正常終了になるので 空文字出ないことを確認します。

空文字でなければ上で紹介したコマンドで復元。

複数のファイルを与えた場合でもそれぞれについて復元を試みます。

まとめ

Gitはサブコマンドが非常に多い上にそれらのオプションも多種多様なので とてもではないですが全ては覚えられません。

その中でも必要なものをエイリアス化しておけばコマンドを打つのも楽になりますし 簡単に覚えられます。

必要そうなものをとりあえずエイリアスにしておけば、 自分の~/.gitconfigを見ることでどういうコマンドがあったか、 ということを確認することも可能です。

これで心置きなく要らないファイルを消すことが出来ると思います。

Sponsored Links
Sponsored Links

« Firefox 56リリース Gitでエイリアスを確認するエイリアスを作る(サブコマンドについても) »

}