Gitの参照
すべての履歴をひと通り見るには git log 1a410e
のように実行します。しかしそれでも履歴を辿りながらそれらすべてのオブジェクトを見つけるためには、1a410e
が最後のコミットであることを覚えていなければなりません。SHA-1ハッシュ値を格納できるファイルが必要です。ファイル名はシンプルなもので、未加工(raw)の SHA-1ハッシュ値ではなくポインタを使用することができます。
Git では、これらは “参照(references)” ないしは “refs” と呼ばれます。SHA-1のハッシュ値を含んでいるファイルは .git/refs
ディレクトリ内に見つけることができます。現在のプロジェクトでは、このディレクトリに何もファイルはありませんが、シンプルな構成を持っています。
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
$
最後のコミットはどこにあるのかを覚えるのに役立つような参照を新しく作るには、これと同じぐらいシンプルなことを技術的にすることができます。
$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master
これであなたは、Git コマンドにある SHA-1のハッシュ値ではなく、たった今作成したヘッダの参照を使用することができます。
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
参照ファイルに対して直接、変更を行うことは推奨されません。Git はそれを行うためのより安全なコマンドを提供しています。もし参照を更新したければ update-ref
というコマンドを呼びます。
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
Git にとって基本的にブランチとは何なのかをこれは示しているのです。すなわちそれはシンプルなポインタ、もしくは作業ライン(line of work)のヘッドへの参照なのです。二回目のコミット時にバックアップのブランチを作るには、次のようにします。
$ git update-ref refs/heads/test cac0ca
これでブランチはそのコミットから下の作業のみを含むことになります。
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
いま、Git のデータベースは概念的には図9-4のように見えます。

図9-4. ブランチのヘッドへの参照を含むGitディレクトリオブジェクト
git branch (ブランチ名)
のようにコマンドを実行すると基本的に Git は update-ref
コマンドを実行します。そして、あなたが作りたいと思っている新しい参照は何であれ、いま自分が作業しているブランチ上のブランチの最後のコミットの SHA-1ハッシュを追加します。
HEADブランチ
では、git branch (ブランチ名)
を実行したときに、どこから Git は最後のコミットの SHA-1ハッシュを知ることができるでしょうか? 答えは、HEADファイルです。HEADファイルは、あなたが現在作業中のブランチに対するシンボリック参照(symbolic reference)です。通常の参照と区別する意図でシンボリック参照と呼びますが、それは、一般的にSHA-1ハッシュ値を持たずに他の参照へのポインタを持ちます。通常は以下のファイルが見えるでしょう。
$ cat .git/HEAD
ref: refs/heads/master
git checkout test
を実行すると、Git はこのようにファイルを更新します。
$ cat .git/HEAD
ref: refs/heads/test
git commit
を実行すると、コミットオブジェクトが作られます。HEADにある参照先の SHA-1ハッシュ値が何であれ、そのコミットオブジェクトの親が参照先に指定されます。
このファイルを直に編集することもできますが、symbolic-ref
と呼ばれる、それを安全に行うためのコマンドが存在します。このコマンドを使ってHEADの値を読み取ることができます。
$ git symbolic-ref HEAD
refs/heads/master
HEADの値を設定することもできます。
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
refs
の形式以外では、シンボリック参照を設定することはできません。
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
タグ
これまで Git の主要な三つのオブジェクトを見てきましたが、タグという四つ目のオブジェクトがあります。タグオブジェクトはコミットオブジェクトにとても似ています。それには、タガー(tagger)、日付、メッセージ、そしてポインタが含まれます。主な違いは、タグオブジェクトはツリーではなくコミットを指し示すことです。タグオブジェクトはブランチの参照に似ていますが、決して変動しません。そのため常に同じコミットを示しますが、より親しみのある名前が与えられます。
2章で述べましたが、タグには二つのタイプがあります。軽量 (lightweight) 版と注釈付き (annotated) 版です。あなたは、次のように実行して軽量 (lightweight) 版のタグを作ることができます。
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
これが軽量版のタグのすべてです。つまり決して変動しないブランチなのです。一方、注釈付き版のタグはもっと複雑です。注釈付き版のタグを作ろうとすると、Git はタグオブジェクトを作り、そして、コミットに対する直接的な参照ではなく、そのタグをポイントする参照を書き込みます。注釈付き版のタグを作ることで、これを見ることができます。(注釈付き版のタグを作るには -a
オプションを指定して実行します)
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 –m 'test tag'
これで、作られたオブジェクトの SHA-1ハッシュ値を見ることができます。
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
ここで、そのSHA-1ハッシュ値に対して cat-file
コマンドを実行します。
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
test tag
オブジェクトエントリはあなたがタグ付けしたコミットの SHA-1 ハッシュ値をポイントすることに注意してください。またそれがコミットをポイントする必要がないことに注意してください。あらゆる Git オブジェクトに対してタグ付けをすることができます。例えば、Git のソースコードの保守では GPG 公開鍵をブロブオブジェクトとして追加して、それからタグ付けをします。Git ソースコードレポジトリで、以下のように実行することで公開鍵を閲覧することができます。
$ git cat-file blob junio-gpg-pub
Linuxカーネルのリポジトリは、さらに、非コミットポインティング(non-commit-pointing)タグオブジェクトを持っています。このタグオブジェクトは、最初のタグが作られるとソースコードのインポートの最初のツリーをポイントします。
リモート
これから見ていく三つ目の参照のタイプはリモート参照です。リモートを追加してそれにプッシュを実行すると、Git は追加したリモートにあなたが最後にプッシュした値をを格納します。そのリモートは refs/remotes
ディレクトリにある各ブランチを参照します。例えば、origin
と呼ばれるリモートを追加して、それを master
ブランチにプッシュすることができます。
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
そして、origin
リモートに対してどの master
ブランチが最後にサーバと通信したのかを、refs/remotes/origin/master
ファイルをチェックすることで知ることができます。
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
リモート参照は主にそれらがチェックアウトされ得ないという点において、ブランチ(refs/heads
への参照)とは異なります。Git はそれらをブックマークとして、それらのブランチがかつてサーバー上に存在していた場所の最後に知られている状態に移し変えます。