Remove local git tags that are no longer on the remote repository

Viewed 220350

We use tags in git as part of our deployment process. From time to time, we want to clean up these tags by removing them from our remote repository.

This is pretty straightforward. One user deletes the local tag and the remote tag in one set of commands. We have a little shell script that combines both steps.

The 2nd (3rd, 4th,...) user now has local tags that are no longer reflected on the remote.

I am looking for a command similar to git remote prune origin which cleans up locally tracking branches for which the remote branch has been deleted.

Alternatively, a simple command to list remote tags could be used to compare to the local tags returned via git tag -l.

16 Answers

Looks like recentish versions of Git (I'm on git v2.20) allow one to simply say

git fetch --prune --prune-tags

Much cleaner!

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

You can also configure git to always prune tags when fetching:

git config fetch.pruneTags true

If you only want to prune tags when fetching from a specific remote, you can use the remote.<remote>.pruneTags option. For example, to always prune tags when fetching from origin but not other remotes,

git config remote.origin.pruneTags true

In new git versions (like v2.26.2 or higher) you could use --prune-tags

-P
--prune-tags
Before fetching, remove any local tags that no longer exist on the remote if --prune is enabled. This option should be used more carefully, unlike --prune it will remove any local references (local tags) that have been created. This option is a shorthand for providing the explicit tag refspec along with --prune, see the discussion about that in its documentation.

So you would need to run:

git fetch origin --prune --prune-tags

I know I'm late to the party, but now there's a quick answer to this:

git fetch --prune --prune-tags # or just git fetch -p -P

Yes, it's now an option to fetch.

If you don't want to fetch, and just prune:

git remote prune origin

Updated @2021/05

enter image description here

Pass $REPO parameter to custom script.

The content of sync_git_tags.sh

#!/bin/sh

# cd to $REPO directory
cd $1
pwd

# sync remote tags
git tag -l | xargs git tag -d && git fetch -t

Old

ps: updated @2021/05, git fetch --prune --prune-tags origin not working in my MacOS.

I add the command to SourceTree as a Custom Action on my MacOS.
Setting Custom Actions by Sourcetree -> Preferences... -> Custom Actions


`Script to run` have to be the `git` path.

I use git fetch --prune --prune-tags origin to sync tags from remote to local.

enter image description here enter image description here

The same answer as @Richard W but for Windows (PowerShell)

git tag | ForEach-Object -Process { git tag -d $_ }
git fetch -t

Just added a git sync-local-tags command to pivotal_git_scripts Gem fork on GitHub:

https://github.com/kigster/git_scripts

Install the gem, then run "git sync-local-tags" in your repository to delete the local tags that do not exist on the remote.

Alternatively you can just install this script below and call it "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)
Related