"Tag sudah ada di kesalahan" setelah membuat ulang tag git


142

Saya mendapatkan kesalahan berikut setelah saya menjalankan langkah-langkah di bawah ini:

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. Membuat repositori
  2. Mengkloning repo pada mesin lokal.
  3. Memodifikasi file README, melakukan perubahan dan mendorong komit.
  4. Tag yang dibuat dev:git tag dev
  5. Tag yang didorong: git push --tags
  6. Memodifikasi file README, melakukan perubahan dan mendorong komit.
  7. Tag yang dihapus dev, membuatnya lagi dan mendorong tag:

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

Mengapa ini terjadi?

Saya di Mac. Teman saya yang menggunakan Linux (Ubuntu) tidak memiliki masalah ini. Saya tahu bahwa saya dapat menggunakan git push --tags -funtuk memaksa pembaruan tag, tetapi ini berbahaya (misalnya menulis ulang komit yang dibuat hanya karena kesalahan dalam tag, bukan di cabang).


1
Komit tidak dilakukan "dalam tag" atau "di cabang" (meskipun rasanya seperti yang terakhir). Bahkan, tag dan nama cabang hanya menunjuk ke (satu, tunggal) komit. Lihat jawaban di bawah ini.
torek

8
ini bekerja untuk saya git pull --tagskemudiangit push origin --tags
Sawe

Jawaban:


175

Edit, 24 Nov 2016: jawaban ini tampaknya populer, jadi saya menambahkan catatan di sini. Jika Anda mengganti tag di server pusat, siapa pun yang memiliki tag lama — klon mana pun dari repositori server pusat yang sudah memiliki tag — dapat mempertahankan tag yang lama . Jadi, sementara ini memberi tahu Anda cara melakukannya, pastikan Anda ingin melakukannya. Anda akan perlu untuk mendapatkan semua orang yang sudah memiliki "salah" tag untuk menghapus mereka "tag yang salah" dan menggantinya dengan yang baru "tag yang tepat".

Pengujian di Git 2.10 / 2.11 menunjukkan bahwa mempertahankan tag lama adalah perilaku default untuk klien yang berjalan git fetch, dan memperbarui adalah perilaku default untuk klien yang menjalankan git fetch --tags.

(Jawaban asli berikut.)


Ketika Anda meminta tag push, git push --tagsmengirim (bersama dengan komit dan objek lain yang diperlukan dan pembaruan ref lainnya dari pengaturan push) ke remote permintaan pembaruan formulir . (Ya, ia mengirimkan banyak: salah satunya untuk setiap tag.)new-sha1 refs/tags/name

Permintaan pembaruan dimodifikasi oleh remote untuk menambahkan old-sha1(atau sekali lagi, satu untuk setiap tag), kemudian dikirim ke kait pra-terima dan / atau perbarui (mana pun kait yang ada pada remote). Kait itu dapat memutuskan apakah akan mengizinkan atau menolak tag buat / hapus / perbarui.

The old-sha1nilai adalah semua-nol "null" SHA-1 jika tag sedang dibuat. Ini new-sha1adalah null SHA-1 jika tag sedang dihapus. Jika tidak, kedua nilai SHA-1 adalah nilai nyata dan valid.

Bahkan tanpa kait, ada semacam "kait bawaan" yang juga dijalankan: remote akan menolak untuk memindahkan tanda kecuali Anda menggunakan bendera "force" (meskipun "kait bawaan" selalu baik-baik saja dengan keduanya "tambah" dan "hapus"). Pesan penolakan yang Anda lihat berasal dari pengait bawaan ini. (Kebetulan, pengait bawaan yang sama ini juga menolak pembaruan cabang yang tidak maju cepat.) 1

Tapi — inilah salah satu kunci untuk memahami apa yang terjadi — git pushlangkah tersebut tidak tahu apakah remote memiliki tag itu sekarang, dan jika demikian, apa nilai SHA-1 yang dimilikinya. Itu hanya mengatakan "inilah daftar lengkap tag saya, bersama dengan nilai SHA-1 mereka". Remote membandingkan nilainya dan jika ada tambahan dan / atau perubahan, jalankan hooks pada itu. (Untuk tag yang sama, tidak melakukan apa-apa. Untuk tag yang tidak Anda miliki, tag juga tidak berfungsi!)

Jika Anda menghapus tag secara lokal, maka push, dorongan Anda tidak akan mentransfer tag. Remote menganggap tidak ada perubahan yang harus dilakukan.

Jika Anda menghapus tag secara lokal, kemudian membuatnya menunjuk ke tempat baru, lalu push, push Anda mentransfer tag, dan remote melihat ini sebagai tag-perubahan dan menolak perubahan, kecuali itu push-paksa.

Dengan demikian, Anda memiliki dua opsi:

  • lakukan push-paksa, atau
  • hapus tag pada remote.

Yang terakhir adalah mungkin melalui git push2 meskipun menghapus tag secara lokal dan pushing tidak berpengaruh. Dengan asumsi nama remote adalah origin, dan tag yang ingin Anda hapus adalah dev:

git push origin :refs/tags/dev

Ini meminta remote untuk menghapus tag. Ada atau tidaknya tag devdi repositori lokal Anda tidak relevan; jenis ini push, dengan sebagai refspec, adalah dorongan penghapusan murni.:remoteref

Remote mungkin atau mungkin tidak mengizinkan penghapusan tag (tergantung pada kait tambahan yang ditambahkan). Jika memungkinkan penghapusan, maka tag akan hilang, dan yang kedua git push --tags, ketika Anda memiliki devtag lokal yang menunjuk ke beberapa objek repo tag berkomitmen atau beranotasi, kirim devtag baru Anda . Pada remote, devsekarang akan menjadi tag yang baru dibuat, jadi remote mungkin akan memungkinkan push (sekali lagi ini tergantung pada kait tambahan yang ditambahkan).

Push-force lebih sederhana. Jika Anda ingin memastikan untuk tidak memperbarui apa-apa lain selain tag, hanya memberitahu git pushuntuk mendorong hanya itu satu refspec:

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

(catatan: Anda tidak perlu --tagsjika Anda secara eksplisit mendorong hanya satu ref-spec tag).


1 Tentu saja, alasan kait bawaan ini adalah untuk membantu menegakkan perilaku yang diharapkan oleh pengguna lain dari repo jarak jauh yang sama: bahwa cabang tidak diputar ulang, dan tag tidak bergerak. Jika Anda mendorong-paksa, Anda harus memberi tahu pengguna lain bahwa Anda melakukan ini, sehingga mereka dapat memperbaikinya. Perhatikan bahwa "tag tidak bergerak sama sekali" baru diberlakukan oleh Git 1.8.2; versi sebelumnya akan memungkinkan tag untuk "bergerak maju" dalam grafik komit, seperti nama cabang. Lihat catatan rilis git 1.8.2 .

2 Ini sepele jika Anda bisa masuk di kendali jarak jauh. Buka saja repositori Git di sana dan jalankan git tag -d dev. Perhatikan bahwa bagaimanapun juga — menghapus tag pada remote, atau menggunakan git pushuntuk menghapusnya — ada periode waktu ketika siapa pun yang mengakses remote akan menemukan bahwa devtag tersebut hilang. (Mereka akan terus memiliki tag lama mereka sendiri , jika mereka sudah memilikinya, dan mereka bahkan mungkin mendorong kembali tag lama mereka sebelum Anda dapat mendorong yang baru.)


Apakah ini hanya terjadi di git versi baru? Saya punya 1.7.9.5dan saya tidak punya masalah ini ...
Ionică Bizău

2
Probalby — Saya memiliki ingatan yang samar tentang git push --tagshanya mengubah tag secara otomatis di versi git yang lebih lama, tanpa --force. Saya menguji ini di bawah 1.8.4, dan Anda memang perlu --force, atau teknik dua tahap pembaruan.
torek

2
@John ツ: perbarui: itu perilaku baru pada 1.8.2, menurut catatan rilis . Saya juga akan mengeditnya di catatan kaki 1.
torek

Tidak tahu bagaimana saya masuk ke dalam situasi ini, tetapi tag ini dihapus dan dibuat ulang dalam trice.
RiggsFolly

4
bagaimana Anda melakukan push-force jika Anda bukan seorang jedi?
Fonix

54

Di Mac SourceTree hanya hapus centang pada kotak centang Push all tags :

masukkan deskripsi gambar di sini


3
hahahah lelaki yang sangat sederhana, saya sedang membaca jawaban yang diterima dan saya pikir saya akan
memalsukan

10
Ini hanya untuk mengatasinya tanpa benar-benar menyelesaikan masalah. Ini tidak memecahkan kecocokan nama tag di jarak jauh dan lokal.
amalBit

1
berfungsi untuk versi windows juga! terima kasih telah menyelamatkan kami dari membaca jawaban yang telah lama diterima yang menghilangkan pengguna sourcetree yang tidak peduli dengan apa yang terjadi pada command prompt :)
schlingel

19

Ini cukup sederhana jika Anda menggunakan SourceTree .

masukkan deskripsi gambar di sini Pada dasarnya Anda hanya perlu menghapus dan menambahkan kembali tag yang bertentangan:

  1. Buka tab Repositori -> Tag -> Hapus Tag
  2. Pilih nama tag yang bertentangan
  3. Periksa Hapus tag dari semua remote
  4. Tekan Hapus
  5. Buat tag baru dengan nama yang sama dengan komit yang tepat
  6. Pastikan untuk memeriksa Dorong semua tag saat mendorong perubahan Anda ke jarak jauh

16

Jika Anda ingin UPDATE tag, katakanlah itu1.0.0

  1. git checkout 1.0.0
  2. buat perubahan Anda
  3. git ci -am 'modify some content'
  4. git tag -f 1.0.0
  5. hapus tag jarak jauh di github: git push origin --delete 1.0.0
  6. git push origin 1.0.0

DIBUAT


12

Tampaknya saya terlambat dalam masalah ini dan / atau sudah dijawab, tetapi, yang bisa dilakukan adalah: (dalam kasus saya, saya hanya punya satu tag secara lokal jadi .. Saya menghapus tag yang lama dan mem-retagnya dengan :

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

Kemudian:

git push --tags -f

Itu akan memperbarui semua tag pada jarak jauh.

Bisa berbahaya! Gunakan dengan risiko sendiri.


1
Ini berhasil untukku! Tag hanya lokal dan tidak di remote :)
pgarciacamou

4

Alasan Anda ditolak adalah bahwa tag Anda kehilangan sinkronisasi dengan versi jarak jauh. Ini adalah perilaku yang sama dengan cabang.

sinkronkan dengan tag dari jarak jauh via git pull --rebase <repo_url> +refs/tags/<TAG>dan setelah Anda menyinkronkan, Anda perlu mengelola konflik . Jika Anda memiliki diftool diinstal (mis. Berbd) git mergetool meldgunakan itu untuk menyinkronkan jarak jauh dan menyimpan perubahan Anda.

Alasan Anda menggunakan flag --rebase adalah karena Anda ingin meletakkan pekerjaan Anda di atas yang jauh sehingga Anda dapat menghindari konflik lainnya.

Juga, apa yang saya tidak mengerti adalah mengapa Anda menghapus devtag dan membuatnya kembali ??? Tag digunakan untuk menentukan versi perangkat lunak atau tonggak sejarah. Contoh tag git v0.1dev, v0.0.1alpha, v2.3-cr(cr - kandidat rilis) dan sebagainya ..


Cara lain yang bisa Anda selesaikan adalah mengeluarkan a git reflogdan buka saat Anda mendorong devtag pada jarak jauh. Salin id komit dan git reset --mixed <commmit_id_from_reflog>dengan cara ini Anda tahu tag Anda telah disinkronkan dengan remote pada saat Anda mendorongnya dan tidak ada konflik akan muncul.


Misalnya jika Anda ingin menandai komit yang saat ini dalam produksi. Apakah Anda kemudian harus menghapus tag produksi lama dari komit tertentu, dan membuat dan mendorong tag baru untuk komit setelah rilis produksi baru.
Ville Miekk-oja

2

Di Windows SourceTree, hapus centang Push all tags to remotes.

masukkan deskripsi gambar di sini


0

Beberapa jawaban bagus di sini. Terutama yang oleh @torek . Saya pikir saya akan menambahkan pekerjaan ini dengan sedikit penjelasan bagi mereka yang terburu-buru.

Untuk meringkas, yang terjadi adalah ketika Anda memindahkan tag secara lokal, itu mengubah tag dari nilai komit non-Null ke nilai yang berbeda. Namun, karena git (sebagai perilaku default) tidak memungkinkan untuk mengubah tag jarak jauh non-Null, Anda tidak dapat mendorong perubahan.

Solusi untuk menghapus tag (dan centang hapus semua remote). Kemudian buat tag yang sama dan tekan.

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.