Déplacer le pointeur de branche vers un autre commit sans payer

760

Pour déplacer le pointeur de branche d'une branche extraite, on peut utiliser la git reset --hardcommande. Mais comment déplacer le pointeur de branche d'une branche non extraite pour pointer vers un commit différent (en gardant toutes les autres choses comme une branche distante suivie)?

Mot
la source
11
On dirait que tout ce que vous vouliez faire, c'est une branche d'un commit différent de celui à partir duquel elle est créée. Si ma compréhension est correcte, alors pourquoi ne créez-vous pas simplement une nouvelle branche à partir du commit que vous souhaitez créer en utilisant git branch <branch-name> <SHA-1-of-the-commit>et vider l'ancienne branche?
yasouser
6
@yasouser - Je ne sais pas quelle que soit la branche "maître" de dumping est une bonne idée.
Bulwersator

Réponses:

578

Vous pouvez le faire pour des références arbitraires. Voici comment déplacer un pointeur de branche:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

La forme générale:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Vous pouvez choisir des lentes sur le message reflog si vous le souhaitez - je crois que celui- branch -fci est différent de reset --hardcelui, et ce n'est pas exactement l'un ou l'autre.

Adam A
la source
39
À quoi sert le message? Où est-il stocké et comment le lire plus tard?
Mot
4
REMARQUE: cela ne fonctionne pas sur les référentiels nus. Sur les référentiels nus, vous devez utiliser 'git branch -f master <commit>' pour mettre à jour la branche (voir la réponse ci-dessous).
Juin Rhodes
37
Si, comme moi, vous utilisez accidentellement <branch> au lieu de refs / heads / <branch>, vous vous retrouverez avec un nouveau fichier dans votre répertoire .git à .git / <branch>, et vous obtiendrez des messages comme "refname 'master' est ambigu" lorsque vous essayez de travailler avec. Vous pouvez supprimer le fichier de votre répertoire .git à corriger.
David Minor
34
Il n'a pas été expliqué à la satisfaction pourquoi cela vaut mieux que git branch -f. Pour être précis, cette méthode semble être: (A) plus difficile à utiliser (B) plus difficile à retenir et (C) plus dangereuse
Steven Lu
10
"qu'est-ce que l'on entend exactement par des références arbitraires" - Les branches ne sont pas le seul type de référence qui pointe vers un commit. Il existe des balises, et vous pouvez également créer vous-même des références de style arbitraire refs / whatevs / myref qui ne sont ni des branches ni des balises. Je crois que cela répond également à la question de Steven Lu sur ce que cela pourrait être "mieux". Je suis d'accord que la branche -f est la plus simple si vous travaillez avec des branches.
Adam A
966
git branch -f <branch-name> <new-tip-commit>
Chris Johnsen
la source
24
Ou pour refs arbitraires, git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Vous pouvez choisir des lentes sur le message reflog si vous le souhaitez - je crois que celui- branch -fci est différent de reset --hardcelui, et ce n'est pas exactement l'un ou l'autre.)
Cascabel
4
Jefromi, veuillez écrire une réponse distincte pour pouvoir obtenir des votes. :)
Mot
16
C'est une meilleure réponse car elle gère le cas à 99% et est en fait conforme à la documentation. git help branchdit "-f, --force Réinitialiser <branchname> à <startpoint> si <branchname> existe déjà. Sans -f, git branch refuse de changer une branche existante."
AlexChaffee
12
Je fais git branch -f master <hash>et ça me dit fatal: Cannot force update the current branch.Ummmm que je dois faire quoi maintenant, consultez une autre branche aléatoire avant de pouvoir utiliser cette commande?
Qwertie
20
Cela ne fonctionnera pas si la branche que vous essayez de déplacer est votre branche actuelle ( HEADpointe dessus).
Vladimir Panteleev
135

Vous pouvez également transmettre git reset --hardune référence de validation.

Par exemple:

git checkout branch-name
git reset --hard new-tip-commit

Je trouve que je fais quelque chose comme ça semi-fréquemment:

En supposant cette histoire

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master
Amiel Martin
la source
Cela a le plus de sens dans la mesure où l'on utilise généralement HEAD ou HEAD ^ pour déplacer la pointe de branche dans le temps. C'est donc cohérent pour spécifier le commit à venir.
justingordon
11
C'est très bien si votre arbre de travail est propre. Si vous avez beaucoup de changements par étapes ou non, il est probablement préférable de procéder git update-refcomme indiqué ci-dessus.
un nerd payé le
16
Avez-vous remarqué que votre «réponse» n'ajoute rien qui ne fasse pas déjà partie de la question ?? - OP a dit: s'il est vérifié ... vous pouvez utiliser git reset --hard ...Pas besoin de le répéter ici! :-(
Robert Siemer
6
@Robert: Je ne suis pas d'accord. La question n'a pas dit comment l' utiliser et c'est le cas. C'était bien de ne pas avoir à chercher comment.
Wilson F
7
@WilsonF, c'était peut-être bien pour vous de trouver cela ici, mais cela ne répond pas du tout à la question. C'est peut-être la réponse à une autre question, mais ici c'est faux .
Robert Siemer
52

Juste pour enrichir la discussion, si vous voulez déplacer la myBranchbranche vers votre commit actuel , omettez simplement le deuxième argument après-f

Exemple:

git branch -f myBranch


Je fais généralement cela lorsque je suis rebasedans un état de tête détachée :)

Matheus Felipe
la source
13

Dans gitk --all:

  • clic droit sur le commit que vous souhaitez
  • -> créer une nouvelle branche
  • entrez le nom d'une succursale existante
  • appuyez sur retour dans la boîte de dialogue qui confirme le remplacement de l'ancienne branche de ce nom .

Attention, recréer au lieu de modifier la branche existante perdra les informations de la branche de suivi . (Ce n'est généralement pas un problème pour les cas d'utilisation simples où il n'y a qu'une seule télécommande et votre branche locale a le même nom que la branche correspondante dans la télécommande. Voir les commentaires pour plus de détails, merci @mbdevpl pour avoir signalé cet inconvénient.)

Ce serait cool s'il y gitkavait une fonctionnalité dans laquelle la boîte de dialogue avait 3 options: écraser, modifier l'existant ou annuler.


Même si vous êtes normalement un drogué en ligne de commande comme moi, git guiet gitkêtes assez bien conçu pour le sous-ensemble d'utilisation de git qu'ils permettent. Je recommande fortement de les utiliser pour ce qu'ils sont bons (c.-à-d. Mettre en place sélectivement des mecs dans / hors de l'index dans git gui, et aussi juste valider. (Ctrl-s pour ajouter une signature: ligne, ctrl-enter pour valider) .)

gitk est idéal pour garder une trace de quelques branches pendant que vous triez vos modifications dans une belle série de correctifs à soumettre en amont, ou toute autre chose où vous devez garder une trace de ce que vous êtes au milieu de plusieurs branches.

Je n'ai même pas de navigateur de fichiers graphique ouvert, mais j'aime gitk / git gui.

Peter Cordes
la source
1
Si facile! Je viens peut-être de passer de gitg à gitk.
Michael Cole
De cette façon, cependant, les informations de branche de suivi sont perdues.
mbdevpl
@mbdevpl: Je ne suis pas vraiment un expert git. Je pense que je comprends ce que vous voulez dire, mais pas les implications. Je l'ai utilisé assez souvent et j'ai toujours pu pousser ces branches vers des branches du même nom sur une télécommande. Qu'est-ce que l'association entre une branche et sa branche de suivi à distance fait pour vous?
Peter Cordes
1
@PeterCordes Ineed, lorsque les noms de branche ne correspondent pas, cela importe. Aussi lorsqu'il y a plus d'une télécommande. De plus, lorsque vous utilisez git prompt pour afficher l'état de la branche, il affichera la distance de validation de votre branche de suivi (si elle est définie). De plus, la git statussortie est affectée. De plus, dans certains cas git fetch, git pushcela ne fonctionnera pas sans spécifier explicitement à distance si vous ne définissez pas la branche de suivi. Je ne connais pas tous les cas, mais pour moi, la règle générale est que pour plus de commodité et de rapidité de travail, il est préférable d'avoir un suivi des branches dans l'ordre.
mbdevpl
7

La solution recommandéegit branch -f branch-pointer-to-move new-pointer dans TortoiseGit :

  • "Git Show log"
  • Cochez "Toutes les succursales"
  • Sur la ligne sur laquelle vous souhaitez déplacer le pointeur de branche (nouveau-pointeur):
    • Clic droit, "Créer une branche sur cette version"
    • À côté de "Branche", entrez le nom de la branche à déplacer (branche-pointeur-à-déplacer)
    • Sous "Base On", vérifiez que le nouveau pointeur est correct
    • Cochez "Forcer"
    • D'accord

entrez la description de l'image ici

entrez la description de l'image ici

hache.
la source
4

Honnêtement, je suis surpris de la façon dont personne n'a pensé à la git pushcommande:

git push -f . <destination>:<branch>

Le point (.) Fait référence au référentiel local et vous pouvez avoir besoin de l'option -f car la destination peut être "derrière son homologue distant" .

Bien que cette commande soit utilisée pour enregistrer vos modifications sur votre serveur, le résultat est exactement le même que si vous déplacez la branche distante ( <branch>) vers le même commit que la branche locale ( <destination>)

Adrian
la source
Vous pouvez également le faire sans -féviter de vous encombrer de quelque chose de local; par exemple, git fetch origin && git push . origin/develop:developest une version rapide sans échec degit checkout develop && git pull --ff-only
btown
1

Ouvrez le fichier .git/refs/heads/<your_branch_name>et changez le hachage qui y est stocké en celui où vous souhaitez déplacer la tête de votre branche. Modifiez et enregistrez simplement le fichier avec n'importe quel éditeur de texte. Assurez-vous simplement que la branche à modifier n'est pas la branche active actuelle.

Avertissement: Probablement pas un moyen conseillé de le faire, mais fait le travail.

Guillermo Gutiérrez
la source
1
Je ne sais pas si c'est la façon chaotique ou mauvaise de le faire. 🤔 😉
Keith Russell
@KeithRussell peut être les deux: P
Guillermo Gutiérrez
0

Dans le cas où la validation que vous souhaitez pointer est en avance sur la branche actuelle (ce qui devrait être le cas à moins que vous ne souhaitiez annuler les dernières validations de la branche actuelle), vous pouvez simplement faire:

git merge <commit>
Jean Paul
la source
Question posée sur ce qu'il faut faire si la succursale n'est pas extraite.
Keith Russell
Oups, j'ai raté ce point. Dans ce cas, vous pouvez faire git push . <commit>:<branch>comme déjà suggéré.
Jean Paul