Изменить дату тега git (или выпуска GitHub на его основе)

96

Я добавляю релизы в свои проекты на GitHub, добавляя теги к различным коммитам в основной ветке.

В одном из своих проектов я не добавлял теги к коммитам в хронологическом порядке. (Я нашел очевидные коммиты и пометил их, а потом нашел менее очевидные, старые коммиты и пометил их.)

Теперь GitHub показывает v1.0.1 , как ток, с v0.7.0 предыдущей, и v1.1.2 предшествующее что .

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

отображение релизов и дат между gitk и GitHub

Phrogz
источник

Ответы:

119

ВНИМАНИЕ: это не сохранит сообщения тегов для аннотированных тегов.

Резюме

Для каждого тега, который необходимо изменить:

  1. Вернитесь во времени к фиксации, представляющей тег
  2. Удалить тег (локально и удаленно)
    • Это превратит ваш «Релиз» на GitHub в черновик, который вы позже сможете удалить.
  3. Повторно добавьте одноименный тег, используя магический вызов, который устанавливает его дату равной дате фиксации.
  4. Отправьте новые теги с фиксированными датами обратно на GitHub.
  5. Перейдите на GitHub, удалите все черновые выпуски и заново создайте новые выпуски с новыми тегами.

В коде:

# Fixing tag named '1.0.1'
git checkout 1.0.1               # Go to the associated commit
git tag -d 1.0.1                 # Locally delete the tag
git push origin :refs/tags/1.0.1 # Push this deletion up to GitHub

# Create the tag, with a date derived from the current head
GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a 1.0.1 -m"v1.0.1"

git push --tags                  # Send the fixed tags to GitHub

подробности

Согласно How to Tag in Git :

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

git checkout SHA1_OF_PAST_COMMIT
git tag -m"Retroactively tagging version 1.5" v1.5

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

# This moves you to the point in history where the commit exists
git checkout SHA1_OF_PAST_COMMIT

# This command gives you the datetime of the commit you're standing on
git show --format=%aD  | head -1

# And this temporarily sets git tag's clock back to the date you copy/pasted in from above
GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"

# Combining the two...
GIT_COMMITTER_DATE="$(git show --format=%aD  | head -1)" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"

Однако, если вы уже добавили тег, вы не можете использовать указанное выше, git tag -f existingtagиначе git будет жаловаться при попытке слияния:

Rammy:docubot phrogz$ git push --tags
To git@github.com:Phrogz/docubot.git
 ! [rejected]        1.0.1 -> 1.0.1 (already exists)
error: failed to push some refs to 'git@github.com:Phrogz/docubot.git'
hint: Updates were rejected because the tag already exists in the remote.

Вместо этого вы должны удалить тег локально:

git tag -d 1.0.1

Отправьте это удаление удаленно:

git push origin :refs/tags/1.0.1

На GitHub перезагрузите выпуски - выпуск теперь отмечен как «Черновик» - и удалите черновик.

Теперь добавьте тег задним числом в соответствии с приведенными выше инструкциями и, наконец, отправьте полученный тег в GitHub:

git push --tags

а затем снова добавьте информацию о выпуске GitHub.

Phrogz
источник
2
Вот сценарий bash, который удаляет и повторно добавляет каждый тег в git tag -l | while read -r tag; do `git checkout $tag && git tag -d $tag && git push origin :refs/tags/$tag && GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a $tag -m"$tag"`; done; git push --tags
репозиторий
11
Вы должны иметь возможность делать все это, не проверяя тег. Вот модификация вашего однострочника, которая была для меня намного быстрее:git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && git tag -d $tag && git push origin :refs/tags/$tag && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a $tag -m"$tag" $COMMIT_HASH ; done && git push --tags
vmrob 01
2
использование git tag -afделает -dненужным, и вы остаетесь на месте, чтобы вы могли убедиться, что все в порядке - тогда вы можетеgit push --tags -f
Mr_and_Mrs_D 02
3
@Mr_and_Mrs_D Хорошее предложение и хороший способ ограничить эту операцию одним нажатием. Имея это в виду, я думаю, что результирующий (непроверенный) однострочный git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force
текст
2
Это работает в оболочке git для PowerShell, но вы должны установить переменную окружения по-другому и сделать это в двух строках: $env:GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800"иgit tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"
roncli
18

Вот однострочный текст, основанный на некоторых комментариях в другом ответе:

git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force

ВНИМАНИЕ: это уничтожит ваши восходящие теги и не сохранит сообщения для аннотированных тегов! Убедитесь, что вы знаете, что делаете, и ОБЯЗАТЕЛЬНО не делайте этого для публичного репозитория !!!

Чтобы разбить это ...

# Loop over tags
git tag -l | while read -r tag
do

    # get the commit hash of the current tag
    COMMIT_HASH=$(git rev-list -1 $tag)

    # get the commit date of the tag and create a new tag using
    # the tag's name and message. By specifying the environment
    # environment variable GIT_COMMITTER_DATE before this is
    # run, we override the default tag date. Note that if you
    # specify the variable on a different line, it will apply to
    # the current environment. This isn't desired as probably
    # don't want your future tags to also have that past date.
    # Of course, when you close your shell, the variable will no
    # longer persist.
    GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH


done

# Force push tags and overwrite ones on the server with the same name
git push --tags --force

Спасибо @Mr_and_Mrs_D за предложение использовать одно нажатие.

vmrob
источник
3

Основываясь на других ответах, вот способ, который сохранит первую строку сообщения тега

git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH ; done
git tag -l -n1           #check by listing all tags with first line of message
git push --tags --force  #push edited tags up to remote

Бит, отвечающий за сохранение сообщений:

COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)

head -n1займет первую строку старого сообщения о фиксации. Вы можете изменить его -n2или-n3 etc, чтобы вместо этого получить две или три строки.

Если вы хотите изменить дату / время только для одного тега, вот как вы можете разбить однострочник, чтобы сделать это в своей оболочке bash:

tag=v0.1.0
COMMIT_HASH=$(git rev-list -1 $tag)
COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)
COMMIT_DATE=$(git show $COMMIT_HASH --format=%aD | head -1)
GIT_COMMITTER_DATE=$COMMIT_DATE git tag -s -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH

Ссылки:

weiji14
источник
Это здорово, спасибо. Однако в командах для изменения одного тега есть -sфлаг, которого нет в однострочном файле, поэтому я получал, error: gpg failed to sign the dataпотому что у меня нет настройки подписи для git. Эта ошибка немного сбила меня с толку.
WCH