Gitのデフォルト参照 (refs)

概要

GitのオブジェクトやコミットはSHA-1ハッシュ値で管理されている。ただ,毎回SHA-1ハッシュ値を直接指定するのは手間なので,SHA-1ハッシュ値を指す参照 (refs) が用意されている。

Gitではデフォルトで用意されている参照がいくつもある。今までよくわからない状態で使っていたが,最近ようやく理解できたでの,忘れたときのために整理する。

HEAD

HEADは最後 (現在) のコミットのSHA-1ハッシュを指す参照 (refs) を保持するシンボリック参照となっている (参考: Git – Gitの参照)。通常の参照と区別するために,シンボリック参照と呼んでいる。

具体的には,.git/HEADに値が格納されている。

cat .git/HEAD
ref: refs/heads/master

通常は上記のように,ブランチへの参照が格納されている。ただし,git checkoutで直接コミットに移動した場合,参照ではなくSHA-1ハッシュ値が格納されている。

git checkout HEAD~1
cat .git/HEAD
d7f38fea38edc7e65388e7c90b125c1fe4f801d9

HEADを参照することで,最後のコミット (現在のコミット) を把握することができる。

日々のコマンドでよく使うシンボリック参照だ。

FETCH_HEAD

git fetchまたはgit pullした際にダウンロードしたリモートリポジトリーのブランチごとのSHA-1ハッシュ値を格納している (参考: Git – git-fetch Documentation)。

cat .git/FETCH_HEAD
27ce7d102010ba6d9232027b5b7afac1db1316e8                branch 'master' of https://github.com/senooken/example
50bf24172bb962ef31f02abcbdce95662213210b        not-for-merge   branch 'gh-pages' of https://github.com/senooken/example

これにより,どこまでリモートリポジトリーをダウンロードしたかがわかるようになっている。

git fetchコマンドを実行した際のメッセージで見かけるくらいで,自分でコマンドで使うことはあまりない。

master

masterはGitのデフォルトのブランチ名を指す参照だ (参考: Git – git-init Documentation)。

具体的には,git initを実行してGItリポジトリーが作成すると,HEADmasterブランチを指している。

git init
cat .git/HEAD
ref: refs/heads/master

Git 2.28から設定やオプションでデフォルトのブランチ名を変更可能になっている。

Gitでブランチを切り変えて作業する場合に,必ず参照されるので,よく見かける参照だ。

origin

originはデフォルトのリモートリポジトリー名となっている。「Git – リモートでの作業」や「Git – git-clone Documentation」でそのことが説明されている。

より具体的には,git cloneしたリモートリポジトリー名のデフォルトがoriginとなっている。以下のコマンドで,現在のoriginを確認できる。

git remote -v
origin	git@github.com:senooken/dotfile.git (fetch)
origin	git@github.com:senooken/dotfile.git (push)

リモートリポジトリー名も参照の一種である。リモートリポジトリー名のおかげで,URL使わずに済んでいる。

リモートリポジトリー名は以下のコマンドで変更できる。

git remote rename <old> <new>

リモートリポジトリーやそのブランチを参照する際に頻繁に使用する。HEADと同じかそれ以上に使用する参照となっている。

例えば,リモートリポジトリーのmasterブランチはorigin/masterで参照する。

ブランチ名だけの場合,ローカルのブランチを指すため,リモートのブランチを参照する際は常にリモートリポジトリー名が必要となる。

refs

参照 (refs) はGitにおけるSHA-1ハッシュ値を示す別名である (参考: Git – Gitの参照)。.git/refsディレクトリーの中身が実体となっている。

find .git/refs
.git/refs/
.git/refs/tags
.git/refs/remotes
.git/refs/remotes/origin
.git/refs/remotes/origin/master
.git/refs/heads
.git/refs/heads/master

refs/直下のディレクトリで用途が以下の通りに分けられている。

Gitの参照の種類
参照 説明
refs/tags ローカルのタグへの参照を格納。
refs/heads ローカルのブランチへの参照を格納。
refs/remotes リモートリポジトリーへの参照 (ブランチ,タグ) を格納

.git/以降のrefsからを参照として使用でき,前半部分はGitが展開するため省略可能となっている。

例えば,以下のコマンドはどれも同じ意味となる。

git log refs/heads/master
git log heads/master
git log master

念のため繰り返すが,ブランチ名だけを指定した場合,ローカルのブランチを指すので,リモートリポジトリー名を指定する場合はリモートリポジトリー名 (origin) などが必須となる。

refspec

refspecはリモートリポジトリーとローカルリポジトリーの対応関係の書式となっている (参考: Git – Refspec)。

具体的には,.git/config内で以下のように指定され,fetch/pullpushで使用する。.git/config上ではそれぞれfetch, pushの別々の設定項目として設定する。

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/*:refs/remotes/origin/*
# fetch = +refs/heads/master:refs/remotes/origin/master
# push = :

2行目のfetchの行の右辺がrefspecsとなっている。git cloneした場合のデフォルト値が2行目となっており,git clone --depth 1などでブランチを限定した場合が3行目となっている。

refspecは+<src>:<dst>という書式になっている。先頭の+はfast-forward以外の場合も取り込むことを意味する。

それ以外は,fetchpushで若干意味が異なる。コマンドごとに以下の通りとなる。

fetchpushのrespecの違い
コマンド <src> <dst>
fetch/pull リモートリポジトリーの参照 ローカルリポジトリーの参照
push ローカルリポジトリーの参照 リモートリポジトリーの参照

データの移動方向に合わせて,<src><dst>が指すものが反対になる。

詳細は以下のマニュアルを参照する。

respecに関するマニュアル

<src><dst>には*のワイルドカードを使用できる。ただし,ファイル名の一部だけ (例: +refs/heads/qa*:refs/remotes/orign/qa*) を指定することはできず,ブランチ全体を指定することしかできない。

.git/configを直接編集する他,以下のコマンドでも変更・追加できる。

git config remote.origin.fetch refs/heads/master:refs/remotes/origin/master
git config --add remote.origin.fetch refs/heads/master:refs/remotes/origin/master

ただ,基本的には自分で編集する必要はない。変更するとしたら,git clone --depth 1でクローンした後に,他のブランチもfetch/pullしたい場合に編集する場合がありえる。

その他,コマンドライン上ではリモートリポジトリーのブランチを削除する場合や,push先を変更する場合に使用する。

git push origin :topic  # delete topic remote branch
git push origin master:gh-pages # push master to remote gh-pages

コマンド上で使う場合はGitが自動で解釈してくれるため,refsから書かなくても指定を一部省略できるようだ。

例えば,git push origin :topic<src>の部分が省略されている。つまり,リモートリポジトリーのブランチ (<dst>) を空にする,つまり削除するという意味になる。

その他,「GitHub Pages用gh-pagesブランチとmasterブランチの自動同期」に記した通り,GitHubでのWeb上での公開するために,masterブランチの内容をgh-pagesブランチにpushしたい場合に,ローカルブランチのpush先を指定する場合に使用する。

こちらのスライド (5分で分かるgitのrefspec) も参考になった。

結論

Gitでデフォルトで用意されている参照に付いて整理した。

なんだかんだでGitの存在を知って使い始めてから数年は経つ。しかし,このデフォルトの参照の意味が理解できておらず,なんだかとっつきにくいものだと抵抗を感じていた。

Gitの公式文書を読み込んで意味が理解でき,すっきりした。時間はかかったが整理してよかった。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です