gitのコミットにはタイムスタンプだけでなくコミットした環境のタイムゾーンも記録されている、という発見です。
gitコミットにはタイムスタンプだけが保存されており、タイムゾーンの表示は見ている人の環境に合わせて表示されているんだと思い込んでいました。しかしそうではなく、タイムゾーンもコミットごとにちゃんと保存されていました。なので、オープンソースのリポジトリのログを見ればいろんなタイムゾーンに開発者が散らばっている様子がわかります。
以下のの記事を読んで、タイムゾーンも保存されてるのか???って疑問から調べてしまったのが今回の記事のきっかけです。
確認した内容
ローカルにclone済みの適当なgitリポジトリを見ます。.git
というディレクトリにGitログや過去のファイルがすべて保存されており、コミットの情報も含まれています。gitリポジトリの内容は .git
がすべてです。
まず以下のファイルを見ます。
$ cat .git/refs/heads/main
最新のmainブランチのコミットのハッシュ値が書いてあります。40文字のSHA-1ハッシュ値です。このファイルがなくても .git/refs/heads/
の中の別名のファイルでもよいです。
ハッシュ値が例えば ca218c30e4ed29eb778f45c75faa2043708b143e
だった場合、以下のファイルの存在を確認します。ハッシュ値の最初の2文字をディレクトリ名にして、残り38文字をファイル名にします。
$ ls .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e
git gc
を実行した直後だったり、 git clone
したばかりの場合は、このファイルがない場合があります。かわりに .git/object/pack/
の中に圧縮されています。この中を見るのは面倒なので、その場合は別のリポジトリを見るなり、もしくはダミーで適当なコミットをしてみて、再チャレンジしてください。
.git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e
はzlibで圧縮されています。Rubyのワンライナーであれば次のようにして展開できます。
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | ruby -e "require 'zlib'; puts Zlib::Inflate.inflate(STDIN.read)"
Perlのワンライナーであれば次の通りです。
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | perl -e 'use Compress::Raw::Zlib; undef $/;new Compress::Raw::Zlib::Inflate()->inflate(<>,$o);print $o'
Pythonのワンライナーであれば次の通りです。
$ cat .git/objects/ca/218c30e4ed29eb778f45c75faa2043708b143e | python -c "import zlib,sys;print(zlib.decompress(sys.stdin.buffer.read()).decode('utf8'))"
どの言語を使っても次のように表示されます。
commit 274tree c15e322196a5f6a9cd34ff42709848e649e156c6
parent 491c797feb18eff93d25fe19cb2a83bb399ec9d8
author suzuki-navi <...> 1689242567 +0900
committer suzuki-navi <...> 1689242567 +0900
dummy commit
これはダミーのコミット
コミットの情報がテキストで表示されます。 .git
に所定のフォーマットのテキスト形式でコミット情報が保存されているのです。
最初の commit 274
は説明省略しますがコミット情報を .git/objects
に保存するためのヘッダみたいなもので、そのあとの tree ...
から後ろがコミット情報の本体です。 ...
と書いた個所は本当はメールアドレスが載っています。
この中にタイムゾーンが +0900
というふうにテキストで記載されていることがわかります。ヨーロッパやアメリカなどタイムゾーンの異なる環境からこのリポジトリをcloneしてもこのコミットに関しては +0900
と表示されるはずです。へぇー。
補足 その1
今回の記事では .git/objects
の中を直接見ましたが、以下のように git cat-file
コマンドでも見ることができます。 git
コマンドが出力をいい具合に整形しているという疑念を払拭するために、生データを直接見ることにしました。
$ git cat-file -p ca218c30e4ed29eb778f45c75faa2043708b143e
tree c15e322196a5f6a9cd34ff42709848e649e156c6
parent 491c797feb18eff93d25fe19cb2a83bb399ec9d8
author suzuki-navi <...> 1689242567 +0900
committer suzuki-navi <...> 1689242567 +0900
dummy commit
これはダミーのコミット
補足 その2
今回の記事の内容は、以下のドキュメントにだいたい書いてあります。コミット情報にある tree
とか parent
とかもだいたい説明されています。
以上。