Как переименовать тег Git?

Сегодня я просматривал логи проекта и понял, что некоторое время назад я нажал на имя тега. Есть ли способ переименовать тег? Google не нашел ничего полезного.

Я понимаю, что могу проверить версию с тегами и создать новый тег, я даже попробовал это. Но это, кажется, создает объект тега, который не совсем прав. Для одного,

git tag -l

перечисляет его не по порядку относительно всех других тегов. Я понятия не имею, насколько это важно, но это заставляет меня поверить, что новый объект тега не совсем то, что я хочу. Я могу с этим смириться, потому что мне действительно важно, чтобы имя тега соответствовало документации, но я бы предпочел сделать это "правильно", предполагая, что есть правильный способ сделать это.

11 ответов

Вот как я переименую тег old в new:

git tag new old
git tag -d old
git push origin :refs/tags/old
git push --tags

Двоеточие в команде push удаляет тег из удаленного хранилища. Если вы этого не сделаете, Git создаст старую метку на вашем компьютере, когда вы потянете.

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

git pull --prune --tags

Первоначальный вопрос заключался в том, как переименовать тег, что легко: сначала создайте NEW как псевдоним OLD: git tag NEW OLD затем удалите СТАРЫЙ: git tag -d OLD,

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

В дополнение к другим ответам:

Сначала вам нужно создать псевдоним старого имени тега, указывающий на исходный коммит:

git tag new old^{}

Затем вам нужно удалить старый локально:

git tag -d old

Затем удалите тег на вашем удаленном местоположении (ях):

# Check your remote sources:
git remote -v
# The argument (3rd) is your remote location,
# the one you can see with `git remote`. In this example: `origin`
git push origin :refs/tags/old

Наконец, вам нужно добавить новый тег в удаленное местоположение. Пока вы этого не сделаете, новые теги не будут добавлены:

git push origin --tags

Повторяйте это для каждого удаленного местоположения.

Помните о последствиях изменения тега Git для потребителей пакета!

На этой вики-странице есть интересный однострочный текст, который напоминает нам, что мы можем нажать несколько ссылок:

git push origin <refs/tags/old-tag>:<refs/tags/new-tag> :<refs/tags/old-tag> && git tag -d <old-tag>

и попросить других клонеров сделать git pull --prune --tags

Так что идея состоит в том, чтобы подтолкнуть:

  • <new-tag> за каждый коммит, на который ссылается <old-tag>: <refs/tags/old-tag>:<refs/tags/new-tag>,
  • удаление<old-tag>: :<refs/tags/old-tag>

См. В качестве примера " Изменить соглашение об именовании тегов в репозитории git?".

Если он опубликован, вы не можете удалить его (не рискуя быть заархивированным и обработанным). "Git way" - это сделать:

Нормальная вещь. Просто признай, что ты облажался, и используй другое имя. Другие уже видели одно имя тега, и если вы сохраняете одно и то же имя, вы можете оказаться в ситуации, когда два человека имеют "версию X", но на самом деле они имеют разные "X". Так что просто назовите это "X.1" и покончите с этим.

С другой стороны,

Безумная вещь. Вы действительно хотите назвать новую версию "X", хотя другие уже видели старую. Так что просто используйте git-tag -f снова, как будто вы еще не опубликовали старый.

Это так безумно, потому что:

Git не изменяет (и не должен) изменять теги пользователей. Так что, если кто-то уже получил старый тег, выполнение git-pull на вашем дереве не должно просто заставить их перезаписать старый.

Если кто-то получил от вас тег выпуска, вы не можете просто изменить тег для него, обновив свой собственный. Это большая проблема безопасности, поскольку люди ДОЛЖНЫ иметь возможность доверять своим именам тегов. Если вы действительно хотите сделать безумную вещь, вы должны просто признать это и сказать людям, что вы все испортили.

Все предоставлено man-страницами.

В качестве дополнения к другим ответам я добавил псевдоним, чтобы сделать все это за один шаг, с более знакомым ощущением команды *nix move. Аргумент 1 - это имя старого тега, аргумент 2 - это имя нового тега.

[alias]
    renameTag = "!sh -c 'set -e;git tag $2 $1; git tag -d $1;git push origin :refs/tags/$1;git push --tags' -"

Использование:

git renametag old new

Следуйте трехэтапному подходу для одного или нескольких тегов.

Шаг 1: Определите идентификатор коммита / объекта для коммита, на который указывает текущий тег

     command: git rev-parse <tag name>
     example: git rev-parse v0.1.0-Demo
     example output: db57b63b77a6bae3e725cbb9025d65fa1eabcde

Шаг 2: Удалить тег из хранилища

     command: git tag -d <tag name>
     example: git tag -d v0.1.0-Demo
     example output: Deleted tag 'v0.1.0-Demo' (was abcde)

Шаг 3. Создайте новый тег, указывающий на тот же идентификатор фиксации, на который указывал старый тег

     command: git tag -a <tag name>  -m "appropriate message" <commit id>
     example: git tag -a v0.1.0-full  -m "renamed from v0.1.0-Demo" db57b63b77a6bae3e725cbb9025d65fa1eabcde
     example output: Nothing or basically <No error>

Когда локальный git готов к изменению имени тега, эти изменения могут быть перенесены обратно в источник, чтобы другие могли их принять.

Этот ответ решает проблему путем создания дубликата аннотированного тега, включая всю информацию тега, такую ​​как тег, сообщение и дату тега, с использованием информации тега из существующего тега.

      SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref \
"refs/tags/$SOURCE_TAG" --format="%($1)" ; }; \
GIT_COMMITTER_NAME="$(deref taggername)" \
GIT_COMMITTER_EMAIL="$(deref taggeremail)" \
GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" \
"$(deref "*objectname")" -a -m "$(deref contents)"

git tag -d old

git push origin new :old

Обновите SOURCE_TAGа также NEW_TAGзначения, соответствующие вашим старым и новым именам тегов.

Мотивация

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

Цель

The git-tagдокументация определяет части аннотированного тега. Чтобы переименование действительно было неразличимым, эти элементы должны быть одинаковыми в новом теге.

Пометить объекты (созданные с помощью -a, -s, или же -u) называются «аннотированными» тегами; они содержат дату создания, имя тегера и адрес электронной почты, сообщение тега и необязательную подпись GnuPG.

В этом ответе я обращаюсь только к неподписанным тегам, хотя расширение этого решения на подписанные теги должно быть простым делом.

Процедура

В примере используется аннотированный тег с именем, который будет переименован в .

Шаг 1. Получите информацию о существующем теге

Во-первых, нам нужно получить информацию для существующего тега. Это может быть достигнуто с помощьюfor-each-ref:

Команда:

      git for-each-ref refs/tags --format="\
Tag name: %(refname:short)
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag message: %(contents)"

Выход:

      Tag commit: 88a6169
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

Шаг 2. Создайте дубликат тега локально

Дубликат тега с новым именем можно создать, используя информацию, собранную на шаге 1 из существующего тега.

Идентификатор фиксации и сообщение фиксации могут быть переданы непосредственно в .

Информация о теге (имя, адрес электронной почты и дата) может быть установлена ​​с помощью переменных среды git . GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_DATE. Использование даты в этом контексте описано в документации On Backdating Tags для git tag; два других я выяснил путем экспериментов.

      GIT_COMMITTER_NAME="John Doe" GIT_COMMITTER_EMAIL="j.doe@example.com" \
GIT_COMMITTER_DATE="Mon Dec 14 12:44:52 2020 -0600" git tag new cda5b4d -a -m "Initial tag

Body line 1.
Body line 2.
Body line 3."

Наглядное сравнение двух тегов показывает, что они идентичны во всех важных аспектах. Единственное, что здесь отличается, — это ссылка фиксации самого тега, что ожидается, поскольку это два разных тега.

Команда:

      git for-each-ref refs/tags --format="\
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag name: %(refname:short)
Tag message: %(contents)"

Выход:

      Tag commit: 580f817
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: new
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

Tag commit: 30ddd25
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

В виде одной команды, включая получение текущих данных тега:

      SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref "refs/tags/$SOURCE_TAG" --format="%($1)" ; }; GIT_COMMITTER_NAME="$(deref taggername)" GIT_COMMITTER_EMAIL="$(deref taggeremail)" GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" "$(deref "*objectname")" -a -m "$(deref contents)"

Шаг 3. Удалите существующий тег локально

Далее существующий тег следует удалить локально. Этот шаг можно пропустить, если вы хотите сохранить старый тег вместе с новым (т.е. дублировать тег, а не переименовывать его).

      git tag -d old

Шаг 4. Отправка изменений в удаленный репозиторий

Предполагая, что вы работаете из удаленного репозитория, теперь изменения могут быть отправлены с помощьюgit push:

      git push origin new :old

Это подталкивает newтег и удаляет oldярлык.

Для любителей приключений это можно сделать одной командой:

mv .git/refs/tags/OLD .git/refs/tags/NEW

Легкая часть - переименование локальных тегов. Более трудная часть - отдаленные. Идея этого трюка состоит в том, чтобы дублировать старый тег / ветку на новый и удалить старый без извлечения.

Удаленное переименование тега / Удаленная ветка → преобразование тега: (Примечание: :refs/tags/)

git push <remote_name> <old_branch_or_tag>:refs/tags/<new_tag> :<old_branch_or_tag>

Удаленное переименование ветви / Удаленный тег → преобразование ветви: (Примечание: :refs/heads/)

git push <remote_name> <old_branch_or_tag>:refs/heads/<new_branch> :<old_branch_or_tag>

Выход переименовывает удаленный тег:

D:\git.repo>git push gitlab App%2012.1%20v12.1.0.23:refs/tags/App_12.1_v12.1.0.23 :App%2012.1%20v12.1.0.23

Total 0 (delta 0), reused 0 (delta 0)
To https://gitlab.server/project/repository.git
 - [deleted]               App%2012.1%20v12.1.0.23
 * [new tag]               App%2012.1%20v12.1.0.23 -> App_12.1_v12.1.0.23

Независимо от проблем, связанных с отправкой тегов и переименованием тегов, которые уже были переданы, в случае, если тег для переименования является аннотированным, вы можете сначала скопировать его благодаря следующей однострочной командной строке:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}

Затем вам просто нужно удалить старый тег:

git tag -d old_tag

Я нашел эту командную строку благодаря следующим двум ответам:

Редактировать:
Возникли проблемы с использованием автоматической синхронизации настроек тегов fetch.pruneTags=true (как описано в /questions/18354534/v-git-kak-mne-sinhronizirovat-moi-tegi-s-udalennyim-serverom/18354540#18354540), я лично предлагаю сначала скопировать новый тег на сервер, а затем удалить старый. Таким образом, новый тег не удаляется случайным образом при удалении старого тега, и синхронизация тегов хотела бы удалить новый тег , которого еще нет на сервере. Так, например, все вместе мы получаем:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}
git push --tags
git tag -d old_tag
git push origin :refs/tags/old_tag
Другие вопросы по тегам