Измененные имена тегов git и сообщения теперь отклоняются, потому что они уже существуют

Я пришел в проект поздно и хотел изменить старые имена и сообщения git-тегов, поэтому я обновил в соответствии с несколькими ответами здесь на stackru:

git tag newname oldname
git tag -d oldname
git push origin :refs/tags/oldname
git push --tags

Это сработало, изменив имя, но я также хотел изменить соответствующие сообщения, поэтому я сделал это:

git tag newname newname -f -m "new message for renamed tag"

Оказалось, работает, когда я смотрел через:

git tag -n1

Но когда я сейчас пытаюсь git push --tagsЯ получаю следующую ошибку:

error: failed to push some refs to 'https://blah@blah/blah/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.

Я не уверен, что делать сейчас...

1) Как я могу это исправить, чтобы я сохранил новые имена / сообщения и мог выдвигать метки без сбоев?

2) Какой был бы лучший способ сделать это в первую очередь?

благодарю вас

2 ответа

Решение

Короткий ответ

Удалите метку на пульте, затем снова нажмите, чтобы создать ее снова (или используйте --force сделать оба за один шаг).

обсуждение

Идея, лежащая в основе тега, заключается в том, что это метка, которая никогда не меняется (в отличие от идеи названия ветви, которая должна быть меткой, которая действительно изменяется). В результате Git, как правило, неохотно берет существующий тег и указывает его в новом месте.

Вот почему вы должны были использовать -f (принудительный) флаг при изменении тега:

git tag newname newname -f -m "new message for renamed tag"

Без -f, Git будет жаловаться, что тег уже существует, и ничего не делать.

Так как вы используете -m, вы получаете аннотированные теги. Это важно, потому что в противном случае вы не изменили бы тег в любом случае, и не было бы никаких проблем.

Отступление: простые против аннотированных тегов

Я упоминал выше, что и ветви (точнее, имена ветвей) и теги являются метками.

Название филиала как master обычно указывает непосредственно на некоторый коммит, по идентификатору коммита. следовательно master это то, что вы можете прочитать и перевести в коммит-идентификатор; git rev-parse Команда делает именно это:

$ git rev-parse master
3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243

Имя тега, однако, может указывать непосредственно на коммит:

$ git tag temp-tag master
$ git rev-parse temp-tag
3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
$ git tag -d temp-tag

Это называется легкой меткой.

Или он может указывать на вновь созданный объект git, представляющий тег (называемый либо объектом тега, либо объектоманнотированного тега, в зависимости от того, кто выполняет вызов и насколько явно они хотят быть). Тег, содержащий сообщение или созданный с помощью-a, делает один из этиханнотированных тегов:

$ git tag -m foo temp-tag master
$ git rev-parse temp-tag
04565b0274c13ac49a70b8e34cdb9c912e02f0ab

Обратите внимание, что этот аннотированный тег имеет другой идентификатор отmaster, На самом деле он состоит из пары элементов: легкий тег стиля, указывающий на аннотированный объект тега в хранилище; и аннотированный объект тега, указывающий на коммит:

$ git cat-file -p temp-tag | sed 's/@/ /'
object 3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
type commit
tag temp-tag
tagger Chris Torek <chris.torek gmail.com> 1461965004 -0700

foo
$ git tag -d temp-tag

Обратите вниманиеobjectстрока, которая содержит идентификатор коммита.

(В сторону: попробуйте git cat-file -p на необработанных идентификаторах, включая идентификаторы фиксации. Вы увидите вещи с tree идентификаторы; пытаться git cat-file -p на тех, возможно, пронизывающих less или же more так как они могут быть довольно длинными. Кроме того, попробуйте запустить git rev-parseна хэш-значениях3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243вещи, сокращая их, например,git rev-parse 3ad15, Все это довольно поучительно.)

Созданные объекты никогда не могут быть изменены - ни один бит, ни один единственный бит. Они могут быть удалены полностью, но не изменены. Таким образом, чтобы переместить аннотированный тег, вы должны удалить старый, а затем создать новый, который получает новый, другой хэш-идентификатор. --force флаг заставляет git сделать это за один шаг.

Вернуться к исходной проблеме

Поскольку теги не должны перемещаться, Git (теперь2) проверяет и гарантирует, что они не перемещаются. Чтобы переместить существующий облегченный или аннотированный тег, необходимо использовать --force или же -f, В случае облегченного тега это - по крайней мере в действительности - удаляет тег (но не фиксацию), а затем присоединяет новый тег с тем же именем к новому объекту. В случае аннотированного тега удаляются как облегченный тег, так и нижележащий объект с аннотированным тегом, затем создается новый базовый аннотированный объект тега и присоединяется новый облегченный тег к новому объекту аннотированного тега.

Конечно, вы можете разделить это на два отдельных шага, что делает это более очевидным.

Те же правила применяются с git push, поскольку git push имеет --force / -fВы можете скрыть (и оптимизировать) два шага в один, но это фактически удаление и повторное создание.


1 Удаление объектов на самом деле довольно сложно. Git построен вокруг добавления объектов, а не их удаления. Сборщик мусора, git gcКоторый внутри состоит из нескольких отдельных фаз мусора, которые вы можете запускать вручную - это то, что действительно удаляет вещи, в конце концов.

2 В версиях Git до 1.8.2, git push применил правила ветвления к тегам, чтобы вы могли вставить тег, если операция была ускоренной. Замечания к выпуску 1.8.2 начинаются с:

"git push $ there tag v1.2.3", используемый для разрешения замены тега v1.2.3, который уже существует в репозитории $ там, если перезаписанный тег, который вы нажимаете, указывает на коммит, который является потомком коммита, что старый тег v1.2.3 баллов в. Было обнаружено, что это подвержено ошибкам, и начиная с этого выпуска любая попытка обновить существующую ссылку в refs/tags/ иерархии потерпит неудачу без "--force".

Лучший способ - не удалить тег, а просто обновить тег до нового коммита.

# create a new annotated tag and force it to replace the old one
git tag -af <tagname> -m <message>

Теперь вставьте теги в пульт:

git push --follow-tags
Другие вопросы по тегам