Измененные имена тегов 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