Alterar a data da tag git (ou lançamento do GitHub com base nela)

95

Estou adicionando lançamentos aos meus projetos no GitHub, adicionando tags a vários commits no branch principal.

Em um de meus projetos, não adicionei as tags aos commits em ordem cronológica. (Eu encontrei commits óbvios e os marquei, e então eu encontrei commits mais antigos e menos óbvios e os marquei.)

Agora GitHub está mostrando v1.0.1 como corrente, com v0.7.0 precedente, e v1.1.2 anterior que .

Parece usar a data de criação de uma tag como a data de lançamento em vez do commit que está sendo marcado. Como posso editar minhas tags para que suas datas sejam as mesmas do commit que estão marcando?

mapeamento de lançamentos e datas entre gitk e GitHub

Phrogz
fonte

Respostas:

118

AVISO: Isso não preservará mensagens de tag para tags anotadas.

Resumo

Para cada tag que precisa ser alterada:

  1. Volte no tempo para o commit que representa a tag
  2. Exclua a tag (local e remotamente)
    • Isso transformará sua "versão" no GitHub em um rascunho que você pode excluir posteriormente.
  3. Adicione novamente a tag com o mesmo nome usando uma invocação mágica que define sua data para a data do commit.
  4. Envie as novas tags com datas fixas de volta ao GitHub.
  5. Vá para o GitHub, exclua todas as versões de rascunho e recrie as novas versões a partir das novas tags

Em código:

# 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

Detalhes

De acordo com Como marcar no Git :

Se você se esquecer de marcar um lançamento ou aumento de versão, pode sempre marcá-lo retroativamente como:

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

E embora seja perfeitamente utilizável, tem o efeito de colocar suas tags fora da ordem cronológica, o que pode atrapalhar os sistemas de construção que procuram pela tag "mais recente". Mas não tenha medo. Linus pensou em tudo:

# 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"

No entanto, se você já adicionou a tag, você não pode usar o acima com git tag -f existingtagou então o git reclamará quando você tentar mesclar:

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

Em vez disso, você deve remover a tag localmente:

git tag -d 1.0.1

Envie essa exclusão remotamente:

git push origin :refs/tags/1.0.1

No GitHub, recarregue as versões - a versão agora foi marcada como "Rascunho" - e remova o rascunho.

Agora, adicione a tag retroativa com base nas instruções acima e, por fim, envie a tag resultante ao GitHub:

git push --tags

e, em seguida, adicione novamente as informações de lançamento do GitHub.

Phrogz
fonte
2
Aqui está um script bash que remove e adiciona novamente todas as tags em um 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
repositório
11
Você deve ser capaz de fazer todas essas coisas sem verificar a tag. Aqui está uma modificação do seu one-liner que foi muito mais rápida para mim: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 de
2
usando git tag -aftorna -ddesnecessário e você permanece local para que possa verificar se está tudo bem - então você podegit push --tags -f
Mr_and_Mrs_D
3
@Mr_and_Mrs_D Boa sugestão e uma boa maneira de limitar esta operação a um push. Com isso em mente, acho que o resultado (não testado) de uma linha seriagit 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
vmrob
2
Isso funciona no shell git para PowerShell, mas você deve definir a variável de ambiente de maneira diferente e fazer isso em duas linhas: $env:GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800"egit tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"
roncli
18

Aqui está uma frase com base em alguns dos comentários na outra resposta:

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

AVISO: isso destruirá suas tags upstream e não preservará mensagens para tags anotadas! Certifique-se de saber o que está fazendo e DEFINITIVAMENTE não faça isso para um repositório público !!!

Para decompô-lo ...

# 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

Obrigado a @Mr_and_Mrs_D pela sugestão de usar um único push.

vmrob
fonte
3

Com base nas outras respostas, aqui está uma forma que irá preservar a primeira linha da mensagem de tag

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

O bit responsável por preservar as mensagens é:

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

head -n1pegará a primeira linha da mensagem de confirmação antiga. Você pode modificá-lo para -n2ou-n3 etc para obter duas ou três linhas.

Se você deseja alterar a data / hora para apenas uma tag, é assim que você pode quebrar o one-liner para fazer isso em seu shell 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

Referências:

weiji14
fonte
Isso é ótimo, obrigado. Nos comandos para alterar uma única tag, entretanto, há um -ssinalizador que não está presente no one-liner, então eu estava recebendo error: gpg failed to sign the dataporque não tenho a assinatura configurada para o git. Esse erro me confundiu um pouco.
semana