Hapus tag git lokal yang tidak lagi ada di repositori jarak jauh


468

Kami menggunakan tag di git sebagai bagian dari proses penerapan kami. Dari waktu ke waktu, kami ingin membersihkan tag ini dengan menghapusnya dari repositori jarak jauh kami.

Ini sangat mudah. Satu pengguna menghapus tag lokal dan tag jarak jauh dalam satu set perintah. Kami memiliki skrip shell kecil yang menggabungkan kedua langkah.

Pengguna ke-2 (ke-3, ke-4, ...) sekarang memiliki tag lokal yang tidak lagi tercermin pada remote.

Saya mencari perintah yang mirip dengan git remote prune originyang membersihkan cabang pelacakan lokal yang cabang jauh telah dihapus.

Atau, perintah sederhana untuk membuat daftar tag jarak jauh dapat digunakan untuk membandingkan dengan tag lokal yang dikembalikan via git tag -l.


2
Saya mengusulkan fitur baru di git untuk mendukung pemangkasan tag basi: thread.gmane.org/gmane.comp.version-control.git/168833
Adam Monsen

1
Catatan: dengan Git 2.17 (Q2 2018), sederhana git config fetch.pruneTags trueakan membuat Anda git fetchmelakukan apa yang Anda inginkan! Lihat jawaban saya untuk pertanyaan lain ini .
VonC

2
Memposting ulang komentar dari salah satu jawaban di bawah ini: Setidaknya dengan git 2.18.0 kita juga dapat menggunakan sintaks ini: git fetch --prune --prune-tag asal
zutnop

Jawaban:


71

Pertanyaan bagus. :) Saya tidak punya jawaban yang lengkap ...

Yang mengatakan, Anda bisa mendapatkan daftar tag jarak jauh via git ls-remote. Untuk daftar tag di repositori yang dirujuk oleh origin, Anda harus menjalankan:

git ls-remote --tags origin

Itu mengembalikan daftar hash dan nama tag ramah, seperti:

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

Anda tentu bisa membuat skrip bash untuk membandingkan tag yang dihasilkan oleh daftar ini dengan tag yang Anda miliki secara lokal. Lihatlah git show-ref --tags, yang menghasilkan nama tag dalam bentuk yang sama seperti git ls-remote).


Selain itu, git show-refmemiliki opsi yang melakukan kebalikan dari apa yang Anda inginkan. Perintah berikut akan mencantumkan semua tag pada cabang jarak jauh yang tidak Anda miliki secara lokal:

git ls-remote --tags origin | git show-ref --tags --exclude-existing

Terima kasih Mike. Saya akan menggulung skrip bash saya sendiri menggunakan setiap daftar untuk perbandingan.
KEND

11
Jawaban Richard W melakukan ini jauh lebih elegan, jika Anda tidak tertarik pada skrip yang rumit.
Kyle Heironimus

1
Catatan samping tentang tag yang tidak ada secara lokal dapat diperluas untuk memeriksa lebih banyak remote:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec

Lihat jawaban berikutnya untuk solusi yang lebih sederhana
sfletche

git mendukung --prune-tag. Tidak yakin versi apa yang diperkenalkan ini. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian

1054

Ini pertanyaan yang bagus, saya bertanya-tanya tentang hal yang sama.

Saya tidak ingin menulis naskah sehingga mencari solusi yang berbeda. Kuncinya adalah menemukan bahwa Anda dapat menghapus tag secara lokal, lalu gunakan git fetch untuk "mendapatkannya kembali" dari server jarak jauh. Jika tag tidak ada pada remote, maka tag akan tetap terhapus.

Jadi, Anda perlu mengetik dua baris dalam urutan:

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

Ini:

  1. Hapus semua tag dari repo lokal. FWIW, xargs menempatkan setiap keluaran tag dengan "tag -l" pada baris perintah untuk "tag -d". Tanpa ini, git tidak akan menghapus apa pun karena tidak membaca stdin (silly git).

  2. Ambil semua tag aktif dari repo jarak jauh.

Ini bahkan berfungsi memperlakukan Windows.


57
Ini pasti jawaban git favorit saya di StackOverflow. Ini menggabungkan pengetahuan, kesederhanaan dan tipu muslihat yang menjelaskan semuanya. Hebat
tymtam

25
seperti tercantum dalam jawaban terpisah, ini menghapus SEMUA tag lokal, dan yang tidak di repo jarak jauh jelas tidak akan dibuat ulang
kedua

13
FWIW ini seharusnya sama sekali tidak perlu. Harus ada git tag prune originperintah.
void.pointer

9
Ini mungkin tidak bekerja untuk semua orang. Anda harus melakukan git fetch - tag agar berada di sisi yang aman.
Adam Kurkiewicz

5
Saya harus pergi git tag -l | %{git tag -d $_}untuk mendapatkan ini berfungsi di PowerShell. Tidak yakin tentang orang lain.
Alain

244

Dari Git v1.7.8 hingga v1.8.5.6, Anda dapat menggunakan ini:

git fetch <remote> --prune --tags

Memperbarui

Ini tidak berfungsi pada versi git yang lebih baru (dimulai dengan v1.9.0) karena komit e66ef7ae6f31f2 . Saya tidak benar-benar ingin menghapusnya karena itu berhasil bagi sebagian orang.

Seperti yang disarankan oleh "Chad Juliano", dengan semua versi Git sejak v1.7.8, Anda dapat menggunakan perintah berikut:

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

Anda mungkin perlu melampirkan bagian tag dengan tanda kutip (pada Windows misalnya) untuk menghindari ekspansi wildcard:

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

2
Saya merujuk pada dokumentasi yang dikemas dengan Git untuk Windows 1.9.4-preview20140611 (dan saya curiga semua versi sebelumnya). Saya mengakses dokumentasi tersebut dengan tag "git fetch --help" [quote] tidak dapat dipangkas jika diambil hanya karena tag default mengikuti otomatis atau karena opsi - tag. [/ Quote]
Félix Cantournet

2
git fetch --prune <remote> +refs/tags/*:refs/tags/*tidak bekerja di ZSH namun bekerja di BASH
Alex

3
@ Alex Itu hanya karena zsh mengembang *tetapi jika Anda mengutip tunggal bahwa itu harus baik-baik saja.
NSF

3
@ v01pe - sekarang ada pintasan git --prune-tag tersedia sejak git 2.17.0 dijelaskan dalam dokumentasi di bawah bagian PRUNING: git-scm.com/docs/git-fetch/2.17.0 Dari dokumen: The - -prune-tag opsi sama dengan memiliki ref / tag / *: refs / tag / * dideklarasikan di refspec dari remote. Setara: git fetch origin --prune --prune-tagsOR git fetch origin --prune 'refs/tags/*:refs/tags/*'OR git fetch <url of origin> --prune --prune-tagsORgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs

3
git fetch origin --prune --prune-tagspangkas cabang dan tag pelacakan jarak jauh. check in versi git 2.18.
Number945

158

Jika Anda hanya ingin tag yang ada di remote, cukup hapus semua tag lokal Anda:

$ git tag -d $(git tag)

Dan kemudian ambil semua tag jarak jauh:

$ git fetch --tags

1
sempurna, saya mengalami masalah dengan xargs yang tidak ditemukannya tag
Marcio Toshio

3
@roquette, saya tidak yakin bagaimana itu lebih baik daripada xargs. Jika Anda memiliki lebih banyak tag daripada ARG_MAX, atau batasan serupa, ini tidak akan berfungsi. Tidak mungkin, tetapi mungkin, dan itu sebabnya xargshebat.
Paul Draper

2
"baik" adalah hal yang subjektif, semua orang akan membuat pendapatnya sendiri. Tentang ARG_MAX, itu benar. Namun, pada sistem yang saya gunakan, ARG_MAX jauh lebih tinggi daripada jumlah tag yang saya miliki di repositori mana pun, jadi saya tidak keberatan dengan batasannya, sama seperti saya tidak keberatan tentang itu ketika saya menulis "ls * .jpg" .
ocroquette

2
solusi terbersih
mitsest

2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Perintah alias wajib. Nikmati. :-)
Karl Wilbur

87

Sepertinya versi terbaru dari Git (I'm on git v2.20) memungkinkan seseorang untuk hanya mengatakan

git fetch --prune --prune-tags

Jauh lebih bersih!

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

Anda juga dapat mengonfigurasi git untuk selalu memangkas tag saat mengambil:

git config fetch.pruneTags true

Jika Anda hanya ingin memangkas tag saat mengambil dari jarak jauh tertentu, Anda dapat menggunakan remote.<remote>.pruneTagsopsi. Misalnya, untuk selalu memangkas tag saat mengambil dari tempat asal tetapi tidak dari jarak jauh lainnya,

git config remote.origin.pruneTags true

Bagus Saya telah mengadaptasinya untuk memposting di SOes -> ¿Apakah Anda ingin menghapus semua ini dengan solo lokal? .
fedorqui 'SO stop harming'

Luar biasa! Saya bertemu kegagalan push git dengan "git-shell mati dari sinyal 13". Tidak ada efek bahkan dengan peningkatan http.postbuffer. Setelah mengaktifkan GIT_TRACE_PACKET dan GIT_TRACE, saya melihat mendorong ke ref / tag yang tidak valid sehingga menggunakan "--prune-tag" menyelesaikannya. Terima kasih banyak!
Ivellios

78

Semua versi Git sejak v1.7.8 mengerti git fetchdengan refspec, sedangkan sejak v1.9.0 --tagsopsi menimpa --pruneopsi. Untuk solusi tujuan umum, coba ini:

$ git --version
git version 2.1.3

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

Untuk membaca lebih lanjut tentang bagaimana perilaku "--tags" dengan "--prune" berubah di Git v1.9.0, lihat: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c


7
Ini harus menjadi jawaban teratas. Ini adalah perintah git tunggal, tanpa bash, tanpa pipa, dan tanpa xargs.
G. Sylvie Davies

1
Diganti origindengan upstreamdan git mengoreksi tag lokal saya berdasarkan hulu; selanjutnya git push origin :<deleted-tag-name>memperbarui garpu GitHub saya, menghapus tag yang dihapus.
leanne

3
Setidaknya dengan git 2.18.0 orang juga dapat menggunakan sintaks ini:git fetch --prune --prune-tags origin
Martin

3
Dimulai dengan git 2.17.0 - opsi --prune-tag dimasukkan dan dijelaskan dalam bagian PRUNING secara terperinci dengan perintah yang setara dalam dokumen berikut: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags ATAU git fetch origin --prune 'refs/tags/*:refs/tags/*' ATAU git fetch <url of origin> --prune --prune-tags ATAUgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs

8

Git secara alami mendukung pembersihan tag lokal:

git fetch --tags --prune

Perintah ini menarik tag terbaru dan menghapus semua tag yang dihapus.


Tampaknya itu harus "--prune" bukan "--prune-tag", kalau tidak itu yang saya butuhkan, terima kasih.
AnyDev

Saya mendapatkan masalah di pohon sumber gagal mendorong beberapa referensi ke ...: Ini berfungsi untuk saya :) Terima kasih banyak
Abhishek Thapliyal


4

Tampilkan perbedaan antara tag lokal dan jarak jauh:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag memberikan daftar tag lokal
  • git ls-remote --tags memberikan daftar path lengkap ke tag jarak jauh
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' mem-parsing hanya nama tag dari daftar jalur tag jarak jauh
  • Akhirnya kami mengurutkan masing-masing dari dua daftar dan membedakannya

Baris yang dimulai dengan "<" adalah tag lokal Anda yang tidak lagi di repo jarak jauh. Jika jumlahnya sedikit, Anda dapat menghapusnya secara manual satu per satu, jika jumlahnya banyak, Anda melakukan lebih banyak pengambilan dan pemipaan untuk mengotomatiskannya.


2
Silakan pertimbangkan untuk menambahkan beberapa penjelasan ke kode Anda. Ini secara definitif akan meningkatkan kualitas jawaban Anda.
membunyikan

Perintah lengkap untuk menghapus semua tag jarak jauh yang tidak ada secara lokal adalah: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

Jika Anda perlu membuat perbedaan dan menampilkan hash komit pada saat yang sama: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux

Perbandingan ini persis apa yang saya cari, terima kasih. Satu-satunya hal yang saya bingung adalah bahwa itu juga menghasilkan beberapa baris yang tidak dimulai dengan panah <, tetapi angka diikuti oleh koma dan kemudian apa yang tampak seperti tiga karakter pertama dari hash komit (?), misalnya 7,8d4...
Kay

3

Baru saja menambahkan perintah git sync-local-tag ke pivotal_git_scripts Gem fork di GitHub:

https://github.com/kigster/git_scripts

Instal gem, lalu jalankan "git sync-local-tag" di repositori Anda untuk menghapus tag lokal yang tidak ada pada remote.

Atau Anda dapat menginstal skrip ini di bawah ini dan menyebutnya "git-sync-local-tag":


#!/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)

3

Saya tahu saya terlambat ke pesta, tapi sekarang ada jawaban cepat untuk ini:

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

Ya, sekarang merupakan opsi untuk mengambil.

Jika Anda tidak ingin mengambil, dan cukup pangkas:

git remote prune origin

1

Bagaimana dengan ini - jatuhkan semua tag lokal dan ambil kembali? Mempertimbangkan repo Anda mungkin mengandung submodul:

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

Jawaban yang sama dengan @Richard W tetapi untuk Windows (PowerShell)

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

1

Saya menambahkan perintah SourceTreesebagai Tindakan Kustom pada MacOS saya.


Pengaturan Custom Actionsoleh Sourcetree-> Preferences...->Custom Actions


Script to runharus menjadi gitjalan.

Saya gunakan git fetch --prune --prune-tags originuntuk menyinkronkan tag dari jarak jauh ke lokal.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini


0

Dalam versi git baru (seperti v2.26.2)

-P, --prune-tag Sebelum mengambil, hapus semua tag lokal yang tidak lagi ada di remote jika --prune diaktifkan. Opsi ini harus digunakan lebih hati-hati, tidak seperti --prune, ia akan menghapus referensi lokal (tag lokal) yang telah dibuat. Opsi ini adalah singkatan untuk memberikan refspec tag eksplisit bersama dengan --prune, lihat diskusi tentang itu dalam dokumentasinya.

Jadi, Anda perlu menjalankan:

git fetch august --prune --prune-tags
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.