メモの日々


2024年09月24日(火) [長年日記]

[dev] git submodule statusで表示される3番目の項目の内容

submoduleを使用しているGitリポジトリにおいて「git submodule」を実行すると次のように表示される。

 a2e59f0e7065404b44dfe92a28aca47ba1378dc4 submodule/pybind11 (v2.11.0-182-ga2e59f0e)

このサブモジュールはpybind11のタグv2.13.6を指すようにしているのだが、括弧内にはv2.11.0と表示されていてモヤモヤする。

この最後の括弧内に表示される内容が何なのかについて調べたのでメモ。手元のGitのバージョンは2.44.0。

括弧内に表示される内容

「git submodule」で何が表示されるのかについては、git submoduleのマニュアル

With no arguments, shows the status of existing submodules.

とある。「status」の説明は無いが、「git submodule status」を実行したときと同じ内容が出力されるという理解でいいのだと思う。

同マニュアルのstatusサブコマンドの説明には次のようにある。

Show the status of the submodules. This will print the SHA-1 of the currently checked out commit for each submodule, along with the submodule path and the output of git describe for the SHA-1.

出力の括弧内には「git describe」の出力結果が表示されるということのようだ。

実際、submodule/pybind11 にて「git describe」を実行すると「v2.11.0-182-ga2e59f0e」と表示された。

git describeの出力

git describeは何を表示しているのか。

git describeのマニュアルには次のようにあった。

The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.

A-B-C という形式の出力で次のようになると考えてよさそう。

  • Aの部分は、カレントのコミットから過去に辿って見つかる最初のタグの名前
  • Bの部分は、Aのタグからカレントのコミットまでにあるコミットの数
  • Cの部分は、カレントのコミットの名前の先頭部分

でもおかしい。手元のサブモジュールはタグv2.13.6を指しているのにAの部分がv2.11.0になっている。これは何故か。

マニュアルの続きに次のようにあった。

By default (without --all or --tags) git describe only shows annotated tags.

Gitのタグにはlightweightとannotatedの2種類があり、オプションなしのgit describeがAの部分に出力するのはannotatedなタグだけのようである。

なので、pybind11のタグv2.13.6はlightweightタグであり、それより古い最新のannotatedタグがv2.11.0だからあのような出力になっているということになる。

タグの種類の確認方法

タグがlightweightなのかannotatedなのかを調べる明快な方法はわからなかったが、git cat-fileの -t オプションを使うのがいいように思う。

このコマンドは指定したオブジェクトのタイプを出力するが、lightweightタグのタイプはcommit、annotatedタグのタイプはtagになるのでこれで区別できる。

$ git cat-file -t v2.13.6
commit

$ git cat-file -t v2.11.0
tag

また、git for-each-refを使うと全てのタグについてタイプを確認できる。

$ git for-each-ref refs/tags
(省略)
8d8aecf4a5579c0e51d07fb93411aa120ae0360c tag    refs/tags/v2.11.0
0630807c3070287c716f6be3eacb00b8816b4215 tag    refs/tags/v2.11.1
95d943ae0ebdf609bbd650d119fda539509929b6 commit refs/tags/v2.11.2
3e9dfa2866941655c56877882565e7577de6fc7b commit refs/tags/v2.12.0
2e0815278cb899b20870a67ca8205996ef47e70f commit refs/tags/v2.12.1
0c69e1eb2177fa8f8580632c7b1f97fdb606ce8f commit refs/tags/v2.13.0
941f45bcb51457884fa1afd6e24a67377d70f75c commit refs/tags/v2.13.1
07f30430d4186c2712761f1ffaea50ede63f2b2b commit refs/tags/v2.13.2
bd67643652d3800837f1f41549a2a5adbaa3fafe commit refs/tags/v2.13.3
c6239a8a1b6871cc0fb5f7af885a02ffd1349f9d commit refs/tags/v2.13.4
7c33cdc2d39c7b99a122579f53bc94c8eb3332ff commit refs/tags/v2.13.5
a2e59f0e7065404b44dfe92a28aca47ba1378dc4 commit refs/tags/v2.13.6
(省略)

これを見ると、v2.11.1もannotatedタグなのでおかしいなと思ったが、どうやらタグv2.11.1はタグv2.13.6の先祖には位置していないようだった。どうしてそうなっているのかはわからないが。