Gitで最新のタグの1つ前のタグを取得する方法
2024/09/10
masyus
業務で
- 最新のタグと1つ前のタグ間でソースコードの差分を確認したい
- 特定ディレクトリ配下のファイルに差分がある時だけデプロイしたい
という要請に応えるべく、1つ前のタグを取得するコマンドがGitHub Actions(以下GHAと称します)上にて書かれているのを見つけて勉強になりました。今回はそのコマンドについて解説します。
バージョン情報
- Git: 2.30.1 (Apple Git-130)
前提条件: セマンティックバージョニングを尊重してtagを付与してきたこと
セマンティックバージョニングはおそらくエンジニア界隈に広く浸透しているかと思いますが、X.Y.Z
のフォーマットで
- メジャーバージョン: X
- マイナーバージョン: Y
- パッチバージョン: Z
を管理するスタイルです。セマンティックバージョニングを採用してGitでタグ付けする場合、接頭辞にv
をつけたv1.0.0
のようにすることが多く、ほとんどの開発現場ではこのスタイルでタグ付けされているかと思われます。1つ注意があり、
v1.0.0
は厳密にはセマンティックバージョンと呼ばず、あくまでタグ名である
という点は気をつけましょう。
ローカルリポジトリから1つ前のタグを取得する方法
下記で取得できます。
git tag --sort=v:refname | tail -n 2 | head -n 1
v:refname
はversion:refname
と同値で、タグをバージョン番号として解釈するようソート時に指定しますtail -n 2
とhead -n 1
はそれぞれ、後方2行および前方1行だけを取得します
ここで1点注意したいのが、
git tag
だけですと辞書順(アルファベット順) でソートし、バージョン番号であると見なしてソートしてくれないことです。たとえばv0.0.0
からv0.0.10
までのタグが付与されおり、v0.0.10
が最新のタグだった場合、セマンティックバージョニングに沿うならばv0.0.10
がgit tag
の実行結果の一番最後に来てほしいところですがソートオプションを何も指定しない場合、
v0.0.0
v0.0.1
v0.0.10
v0.0.2
v0.0.3
v0.0.4
v0.0.5
v0.0.6
v0.0.7
v0.0.8
v0.0.9
のような結果になってしまいます。
git tag --sort=v:refname
にすると
v0.0.0
v0.0.1
v0.0.2
v0.0.3
v0.0.4
v0.0.5
v0.0.6
v0.0.7
v0.0.8
v0.0.9
v0.0.10
のように、期待通りのソート結果となります。v:refname
の指定は他のGitコマンドでも使うことが多いため、覚えておくと何かと重宝します。
リモートリポジトリから1つ前のタグを取得する方法
下記で取得できます。
git ls-remote --tags --sort=v:refname origin 'v*.*.*' | tail -n 2 | head -n 1 | cut -f 2 | cut -d '/' -f 3
v*.*.*
は、タグ名がこのフォーマットに沿ったものだけをフィルターしてくれる便利オプションです
git ls-remote --tags --sort=v:refname origin 'v*.*.*'
の実行結果は、各タグのコミットハッシュとタグ名(refs/tags/タグ名の形式)の2つを出力します。
c472d3f1ae20db91f24190b84bad1c43e069d72b refs/tags/v0.0.0
b8bf98df470d0ea4a982176711798e3b833ee628 refs/tags/v0.0.1
d6b2fbfa22e24eb9390bbea9ef8d9ac8965b5401 refs/tags/v0.0.2
90aaa9c4d34e855f79133e6671fde3bfb0554d6d refs/tags/v0.0.3
...
1947ac8c43e10984ffe9d3002aa824914b5cc943 refs/tags/v0.0.9
9a3320acc941217734de78ea9211cdd4521a348b refs/tags/v0.0.10
この中からタグ名だけを取得する場合、tail + headで1つ前のタグを取得するのに加えてcutによる抽出が必要となります。
ローカルリポジトリとリモートリポジトリ、どちらからタグを取得するのが良い?
コマンドの性能差だけで言いますと、リモートリポジトリからタグを取得するほうが良いと思います。v*.*.*
のフィルター機能が便利で、誤ってセマンティックバージョニングに沿わなかったタグを除外することができますので。他に決め手があるとしたら、
タグ情報をfetchする速度が、どちらのコマンドでどれくらい時間かかるかに寄る
と思われます。たとえばGHAのContinuous deployment(以下CDと称します)環境上でGitからソースコードをチェックアウトしつつタグ情報を取得する場合、別途タグ情報をfetchしないとタグを参照できません。方法はいくつかありますが、
uses: actions/checkout@v4
with:
fetch-depth: 0
のように、チェックアウト時にfetch-depth: 0
を指定する方法があります。もしくはチェックアウト後にgit fetch
するかです。CD環境上でタグ取得する場合、時間がかかる方法ですとデプロイにも時間をかけることになり望ましくありません。Gitリポジトリの状況を鑑みながら最適な選択をする必要があります。