Git etiketi yeniden oluşturulduktan sonra "etiket uzaktan kumandada zaten var" hatası


142

Aşağıdaki adımları çalıştırdıktan sonra aşağıdaki hatayı alıyorum:

To git@provider.com:username/repo-name.git
 ! [rejected]        dev -> dev (already exists)
error: failed to push some refs to 'git@provider.com:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.
  1. Depo oluşturuldu
  2. Yerel makinede repo kopyalandı.
  3. README dosyasını değiştirdi, değişiklikleri taahhüt etti ve taahhüdü zorladı.
  4. Oluşturulan etiket dev:git tag dev
  5. Aktarılan etiketler: git push --tags
  6. README dosyasını değiştirdi, değişiklikleri taahhüt etti ve taahhüdü zorladı.
  7. Etiket silindi dev, yeniden oluşturuldu ve etiketleri itti:

    git tag -d dev
    git tag dev
    git push --tags
    

Bu neden oluyor?

Mac kullanıyorum. Linux (Ubuntu) kullanan arkadaşlarımda bu problem yok. git push --tags -fEtiket güncellemesini zorlamak için kullanabileceğimi biliyorum , ancak bu tehlikelidir (örneğin, sadece etikette değil, şubede değil yanlışlıkla yapılan bir taahhüdü yeniden yazmak).


1
Taahhütler "etiketlerde" veya "dallarda" yapılmaz (her ne kadar sonuncusu da öyle olsa da). Aslında, etiket ve şube isimleri sadece işaret (bir tek) işlemek. Aşağıdaki cevaba bakınız.
torek

8
Bu benim için çalıştı git pull --tagssonragit push origin --tags
sawe

Yanıtlar:


175

Edit, 24 Kas 2016: Bu cevap görünüşte popüler, bu yüzden buraya bir not ekliyorum. Eğer varsa değiştirin merkezi bir sunucuda bir etiket, olan herkes eski zaten sahip olduğu merkezi sunucu veri havuzunun etiket herhangi klonu etiketi-ebil eski etiketini muhafaza . Bu size bunu nasıl yapacağınızı söylese de, gerçekten yapmak istediğinizden emin olun . Zaten silmek için "yanlış" etiketi var herkesi gerekir onların "yanlış etiket" ve yeni "doğru etiketiyle" ile değiştirin.

Git 2.10 / 2.11 sürümündeki sınama, eski etiketi tutmanın çalışan istemciler için varsayılan davranış olduğunu git fetchve güncelleştirmenin çalışan istemciler için varsayılan davranış olduğunu gösterir git fetch --tags.

(Orijinal cevap aşağıdadır.)


Etiketleri git push --tagsitmek istediğinizde, uzaktan kumandaya formun bir güncelleme isteğini gönderir (gerekli taahhütler ve diğer nesnelerle ve push ayarlarındaki diğer ref güncellemeleriyle birlikte) . (Ancak, birçok etiket gönderir: her etiket için bunlardan biri.)new-sha1 refs/tags/name

Güncelleme talebi uzaktan kumanda tarafından bir old-sha1(veya her etiket için bir tane) eklenecek şekilde değiştirilir , ardından ön alma ve / veya güncelleme kancalarına (uzaktan kumandada hangi kancalar varsa) gönderilir. Bu kancalar, etiket oluştur / sil / güncelle etiketine izin verip vermemeye karar verebilir.

old-sha1Değeri her sıfır "boş" SHA-1 etiket yaratılıyor eğer olduğunu. new-sha1Etiketi silinirse boş SHA-1 'dir. Aksi takdirde her iki SHA-1 değeri de gerçek, geçerli değerlerdir.

Kanca olmasa bile, bir tür "yerleşik kanca" da çalıştırılır: "kuvvet" bayrağını kullanmadığınız sürece uzaktan kumanda bir etiketi taşımayı reddeder ("yerleşik kanca" her ikisinde de sorun olmazsa) "ekle" ve "sil"). Gördüğünüz ret mesajı, bu yerleşik kancadan geliyor. (Bu arada, aynı yerleşik kanca aynı zamanda hızlı ileri olmayan şube güncellemelerini de reddeder.) 1

Ancak — neler olup bittiğini anlamanın anahtarlarından biri - git pushadımın uzaktan kumandanın bu etikete sahip olup olmadığı ve varsa SHA-1 değerine sahip olduğu hakkında hiçbir fikri yok. Yalnızca "SHA-1 değerleriyle birlikte eksiksiz etiket listem burada" yazıyor. Uzaktan kumanda, değerleri karşılaştırır ve ekleme ve / veya değişiklik varsa, bu kancaları çalıştırır. (Aynı etiketler için hiçbir şey yapmaz. Yapmadıkları etiketler için hiçbir şey yapmaz!)

Etiketi yerel olarak silerseniz, pushaktarmanız etiketi aktarmaz. Uzaktan kumanda herhangi bir değişiklik yapılmaması gerektiğini varsayar.

Etiketi yerel olarak silerseniz, yeni bir yere işaret ederek oluşturun, ardından pushpush'unuz etiketi aktarır ve uzaktan kumanda bunu bir etiket değişikliği olarak görür ve zorla itme olmadığı sürece değişikliği reddeder.

Böylece, iki seçeneğiniz vardır:

  • zorla itmek veya
  • uzaktan kumandadaki etiketi silin.

Etiketi yerel olarak silmek ve hiçbir etkisi olmamasına rağmen , ikincisi git push2 aracılığıyla mümkündür push. Uzaktan kumandanın adının originve silmesini istediğiniz etiketin dev:

git push origin :refs/tags/dev

Bu, uzaktan kumandadan etiketi silmesini ister. devYerel deponuzda etiketin varlığı veya yokluğu önemsizdir; bu tür pushile, bir refspec olarak, saf-silme itmek.:remoteref

Uzaktan kumanda, etiketin silinmesine izin verebilir veya vermeyebilir (eklenen ekstra kancalara bağlı olarak). Silme işlemine izin veriyorsa, etiket silinir ve bir saniye git push --tags, devbazı taahhütlü veya açıklamalı etiket repo nesnesine işaret eden yerel bir etiketiniz varsa , yeni devetiketinizi gönderin . Uzaktan kumandada, devşimdi yeni oluşturulan bir etiket olacak, bu yüzden uzaktan kumanda muhtemelen itmeye izin verecektir (yine bu, eklenen ekstra kancalara bağlıdır).

Zorla itme daha basittir. Eğer güncelleme şey emin olmak istiyorsanız diğer etiketi yerine, sadece söylemek git pushyalnızca bu refspec itmek:

git push --force origin refs/tags/dev:refs/tags/dev

(not: --tagsaçıkça yalnızca bir etiketi ref spesifikasyonuna itiyorsanız ihtiyacınız yoktur).


1 Elbette, bu yerleşik kancanın nedeni , aynı uzaktan repodaki diğer kullanıcıların beklediği davranışı güçlendirmeye yardımcı olmaktır: dalların geri sarılmaması ve etiketlerin hareket etmemesi. Zorla iterseniz, diğer kullanıcılara bunu yaptığınızı bildirmelisiniz, böylece bunu düzeltebilirler. "Etiketler hiç hareket etmiyor" un Git 1.8.2 tarafından yeni uygulandığını unutmayın; önceki sürümler, etiketin, dal adları gibi, kesinleştirme grafiğinde "ilerlemesine" olanak tanır. Bkz git 1.8.2 sürüm notlarını .

2 Uzaktan kumandadan oturum açabilmeniz önemsizdir. Sadece Git deposuna git ve koş git tag -d dev. Her iki şekilde de (uzaktan kumandadaki etiketi silme veya git pushsilmek için kullanma) , uzaktan kumandaya erişen herkesin devetiketin eksik olduğunu bulacağı bir süre olduğunu unutmayın . (Onlar sahip olmaya devam edecek kendi onlar zaten varsa, eski etiket ve hatta itmek olabilir onların yenisini zorlayabilir önce eski etiket Arkayı.)


Bu sadece git'in yeni sürümlerinde mi oluyor? Bende var 1.7.9.5ve bu sorun yok ...
Ionică Bizău

2
Probalby - Git'in git push --tagseski sürümlerinde etiketi otomatik olarak değiştirmenin belirsiz bir anısı var --force. Bunu 1.8.4 altında test ettim ve ihtiyacınız --forceya da iki aşamalı güncelleme tekniğine ihtiyacınız var.
torek

2
@John ツ: güncelleme: sürüm notlarına göre 1.8.2 itibariyle yeni bir davranış . Bunu da dipnot 1'de düzenleyeceğim.
torek

Bu duruma nasıl geldiğimi bilmiyorum, ama bu bir etiketi silip yeniden oluşturdu.
RiggsFolly

4
Eğer bir jedi değilseniz nasıl bir kuvvet itme yaparsınız?
Fonix

54

Mac SourceTree'de yalnızca Tüm etiketleri it onay kutusunun işaretini kaldırın :

resim açıklamasını buraya girin


3
hahahah çok basit bir adam, kabul edilen cevabı okuyordum ve ben bu kadar fak yapacağım sanıyordum
MegaManX

10
Bu sadece sorunu çözmeden üstesinden gelmektir. Bu, uzak ve yerel etiket adı özledim eşleşmesini çözmez.
amalBit

1
windows sürümü için de çalışıyor! komut isteminde neler olup bittiğini umursamayan Sourcetree kullanıcılarını ihmal eden uzun süredir kabul edilen cevabı okurken bizi kurtardığınız için teşekkür ederiz :)
schlingel

19

Bu var oldukça basittir kullandığınız takdirde SourceTree .

resim açıklamasını buraya girin Temel olarak, çakışan etiketi kaldırmanız ve yeniden eklemeniz yeterlidir:

  1. Depo -> Etiket -> Etiketi Kaldır sekmesine gidin
  2. Çakışan etiket adını seçin
  3. Kontrol tüm kumandalarınızdan Kaldır etiketi
  4. Kaldır'a basın
  5. Doğru işleme aynı adla yeni bir etiket oluşturun
  6. Değişikliklerinizi uzaktan kumandaya aktarırken Tüm etiketleri it seçeneğini işaretlediğinizden emin olun.

16

Bir etiketi GÜNCELLEME istiyorsanız , diyelim ki1.0.0

  1. git checkout 1.0.0
  2. değişikliklerini yap
  3. git ci -am 'modify some content'
  4. git tag -f 1.0.0
  5. github'daki uzak etiketi sil: git push origin --delete 1.0.0
  6. git push origin 1.0.0

YAPILAN


12

Görünüşe göre bu konuya geç kaldım ve / veya zaten cevaplandı, ancak yapılabilecek şey: (benim durumumda, yerel olarak sadece bir etiketim vardı.) Eski etiketi sildim ve yeniden etiketledim :

git tag -d v1.0
git tag -a v1.0 -m "My commit message"

Sonra:

git push --tags -f

Bu , uzaktan kumandadaki tüm etiketleri güncelleyecektir .

Tehlikeli olabilir! Risk size aittir.


1
Bu benim için yaptı! Etiketler sadece yerel ve uzak değildi :)
pgarciacamou

4

Reddedilmenizin nedeni , etiketinizin uzak sürümle senkronizasyonunu kaybetmesidir. Bu dallarla aynı davranıştır.

uzaktan kumandadaki etiketle senkronize edin ve senkronize git pull --rebase <repo_url> +refs/tags/<TAG>ettikten sonra çakışmaları yönetmeniz gerekir . Bir diftool yüklüyse (örn. Meld) git mergetool melduzaktan kumandayı senkronize etmek ve değişikliklerinizi korumak için kullanın.

--Rebase bayrağını çekmenizin sebebi , diğer çatışmalardan kaçınabilmeniz için çalışmanızı uzak olanın üstüne koymak istemenizdir.

Ayrıca, anlamıyorum neden devetiketi silmek ve yeniden oluşturmak ?? Etiketler, yazılım sürümlerini veya kilometre taşlarını belirtmek için kullanılır. Git etiketlerine örnek v0.1dev, v0.0.1alpha, v2.3-cr(cr - aday sürüm) ve benzeri ..


Bunu çözmenin başka bir yolu da sorun a git reflogve devetiketi uzaktan ittiğiniz ana kadar gitmek . Kopya kimliği işlemek ve git reset --mixed <commmit_id_from_reflog>Etiketinizi biliyorum bu şekilde bunu itti anda uzaktan kumanda ile senkronize oldu ve çakışma ortaya çıkacaktır.


Örneğin, şu anda üretimde olan bir taahhüdü etiketlemek istiyorsanız. Daha sonra eski üretim etiketini belirli bir işlemden silmeniz ve yeni üretim sürümünden sonra taahhüt için yeni etiket oluşturup aktarmanız gerekir.
Ville Miekk-oja

2

Windows SourceTree'de, işaretini kaldırın Push all tags to remotes.

resim açıklamasını buraya girin


0

Burada bazı iyi cevaplar. Özellikle @torek'ten . Bu işi acele edenler için küçük bir açıklama ile ekleyeceğimi düşündüm.

Özetlemek gerekirse, bir etiketi yerel olarak taşıdığınızda etiketi Null olmayan bir taahhüt değerinden farklı bir değere değiştirir. Ancak git (varsayılan davranış olarak) Null olmayan uzak etiketlerin değiştirilmesine izin vermediğinden, değişikliği zorlayamazsınız.

Çözüm, etiketi silmek (ve tüm uzaktan kumandaları kaldırmak) seçeneğini işaretlemektir. Ardından aynı etiketi oluşturun ve itin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.