Помилка "тег уже існує у віддаленій" після відтворення тегу git


142

Після виконання наведених нижче кроків я отримую таку помилку:

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. Створено сховище
  2. Клонували репо на місцевій машині.
  3. Змінив файл README, вніс зміни та підштовхнув команду.
  4. Створений тег dev:git tag dev
  5. Натиснуті теги: git push --tags
  6. Змінив файл README, вніс зміни та підштовхнув команду.
  7. Видалено тег dev, створило його ще раз і натиснуло теги:

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

Чому це відбувається?

Я на Mac. Мої друзі, які використовують Linux (Ubuntu), не мають цієї проблеми. Я знаю, що я можу використовувати git push --tags -fдля примушування оновлення тегів, але це небезпечно (наприклад, переписування комітету, зробленого помилково, лише в тег, а не у гілку).


1
Коміти не виконуються "в тегах" або "в гілках" (хоча, напевно, відчувається, що останнє саме так). Насправді назви тегів та гілок просто вказують на (один, єдиний) фіксація. Дивіться відповідь нижче.
torek

8
це працювало для мене git pull --tagsтодіgit push origin --tags
побачили

Дивіться також stackoverflow.com/questions/31929667 / ...
icc97

Відповіді:


175

Редагувати, 24 листопада 2016 року: ця відповідь, мабуть, популярна, тому я тут додаю примітку. Якщо ви заміните тег на центральному сервері, кожен, хто має старий тег - будь-який клон цього сховища центрального сервера, у якого вже є тег, може зберегти його старий тег . Тому, поки це говорить вам, як це зробити, будьте впевнені, що хочете це зробити. Ви повинні отримати всі , хто вже має «неправильний» тег , щоб видалити їх «неправильний тег» і замінити його на новий «правий тег».

Тестування в Git 2.10 / 2.11 показує, що збереження старого тегу - це поведінка за замовчуванням для клієнтів, що працюють git fetch, а оновлення - це поведінка за замовчуванням для клієнтів, які працюють git fetch --tags.

(Оригінальна відповідь випливає.)


Коли ви попросите натиснути теги, він git push --tagsнадсилає (разом з будь-якими комісіями та іншими необхідними об'єктами та будь-якими іншими оновленнями оновлення з налаштувань push) на віддалений запит на оновлення форми . (Що ж, він надсилає скільки завгодно: по одному для кожного тегу.)new-sha1 refs/tags/name

Запит на оновлення дистанційним шляхом змінюється, щоб додати old-sha1(або знову ж таки, по одному для кожного тегу), після чого доставляється на гачки попереднього прийому та / або оновлення (залежно від того, які гачки існують на пульті). Ці гачки можуть вирішити, дозволити чи відхилити створення тегу / видалення / оновлення тегу.

old-sha1Значення є все-нулі «нуль» SHA-1 , якщо тег створюється. new-sha1Є нульовою SHA-1 , якщо мітка видаляється. В іншому випадку обидва значення SHA-1 - це дійсні, дійсні значення.

Навіть не маючи гаків, є такий собі "вбудований гачок", який також запускається: пульт відмовиться переміщувати тег, якщо ви не використовуєте прапор "сила" (хоча "вбудований гачок" завжди добре з обома "додати" та "видалити"). Повідомлення про відхилення, яке ви бачите, надходить із цього вбудованого гака. (Між іншим, цей самий вбудований гачок також відхиляє оновлення гілок, які не є швидкими вперед.) 1

Але ось ось один з ключів до розуміння того, що відбувається - цей git pushкрок не має жодного поняття, чи має пульт тепер тег, і якщо так, яке значення має SHA-1. Він говорить лише "ось мій повний список тегів, разом із їх значеннями SHA-1". Пульт дистанційного порівняння значень і, якщо є доповнення та / або зміни, запускає гачки на них. (Для однакових тегів він взагалі нічого не робить. Для тегів у вас цього немає, він також нічого не робить!)

Якщо ви видалите тег локально, то pushваш натискання просто не перенесе тег. Пульт припускає, що ніяких змін не слід робити.

Якщо ви видалите тег локально, то створіть його, вказуючи на нове місце, тоді pushваш натискання передає тег, а пульт дистанційного розгляду бачить це як зміну тегу та відхиляє зміну, якщо тільки це не є примусовим натисканням.

Таким чином, у вас є два варіанти:

  • робити натиск, або
  • видалити тег на пульті.

Останнє є можливим через git push2 , навіть якщо видалити тег локально і pushING не має ніякого ефекту. Припустимо, що ім'я віддаленого є origin, і тег, який ви хочете, щоб його видалити, це dev:

git push origin :refs/tags/dev

Це вимагає від пульта видалити тег. Наявність або відсутність тегу devу вашому локальному сховищі не має значення; такий тип push, як респект, - це поштовх із чистою видаленням.:remoteref

Пульт може або не може дозволити видалення тегів (залежно від доданих додаткових гачків). Якщо це дозволить видалити, тег не буде втрачено, а по-друге git push --tags, коли у вас є локальний devтег, який вказує на якийсь об'єкт репортажу чи анотованого тегу, відправте новий devтег. На пульті devтепер буде новостворений тег, тому віддалений, ймовірно, дозволить натиснути (знову це залежить від будь-яких додаткових доданих гаків).

Силовий натиск простіший. Якщо ви хочете бути впевнені , що не її поновлення нічого іншого крім тега, просто скажіть , git pushщоб натиснути тільки , що один refspec:

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

(зверніть увагу: вам не потрібно, --tagsякщо ви чітко натискаєте лише один тег ref-spec).


1 Звичайно, причина цього вбудованого гака полягає в тому, щоб допомогти застосувати поведінку, на яку очікують інші користувачі того ж віддаленого репо: те, що гілки не перемотуються назад, а теги не рухаються. Якщо ви натискаєте, ви повинні повідомити іншим користувачам, що ви це робите, щоб вони могли виправити це. Зауважте, що "теги взагалі не рухаються" знову застосовується Git 1.8.2; попередні версії дозволять тегу "рухатися вперед" у графі фіксації, як імена гілок. Дивіться примітки до випуску git 1.8.2 .

2 Це банально, якщо ви можете увійти на пульт дистанційного керування. Просто перейдіть до сховища Git і запустіть git tag -d dev. Зауважте, що в будь-якому випадку - видалення тегу на пульті або використання git pushдля видалення - існує певний період часу, коли кожен, хто має доступ до пульта, виявить, що devтег відсутній. (Вони будуть продовжувати мати свій власний старий тег, якщо вони вже є, і вони можуть навіть підштовхнути їх старий тег назад, перш ніж ви можете натиснути на новий.)


Це відбувається лише в нових версіях git? У мене є 1.7.9.5і у мене немає цього питання ...
Ionică Bizău

2
Probalby - у мене неясна пам'ять про те, щоб git push --tagsпросто змінити тег автоматично у старих версіях git, без --force. Я протестував це в розділі 1.8.4, але вам потрібна --forceабо двоступенева техніка оновлення.
торек

2
@John ツ: update: це нова поведінка станом на 1.8.2, відповідно до приміток до випуску . Я також відредагую це у виносці 1.
torek

Не знаю, як я потрапив у цю ситуацію, але цей тег був видалений та відтворений у трійці.
RiggsFolly

4
як ти робиш силовий натиск, якщо ти не джеді?
Фонікс

54

У Mac SourceTree зніміть лише прапорець Push all теги :

введіть тут опис зображення



10
Це просто для того, щоб подолати його, не фактично вирішуючи питання. Це не вирішує відповідність пропуску імені тегів на віддаленому та локальному рівні.
amalBit

1
працює і для Windows версії! спасибі за позбавляючи нас від читання довго обслуговується відповідь , який опускає sourcetree користувачів , які не дбають , що відбувається в командному рядку :)
schlingel

19

Це досить просто, якщо ви використовуєте SourceTree .

введіть тут опис зображення В основному вам потрібно просто видалити та знову додати конфліктуючий тег:

  1. Перейдіть на вкладку Репозиторій -> Тег -> Видалити тег
  2. Виберіть назву суперечливого тегу
  3. Поставте прапорець Видалити тег з усіх видалень
  4. Натисніть Видалити
  5. Створіть новий тег з такою ж назвою для відповідного фіксації
  6. Переконайтесь у тому, щоби поставити прапорець Натисніть усі теги, натискаючи зміни на віддалений

16

Якщо ви хочете оновити тег, скажімо це1.0.0

  1. git checkout 1.0.0
  2. внести свої зміни
  3. git ci -am 'modify some content'
  4. git tag -f 1.0.0
  5. видалити віддалений тег на github: git push origin --delete 1.0.0
  6. git push origin 1.0.0

Зроблено


12

Здається, я запізнююся на це питання та / або на нього вже відповіли, але, що можна зробити, це: (у моєму випадку я мав лише один тег локально, тому я видалив старий тег і переписав його на :

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

Тоді:

git push --tags -f

Це дозволить оновити всі теги на віддаленому.

Може бути небезпечним! Використовуйте на власний ризик.


1
Це зробив це для мене! Теги були лише локально, а не у віддаленому :)
pgarciacamou

4

Причина, яку ви відхиляєте, полягає в тому, що ваш тег втратив синхронізацію з віддаленою версією. Це та ж поведінка з гілками.

синхронізувати з тегом віддалено через git pull --rebase <repo_url> +refs/tags/<TAG>та після синхронізації, вам потрібно керувати конфліктами . Якщо у вас встановлено diftool (наприклад, meld), git mergetool meldвикористовуйте його для синхронізації віддалених даних та збереження змін.

Причина, яку ви тягнете з прапором --rebase, полягає в тому, що ви хочете поставити свою роботу поверх віддаленого, щоб уникнути інших конфліктів.

Крім того, що я не розумію, це чому б ви видалили devтег і створили його знову ??? Теги використовуються для вказівки версій програмного забезпечення або важливих етапів. Приклад GIT тегів v0.1dev, v0.0.1alpha, v2.3-cr(кр - реліз - кандидат) і так далі ..


Ще один спосіб вирішити це - це питання git reflogі перейти до того моменту, як ви натиснули devтег на пульт. Скопіюйте ідентифікатор фіксації, і git reset --mixed <commmit_id_from_reflog>таким чином ви дізнаєтесь, що ваш тег синхронізувався з пультом у той момент, коли ви його натиснули, і конфліктів не виникне.


Наприклад, якщо ви хочете позначити комісію, яка наразі виробляється. Тоді вам слід буде видалити старий тег виробництва з певного комітету та створити та натиснути новий тег для комісії після нового випуску.
Ville Miekk-oja


0

Тут є кілька хороших відповідей. Особливо той, від @torek . Я думав, що я доповнив цю обробку з невеликим поясненням для тих, хто поспішає.

Підсумовуючи, що трапляється, що коли ви переміщуєте тег локально, він змінює тег з ненульового значення фіксації на інше значення. Однак, оскільки git (як поведінка за замовчуванням) не дозволяє змінювати ненульові віддалені теги, ви не можете натиснути зміни.

Обхід полягає в тому, щоб видалити тег (і поставити галочку видалити всі віддалені). Потім створіть той же тег і натисніть.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.