GitのブランチやHEADをサブコマンドで操作する

いきなりですが、git branchコマンドを使わずにブランチを作ってみます。 ブランチは、とある一時点のコミットのSHA-1ハッシュを参照するポインターに過ぎません。 配管コマンドと呼ばれる、低次なサブコマンドを用いることで、簡単にブランチを操作することができます。 以下のような3つのログがある時、

2番目のコミット1234567890abcdef1234567890abcdef87654321を参照するブランチfeatureを作成するには下記のコマンドを実行することで可能です。

つまり、ブランチを作成する、というのはrefsファイル(参照ファイル)を作成することと内部的には等価なのです。 ただ、refsファイルを直接操作するのは非推奨なので、git update-refコマンドを用いて以下のようにします。

これでfeatureが作成されました。

HEAD

git branchコマンドに、起点となるコミットを渡さなかった場合、HEADがデフォルトの起点として選択され、HEADと同位置に新しいブランチが作成されます。 先ほどの例では、下記のコマンドを実行すると、masterと同位置に作成されます。

HEADは基本的に現在チェックアウトしているブランチに対するシンボリック参照という、特殊な存在で、直接的にSHA-1ハッシュを格納しているわけではありません。 実際にHEADファイルを確認してみるとrefs/heads/masterを参照しています。

つまりrefs/heads/master1234567890abcdef1234567890abcdef12345678を参照しているため、結果的にmasterと同位置になったという訳です。 git checkoutコマンドを実行するとHEADのシンボリック参照が変化します。

これをサブコマンドで実行するにはgit symbolic-refコマンドを使用します。 先ほど作ったtestブランチにHEADの参照先を移動させてみます。

参照先をtestに移動することができました。

HEADは必ずしもブランチに対するシンボリック参照とは限りません。 いわゆるdetached HEADの状態です。 その状態を再現してみます。 先ほどの例の1番目のコミットにHEADを移動してみます。

git symbolic-refコマンドではrefsファイル以外を参照先に選ぶことはできないので、直接書き換えます。

HEADがシンボリック参照ではなくなったのでgit symbolic-refコマンドで確認できなくなりました。
ログを確認するとHEADが1234567890abcdef1234567890abcdef01010101のコミットを指していることがわかります。

最後に、コミットが実行されるとrefsファイルが、どのように変化するのか見てみます。 まず、masterをチェックアウトします。

refs/heads/master1234567890abcdef1234567890abcdef12345678を参照している状態です。 コミットを実行します。

コミットが実行されるとrefs/heads/masterが、今新たに追加した4番目のコミットのSHA-1ハッシュ1234567890abcdef1234567890abcdef99999999を参照していることがわかります。 Gitは、コミットやリセットが実行され、参照すべきSHA-1ハッシュが変化するとrefsファイルを書き換えます。 結果的に、HEADが常に最後のコミットの位置を知ることができるようになるのです。

Gitの内部構造はとても面白いので、公式のGitの内側は、一度読んでみると、新たな発見があるかもしれません。

●この記事を書いた人