¿Cómo puedo mover una etiqueta en una rama de git a una confirmación diferente?

858

Creé una etiqueta en la rama maestra llamada v0.1así:

git tag -a v0.1

Pero luego me di cuenta de que todavía había algunos cambios que necesitaba fusionar en master para la versión 0.1, así que lo hice. Pero ahora mi v0.1etiqueta está pegada (para invocar la analogía de la nota post-it) la confirmación incorrecta. Quiero que esté atascado en el commit más reciente en master, pero en cambio está atascado en el segundo commit más reciente en master.

¿Cómo puedo moverlo al commit más reciente en master?

eedeep
fuente

Respuestas:

1200

Use la -fopción para git tag:

-f
--force

    Replace an existing tag with the given name (instead of failing)

Probablemente quiera usar -fjunto con -aforzar a crear una etiqueta anotada en lugar de una no anotada.

Ejemplo

  1. Elimine la etiqueta en cualquier control remoto antes de presionar

    git push origin :refs/tags/<tagname>
    
  2. Reemplace la etiqueta para hacer referencia a la confirmación más reciente

    git tag -fa <tagname>
    
  3. Empuje la etiqueta al origen remoto

    git push origin master --tags
    
Greg Hewgill
fuente
90
Puede ser una buena idea eliminar la etiqueta en cualquier control remoto antes de presionar también, haciendo esto: git push origin :refs/tag/<tagname>y luego hacer git tag -fa <tagname>y luego git push origin master --tags. De lo contrario, podría terminar con cosas extrañas en la lista de referencias en el control remoto con caracteres ^ y {} añadidos. Gracias a Dan en codebasehq.com por señalar esto.
eedeep
47
@eedeep: Corrección menor, en lugar de :refs/tag/<tagname>serlo :refs/tags/<tagname>.
Ben Hocking
8
Esto solo funciona si no ha eliminado el código de su máquina. Si es así, la mejor respuesta es "hay muchos números en el mundo", ya que probablemente no valga la pena.
Chris Huang-Leaver
33
Si ya había empujado a su etiqueta todavía se puede actualizar la etiqueta a distancia con un empuje forzadagit push -f origin <tagname>
rc_luke
11
Lo que no se menciona aquí y en los documentos es que, de hecho, esto mueve el mensaje de etiqueta, si no se da un mensaje nuevo.
Twonky
259

Más precisamente, debe forzar la adición de la etiqueta, luego presionar con la opción --tags y -f:

git tag -f -a <tagname>
git push -f --tags
Daniel
fuente
171

Para resumir si se llama a su control remoto originy está trabajando en una mastersucursal:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • La línea 1 elimina la etiqueta en el entorno local.
  • La línea 2 elimina la etiqueta en env remoto.
  • La línea 3 agrega la etiqueta a diferentes commit
  • La línea 4 empuja el cambio al control remoto

También puede intercambiar la línea 4 para git push origin --tagsempujar todos los cambios con etiquetas de sus cambios locales.

Basándome en @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking respuestas, comentarios debajo de sus respuestas y comentarios NateS debajo de mi respuesta.

Vive
fuente
87

Elimínelo con git tag -d <tagname>y luego vuelva a crearlo en la confirmación correcta.

Stuart Golodetz
fuente
3
@eedeep: Creo que la respuesta de Greg es realmente mejor aquí para ser justos.
Stuart Golodetz
Mantenlo simple. Bórralo, haz lo que hiciste antes otra vez.
ooolala
1
Esta debería ser la respuesta aceptada, por su simplicidad. Tampoco utiliza -f force excesivamente.
chinnychinchin
48

Intento evitar algunas cosas cuando uso Git.

  1. Uso del conocimiento de los elementos internos, por ejemplo, referencias / etiquetas. Intento usar únicamente los comandos Git documentados y evito usar cosas que requieren el conocimiento del contenido interno del directorio .git. (Es decir, trato a Git como un usuario de Git y no como un desarrollador de Git).

  2. El uso de la fuerza cuando no se requiere.

  3. Exagerar las cosas. (Empujando una rama y / o muchas etiquetas, para obtener una etiqueta donde la quiero).

Así que aquí está mi solución no violenta para cambiar una etiqueta, tanto local como remotamente, sin conocimiento de los aspectos internos de Git.

Lo uso cuando una solución de software finalmente tiene un problema y necesita ser actualizada / relanzada.

git tag -d fix123                # delete the old local tag
git push github :fix123          # delete the old remote tag (use for each affected remote)
git tag fix123 790a621265        # create a new local tag
git push github fix123           # push new tag to remote    (use for each affected remote)

githubes un nombre remoto de muestra, fix123es un nombre de etiqueta de muestra y 790a621265una confirmación de muestra.

Ivan
fuente
26

Dejaré aquí solo otra forma de este comando que se adapta a mis necesidades.
Había una etiqueta v0.0.1.2que quería mover.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

Y entonces:

$ git push --tags --force
Nakilon
fuente
bien, gracias, 2 comandos simples y sencillos
Sérgio
10

Otra forma:

Mueva la etiqueta en el repositorio remoto (reemplace HEAD con cualquier otro si es necesario).

$ git push --force origin HEAD:refs/tags/v0.0.1.2

Fetch vuelve a cambiar.

$ git fetch --tags
Алексей Югов
fuente
Esto es más "transaccional" que las otras respuestas.
Justin M. Keyes
9

Alias ​​para mover una etiqueta a una confirmación diferente.

En su muestra, a medida comprometerse con e2ea1639 de hash hacer: git tagm v0.1 e2ea1639.

Para etiquetas empujadas, use git tagmp v0.1 e2ea1639.

Ambos alias te mantienen la fecha y el mensaje originales. Si lo usa git tag -d, perdió su mensaje original.

Guárdalos en tu .gitconfigarchivo

# Return date of tag. (To use in another alias)
tag-date = "!git show $1 | awk '{ if ($1 == \"Date:\") { print substr($0, index($0,$3)) }}' | tail -2 | head -1 #"

# Show tag message
tag-message = "!git show $1 | awk -v capture=0 '{ if(capture) message=message\"\\n\"$0}; BEGIN {message=\"\"}; { if ($1 == \"Date:\" && length(message)==0 ) {capture=1}; if ($1 == \"commit\" ) {capture=0}  }; END { print message }' | sed '$ d' | cat -s #"

### Move tag. Use: git tagm <tagname> <newcommit> 
tagm = "!GIT_TAG_MESSAGE=$(git tag-message $1) && GIT_COMMITTER_DATE=$(git tag-date $1) && git tag-message $1 && git tag -d $1 && git tag -a $1 $2 -m \"$GIT_TAG_MESSAGE\" #"

### Move pushed tag. Use: git tagmp <tagname> <newcommit> 
tagmp = "!git tagm $1 $2 && git push --delete origin $1 && git push origin $1 #"
Juan Antonio Tubío
fuente
1

Si desea mover una etiqueta anotada, cambiando solo la confirmación dirigida pero conservando el mensaje de anotación y otro uso de metadatos:

moveTag() {
  local tagName=$1
  # Support passing branch/tag names (not just full commit hashes)
  local newTarget=$(git rev-parse $2^{commit})

  git cat-file -p refs/tags/$tagName | 
    sed "1 s/^object .*$/object $newTarget/g" | 
    git hash-object -w --stdin -t tag | 
    xargs -I {} git update-ref refs/tags/$tagName {}
}

uso: moveTag <tag-to-move> <target>

La función anterior se desarrolló haciendo referencia a teerapap / git-move-annotated-tag.sh .

vossad01
fuente
1
Parece que esto ya no es necesario: git tag -f -a my_tagya conserva el mensaje de un mensaje anterior (con git versión 2.11.0).
Matthijs Kooijman