Ошибка «тег уже существует на удаленном компьютере» после воссоздания тега git

145

После выполнения следующих шагов я получаю следующую ошибку:

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для принудительного обновления тега, но это опасно (например, перезапись фиксации, сделанной по ошибке, только в теге, а не в ветке).

Лука Бойеру
источник
2
Коммиты не выполняются «в тегах» или «в ветках» (хотя, конечно, кажется, что последнее имеет место). Фактически, имена тегов и веток просто указывают на (одну, единственную) фиксацию. См. Ответ ниже.
torek
9
это работало для меня git pull --tagsтогдаgit push origin --tags
sawe

Ответы:

177

Изменить, 24 ноября 2016 года: этот ответ, по-видимому, популярен, поэтому я добавляю здесь примечание. Если вы замените тег на центральном сервере, любой, у кого есть старый тег - любой клон этого репозитория центрального сервера, который уже имеет этот тег, - может сохранить свой старый тег . Итак, хотя здесь рассказывается, как это сделать, будьте уверены, что вы хотите это сделать. Вам нужно будет убедить всех, у кого уже есть «неправильный» тег, удалить свой «неправильный тег» и заменить его новым «правильным тегом».

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

(Исходный ответ следует.)


Когда вы запрашиваете push-теги, git push --tagsотправляет (вместе с любыми коммитами и другими необходимыми объектами, а также любыми другими обновлениями ref из настроек 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 просто не передаст тег. Пульт ДУ предполагает, что никаких изменений вносить не следует.

Если вы удаляете тег локально, а затем создаете его, указывая на новое место, тогда pushваш push передает тег, а удаленный видит это как изменение тега и отклоняет изменение, если только это не принудительное нажатие.

Таким образом, у вас есть два варианта:

  • сделать силовой толчок, или
  • удалить метку на пульте.

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

git push origin :refs/tags/dev

Это попросит пульт удалить тег. Наличие или отсутствие тега devв вашем локальном репозитории не имеет значения; этот вид push, с refspec, представляет собой принудительное удаление.:remoteref

Пульт дистанционного управления может разрешать или не разрешать удаление тегов (в зависимости от добавленных дополнительных хуков). Если он разрешает удаление, тогда тег исчезнет, ​​а во-вторых git push --tags, когда у вас есть локальный devтег, указывающий на какой-то фиксированный или аннотированный объект репо тега, отправьте новый devтег. На пульте devтеперь будет вновь созданный тег, поэтому пульт, вероятно, разрешит push (опять же, это зависит от любых добавленных дополнительных хуков).

Force-push проще. Если вы хотите быть уверены , что не обновление ничего другого кроме тега, просто скажите , 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
Пробалби - я смутно помню, как git push --tagsпросто автоматически менял тег в старых версиях git, без --force. Я тестировал это в версии 1.8.4, и вам действительно нужна --forceтехника двухэтапного обновления.
torek
2
@John ツ: обновление: это новое поведение с версии 1.8.2, согласно примечаниям к выпуску . Я тоже отредактирую это в сноске 1.
torek
Не знаю, как я попал в такую ​​ситуацию, но тег был удален и воссоздан в мгновение ока.
RiggsFolly
4
как сделать форс-толчок, если вы не джедай?
Fonix
54

Только в Mac SourceTree снимите флажок «Отправить все теги» :

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

Ицхар
источник
3
хахаха, такой простой человек, я читал принятый ответ и думал, что собираюсь подделать это
MegaManX
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

СДЕЛАННЫЙ

Кайю Ли
источник
15

Кажется, я опаздываю по этой проблеме и / или на нее уже был дан ответ, но что можно сделать: (в моем случае у меня был только один тег локально, поэтому ... Я удалил старый тег и пометил его с помощью :

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>и после синхронизации вам необходимо управлять конфликтами . Если у вас установлен difftool (например, meld)git mergetool meld используйте его для удаленной синхронизации и сохранения изменений.

Причина, по которой вы используете флаг --rebase, заключается в том, что вы хотите разместить свою работу поверх удаленной, чтобы избежать других конфликтов.

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


Другой способ решить эту проблему - это проблема a git reflogи перейти к моменту нажатия devтега на удаленном компьютере. Скопируйте идентификатор фиксации, и git reset --mixed <commmit_id_from_reflog>таким образом вы узнаете, что ваш тег был синхронизирован с удаленным в тот момент, когда вы его нажали, и конфликтов не возникнет.

Даниэль Андрей Минкэ
источник
Например, если вы хотите пометить фиксацию, которая в настоящее время находится в разработке. Придется ли вам затем удалить старый производственный тег из определенного коммита и создать и отправить новый тег для фиксации после новой производственной версии.
Ville Miekk-oja,
2

В Windows SourceTree снимите флажок Push all tags to remotes.

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

Контанго
источник
0

Здесь есть несколько хороших ответов. Особенно от @torek . Я подумал, что добавлю этот обходной путь с небольшим объяснением для тех, кто спешит.

Подводя итог, происходит следующее: когда вы перемещаете тег локально, он меняет тег с ненулевого значения фиксации на другое значение. Однако, поскольку git (по умолчанию) не позволяет изменять удаленные теги, отличные от Null, вы не можете отправить это изменение.

Чтобы решить эту проблему, необходимо удалить тег (и установить флажок «Удалить все пульты»). Затем создайте такой же тег и нажмите.

иднавид
источник