web-dev-qa-db-ja.com

リモートリポジトリに存在しなくなったローカルgitタグを削除する

私たちは展開プロセスの一部としてgitのタグを使います。ときどき、これらのタグをリモートリポジトリから削除してクリーンアップします。

これはかなり簡単です。 1人のユーザーが1組のコマンドでローカルタグとリモートタグを削除します。両方のステップを組み合わせた小さなシェルスクリプトがあります。

2番目(3番目、4番目、...)のユーザーには、リモートに反映されなくなったローカルタグが追加されました。

リモートブランチが削除されているブランチをローカルで追跡するためにクリーンアップするgit remote Prune Originのようなコマンドを探しています。

あるいは、リモートタグを一覧表示する単純なコマンドを使用して、git tag -lを介して返されたローカルタグと比較することもできます。

406
kEND

良い質問。完全な答えがありません。

そうは言っても、あなたはgit ls-remoteを通してリモートタグのリストを得ることができます。 Originによって参照されるリポジトリ内のタグを一覧表示するには、次のように実行します。

git ls-remote --tags Origin

次のようなハッシュとわかりやすいタグ名のリストが返されます。

94bf6de8315d9a7b22385e86e1f5add9183bcb3c        refs/tags/v0.1.3
cc047da6604bdd9a0e5ecbba3375ba6f09eed09d        refs/tags/v0.1.4
...
2f2e45bedf67dedb8d1dc0d02612345ee5c893f2        refs/tags/v0.5.4

このリストによって生成されたタグとあなたがローカルに持っているタグとを比較するためのbashスクリプトを確かに組み合わせることができます。 git show-ref --tagsを見てください。これはgit ls-remoteと同じ形式でタグ名を生成します。


余談ですが、git show-refにはあなたが望むものとは反対のことをするオプションがあります。次のコマンドは、あなたが持っていないローカルブランチにあるリモートブランチ上のすべてのタグを一覧表示します。

git ls-remote --tags Origin | git show-ref --tags --exclude-existing
62
Mike West

これは大きな問題です。私は同じことを疑問に思っていました。

私はスクリプトを書きたくなかったので、別の解決策を探しました。重要なのは、タグをローカルに削除してから、git fetchを使用してリモートサーバーから「元に戻す」ことができることです。タグがリモートに存在しない場合は、削除されたままになります。

したがって、2行を順番に入力する必要があります。

git tag -l | xargs git tag -d
git fetch --tags

これら:

  1. ローカルリポジトリからすべてのタグを削除します。 FWIW、xargsは "tag -l"によって出力された各タグを "tag -d"のコマンドラインに配置します。これがなければ、gitは何も削除しません(stdinを読んでいないので(愚かなgit))。

  2. リモートリポジトリからすべてのアクティブなタグを取得します。

これはWindows上でも問題ありません。

932
Richard W

Git v1.7.8からv1.8.5.6まで、これを使うことができます。

git fetch <remote> --Prune --tags

更新

Commit e66ef7ae6f31f2 のため、これは新しいバージョンのgit(v1.9.0以降)では機能しません。それは何人かの人々のために働いたので私は本当にそれを削除したくない。

"Chad Juliano"によって示唆されているように、v1.7.8以降のすべてのGitバージョンでは、次のコマンドを使うことができます。

git fetch --Prune <remote> +refs/tags/*:refs/tags/*

ワイルドカード拡張を回避するために、タグ部分を引用符で囲む必要がある場合があります(Windowsの場合など)。

git fetch --Prune <remote> "+refs/tags/*:refs/tags/*"
225
loganfsmyth

リモートに存在するタグだけが必要な場合は、ローカルタグをすべて削除してください。

$ git tag -d $(git tag)

そして、すべてのリモートタグを取得します。

$ git fetch --tags
141
newmangt

V1.7.8以降のGitのすべてのバージョンは、refspecでgit fetchを理解しますが、v1.9.0以降、--tagsオプションは--Pruneオプションをオーバーライドします。汎用的な解決策として、これを試してください。

$ git --version
git version 2.1.3

$ git fetch --Prune Origin "+refs/tags/*:refs/tags/*"
From ssh://xxx
 x [deleted]         (none)     -> rel_test

Git v1.9.0での "--tags"と "--Prune"の動作の違いについての詳細は、 https://github.com/git/git/commit/を参照してください。 e66ef7ae6f31f246dead62f574cc2acb75fd001c

73
Chad Juliano

最新バージョンのGit(私はgit v2.20を使っています)のように見えるので、単純に言うことができます。

git fetch --Prune --Prune-tags

ずっときれい!

https://git-scm.com/docs/git-fetch#_pruning

取得時に常にタグをプルーニングするようにgitを設定することもできます。

git config fetch.pruneTags true

特定のリモートから取得するときにタグを整理するだけの場合は、remote.<remote>.pruneTagsオプションを使用できます。たとえば、Originから取得するときに常にタグをプルーニングし、他のリモートからは取得しないようにするには、

git config remote.Origin.pruneTags true
28
Nicholas Carey

Gitはローカルタグのクリーンアップをネイティブにサポートします。

git fetch --tags --Prune

このコマンドは最新のタグを取り込み、削除されたすべてのタグを削除します。

7
Nirav Shah

これは良い方法です。

git tag -l | xargs git tag -d && git fetch -t

出典: demisx.GitHub.io

7
imjoseangel

ローカルタグとリモートタグの違いを表示します。

diff <(git tag | sort) <( git ls-remote --tags Origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tagはローカルタグのリストを与えます
  • git ls-remote --tagsはリモートタグへのフルパスのリストを与えます
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##'は、リモートタグパスのリストからタグ名だけを解析します。
  • 最後に、2つのリストのそれぞれをソートしてそれらを比較します。

"<"で始まる行はあなたのローカルタグで、もうリモートリポジトリにはありません。それらが少ない場合は、手動で1つずつ削除できます。多い場合は、自動化するためにさらに多くのグリップと配管を行います。

4
dotstaraj

GitHubのpivotal_git_scripts Gem forkにgit sync-local-tagsコマンドを追加したばかりです。

https://github.com/kigster/git_scripts

Gemをインストールしてから、リポジトリに "git sync-local-tags"を実行してリモートに存在しないローカルタグを削除してください。

あるいは、以下のスクリプトをインストールして "git-sync-local-tags"と呼ぶこともできます。


#!/usr/bin/env Ruby

# Delete tags from the local Git repository, which are not found on 
# a remote Origin
#
# Usage: git sync-local-tags [-n]
#        if -n is passed, just print the tag to be deleted, but do not 
#        actually delete it.
#
# Author: Konstantin Gredeskoul (http://tektastic.com)
#
#######################################################################

class TagSynchronizer
  def self.local_tags
    `git show-ref --tags | awk '{print $2}'`.split(/\n/)
  end

  def self.remote_tags
    `git ls-remote --tags Origin | awk '{print $2}'`.split(/\n/)
  end

  def self.orphaned_tags
    self.local_tags - self.remote_tags
  end

  def self.remove_unused_tags(print_only = false)
    self.orphaned_tags.each do |ref|
      tag = ref.gsub /refs\/tags\//, ''
      puts "deleting local tag #{tag}"
      `git tag -d #{tag}` unless print_only
    end
  end
end

unless File.exists?(".git")
  puts "This doesn't look like a git repository."
  exit 1
end

print_only = ARGV.include?("-n")
TagSynchronizer.remove_unused_tags(print_only)

TortoiseGitは今タグを比較することができます。

左のログはリモートにあり、右のログはローカルにあります。

enter image description here

同期ダイアログのタグ比較機能を使用する:

enter image description here

TortoiseGit issue 2973も参照してください。

2
Yue Lin Ho

@Richard Wと同じ回答ですが、Windows用(PowerShell)

git tag | foreach-object -process { git tag -d $_ }
git fetch -t
1
Danon

これはどうですか - すべてのローカルタグを削除してから再取得しますか?リポジトリを検討することはサブモジュールを含むかもしれません:

git submodule foreach --recursive  'git tag | xargs git tag -d'
(alternatively, "for i in `find .git  -type d -name '*tags*'`; do rm -f $i/*;  done")
git fetch -t
git submodule foreach --recursive git fetch -t
1
tetzu0