Entfernen Sie lokale Git-Tags, die sich nicht mehr im Remote-Repository befinden

468

Wir verwenden Tags in Git als Teil unseres Bereitstellungsprozesses. Von Zeit zu Zeit möchten wir diese Tags bereinigen, indem wir sie aus unserem Remote-Repository entfernen.

Das ist ziemlich einfach. Ein Benutzer löscht das lokale Tag und das Remote-Tag in einem Befehlssatz. Wir haben ein kleines Shell-Skript, das beide Schritte kombiniert.

Der 2. (3., 4., ...) Benutzer verfügt jetzt über lokale Tags, die nicht mehr auf der Fernbedienung angezeigt werden.

Ich suche nach einem ähnlichen Befehl, git remote prune originder lokale Verfolgungszweige bereinigt, für die der Remote-Zweig gelöscht wurde.

Alternativ könnte ein einfacher Befehl zum Auflisten entfernter Tags verwendet werden, um sie mit den über zurückgegebenen lokalen Tags zu vergleichen git tag -l.

KEND
quelle
2
Ich schlug eine neue Funktion in Git vor, um das Beschneiden veralteter Tags zu unterstützen: thread.gmane.org/gmane.comp.version-control.git/168833
Adam Monsen
1
Hinweis: Mit Git 2.17 (Q2 2018) können Sie mit einer einfachen Funktion git config fetch.pruneTags truedas git fetchtun, was Sie wollen! Siehe meine Antwort auf diese andere Frage .
VonC
2
Reposting eines Kommentars aus einer der folgenden Antworten: Zumindest mit git 2.18.0 kann man auch diese Syntax verwenden: git fetch --prune --prune-tags origin
zutnop

Antworten:

71

Gute Frage. :) Ich habe keine vollständige Antwort ...

Das heißt, Sie können eine Liste der Remote-Tags über erhalten git ls-remote. Um die Tags in dem Repository aufzulisten, auf die verwiesen wird origin, führen Sie Folgendes aus:

git ls-remote --tags origin

Das gibt eine Liste von Hashes und Anzeigenamen zurück, wie zum Beispiel:

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

Sie könnten sicherlich ein Bash-Skript zusammenstellen, um die von dieser Liste generierten Tags mit den lokal vorhandenen Tags zu vergleichen. Schauen Sie sich an git show-ref --tags, welche die Tag-Namen in der gleichen Form wie git ls-remote) generiert .


Nebenbei git show-refhat eine Option, die das Gegenteil von dem tut, was Sie möchten. Der folgende Befehl listet alle Tags in der Remote-Verzweigung auf, die Sie lokal nicht haben:

git ls-remote --tags origin | git show-ref --tags --exclude-existing
Mike West
quelle
Danke Mike. Ich werde mein eigenes Bash-Skript mit jeder Liste zum Vergleich rollen.
Kend
11
Die Antwort von Richard W macht dies viel eleganter, falls Sie nicht an einem komplizierten Skript interessiert sind.
Kyle Heironimus
1
Die Randnotiz über Tags, die lokal nicht vorhanden sind, kann erweitert werden, um weitere Fernbedienungen zu überprüfen:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec
Siehe nächste Antwort für eine einfachere Lösung
sfletche
git unterstützt --prune-tags. Unsicher, welche Version dies eingeführt wurde. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian
1053

Das ist eine großartige Frage, ich hatte mich das Gleiche gefragt.

Ich wollte kein Skript schreiben und suchte nach einer anderen Lösung. Der Schlüssel besteht darin, zu erkennen, dass Sie ein Tag lokal löschen und dann mit git fetch vom Remote-Server "zurückholen" können. Wenn das Tag auf der Fernbedienung nicht vorhanden ist, bleibt es gelöscht.

Daher müssen Sie zwei Zeilen in der folgenden Reihenfolge eingeben:

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

Diese:

  1. Löschen Sie alle Tags aus dem lokalen Repo. FWIW, xargs platziert jedes von "tag -l" ausgegebene Tag in der Befehlszeile für "tag -d". Ohne dies wird git nichts löschen, da es nicht stdin (dummes git) liest.

  2. Rufen Sie alle aktiven Tags vom Remote-Repo ab.

Dies funktioniert sogar unter Windows.

Richard W.
quelle
57
Dies muss meine Lieblings-Git-Antwort auf StackOverflow sein. Es kombiniert Wissen, Einfachheit und Trickserei und erklärt alles. Großartig
Tymtam
25
wie in einer separaten Antwort erwähnt, diese löscht alle lokale Tags und diejenigen in der Remote - Repo nicht offensichtlich nicht neu erstellt werden
zweite
13
FWIW sollte dies völlig unnötig sein. Es sollte einen git tag prune originBefehl geben.
void.pointer
9
Dies funktioniert möglicherweise nicht für alle. Sie sollten git fetch --tags ausführen, um auf der sicheren Seite zu sein.
Adam Kurkiewicz
5
Ich musste gehen git tag -l | %{git tag -d $_}, um dies in PowerShell zum Laufen zu bringen. Ich bin mir über niemanden sicher.
Alain
244

Von Git v1.7.8 bis v1.8.5.6 können Sie Folgendes verwenden:

git fetch <remote> --prune --tags

Aktualisieren

Dies funktioniert bei neueren Versionen von git (ab Version 1.9.0) aufgrund des Commits e66ef7ae6f31f2 nicht . Ich möchte es jedoch nicht wirklich löschen, da es bei einigen Leuten funktioniert hat.

Wie von "Chad Juliano" vorgeschlagen, können Sie mit allen Git-Versionen seit Version 1.7.8 den folgenden Befehl verwenden:

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

Möglicherweise müssen Sie den Tag-Teil in Anführungszeichen setzen (z. B. unter Windows), um eine Platzhaltererweiterung zu vermeiden:

git fetch --prune <remote> "+refs/tags/*:refs/tags/*"
loganfsmyth
quelle
2
Ich beziehe mich auf die Dokumentation, die mit Git für Windows 1.9.4-Preview20140611 gepackt ist (und ich vermute alle vorherigen Versionen). Ich greife mit "git fetch --help" [quote] auf diese Dokumentation zu. Tags unterliegen nicht dem Bereinigen, wenn sie nur aufgrund der automatischen Standardverfolgung des Tags oder aufgrund einer Option --tags abgerufen werden. [/
Quote
2
git fetch --prune <remote> +refs/tags/*:refs/tags/*funktionierte nicht in ZSH, aber es funktioniert in BASH
Alex
3
@Alex Das liegt nur daran, dass zsh erweitert wird, *aber wenn Sie ein einfaches Anführungszeichen setzen, sollte es in Ordnung sein.
NSF
3
@ v01pe - Es gibt jetzt eine Git-Verknüpfung --prune-Tags seit Git 2.17.0, die in der Dokumentation im Abschnitt PRUNING beschrieben ist: git-scm.com/docs/git-fetch/2.17.0 Aus dem Dokument: The - Die Option -prune-tags entspricht der Deklaration von refs / tags / *: refs / tags / * in den refspecs der Fernbedienung. Äquivalente: git fetch origin --prune --prune-tagsODER git fetch origin --prune 'refs/tags/*:refs/tags/*'ODER git fetch <url of origin> --prune --prune-tagsODERgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs
3
git fetch origin --prune --prune-tagsBeschneiden Sie sowohl Fernverfolgungszweige als auch Tags. in git 2.18 version eingecheckt.
Nummer 945
158

Wenn Sie nur die Tags möchten, die auf der Fernbedienung vorhanden sind, löschen Sie einfach alle Ihre lokalen Tags:

$ git tag -d $(git tag)

Und dann holen Sie alle Remote-Tags:

$ git fetch --tags
Newmangt
quelle
1
makellos, ich hatte ein Problem mit dem Xargs, bei dem einige Tags nicht gefunden wurden
Marcio Toshio
3
@ocroquette, ich bin mir nicht sicher, wie es schöner ist als xargs. Wenn Sie mehr Tags als ARG_MAXoder ähnliche Einschränkungen haben, funktioniert dies nicht. Unwahrscheinlich, aber möglich, und deshalb xargsist es großartig.
Paul Draper
2
"nett" ist eine subjektive Sache, jeder wird seine eigene Meinung abgeben. Über ARG_MAX stimmt das. Auf den von mir verwendeten Systemen ist ARG_MAX jedoch viel höher als die Anzahl der Tags, die ich in einem Repository habe. Daher macht mir die Einschränkung nichts aus, genauso wie es mir nichts ausmacht, wenn ich "ls * .jpg" schreibe. .
Okroquette
2
sauberste Lösung
mitsest
2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Obligatorischer Alias-Befehl. Genießen. :-)
Karl Wilbur
87

Es sieht so aus, als ob neuere Versionen von Git (ich bin auf Git v2.20) es einem erlauben, einfach zu sagen

git fetch --prune --prune-tags

Viel sauberer!

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

Sie können git auch so konfigurieren, dass Tags beim Abrufen immer beschnitten werden:

git config fetch.pruneTags true

Wenn Sie Tags nur beim Abrufen von einer bestimmten Fernbedienung entfernen möchten, können Sie diese remote.<remote>.pruneTagsOption verwenden. Zum Beispiel, um Tags beim Abrufen vom Ursprung, aber nicht von anderen Fernbedienungen immer zu beschneiden,

git config remote.origin.pruneTags true
Nicholas Carey
quelle
Tolle Sache. Ich habe es angepasst, um auf SOes zu posten -> ¿Cómo puedo eliminar las etiquetas de Git que solo tengo en local? .
Fedorqui 'SO hör auf zu schaden'
Ausgezeichnet! Ich habe einen Git-Push-Fehler mit "Git-Shell ist an Signal 13 gestorben" festgestellt. Keine Auswirkung auch mit dem erhöhten http.postbuffer. Nachdem ich GIT_TRACE_PACKET und GIT_TRACE aktiviert hatte, sah ich, wie auf ungültige Refs / Tags verschoben wurde, sodass es mit "--prune-tags" behoben wurde. Vielen Dank!
Ivellios
78

Alle Versionen von Git seit v1.7.8 verstehen sich git fetchmit einer Referenz, während seit v1.9.0 die --tagsOption die Option überschreibt --prune. Versuchen Sie Folgendes, um eine allgemeine Lösung zu finden:

$ git --version
git version 2.1.3

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

Weitere Informationen dazu, wie sich das Verhalten von "--tags" mit "--prune" in Git v1.9.0 geändert hat, finden Sie unter: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c

Chad Juliano
quelle
7
Dies sollte die beste Antwort sein. Es ist ein einzelner Git-Befehl ohne Bash, ohne Pipes und ohne Xargs.
G. Sylvie Davies
1
Ersetzt origindurch upstreamund Git korrigiert meine lokalen Tags basierend auf dem Upstream; Als nächstes wurde git push origin :<deleted-tag-name>meine GitHub-Gabel aktualisiert und das gelöschte Tag entfernt.
Leanne
3
Zumindest mit Git 2.18.0 kann man auch diese Syntax verwenden:git fetch --prune --prune-tags origin
Martin
3
Ab Git 2.17.0 wurde die Option --prune-tags aufgenommen und im Abschnitt PRUNING mit entsprechenden Befehlen im folgenden Dokument ausführlich beschrieben: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags OR git fetch origin --prune 'refs/tags/*:refs/tags/*' OR git fetch <url of origin> --prune --prune-tags ORgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
Mkisaacs
8

Git unterstützt nativ die Bereinigung lokaler Tags:

git fetch --tags --prune

Dieser Befehl ruft die neuesten Tags ab und entfernt alle gelöschten Tags.

Nirav Shah
quelle
Es scheint, es sollte "--prune" statt "--prune-tags" sein, sonst brauchte ich das, danke.
AnyDev
Ich habe ein Problem im
Quellbaum
6

Das ist eine gute Methode:

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

Quelle: demisx.GitHub.io

imjoseangel
quelle
4

Zeigen Sie den Unterschied zwischen lokalen und Remote-Tags:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag gibt die Liste der lokalen Tags an
  • git ls-remote --tags Gibt die Liste der vollständigen Pfade zu Remote-Tags an
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' analysiert nur den Tag-Namen aus der Liste der Remote-Tag-Pfade
  • Schließlich sortieren wir jede der beiden Listen und unterscheiden sie

Die Zeilen, die mit "<" beginnen, sind Ihre lokalen Tags, die sich nicht mehr im Remote-Repo befinden. Wenn es nur wenige sind, können Sie sie einzeln manuell entfernen. Wenn es viele sind, führen Sie mehr Greping und Piping durch, um sie zu automatisieren.

dotstaraj
quelle
2
Bitte erwägen Sie, Ihrem Code eine Erklärung hinzuzufügen. Dies würde die Qualität Ihrer Antwort definitiv verbessern.
Hupen
Der vollständige Befehl zum Löschen aller nicht lokal vorhandenen Remote-Tags wäre dann:diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort) | grep ">" | cut -c3- | xargs -I{} git push origin :refs/tags/{}
Daniel Gehriger
Wenn Sie einen solchen Unterschied machen und gleichzeitig den Commit-Hash anzeigen müssen: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
Piroux
Dieser Vergleich war genau das, wonach ich gesucht habe, danke. Das einzige, worüber ich verwirrt bin, ist, dass es auch ein paar Zeilen ausgibt, die nicht mit einem Pfeil beginnen <, sondern mit einer Zahl gefolgt von einem Komma und dann wie die ersten drei Zeichen eines Commit-Hash (?) Aussehen. zB 7,8d4...
Kay
3

Ich habe gerade einen git sync-local-tags-Befehl zu pivotal_git_scripts Gem fork auf GitHub hinzugefügt:

https://github.com/kigster/git_scripts

Installieren Sie das Gem und führen Sie dann "git sync-local-tags" in Ihrem Repository aus, um die lokalen Tags zu löschen, die auf der Fernbedienung nicht vorhanden sind.

Alternativ können Sie dieses Skript einfach unten installieren und es "git-sync-local-tags" nennen:


#!/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)
Konstantin Gredeskoul
quelle
3

Ich weiß, dass ich zu spät zur Party komme, aber jetzt gibt es eine schnelle Antwort darauf:

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

Ja, es ist jetzt eine Option zum Abrufen.

Wenn Sie nicht holen und nur beschneiden möchten:

git remote prune origin
Joker
quelle
1

Wie wäre es damit - alle lokalen Tags löschen und dann erneut abrufen? In Anbetracht dessen, dass Ihr Repo möglicherweise Submodule enthält:

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
tetzu0
quelle
1

TortoiseGit kann jetzt Tags vergleichen.

Das linke Protokoll befindet sich auf der Fernbedienung, das rechte ist lokal.

Geben Sie hier die Bildbeschreibung ein

Verwenden der Funktion "Tags vergleichen" im Dialogfeld "Synchronisieren":

Geben Sie hier die Bildbeschreibung ein

Siehe auch TortoiseGit Ausgabe 2973

Yue Lin Ho
quelle
1

Die gleiche Antwort wie @Richard W, jedoch für Windows (PowerShell)

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

Ich füge den Befehl SourceTreeals benutzerdefinierte Aktion unter meinem MacOS hinzu.


Einstellung Custom Actionsdurch Sourcetree-> Preferences...->Custom Actions


Script to runmuss der gitWeg sein.

Ich verwende, git fetch --prune --prune-tags originum Tags von Remote zu Local zu synchronisieren.

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

AechoLiu
quelle
0

In der neuen Git-Version (wie v2.26.2)

-P, --prune-tags Entfernen Sie vor dem Abrufen alle lokalen Tags, die auf der Fernbedienung nicht mehr vorhanden sind, wenn --prune aktiviert ist. Diese Option sollte sorgfältiger verwendet werden, im Gegensatz zu --prune werden alle lokalen Referenzen (lokale Tags) entfernt, die erstellt wurden. Diese Option ist eine Abkürzung für die Bereitstellung des expliziten Tags refspec zusammen mit --prune. Weitere Informationen finden Sie in der Dokumentation dazu.

Sie müssten also laufen:

git fetch august --prune --prune-tags
Ela Dute
quelle