🌳

Git のブランチ名のスラッシュの解釈について

に公開

きっかけ

自分で作ったアプリの Git のコミット履歴や構造がぐちゃぐちゃだったので、整理しようと思って ChatGPT に色々相談してたら 「git branch backup/before-history-edit とかバックアップ用のブランチ切っとくといいよ。」って言われた時に、backup/ は Git 的に単なるブランチ名文字列の一部扱いなのか、ブランチの階層的な意味合いがあるのか気になったので、ブランチについて調べてみた。

ブランチ名の運用例

役割、用途ごとにプレフィックスを付ける形で名前を付けると解り易い。

例:

  • backup/before-history-edit
  • backup/before-cleanup
  • backup/before-filter-repo
  • wip/readme-polish
  • feature/login-form
  • fix/null-check

こんな感じにすると

  • 何のためのブランチか分かりやすい
  • 一覧で並んだときにまとまって見える
  • GUI ツールによってはフォルダっぽくグループ表示される

みたいな利点があるし、管理しやすい。

ブランチ名の / は階層構造として認識されるの?

結論

完全にただの文字列ではなく、場合によって区切りとして意味があることもある。

Git 内部の扱い

refs/heads/ブランチ名 という参照名として扱われる

例:
backup/before-history-edit は内部の概念としては
refs/heads/backup/before-history-edit

誤解に注意

/ を入れても、 親ブランチ backup の下に子ブランチがある みたいな階層機能があるわけではない。
あくまで 1つのブランチ名

refsheads について

  • refs: Git の参照(ref)を置くための固定の大きな名前空間
  • heads: refs の中でもローカルブランチ用の固定サブ名前空間

refsheads 自体は基本的に参照としてそのままの文字列で、ブランチを作る際の状況でこの部分が変わるわけじゃない。

参照とブランチの対応確認

git symbolic-ref HEAD
git symbolic-ref --short HEAD
git show-ref --branches
  • git symbolic-ref HEAD: refs/heads/main みたいな形を返す
  • --short: main のような短縮表示される
  • git show-ref: ローカルの参照一覧を見るためのコマンド

参照の例

  • refs: 参照全体の箱
  • refs/heads: ローカルブランチの箱
  • refs/tags: タグの箱
  • refs/remotes: リモート追跡ブランチの箱

headsHEAD は別物

HEAD今どこを見てるかを表す特別な参照で、通常は refs/heads/<現在のブランチ> を指すシンボリック参照になってる。

  • heads: 参照のなかでローカルブランチ用の名前空間
  • HEAD: 今見ている場所を表す特別な参照 (通常は refs/heads/... を指す)

参照の名前空間 != 参照
なので別物。

Tips

refs/heads/... という“名前”は固定だけど、必ずしも .git/refs/heads/... に個別ファイルで見えるとは限らない。

Git は参照を packed-refs にまとめて保存することもあるので、概念としては refs/heads/... でも、保存場所は毎回同じ見え方とは限らない。

/ を含んだブランチ名を使うときの制約

  • backup
  • backup/before-history-edit
    これらのブランチ名は同時には作れない。

なんで?

  • refs/heads/backup
  • refs/heads/backup/before-history-edit
    内部的にはこんな参照になる。

ブランチ backup

  • 1本の参照そのもの
  • その下に子要素をぶら下げるための途中ノード
    の両方になってしまう。この衝突がダメ。

その名前空間では、ある名前を終端ノードとして使うなら、その名前を途中ノードとしても使うことはできない

だから backup を終端(= ブランチ)として使ったら、backup/... は作れない
逆も同じで、backup/... があるなら backup は作れない

まとめ

/ 区切りのプレフィックスを付けてブランチを作っても、Git の概念的には階層構造で解釈されている訳じゃなく、あくまでブランチ名や参照文字列の一部。

参照として "終端になる文字列" と "途中ノードになるような文字列" を名前に持つブランチを同時に存在させることはできない。

ブランチ名に / で区切ったプレフィックスを付けるとツールによっては階層構造で解釈してくれる場合もある。

雑感

プログラミングとかIT技術的なものって、言語やツールによって解釈や扱いが違ったりするからこういうところ難しいなぁと思う。

結構 "こう書けば動く" で作れちゃったりするけど、"なんでそうするのか" や "どんな処理が行われているのか" まで理解して使えるようになりたいと思いながら少しずつ学んでいく。

Discussion