Gitのタグを連番でまとめて消すならブレース展開が楽だった

  • Git
  • CLI
  • Bash

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

検証用に v1.1.0-rc.260925a から v1.1.0-rc.260925j までrcタグを切っていて、そのうち a〜h を消したくなった。i と j は残す。1個ずつ git tag -d するのは面倒なので、範囲指定でまとめて消した。

結論

ターミナル
# ローカル
git tag -d v1.1.0-rc.260925{a..h}
# リモート
git push origin --delete v1.1.0-rc.260925{a..h}

これで a〜h の8個がローカルとリモートの両方から消える。i と j は範囲外なので残る。

何が起きているか

{a..h} はGitの機能ではなく、シェル(bash / zsh)のブレース展開。コマンドが実行される前にシェルが展開するので、Gitには次のように8個のタグ名が並んだ状態で渡る。

ターミナル
git tag -d v1.1.0-rc.260925a v1.1.0-rc.260925b ... v1.1.0-rc.260925h

git tag -d も git push origin --delete も複数のref名をまとめて受け取れるので、1コマンドで済む。

flowchart LR
  A["v1.1.0-rc.260925{a..h}"] -->|シェルが展開| B["…a …b …c … …h(8個)"]
  B --> C["git tag -d"]
  B --> D["git push origin --delete"]

実行前に展開結果を確認する

範囲を間違えると消したくないタグまで消えるので、先に echo で展開結果を見ておくと安全。

ターミナル
echo v1.1.0-rc.260925{a..h}

ローカルにどのタグがあるかは git tag -l のパターン指定で絞れる。

ターミナル
git tag -l 'v1.1.0-rc.260925*'

リモート側は git ls-remote で確認できる。

ターミナル
git ls-remote --tags origin 'v1.1.0-rc.260925*'

注意点

  • ブレース展開はbash / zshの機能で、POSIX sh(dashなど)では展開されない。CIのスクリプトなどで sh 実行される環境だとそのまま文字列として渡ってしまう
  • 数字の連番も同じ書き方ができる(例: {1..9})。bash 4以降・zshなら {01..10} のようなゼロ埋めも効く
  • リモートから消しても、他の人のローカルにはタグが残る。その人が git fetch --prune --prune-tags などで掃除しない限り、再pushで復活する可能性がある
  • ローカルを先に消してもリモート削除には影響しない。git push origin --delete はリモートのref名を指定しているだけなので、順番はどちらでもいい