Gitのブランチ・タグ・HEAD
ブランチ切替えと履歴の追加を、HEAD・ブランチ・タグ・親コミットの関係から説明します。
説明
Gitのブランチは、あるコミットを指す名前です。通常の作業ではHEADが現在のブランチを指し、コミットを追加するとそのブランチの参照先が進みます。ほかのブランチやタグが同時に進むわけではありません。
alphaという1行を持つ初期コミットから始めます。featureブランチとv1タグを作り、featureだけにbeta、gammaを追加します。ファイルの内容、コミットID、親への参照を使って、どの名前がどこを指すか確認します。
ブランチ切替えと履歴の追加を、HEAD・ブランチ・タグ・親コミットの関係から説明します。
1HEADが現在のブランチを指す
初期コミットの短いIDと、HEADの参照先を表示します。
git log -1直近コミットを表示する --format="%h %s"
git symbolic-ref HEADHEADが指す参照名を表示するHEADはrefs/heads/mainを指しています。mainが指すコミットが、現在の作業の基準になります。短いIDは完全なオブジェクトIDの省略表記です。
2同じコミットへ別の名前を付ける
featureブランチと軽量タグv1を作ります。まだファイルを変更していません。
git branch featureブランチ名を作る
git tag v1軽量タグを作る
git show-ref --heads --tagsブランチとタグの参照先を表示するfeature・main・v1が同じIDを指します。ここで作った軽量タグはコミットへ直接名前を付ける参照で、注釈付きタグとは構造が異なります。
3featureでコミットを追加
featureへ切り替え、betaを追加して記録します。
git switch feature現在のブランチを切り替える
printf 'alpha\nbeta\n' > note.txt
git add note.txt
git commit -m 'Add beta'featureへコミットを追加する
git log --oneline --all --decorate各参照と名前を含めて履歴を表示するHEADとfeatureが新しいコミットに進み、mainとv1は初期コミットに残ります。ブランチを作っただけでファイルの複製が増えるのではなく、参照が分かれた後で履歴が伸びています。
4現在・親・各名前のIDを照合
五つの参照を指定順に解決します。HEAD^は、現在のコミットの第1親を表します。
git rev-parse参照名を完全なIDへ解決する HEAD HEAD^現在のコミットの第1親 main v1 feature1行目のHEADと5行目のfeatureが同じID、2〜4行目の親・main・v1が同じIDです。新しいコミットは、直前のコミットを親として記録しています。
5mainへ戻ると内容も戻る
作業状態が記録済みなので、mainへ切り替えます。
git switch mainmainのコミットへ作業を切り替える
cat note.txt切替え後のファイルを読む
git symbolic-ref HEADファイルはalphaだけになり、HEADはmainを指します。betaのコミットが削除されたわけではなく、別のコミットを基準に作業ファイルが展開されています。
6切り替えずに別ブランチを読む
mainにいるまま、feature側のファイルを参照します。
git show feature:note.txtfeature内のファイルを読む
git symbolic-ref HEAD現在のブランチが変わっていないことを確認する表示内容はalphaとbetaですが、HEADはmainのままです。git showは対象の履歴を読む操作で、作業ブランチを切り替えません。
7さらに親子関係を一段伸ばす
featureへ戻り、gammaを追加します。logに各コミットの短いIDと親IDを表示します。
git switch feature
printf 'alpha\nbeta\ngamma\n' > note.txt
git add note.txt
git commit -m 'Add gamma'次の変更を記録する
git log feature --format='%h parent=%p %s'コミットID・親ID・件名を表示するgammaの親はbeta、betaの親は初期コミットです。初期コミットには親がないためparent=の後が空です。通常のコミットはこの親参照で履歴をつなぎます。
8タグは追加コミットに追随しない
v1が保持する内容とIDを確認します。
git show v1:note.txtタグが指す内容を読む
git rev-parse v1 mainタグとmainのIDを比較するv1はalphaだけの初期コミットを指したままで、mainとも同じIDです。タグは通常、新しいコミットを作っても自動では移動しません。明示的な付け替えは可能なので、絶対に変更できない名前ではありません。
9差分と履歴の範囲を使い分ける
mainとfeatureのファイル差分、mainにないfeature側のコミットを順に表示します。
git diff main..feature二つの参照先の内容を比較する -- note.txt
git log main..featuremainに含まれないfeature側の履歴を表示する --onelinediffでは両端の内容を比較し、betaとgammaの追加が出ます。logのmain..featureはfeatureから到達でき、mainから到達できないコミットの集合です。同じ二点表記でも、diffとlogで示す対象は異なります。
10コミットに保存された親参照
コミットオブジェクトの内容を直接読みます。treeはファイル構成、parentは親コミット、authorとcommitterは作成・記録の情報です。
git cat-file -p HEADコミットオブジェクトを読む
git show HEAD^:note.txt親コミット内のファイルを読むparentの完全なIDがあり、その親のファイルにはalphaとbetaが入っています。コミットは差分だけの箱ではなく、ファイル構成を示すtreeと親参照などを持つオブジェクトです。
まとめ
HEADは通常、現在のブランチを指します。コミットを追加すると、そのブランチの参照先が進みます。
ブランチ切替えは基準と作業ファイルを切り替えます。git showなら切り替えずに別の履歴を読めます。
親参照で履歴がつながり、タグやほかのブランチは自動では同じ先へ進みません。
操作履歴と解説を振り返れます。
Git / シェル
git log -1 --format="%h %s"
git symbolic-ref HEADdfaf585 Initial files refs/heads/main
git branch feature
git tag v1
git show-ref --heads --tagsdfaf585ee68990808a5f4c486d0007de53bee54d refs/heads/feature dfaf585ee68990808a5f4c486d0007de53bee54d refs/heads/main dfaf585ee68990808a5f4c486d0007de53bee54d refs/tags/v1
git switch feature
printf 'alpha\nbeta\n' > note.txt
git add note.txt
git commit -m 'Add beta'
git log --oneline --all --decorateSwitched to branch 'feature' [feature 5f4534f] Add beta 1 file changed, 1 insertion(+) 5f4534f (HEAD -> feature) Add beta dfaf585 (tag: v1, main) Initial files
git rev-parse HEAD HEAD^ main v1 feature5f4534f7a93dba890e3a4be2e8d272d88de79ea7 dfaf585ee68990808a5f4c486d0007de53bee54d dfaf585ee68990808a5f4c486d0007de53bee54d dfaf585ee68990808a5f4c486d0007de53bee54d 5f4534f7a93dba890e3a4be2e8d272d88de79ea7
git switch main
cat note.txt
git symbolic-ref HEADSwitched to branch 'main' alpha refs/heads/main
git show feature:note.txt
git symbolic-ref HEADalpha beta refs/heads/main
git switch feature
printf 'alpha\nbeta\ngamma\n' > note.txt
git add note.txt
git commit -m 'Add gamma'
git log feature --format='%h parent=%p %s'Switched to branch 'feature' [feature c9e8e19] Add gamma 1 file changed, 1 insertion(+) c9e8e19 parent=5f4534f Add gamma 5f4534f parent=dfaf585 Add beta dfaf585 parent= Initial files
git show v1:note.txt
git rev-parse v1 mainalpha dfaf585ee68990808a5f4c486d0007de53bee54d dfaf585ee68990808a5f4c486d0007de53bee54d
git diff main..feature -- note.txt
git log main..feature --onelinediff --git a/note.txt b/note.txt index 4a58007..85c3040 100644 --- a/note.txt +++ b/note.txt @@ -1 +1,3 @@ alpha +beta +gamma c9e8e19 Add gamma 5f4534f Add beta
git cat-file -p HEAD
git show HEAD^:note.txttree f6af0574449653e84bc2964063c166fea24ac722 parent 5f4534f7a93dba890e3a4be2e8d272d88de79ea7 author Learner <learner@example.test> 1793491200 +0900 committer Learner <learner@example.test> 1793491200 +0900 Add gamma alpha beta
演習完了