git オブジェクトの表示

最近、ふたたび Ruby on Rails を使って仕事をしている。Rails 4 を使っているのだが、この数年での Rails 界隈の長足の進歩には驚かされることばかり。昔、不満だった点がことごとく改善されて、本当に良くなっている。IT は、この停滞した世界にあって、唯一、真に猛スピードで進歩を遂げている分野なのかもしれない(これが社会を大きく変えていくだろうことを妄想すると頭がクラクラしてくるわけだが)。

いまの仕事仲間は、git と GitHub を当たり前に使いこなしている。正直、個人的にちまちま git を使っていただけの私は大いにめんくらった。ブランチだのプルリクエストだのいろいろ言われても、わけわからん、というレベルであった(本当に仕事仲間には申し訳ない…)。

で、仕方ないので猛勉強した。

最初は、

サルでもわかるGit入門 〜バージョン管理を使いこなそう〜【プロジェクト管理ツールBacklog】

で学習。よいサイトだと思うが、どこかしっくりこない。Gitはコマンド体系が煩雑すぎるように感じる。

やはり、最強は本家のドキュメント。

Git - Book

これを読んではじめて git の仕組みが腑に落ちた。というか、感動で心が打ち震えた。git は(ほぼ)すべての情報を git オブジェクトで管理しており、中身の SHA1 ハッシュをそのままファイル名にしていること。git は基本的にファイルシステムのスナップショットの集合を管理するツールであること。ファイルシステムのスナップショットは、(ルート)ツリーオブジェクトで表され、コミットオブジェクトはスナップショットに対する注釈にすぎないこと。

上のサイトのうち特に

Git - Gitの内側

の章をおすすめしたい。つか、プログラマーなら全員読め!!と言いたい。これを読まずして git が理解できるか!という勢いである(すみません・・・自分を棚に置いて)。

Git の内部構造を説明した文章としては、

実践 Git - 低レベルに知る Git
見えないチカラ: 【翻訳】Gitをボトムアップから理解する
ファイルシステムとしての Git - 言語ゲーム

あたりもよい。

上で紹介した文章を読めば一番わかり易いので、私がとやかくいう必要もないのだが、とりあえず git 関係のシェルスクリプト(半分 Ruby だが)をさらしておく。

ただ使ったアルゴリズムについては、100%の自信があるわけではないので、ご使用は自己責任で。間違いがあったらぜひ教えて下さい。
(あと .git/index ファイルの内部構造がわからなくて困っています。インターネットをいくら探しても資料が見つからないのでだれか教えて下さい)

これらのコマンドが git レポジトリ(.git ディレクトリ)がある場所で使う。

gitobj

SHA1 ハッシュ(最初の7文字) + git オブジェクトタイプ(commit, tree, blob, tag) の表示

#!/bin/sh

gitobjhash() {
  # .git/objects 以下の git オブジェクトの閲覧
  (cd .git/objects ; find . -type f | grep -v info | grep -v pack | sed 's#[\./]##g')
  # pack された git オブジェクトの閲覧
  (cd .git/objects/pack; git verify-pack -v pack-*.idx 2> /dev/null | ruby -ne 'puts $1 if /^([\da-f]{40})/')
}

# git オブジェクトタイプの表示
gitobjhash | ruby -ne '$_.chomp!; puts "#{$_[0,7]} #{`git cat-file -t #{$_}`}"'

gitcm

すべてのコミットメッセージの表示

#!/bin/sh

grep commit | awk '{print $1}' | ruby -ne '$_.chomp!; puts "#{$_[0,7]}\t#{`git log -n 1 --pretty=format:%an #{$_}`[0,3]}\t#{`git log -n 1 --pretty=format:%at #{$_}`}\t#{`git log -n 1 --pretty=format:%ai #{$_}`[5,11]}\t#{`git log -n 1 --pretty=format:%s #{$_}`}"' | sort -k 3

gitobj コマンドの出力結果は下のような感じ。

$ gitobj
=>
198f3c9 blob
d1990c1 blob
5c5a274 blob
bdc88f3 commit
6bf9b0e blob
4c1cd76 tree
...

パイプで gitcm コマンドにつなぐことができる。

$ gitobj | gitcm
=>
...
521f612 Eij 1393018559 02-22 06:35 b1-2
bc91937 Eij 1393018674 02-22 06:37 b1-3
6c341ab Eij 1393018758 02-22 06:39 m4
b0b0f23 Eij 1393018795 02-22 06:39 Merge branch 'b1'
...

1列目:コミットの SHA1 ハッシュ
2列目:Author の最初3文字
3列目:Author date の UNIX タイムスタンプ
4列目:Author date (月・日・時間・分のみ)
5列目:コミットメッセージ

Have fun with Git!