"Тег уже существует в удаленном" ошибка после воссоздания тега git
Я получаю следующую ошибку после выполнения следующих действий:
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.
- Создан репозиторий
- Клонировал репо на локальной машине.
- Модифицировал файл README, зафиксировал изменения и отправил коммит.
- Созданный тег
dev
:git tag dev
- Размещенные метки
git push --tags
- Модифицировал файл README, зафиксировал изменения и отправил коммит.
Удаленный тег
dev
, создал его снова и нажал теги:git tag -d dev git tag dev git push --tags
Почему это происходит?
Я на Mac. Мои друзья, которые используют Linux (Ubuntu), не имеют этой проблемы. Я знаю, что я могу использовать git push --tags -f
принудительно обновлять тег, но это опасно (например, переписать сделанный по ошибке коммит только в теге, а не в ветке).
9 ответов
Редактировать, 24 ноября 2016 г.: этот ответ, по-видимому, популярен, поэтому я добавляю примечание здесь. Если вы замените тег на центральном сервере, любой, у кого есть старый тег - любой клон этого репозитория центрального сервера, у которого уже есть тег - может сохранить его старый тег. Так что, пока это говорит вам, как это сделать, будьте уверены, что хотите это сделать. Вам нужно будет заставить всех, у кого уже есть "неправильный" тег, удалить свой "неправильный тег" и заменить его новым "правильным тегом".
Тестирование в Git 2.10/2.11 показывает, что сохранение старого тега является поведением по умолчанию для клиентов, работающих git fetch
и обновление является поведением по умолчанию для работающих клиентов git fetch --tags
,
(Оригинальный ответ следует.)
Когда вы просите нажать метки, git push --tags
отправляет (вместе со всеми коммитами и другими необходимыми объектами и любыми другими обновлениями ref из настроек push) удаленному серверу запрос на обновление формы new-sha1 refs/tags/name
, (Ну, он отправляет, однако, много: по одному для каждого тега.)
Запрос на обновление модифицируется пультом дистанционного управления, чтобы добавить old-sha1
(или опять же, по одному для каждого тега), затем доставляется в ловушки предварительного получения и / или обновления (какие бы ловушки не были на пульте дистанционного управления). Эти хуки могут решить, разрешить или отклонить тег создания / удаления / обновления.
old-sha1
значение - это ноль " SHA-1" из всех нулей, если тег создается. new-sha1
является нулевым SHA-1, если тег удаляется. В противном случае оба значения SHA-1 являются действительными, действительными значениями.
Даже без хуков, есть своего рода "встроенный хук", который также запускается: пульт дистанционного управления откажется перемещать тег, если вы не используете флаг "force" (хотя "встроенный хук" всегда в порядке с обоими "добавить" и "удалить"). Сообщение об отклонении, которое вы видите, исходит от этого встроенного хука. (Между прочим, этот же встроенный хук также отклоняет обновления веток, которые не являются ускоренными.) 1
Но - вот один из ключей к пониманию того, что происходит - git push
step не знает, есть ли сейчас у этого тега пульт, и если да, то какое значение SHA-1 он имеет. В нем говорится только "вот мой полный список тегов вместе с их значениями SHA-1". Пульт ДУ сравнивает значения и, если есть дополнения и / или изменения, запускает их. (Для тегов, которые одинаковы, он вообще ничего не делает. Для тегов, которых у вас нет, они тоже ничего не делают!)
Если вы удалите тег локально, то push
твой пуш просто не передает тэг. Пульт ДУ предполагает, что никаких изменений не должно быть.
Если вы удалите тег локально, затем создайте его, указывая на новое место, затем push
ваш push передает тег, а пульт видит это как изменение тега и отклоняет изменение, если только это не принудительное нажатие.
Таким образом, у вас есть два варианта:
- сделать принудительный толчок, или
- удалить метку на пульте.
Последнее возможно через git push
2, хотя удаление тега локально и push
Инг не имеет никакого эффекта. Предполагая, что имя пульта origin
и тег, который вы хотите удалить, dev
:
git push origin :refs/tags/dev
Это просит пульт дистанционного управления удалить тег. Наличие или отсутствие тега dev
в вашем локальном хранилище это неактуально; Этот вид push
, с :remoteref
в качестве refspec, это push-удаление.
Пульт дистанционного управления может разрешать или запрещать удаление тегов (в зависимости от добавленных дополнительных хуков). Если это позволяет удаление, то тег исчезнет, и второй git push --tags
когда у вас есть местный dev
тег, указывающий на какой-либо коммит или аннотированный объект тега репо, отправьте ваш новый dev
тег. На пульте, dev
теперь будет вновь созданным тегом, так что пульт, вероятно, разрешит толчок (опять же, это зависит от добавленных дополнительных хуков).
Сила-толчок проще. Если вы хотите быть уверены, что не обновляете ничего, кроме тега, просто скажите git push
нажать только одну ссылку:
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
тег отсутствует. (У них по-прежнему будет свой собственный старый тег, если он у него уже есть, и они могут даже сдвинуть свой старый тег обратно, прежде чем вы сможете нажать новый.)
Это довольно просто, если вы используете SourceTree.
По сути, вам просто нужно удалить и повторно добавить конфликтующий тег:
- Перейти на вкладку Репозиторий -> Тег -> Удалить тег
- Выберите конфликтующее имя тега
- Установите флажок Удалить тег со всех пультов.
- Нажмите Удалить
- Создайте новый тег с тем же именем для правильного коммита
- Обязательно установите флажок Push all tags при отправке изменений на удаленный
Кажется, я опоздал на этот вопрос и / или на него уже был дан ответ, но что можно было сделать: (в моем случае у меня был только один тег локально, так что.. я удалил старый тег и повторно пометил его с помощью:
git tag -d v1.0
git tag -a v1.0 -m "My commit message"
Затем:
git push --tags -f
Это обновит все теги на пульте.
Может быть опасно! Используйте на свой страх и риск.
Если вы хотите обновить тег, скажем так 1.0.0
git checkout 1.0.0
- внесите свои изменения
git ci -am 'modify some content'
git tag -f 1.0.0
- удалить удаленный тег на github:
git push origin --delete 1.0.0
git push origin 1.0.0
СДЕЛАННЫЙ
Хотя я до сих пор удивляюсь, как я попал в это состояние...
Я нашел простое решение: удалить все локальные повторяющиеся теги, а затем извлечь эти теги из удаленного. Такой как:
git tag -d some-tag
git pull --tags
Больше никаких конфликтов или предупреждений.
Возможно, вы захотите заранее создать резервную копию локального репозитория.
Причина, по которой вы получаете отклонение, заключается в том, что ваш тег потерял синхронизацию с удаленной версией. Это то же самое поведение с ветками.
синхронизировать с тегом с пульта через 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>
Таким образом, вы знаете, что ваш тег был синхронизирован с пультом в тот момент, когда вы его нажали, и никаких конфликтов не возникнет.
Здесь есть несколько хороших ответов. Особенно от @torek. Я подумал, что добавлю этот обходной путь с небольшим объяснением для тех, кто спешит.
Подводя итог, происходит следующее: когда вы перемещаете тег локально, он меняет тег с ненулевого значения фиксации на другое значение. Однако, поскольку git (по умолчанию) не позволяет изменять удаленные теги, отличные от Null, вы не можете отправить это изменение.
Чтобы решить эту проблему, необходимо удалить тег (и установить флажок "Удалить все пульты"). Затем создайте такой же тег и нажмите.