gitのファイル変更日時をファイルのアクセス日時に設定

普段使っているファイラーはファイルのアクセス日時でソートされるように設定しています。大きめのリポジトリをcloneしてコードを読む時に、意外とファイルの最終変更日時が参考になったりします。仕事で使うリポジトリや、定期的にpullしているなら、徐々に変更のないファイルはファイラーの下の方に移動していく (上の方からアクセス日時の降順として) のですが、cloneしたばかりだとこうは行きません。

要はgitリポジトリ内の各ファイルのアクセス日時を、そのファイルのgit履歴上での最終変更日時に戻したいという気持ちになるわけです。そうするとファイラー上でもいい感じにファイルがソートされるのです。

#!/usr/bin/env bash

if command -v gdate >/dev/null 2>&1; then
  DATE=gdate
else
  DATE=date
fi

while IFS= read -r -d '' file; do
  logtime=$(git log -1 --format=%ci "$file")
  mtime=$("$DATE" -d "$logtime" +%Y%m%d%H%M.%S)
  echo "$(printf "%-80s" "$file")"$'\t'"$logtime"$'\t'"$mtime"
  touch -t "$mtime" "$file"
done < <(git ls-files -z)

実行してみるとこういう感じ。

 $ git-touch
.ctags                                                                              2015-08-28 10:47:55 +0900   201508281047.55
.tmux.conf                                                                          2016-02-05 08:43:46 +0900   201602050843.46
.vimrc                                                                              2017-05-01 18:38:35 +0900   201705011838.35
.vimshrc                                                                            2017-03-10 20:45:22 +0900   201703102045.22
.zshrc                                                                              2017-04-20 00:32:39 +0900   201704200032.39
 $ stat -x .zshrc
  File: ".zshrc"
  Size: 10518        FileType: Regular File
  Mode: (0644/-rw-r--r--)         Uid: (  501/ itchyny)  Gid: (   20/   staff)
Device: 1,4   Inode: 203408150    Links: 1
Access: Thu Apr 20 00:32:39 2017
Modify: Thu Apr 20 00:32:39 2017
Change: Sun May  7 01:03:05 2017

atimeとmtimeがgitでのファイル更新時刻になりました。やったー!

git logはタイムゾーン込みで保存しているようなので、touchする前にローカルタイムゾーンに変換しないといけない。最初はsedタイムゾーン取り除いていたけれど、流石に乱暴だったのでdateコマンドを挟むようにしました。

できたーと思ってふと検索してみるといっぱいでてきた… まぁみんなやるよねぇ…

macOSの (というかFreeBSDの) dateコマンドの-dは日付を指定するオプションじゃないのが罠っぽい。date -jfであれこれしたほうが本当はいいけれど、coreutilsのgdateに逃げた。あとスペース含むファイル名の扱いにはご注意を。

dateコマンドのところはPythonでやろうかと思ったけれど、実装してみたら意外とオーバーヘッドが大きかった。まぁオーバーヘッドと言っても二倍時間がかかるくらいなんですが、リポジトリ内のファイルを全部なめて更新していくので、できれば速いほうが嬉しい。速度を取るかポータビリティを取るかはいつも難しい。PythonPythonで2.7と3系両方で動くスクリプトを書ける自信はない。ところで jq fromdateiso8601 を使う手も考えたのですが (ポータビリティ的には良いアイディア)、タイムゾーン部分をパースできなくて (Zしか対応してない)、なーにがISO 8601じゃと思いました。ああ、いい話だなぁ。それじゃーね!ばいばい!