Help us understand the problem. What is going on with this article?

GitのHEADとは何者なのか

More than 1 year has passed since last update.

最初に

なんとなくでも使用できるGitですが実はとても奥深く複雑な構造をしています。

そんなGitを使い始めた時ほぼ全員が思う「HEAD」とは何者なのか説明したいと思います。
また合わせて「Branchとは」「detached HEADとは」についても話します。

先に結論ファーストで話しますと

HEADとは

今自分が作業している場所を示すポインタ

Branchとは

開発の本流から分岐し、本流の開発を邪魔することなく作業を続ける機能

detached HEADとは

HEADがBranchを指していない状態のこと


そして僕自身以前までブランチとはなにか聞かれた場合、下図のようなイメージを持っていました。
そしてこれは誤った認識です。

yokuaru_ayamari.PNG

この記事はMake IT アドベントカレンダー9日目の記事として寄稿しています!

明日は @wh1tecat が投稿する予定です。
楽しみですね(笑)

Branchとは

まずGitのブランチというシステムについてお話します。

ブランチと言われてなにを想像しますか?
ブランチを説明するために図を使って説明したいと思います。

下図のGitでは左上が最初のコミットを示し、コミットを重ねるごとに下に向かって伸びています。左上のmasterブランチから始まり、途中でdevelopブランチ、またdevelopからfeat/aブランチに派生してる様子を示しています。

yokuaru_commit_1.PNG

このGitでは3つのブランチを管理しています。
そして今あなたはmasterブランチで作業しています。
ではもしこのツリーを見た時『「master」「develop」「feat/a」のブランチはそれぞれどこですか?』と質問された場合、僕自身以前まで下図のように考えていました。そしてそれは間違った認識でした。

yokuaru_ayamari.PNG

青枠で囲った中全体がmasterブランチであると認識していました。
また後述しますHEADも青い枠を指しているとなんとなく考えていました。

しかし、実際のブランチとは下図のようになります

zissaino_branch.PNG

この状況の結論を言うと
Gitにおけるブランチとは、単にコミットを指す軽量なポインタに過ぎません
そしてそれぞれ3つのブランチはある特定のコミットを示すポインタです

僕自身以前まではブランチとは派生元から最新の履歴までの枝全体、もしくはファイル群のようなものを指し示していると考えていましたがそれは誤っていました。

ではそれ以外のコミットはどこのブランチに所属しているのか?
そもそもコミットとはなんなのか
Gitはどの様にしてファイルの履歴を管理しているのか
結局HEADとは?

こうした疑問が出てきたところで次はGitの仕組みについて少し触れたいと思います。

Gitのファイル管理の仕組み

Gitをコミットするために必要なコマンドはおおよそ以下のものです。

1. /* ファイルを編集 */
2. git add -A
3. git commit -m "add my-files"

この時Git内部の流れは下のようになります

  1. ステージされたファイルのハッシュを計算
  2. ツリーオブジェクトが作成作成される
  3. ツリーオブジェクトにステージしたコードのスナップショットへのポインタが格納される
  4. git commit が実行されるとコミットオブジェクトを作成
  5. コミットオブジェクトにツリーオブジェクトへのポインタ、親コミットへのポインタ、作成者のメタデータなどが格納される
  6. ブランチのポインタを最新のコミットオブジェクトに進める

コミットが繰り返されるごとブランチは次のブランチに自動で移動します
合わせてHEADも移動します。

commit_tree.PNG

ステージングされたファイルのポインタがツリーオブジェクトにblobとして格納されます。
ポインタの先はステージされたファイルのスナップショットが格納されています。
コミットオブジェクトが作られる度ツリーオブジェクトのポインタが格納されます
コミットオブジェクトにはツリーオブジェクトへのポインタの他、親コミットのポインタ、コミッターのメタ情報、コミットメッセージなども合わせて格納されます。
そしてそれらのコミットオブジェクトが数珠つなぎとなることでGitのツリーは形成されています

このようにしてGitはコミットを作成し管理しています。
そしてGitにおけるブランチとは単にこれらのコミットを示す軽量なポインタでしかありません。

もし仮に新しいブランチが作られた場合は単に新しいポインタが作られるだけです。

ブランチとはコミットを示すポインタのことでファイルの履歴群や枝の様に見えるもの全体を指すわけではありません。

Gitはそれぞれのコミットの親となるコミットのハッシュを持つことでファイルの履歴を管理しています。
この親の値をたどることでファイルの変更履歴を確認しています。

一つのコミットが複数の親コミットを保つ場合もあります。マージした場合などが該当します。
また一つのコミットを複数のブランチが参照する時もあります。ブランチはポインタであるためブランチが被っていても特に害はありません。

HEADとは

Gitがどうやって今作業しているブランチを把握しているかご存知でしょうか。その時に使われるのがHEADです。
HEADの中身はこちらもポインタであり、Gitの中で特殊で唯一の存在です。
HEADがブランチを指すことで自分が現在いるブランチがどれか確認できる仕組みになっています

つまりコミットの場所を記憶しているのがブランチ、ブランチの場所を記憶しているのがHEADです
いわゆるポインタのポインタってやつです

commit.PNG

もし、新しいコミットが発生した場合、自動的にブランチのポインタも進みます。HEADがブランチを指していいる場合HEADの値も合わせて追尾する仕組みになっています

GitはHEADが示しているブランチから自分が作業しているブランチを確認しています

因みに直近で自分が移動したHEADの位置を確認したい場合は下記のコマンドを実行します。

git reflog

またブランチのツリー図が見たい場合はSourceTreeやGitUPなどのGUIツールやtigなどを使用して確認するのが良いでしょう。

detached HEADとは

最後にdetached HEADとはなにか説明します。

detached HEADが起こることは稀ですが、rebase等を行った際に起こることがあります。

detached HEADとはなにか結論からいうと
HEADがブランチ以外のコミットのポインタを示している状態のことです。

detached_head.PNG

先程HEADはブランチを示しているといいましたが、HEADはブランチ以外のなんでもないただのコミットを示すこともできます。
そうした状態をdetached HEADと呼びます。
例えば特定のコミット時のファイルの状態が確認したい時など敢えてHEADをブランチ以外に移動させたりなどを行います。
detached HEADになった場合の対処ですが、任意のブランチにHEADをチェックアウトさせれば、ブランチを参照しているのでdetached HEADではなくなります。

detached HEADの簡単な起こし方を紹介します

  1. git logでコミットを確認しブランチが示していないなんでもないコミットのハッシュを控えます
  2. 控えたハッシュ宛にチェックアウトします
  3. git branchで確認
git log
git checkout c215891f5b9b997ec4020c4539b773ef94c2449c
git branch
* (HEAD detached at c215891)
  develop
  feat/a
  master

戻し方

  1. git branchで戻るブランチ名を確認
  2. 確認したブランチ宛にチェックアウト
git branch
* (HEAD detached at c215891)
  develop
  feat/a
  master

git checkout develop
git branch
* develop
  feat/a
  master

detached HEADがいい状態か悪い状態か状況によりますのでなんとも言えませんが、意図せず発生してしまった場合はいい状態とは言えないでしょう。詳しい人に状況を説明して対処してもらうのがいいと思います。

終わりに

この記事の動機ですが、元々は数ヶ月前にファストフォワードとノンファストフォワードを理解するために調べ、ブランチについて知ったたのがきっかけでした。しかしまとめる気力がなくまた今度まとめようと思うばかりでしたが、今回いい機会だと思いまとめたのがこの記事の動機になります。

GitのHEADについて分かっている風に説明しましたが、僕自身も分からないことが多く日々勉強の毎日です。
いつかGitマスターになれることを夢見て生きていきたいです。

精進したいお気持ち:innocent:

参考

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%A8%E3%81%AF

ymzk-jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした