Cambiar la fecha de la etiqueta git (o el lanzamiento de GitHub en función de ella)

95

Estoy agregando lanzamientos a mis proyectos en GitHub agregando etiquetas a varias confirmaciones en la rama principal.

En uno de mis proyectos no agregué las etiquetas a las confirmaciones en orden cronológico. (Encontré confirmaciones obvias y las etiqueté, y luego encontré confirmaciones más antiguas y menos obvias y las etiqueté).

Ahora GitHub está mostrando v1.0.1 como corriente, con v0.7.0 que lo precede, y v1.1.2 precedente que .

Parece utilizar la fecha de creación de una etiqueta como fecha de lanzamiento en lugar de la confirmación que se está etiquetando. ¿Cómo puedo editar mis etiquetas para que sus fechas sean las mismas que las de la confirmación que están etiquetando?

mapeo de lanzamientos y fechas entre gitk y GitHub

Phrogz
fuente

Respuestas:

118

ADVERTENCIA: Esto no conservará los mensajes de etiqueta para etiquetas anotadas.

Resumen

Para cada etiqueta que deba cambiarse:

  1. Retroceda en el tiempo hasta la confirmación que representa la etiqueta
  2. Eliminar la etiqueta (local y remotamente)
    • Esto convertirá su "Lanzamiento" en GitHub en un Borrador que luego podrá eliminar.
  3. Vuelva a agregar la etiqueta del mismo nombre mediante una invocación mágica que establece su fecha en la fecha de la confirmación.
  4. Inserte las etiquetas nuevas con fechas fijas en GitHub.
  5. Vaya a GitHub, elimine las versiones en borrador actual y vuelva a crear nuevas versiones a partir de las nuevas etiquetas

En codigo:

# 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

Detalles

Según Cómo etiquetar en Git :

Si olvida etiquetar un lanzamiento o un salto de versión, siempre puede etiquetarlo retroactivamente así:

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

Y aunque eso es perfectamente utilizable, tiene el efecto de poner sus etiquetas fuera de orden cronológico, lo que puede arruinar los sistemas de construcción que buscan la etiqueta "más reciente". Pero no tengas miedo. Linus pensó en todo:

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

Sin embargo, si ya ha agregado la etiqueta, no puede usar lo anterior con git tag -f existingtago, de lo contrario, git se quejará cuando intente fusionar:

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.

En su lugar, debe eliminar la etiqueta localmente:

git tag -d 1.0.1

Empuje esa eliminación de forma remota:

git push origin :refs/tags/1.0.1

En GitHub, vuelva a cargar Versiones (la versión ahora se ha marcado como "Borrador") y elimine el borrador.

Ahora, agregue la etiqueta retroactiva según las instrucciones anteriores y finalmente envíe la etiqueta resultante a GitHub:

git push --tags

y luego vaya y vuelva a agregar la información de la versión de GitHub nuevamente.

Phrogz
fuente
2
Aquí hay un script de bash que elimina y vuelve a agregar cada etiqueta en un repositorio de git: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
Phrogz
11
Debería poder hacer todas esas cosas sin revisar la etiqueta. Aquí hay una modificación de su 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
frase
2
el uso de git tag -afmarcas -dinnecesarias y te mantienes local para que puedas comprobar que todo está bien, entonces puedesgit push --tags -f
Mr_and_Mrs_D
3
@Mr_and_Mrs_D Buena sugerencia y una buena manera de limitar esta operación a un empujón. Con eso en mente, creo que el resultado de una sola línea (no probado) seríagit 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
Esto funciona en git shell para PowerShell, pero debe configurar la variable de entorno de manera diferente y hacerlo en dos líneas: $env:GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800"ygit tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"
roncli
18

Aquí hay un resumen basado en algunos de los comentarios de la otra respuesta:

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

ADVERTENCIA: ¡esto destruirá sus etiquetas ascendentes y no conservará los mensajes de las etiquetas anotadas! ¡Asegúrese de saber lo que está haciendo y DEFINITIVAMENTE no haga esto para un repositorio público!

Para romperlo ...

# 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

Gracias a @Mr_and_Mrs_D por la sugerencia de usar un solo empujón.

vmrob
fuente
3

Sobre la base de las otras respuestas, aquí está una manera que va a conservar la primera línea del mensaje de la etiqueta

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

El bit responsable de conservar los mensajes es:

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

head -n1tomará la primera línea del antiguo mensaje de confirmación. Puede modificarlo a -n2o -n3etc para obtener dos o tres líneas en su lugar.

Si desea cambiar la fecha / hora para una sola etiqueta, así es como puede desglosar el resumen para hacerlo en su 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

Referencias:

weiji14
fuente
Esto es genial, gracias. Sin embargo, en los comandos para cambiar una sola etiqueta, hay una -sbandera que no está presente en el one-liner, así que lo recibí error: gpg failed to sign the dataporque no tengo la firma configurada para git. Ese error me desconcertó un poco.
miércoles