【Git】git tag について全然知らなかったので色々と調べてみた

本投稿は TECOTEC Advent Calendar 2022 の14日目の記事です。 こんにちは。次世代デジタル基盤開発事業部の河野 晃基です。

突然ですが、皆さんはGitで使用できるタグというのを知っていますか?
Gitにはコミットに目印をつけられるタグというものがあるのですが、タグについて色々調べてみると意外と利点が多いです。

このgit tagコマンドについて、色々と調べたら面白かったので備忘録として書いていきたいと思います。

そもそもタグって?

タグとは、GitSubVersionといったバージョン管理システムにおいて「ある時点の変更に名前をつけれる名札」のようなものです。
業務では、「どのコミットの時点で本番リリースしたのか」「仮で追加機能を作成したときの目印」などとしてタグをつけて参照しやすくすることが多いです。

タグの性質上、タグ名は必ずリポジトリ内で一意の名前でなければいけません。
気をつけましょう。

メリット

タグを用いることで様々なメリットがあります。

  • タグを使ってコミットに目印をつけられる
  • ブランチ名を選ぶ代わりに、タグを使ってチェックアウトできる
  • git logコマンドで、タグがハイライト表示されるのでログが追いやすくなる
  • GitHub上で、タグ付けした時点の圧縮ファイルをダウンロードできる
  • GitHub上で、タグがあると リリースノート を作成することができる

コミットに目印をつけられることはもちろんですが、ブランチ名の代わりにタグ名を使用することができます。

$ git checkout v1.0.0

リリース時にタグ付けすると、動作確認などでチェックアウトするときにとても便利です。

また、GitHubのtags(タグ一覧)では、それぞれの作成したタグに対してziptar.gz形式の圧縮ファイルが自動的に置かれ、ダウンロードすることができます。
新しくプロジェクトに参画した人にコードを渡す時など、とても便利です。

GitHubのtags画面
GitHubのtags画面

リリースノートについても、GitHubから簡単に作成できたり、前回のタグと比較して差分からリリースノートを自動生成することもできます。
ここでは割愛しますが、かなり便利なので詳しくは下記のリファレンスをご覧ください。
参考:Automatically generated release notes

git tagのマニュアルを見る

git tagのマニュアルはmanコマンドを使うと、オプションなどのマニュアルを確認することができます。

$ man git-tag

サイトでもマニュアルが公開されているので確認することができます。 git-tag(1) - Linux man page

タグコマンド

簡単にですがタグの素晴らしさを知ったところで、用途別でタグコマンドを紹介していきます。

基本操作

タグを作成する

現在チェックアウトしているコミットに対してタグ付けを行います。
過去のコミットに対してタグ付けしたい場合は、タグ名の後にコミット番号を指定します。

-a オプションをつけ、-m オプションの後にコメントを入れることで、コメント付きタグが作成できます。 -mオプションの後に、何も入力せずに実行すると、メッセージ入力のためのエディタが開かれます。

ほとんどの場合は3番目のgit tag -a <タグ名> -m <コメント>のように、コメント(注釈)付きタグを作るのがオススメです。

$ git tag <タグ名>
$ git tag <タグ名> <コミット番号>
$ git tag -a <タグ名> -m <コメント>

# 例
$ git tag v1.0.0
$ git tag v1.0.0 09bc3da
$ git tag -a v1.0.0 -m "最初のリリース" 

リモートリポジトリにタグをプッシュ

作成したタグをリモートリポジトリにプッシュすることで、指定したタグを全体共有させることができます。
タグを半角空白で区切って指定することで、複数のタグを送信することも可能です。

タグ名を指定せず、--tagオプションを付与すると、全てのローカルリポジトリのタグをプッシュすることができます。
リモートリポジトリを汚してしまう原因になるので、できることなら1つずつ確認してプッシュしましょう。

$ git push <リモートリポジトリ名> <タグ名>
$ git push <リモートリポジトリ名> <タグ名>  <タグ名> ...

# 例
$ git push origin v1.0.0
$ git push origin v1.0.0 v1.0.1 v1.0.2
# 全てのローカルリポジトリのタグをプッシュ
$ git push origin --tag

リモートリポジトリのタグをローカルに反映

他の人がタグをあげたときに、fetchコマンドでリモートリポジトリにあるタグをローカルリポジトリに反映させます。
このとき、リモートリポジトリとローカルリポジトリでタグの差異があると コンフリクト が起こる可能性があるので、ローカルのタグを削除するなどして対応する必要があります。

強制的にリモートリポジトリに合わせる時には-fオプションを使用してfetchします。

$ git fetch --tags
$ git fetch --tags -f

タグの一覧を表示

全ての作成したタグの一覧を表示します。

様々なオプションをつけることで、タグ名検索や表示するコメント行の指定、タグを1行にまとめて表示することも可能です。

$ git tag 

# 検索オプション
# 1. --column : タグを1行に列挙します
$ git tag --column

# 2. -n<num> : タグコメントを num 行分表示できます。デフォルトは1行です
$ git tag -n30

# 3. -l <正規表現> : 正規表現で検索します
$ git tag -l "v1.0.*"

# 4. --contains <コミット番号> : 指定したコミットを含むタグを表示します
$ git tag --contains 09b32af

並び替えをしたい時は--sort オプションと、並び替える列を指定します。

  • refname: タグ名
  • authorname: タグの作者
  • authordate: タグを作成した日付
  • subject: コミットメッセージ

並び替える列をそのまま指定すると昇順、先頭に-(ハイフン)をつけることで降順になります。
下の例では-refname というようにハイフンをつけて指定しているので、タグ名の降順を表示しています。

# 例)タグ名を降順で並び替え
$ git tag -n --sort -refname

v1.0.3         v1.0.3 release
v1.0.2         v1.0.2 release
v1.0.1          v1.0.1 release
v1.0.0         first release

タグの詳細情報を表示

タグの詳細情報を表示します。
コメントなしタグの時は下記の情報が表示されます。

  • commit:コミット番号
  • Merge:マージ番号
  • Author:タグの作者
  • Date:タグの作成日
# コメントなしのタグの場合
$ git show v1.0.0

commit 1eef3e978571312021439250763fb19dc7e28eb2 (tag: v1.0.0)
Merge: 12fca8f 3b1c98g
Author: kouno-sample <112612378+kouno-sample@users.noreply.github.com>
Date:   Thu Dec 1 05:00:00 2022 +0900

    Merge pull request #1 from practice/develop
    
    [UPDATE] README.mdを修正しました

コメント付きタグの場合は、下記の情報が 追加で 表示されます。

  • Tag Name:タグ名
  • Tagger:タグづけした人の情報
  • Date:タグコメントをつけた日
  • Comment:コメントメッセージ
# コメント付きタグの場合
$ git show v1.0.0

tag v1.0.0
Tagger: kouno.teruki <kouno-sample@example.com>
Date:   Fri Dec 2 07:00:00 2022 +0900

最初のリリース

commit 1eef3e978571312021439250763fb19dc7e28eb2 (tag: v1.0.0)
Merge: 12fca8f 3b1c98g
Author: kouno-sample <112612378+kouno-sample@users.noreply.github.com>
Date:   Thu Dec 1 05:00:00 2022 +0900

    Merge pull request #1 from practice/develop
    
    [UPDATE] README.mdを修正しました

タグのコメントを更新

タグコメントを更新したい場合には、-fオプションで変更します。

$ git tag -a -f <タグ名> -m <コメント>

# 例
$ git tag -a -f v1.0.0 -m "First Release"

タグを削除

タグを削除したい場合は、-dオプションでタグを削除します。
半角空白で区切って複数タグを指定することも可能です。

$ git tag -d <タグ名>
$ git tag -d <タグ名> <タグ名> ...

リモートリポジトリのタグを削除するときには、pushコマンドで指定します。

$ git push <リモートリポジトリ> -d <タグ名>
$ git push <リモートリポジトリ> -d <タグ名> <タグ名> ...

ただし、リモートリポジトリのタグは削除しても「全員のローカルリポジトリには反映されない」ので、 git fetch origin <タグ名> で反映してもらう必要があります。

プッシュしたタグを勝手に削除するのは控えましょう。

応用操作

タグ名を変更したい

作成したタグ名を変更するコマンドは存在しないので、元のタグを削除して新たにタグをつける必要があります。

# 特定のコミット番号に対して新しくタグを作成
$ git tag <新しいタグ名> <古いタグをつけたコミット番号>

# 古いタグを削除
$ git tag -d <古いタグ>

また、作成したタグはコミット番号の代わりに使用することができるので、このような書き方もできます。

# 古いタグがついているコミットに新しくタグを作成
$ git tag <新しいタグ名> <古いタグ名>

間違ったコミットにタグをつけてしまった場合

違うコミットに対してタグをつけてしまい、別のコミットにタグを付け直したいときはどうしたらよいでしょう。

git tag マニュアル - DISCUSSION の部分を見てみると、プッシュ前だったら「-f」を使用して古いものを置き換えてください と書いてあります。
プッシュ前の場合は、-fオプションをつけて修正することができます。

$ git tag -f v1.0.0 <コミット番号>

ではプッシュ後はどうしたら良いでしょうか?
マニュアルのDISCUSSIONの続きを読んでみると、プッシュ後のタグを付け直したい場合は、2種類の方法があるとのことです。

  1. 諦めて別のタグ名を使用する
  2. -fオプションで変更を無理やりプッシュし、他の人に状態を合わせてもらう

1番目の方法は、もしタグ名をv1.0.0というように間違えて作成してしまったら、v1.0.0-1などといったように、別の名前のタグを使って代用しましょうということです。
冒頭で説明したように、タグは一意で信頼されるものでなければいけませんので、タグを書き換えることはすべきではないのです。

そして2番目の方法は、マニュアル内では「非常識な方法」「セキュリティ上の大きな問題」などと怒りの文章が書き綴られいる方法です。
無理やりタグ名を変更する為、タグの信頼性を落とすことになります。マニュアルの筆者も推奨していないですが、どうしても、どうしてもやりたい場合は下記の方法で再タグ付けを行います。

非常識な方法

変更したい人は、再タグ付けを行います。自身のローカルリポジトリのタグを更新してリモートリポジトリに強制的にプッシュします。

# コミットを変えて強制プッシュを行う
$ git tag -f <タグ名> <コミット番号>
$ git push -f <タグ名>

# 照合のためにタグのハッシュ値を取得する
$ git rev-parse <タグ名>

プッシュしたら、別の人のローカルリポジトリのタグも更新していただくため下記のコマンドを行ってもらうように連絡します。
マニュアルでは、「『大変申し訳ありません』の文章を添えて大々的に告知するように」といったニュアンスで記載されています。

# ローカルリポジトリのタグを削除し、フェッチを行う。
$ git tag -d <タグ名>
$ git fetch origin tag <タグ名>

# 変更者のハッシュ値と同じになっているかどうかを、全員の環境で確認
$ git rev-parse <タグ名>

これで全員の環境で確認できたら変更完了です。 少々面倒臭い手段となっていますが、マニュアルでは「この手順は面倒であるべきです」と言っています。もし簡単に行えてしまったらタグの意味がなくなってしまうからです。

よほどの理由がない限りは、1番目の方法を採用しましょう。

マニュアルの怒りの文章は長かったので詳細は割愛しますが、この文章について説明している記事があったので是非そちらも面白いのでご覧ください。

【git tag】プッシュしたtag名を削除・変更してはいけない理由〜manコマンドで読めるgitメンテナの怒り〜 - Qiita

まとめ

色々調べてみるとタグ(git tagコマンド)はとても奥が深いなと感じました。 これを機にタグを使ったことがない人は試してみてはいかがでしょうか。

最後まで読んでくださりありがとうございました。

www.tecotec.co.jp