Comment puis-je déplacer une balise sur une branche git vers un autre commit?

858

J'ai créé une balise sur la branche principale appelée v0.1comme ceci:

git tag -a v0.1

Mais j'ai réalisé qu'il y avait encore quelques changements dont j'avais besoin pour fusionner en master pour la version 0.1, alors j'ai fait ça. Mais maintenant, mon v0.1tag est collé (pour invoquer l'analogie de la note post-it) le mauvais commit. Je veux qu'il soit bloqué sur le dernier commit sur master, mais à la place, il est bloqué sur le deuxième commit le plus récent sur master.

Comment puis-je le déplacer vers le commit le plus récent sur master?

eedeep
la source

Réponses:

1200

Utilisez l' -foption pour git tag:

-f
--force

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

Vous souhaiterez probablement utiliser -fconjointement avec -apour forcer la création d'une balise annotée au lieu d'une balise non annotée.

Exemple

  1. Supprimez la balise sur n'importe quelle télécommande avant d'appuyer sur

    git push origin :refs/tags/<tagname>
    
  2. Remplacez la balise pour référencer le commit le plus récent

    git tag -fa <tagname>
    
  3. Poussez le tag vers l'origine distante

    git push origin master --tags
    
Greg Hewgill
la source
90
Il peut être judicieux de supprimer la balise sur n'importe quelle télécommande avant de pousser également, en procédant ainsi: git push origin :refs/tag/<tagname>puis faites git tag -fa <tagname>et puis git push origin master --tags. Sinon, vous pourriez vous retrouver avec des choses étranges dans la liste des références sur la télécommande avec des caractères ^ et {} ajoutés. Merci à Dan sur codebasehq.com de l'avoir signalé.
eedeep
47
@eedeep: correction mineure - au lieu de :refs/tag/<tagname>cela devrait l'être :refs/tags/<tagname>.
Ben Hocking
8
Cela ne fonctionne que si vous n'avez pas poussé le code hors de votre machine. Si vous l'avez, la meilleure réponse est «il y a beaucoup de chiffres dans le monde» car cela ne vaut probablement pas la peine.
Chris Huang-Leaver
33
Si vous avez déjà poussé votre balise, vous pouvez toujours mettre à jour la balise distante avec une poussée forcéegit push -f origin <tagname>
rc_luke
11
Ce qui n'est pas mentionné ici et dans la documentation, c'est que cela déplace effectivement le message de balise, si aucun nouveau message n'est donné.
Twonky
259

Plus précisément, vous devez forcer l'ajout de la balise, puis pousser avec l'option --tags et -f:

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

Pour résumer si votre télécommande est appelée originet que vous travaillez sur une mastersuccursale:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • La ligne 1 supprime la balise en env local.
  • La ligne 2 supprime le tag dans env distant.
  • La ligne 3 ajoute la balise à différents commit
  • La ligne 4 pousse le changement vers la télécommande

Vous pouvez également échanger la ligne 4 pour git push origin --tagspousser toutes les modifications avec des balises à partir de vos modifications locales.

Sur la base des réponses @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking, des commentaires sous leurs réponses et des commentaires NateS sous ma réponse.

Vive
la source
87

Supprimez-le avec git tag -d <tagname>, puis recréez-le sur le bon commit.

Stuart Golodetz
la source
3
@eedeep: Je pense que la réponse de Greg est en fait meilleure ici pour être juste.
Stuart Golodetz
Rester simple. Supprimez-le, faites à nouveau ce que vous avez fait auparavant.
ooolala
1
Ce devrait être la réponse acceptée, pour sa simplicité. N'utilise pas non plus -f de manière excessive.
chinnychinchin
48

J'essaie d'éviter certaines choses lors de l'utilisation de Git.

  1. Utiliser la connaissance des internes, par exemple les références / balises. J'essaie d'utiliser uniquement les commandes Git documentées et d'éviter d'utiliser des choses qui nécessitent la connaissance du contenu interne du répertoire .git. (C'est-à-dire que je traite Git comme un utilisateur Git et non comme un développeur Git.)

  2. L'utilisation de la force lorsqu'elle n'est pas requise.

  3. Trop de choses. (Pousser une branche et / ou beaucoup de balises, pour obtenir une balise où je le veux.)

Voici donc ma solution non violente pour changer une balise, à la fois localement et à distance, sans connaissance des internes de Git.

Je l'utilise lorsqu'un correctif logiciel a finalement un problème et doit être mis à jour / réédité.

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)

githubest un exemple de nom distant, fix123un exemple de nom de balise et 790a621265un exemple de validation.

Ivan
la source
26

Je vais laisser ici juste une autre forme de cette commande qui correspondait à mes besoins.
Il y avait une étiquette v0.0.1.2que je voulais déplacer.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

Et alors:

$ git push --tags --force
Nakilon
la source
bon, merci, 2 commandes simples et simples
Sérgio
10

Une autre façon:

Déplacez le tag dans le référentiel à distance (remplacez HEAD par un autre si nécessaire).

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

Récupérez les modifications.

$ git fetch --tags
Алексей Югов
la source
C'est plus "transactionnel" que les autres réponses.
Justin M. Keyes
9

Alias ​​pour déplacer une balise vers un autre commit.

Dans votre exemple, de se déplacer avec e2ea1639 engager de hachage faire: git tagm v0.1 e2ea1639.

Pour les balises poussées, utilisez git tagmp v0.1 e2ea1639.

Les deux alias vous gardent la date et le message d'origine. Si vous utilisez, git tag -dvous avez perdu votre message d'origine.

Enregistrez-les sur votre .gitconfigfichier

# 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
la source
1

Si vous souhaitez déplacer une balise annotée, en modifiant uniquement la validation ciblée mais en préservant le message d'annotation et d'autres métadonnées, utilisez:

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 {}
}

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

La fonction ci-dessus a été développée en référençant teerapap / git-move-annotated-tag.sh .

vossad01
la source
1
Il semble que ce ne soit plus nécessaire: git tag -f -a my_tagconserve déjà le message d'un message précédent (avec la version 2.11.0 de git).
Matthijs Kooijman