Xóa các thẻ git cục bộ không còn trên kho lưu trữ từ xa


468

Chúng tôi sử dụng các thẻ trong git như một phần của quy trình triển khai của chúng tôi. Thỉnh thoảng, chúng tôi muốn dọn sạch các thẻ này bằng cách xóa chúng khỏi kho lưu trữ từ xa.

Việc này thật thẳng thắn. Một người dùng xóa thẻ cục bộ và thẻ từ xa trong một bộ lệnh. Chúng tôi có một kịch bản shell nhỏ kết hợp cả hai bước.

Người dùng thứ 2 (thứ 3, thứ 4, ...) hiện có các thẻ cục bộ không còn được phản ánh trên điều khiển từ xa.

Tôi đang tìm kiếm một lệnh tương tự để git remote prune origindọn sạch các nhánh theo dõi cục bộ mà nhánh từ xa đã bị xóa.

Ngoài ra, một lệnh đơn giản để liệt kê các thẻ từ xa có thể được sử dụng để so sánh với các thẻ cục bộ được trả về qua git tag -l.


2
Tôi đã đề xuất một tính năng mới trong git để hỗ trợ cắt tỉa các thẻ cũ: thread.gmane.org/gmane.comp.version-control.git/168833
Adam Monsen

1
Lưu ý: với Git 2.17 (quý 2 năm 2018), một đơn giản git config fetch.pruneTags truesẽ giúp bạn git fetchlàm những gì bạn muốn! Xem câu trả lời của tôi cho câu hỏi khác này .
VonC

2
Đăng lại một nhận xét từ một trong những câu trả lời dưới đây: Ít nhất với git 2.18.0 người ta cũng có thể sử dụng cú pháp này: git fetch --prune --prune-tags origin
zutnop

Câu trả lời:


71

Câu hỏi hay. :) Tôi không có câu trả lời hoàn chỉnh ...

Điều đó nói rằng, bạn có thể nhận được một danh sách các thẻ từ xa thông qua git ls-remote. Để liệt kê các thẻ trong kho lưu trữ được tham chiếu bởi origin, bạn sẽ chạy:

git ls-remote --tags origin

Điều đó trả về một danh sách băm và tên thẻ thân thiện, như:

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

Bạn chắc chắn có thể kết hợp một tập lệnh bash để so sánh các thẻ được tạo bởi danh sách này với các thẻ bạn có cục bộ. Hãy xem git show-ref --tags, trong đó tạo ra các tên thẻ ở dạng tương tự như git ls-remote).


Bên cạnh, git show-refcó một tùy chọn ngược lại với những gì bạn thích. Lệnh sau sẽ liệt kê tất cả các thẻ trên nhánh từ xa mà bạn không có cục bộ:

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

Cảm ơn Mike. Tôi sẽ cuộn tập lệnh bash của riêng mình bằng cách sử dụng từng danh sách để so sánh.
kEND

11
Câu trả lời của Richard W làm điều này thanh lịch hơn nhiều, trong trường hợp bạn không quan tâm đến một kịch bản phức tạp.
Kyle Heironimus

1
Lưu ý bên lề về các thẻ không xuất hiện cục bộ có thể được mở rộng để kiểm tra thêm từ xa:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec

Xem câu trả lời tiếp theo cho một giải pháp đơn giản hơn
sfletche

git hỗ trợ --prune-tags. Không chắc chắn phiên bản này đã được giới thiệu. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian

1054

Đây là câu hỏi tuyệt vời, tôi đã tự hỏi điều tương tự.

Tôi không muốn viết một kịch bản nên đã tìm một giải pháp khác. Chìa khóa phát hiện ra rằng bạn có thể xóa một thẻ cục bộ, sau đó sử dụng git fetch để "lấy lại" từ máy chủ từ xa. Nếu thẻ không tồn tại trên điều khiển từ xa, thì nó sẽ vẫn bị xóa.

Vì vậy, bạn cần phải gõ hai dòng theo thứ tự:

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

Những

  1. Xóa tất cả các thẻ từ repo địa phương. FWIW, xargs đặt mỗi đầu ra thẻ bằng "tag -l" vào dòng lệnh cho "tag -d". Không có cái này, git sẽ không xóa bất cứ thứ gì vì nó không đọc stdin (git ngớ ngẩn).

  2. Lấy tất cả các thẻ hoạt động từ repo từ xa.

Điều này thậm chí hoạt động một điều trị trên Windows.


57
Đây phải là câu trả lời git yêu thích của tôi trên StackOverflow. Nó kết hợp kiến ​​thức, sự đơn giản và mánh khóe giải thích mọi thứ. Tuyệt vời
tymtam

25
như đã lưu ý trong một câu trả lời riêng biệt, điều này sẽ xóa TẤT CẢ các thẻ cục bộ và những thẻ không có trong repo từ xa rõ ràng sẽ không được tạo lại
thứ hai

13
FWIW này nên hoàn toàn không cần thiết. Cần có một git tag prune originmệnh lệnh.
void.pulum

9
Điều này có thể không làm việc cho tất cả mọi người. Bạn nên thực hiện git fetch --tags để ở bên an toàn.
Adam Kurkiewicz

5
Tôi đã phải đi git tag -l | %{git tag -d $_}để làm việc này trong PowerShell. Không chắc chắn về bất cứ ai khác.
Alain

244

Từ Git v1.7.8 đến v1.8.5.6, bạn có thể sử dụng:

git fetch <remote> --prune --tags

Cập nhật

Điều này không hoạt động trên các phiên bản mới hơn của git (bắt đầu với v1.9.0) vì cam kết e66ef7ae6f31f2 . Tôi thực sự không muốn xóa nó vì nó đã làm việc với một số người.

Theo đề xuất của "Chad Juliano", với tất cả phiên bản Git kể từ v1.7.8, bạn có thể sử dụng lệnh sau:

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

Bạn có thể cần phải đính kèm phần thẻ với dấu ngoặc kép (ví dụ trên Windows) để tránh mở rộng ký tự đại diện:

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

2
Tôi tham khảo tài liệu được đóng gói với Git cho Windows 1.9.4-preview20140611 (và tôi nghi ngờ tất cả các phiên bản trước đó). Tôi truy cập tài liệu đã nói với "git fetch --help" [quote] Thẻ không bị cắt xén nếu chúng được tìm nạp chỉ vì thẻ mặc định tự động theo dõi hoặc do tùy chọn --tags. [/ Quote]
Félix Cantournet

2
git fetch --prune <remote> +refs/tags/*:refs/tags/*không hoạt động trong ZSH tuy nhiên nó hoạt động trong BASH
Alex

3
@Alex Điều đó chỉ vì zsh mở rộng *nhưng nếu bạn trích dẫn một lần thì sẽ ổn thôi.
NSF

3
@ v01pe - hiện có một phím tắt git - thẻ có sẵn từ git 2.17.0 được mô tả trong tài liệu trong phần PRUNING: git-scm.com/docs/git-fetch/2.17.0 Từ tài liệu: The - Tùy chọn -prune-tags tương đương với việc có refs / tags / *: refs / tags / * được khai báo trong refspecs của điều khiển từ xa. Tương đương: git fetch origin --prune --prune-tagsHOẶC git fetch origin --prune 'refs/tags/*:refs/tags/*'HOẶC git fetch <url of origin> --prune --prune-tagsHOẶCgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs

3
git fetch origin --prune --prune-tagstỉa cả nhánh và thẻ theo dõi từ xa. kiểm tra trong phiên bản git 2.18.
Số945

158

Nếu bạn chỉ muốn những thẻ tồn tại trên điều khiển từ xa, chỉ cần xóa tất cả các thẻ cục bộ của bạn:

$ git tag -d $(git tag)

Và sau đó tìm nạp tất cả các thẻ từ xa:

$ git fetch --tags

1
Thật hoàn hảo, tôi đã gặp vấn đề với xargs mà nó không tìm thấy một số thẻ
Marcio Toshio

3
@ocroquette, tôi không chắc nó đẹp hơn thế nào xargs. Nếu bạn có nhiều thẻ hơn ARG_MAXhoặc hạn chế tương tự, điều này sẽ không hoạt động. Không thể, nhưng có thể, và đó là lý do tại sao xargslà tuyệt vời.
Paul Draper

2
"Đẹp" là một điều chủ quan, mọi người sẽ đưa ra ý kiến ​​của riêng mình. Về ARG_MAX, điều đó đúng. Tuy nhiên, trên các hệ thống tôi sử dụng, ARG_MAX cao hơn nhiều số lượng thẻ tôi có trong bất kỳ kho lưu trữ nào, vì vậy tôi không bận tâm đến giới hạn, giống như tôi không bận tâm về nó khi tôi viết "ls * .jpg" .
ocroquette

2
giải pháp sạch nhất
mitsest

2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Lệnh bí danh bắt buộc. Thưởng thức. :-)
Karl Wilbur

87

Có vẻ như các phiên bản Git gần đây (Tôi đang trên git v2.20) cho phép người ta nói đơn giản

git fetch --prune --prune-tags

Sạch sẽ hơn nhiều!

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

Bạn cũng có thể định cấu hình git để luôn lược bớt các thẻ khi tìm nạp:

git config fetch.pruneTags true

Nếu bạn chỉ muốn lược bớt các thẻ khi tìm nạp từ một điều khiển từ xa cụ thể, bạn có thể sử dụng remote.<remote>.pruneTagstùy chọn này. Ví dụ: để luôn cắt tỉa các thẻ khi tìm nạp từ nguồn gốc nhưng không phải các điều khiển từ xa khác,

git config remote.origin.pruneTags true

Tuyệt vời Tôi đã điều chỉnh nó để đăng trên SOes -> óm Cómo puedo Eliminar las etiquetas de Git que solo tengo en local? .
fedorqui 'SO ngừng làm hại'

Thông minh! Tôi đã gặp lỗi git đẩy với "git-shell chết vì tín hiệu 13". Không có hiệu lực ngay cả với http.postbuffer tăng. Sau khi bật GIT_TRACE_PACKET và GIT_TRACE, tôi thấy việc đẩy các thẻ / thẻ không hợp lệ để sử dụng "--prune-tags" giải quyết nó. Cảm ơn rất nhiều!
Ivellios

78

Tất cả các phiên bản của Git kể từ v1.7.8 đều hiểu git fetchvới một refspec, trong khi kể từ v1.9.0, --tagstùy chọn sẽ ghi đè --prunetùy chọn. Đối với một giải pháp cho mục đích chung, hãy thử điều này:

$ git --version
git version 2.1.3

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

Để đọc thêm về cách thay đổi hành vi "--tags" với "--prune" trong Git v1.9.0, hãy xem: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c


7
Đây phải là câu trả lời hàng đầu. Đó là một lệnh git duy nhất, không có bash, không có đường ống và không có xargs.
G. Sylvie Davies

1
Thay thế originbằng upstreamvà git đã sửa các thẻ cục bộ của tôi dựa trên dòng ngược; tiếp theo git push origin :<deleted-tag-name>cập nhật ngã ba GitHub của tôi, xóa thẻ đã xóa.
leanne

3
Ít nhất với git 2.18.0 người ta cũng có thể sử dụng cú pháp này:git fetch --prune --prune-tags origin
Martin

3
Bắt đầu với git 2.17.0 - tùy chọn --prune-tags được bao gồm và mô tả trong phần PRUNING chi tiết với các lệnh tương đương trong tài liệu sau: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags HOẶC git fetch origin --prune 'refs/tags/*:refs/tags/*' HOẶC git fetch <url of origin> --prune --prune-tags HOẶC HOẶCgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs

8

Git thực sự hỗ trợ dọn dẹp các thẻ cục bộ:

git fetch --tags --prune

Lệnh này lấy các thẻ mới nhất và xóa tất cả các thẻ đã xóa.


Có vẻ như nó phải là "--prune" thay vì "--prune-tags", nếu không đó là những gì tôi cần, cảm ơn.
AnyDev

Tôi gặp vấn đề trong cây nguồn không thành công khi đẩy một số ref đến ...: Nó hoạt động với tôi :) Cảm ơn rất nhiều
Abhishek Thapliyal


4

Hiển thị sự khác biệt giữa các thẻ cục bộ và từ xa:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag đưa ra danh sách các thẻ địa phương
  • git ls-remote --tags đưa ra danh sách các đường dẫn đầy đủ đến các thẻ từ xa
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' chỉ phân tích tên thẻ từ danh sách các đường dẫn thẻ từ xa
  • Cuối cùng, chúng tôi sắp xếp từng trong hai danh sách và tìm chúng

Các dòng bắt đầu bằng "<" là các thẻ cục bộ của bạn không còn trong repo từ xa. Nếu chúng là số ít, bạn có thể loại bỏ chúng theo cách thủ công từng cái một, nếu chúng là nhiều, bạn thực hiện nhiều thao tác và đường ống để tự động hóa nó.


2
Vui lòng xem xét thêm một số giải thích cho mã của bạn. Điều này chắc chắn sẽ cải thiện chất lượng câu trả lời của bạn.
bấm còi

Lệnh hoàn chỉnh để xóa tất cả các thẻ từ xa không có mặt cục bộ sau đó sẽ là: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

Nếu bạn cần tạo một khác biệt như vậy và hiển thị băm xác nhận cùng một lúc: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux 15/03/19

So sánh này là chính xác những gì tôi đang tìm kiếm, cảm ơn bạn. Điều duy nhất tôi bối rối là nó cũng xuất ra một vài dòng không bắt đầu bằng một mũi tên <, nhưng một số được theo sau bởi dấu phẩy và sau đó trông giống như ba ký tự đầu tiên của hàm băm cam kết (?), ví dụ 7,8d4...
Kay

3

Chỉ cần thêm lệnh git sync-local-tags vào pivotal_git_scripts Gem fork trên GitHub:

https://github.com/kigster/git_scripts

Cài đặt đá quý, sau đó chạy "git sync-local-tags" trong kho lưu trữ của bạn để xóa các thẻ cục bộ không tồn tại trên điều khiển từ xa.

Ngoài ra, bạn có thể chỉ cần cài đặt tập lệnh này bên dưới và gọi nó là "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)

3

Tôi biết tôi đến bữa tiệc muộn, nhưng bây giờ có câu trả lời nhanh cho việc này:

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

Vâng, bây giờ nó là một tùy chọn để tìm nạp.

Nếu bạn không muốn tìm nạp và chỉ cần cắt tỉa:

git remote prune origin

1

Làm thế nào về điều này - thả tất cả các thẻ địa phương và sau đó tìm nạp lại? Xem xét repo của bạn có thể chứa các mô hình con:

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

TortoiseGit có thể so sánh các thẻ bây giờ.

Nhật ký bên trái là trên điều khiển từ xa, bên phải là tại địa phương.

nhập mô tả hình ảnh ở đây

Sử dụng tính năng Thẻ so sánh của hộp thoại Đồng bộ hóa:

nhập mô tả hình ảnh ở đây

Cũng xem vấn đề TortoiseGit 2973


1

Câu trả lời tương tự như @Richard W nhưng dành cho Windows (PowerShell)

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

1

Tôi thêm lệnh vào SourceTreedưới dạng Hành động tùy chỉnh trên MacOS của mình.


Cài đặt Custom Actionstheo Sourcetree-> Preferences...->Custom Actions


Script to runphải là gitcon đường

Tôi sử dụng git fetch --prune --prune-tags originđể đồng bộ thẻ từ xa đến địa phương.

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


0

Trong phiên bản git mới (như v2.26.2)

-P, --prune-tags Trước khi tìm nạp, hãy xóa mọi thẻ cục bộ không còn tồn tại trên điều khiển nếu --prune được bật. Tùy chọn này nên được sử dụng cẩn thận hơn, không giống như --prune, nó sẽ xóa mọi tham chiếu cục bộ (thẻ cục bộ) đã được tạo. Tùy chọn này là một cách viết tắt để cung cấp refspec thẻ rõ ràng cùng với --prune, xem phần thảo luận về điều đó trong tài liệu của nó.

Vì vậy, bạn sẽ cần chạy:

git fetch august --prune --prune-tags
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.