Comment puis-je annuler la validation du dernier commit dans un dépôt nu git?

91

En tenant compte du fait qu'il existe plusieurs commandes git qui n'ont aucun sens dans un référentiel nu (car les référentiels nus n'utilisent pas d'index et n'ont pas de répertoire de travail),

git reset --hard HEAD^ 

n'est pas une solution pour annuler la dernière modification d'un tel référentiel.

En cherchant sur Internet, tout ce que j'ai pu trouver en rapport avec le sujet est celui-ci , dans lequel on me présente trois façons de le faire:
1. "mettre à jour la référence manuellement (ce qui implique la plomberie)";
2. "à git push -fpartir d'un référentiel non nu";
3. " git branch -f this $that".

Quelle solution pensez-vous être la plus appropriée ou quels autres moyens existe-t-il pour y parvenir? Malheureusement, la documentation que j'ai trouvée sur les référentiels git bare est assez pauvre.

Lavinia-Gabriela Dobrovolschi
la source
8
@ Lavinia-Garbriela Dobrovol N'utilisez pas les choses compliquées ci-dessous. Vous essayez de déplacer HEAD vers un commit différent et c'est à cela que git reset est destiné, même dans un dépôt nu. Selon ma réponse ci-dessous, utilisez: git reset --soft <commit> Avec --soft, vous n'essayez pas de changer un arbre de travail et un index qui n'existent pas, donc git vous permet de réinitialiser sans problème.
Hazok

Réponses:

130

Vous pouvez utiliser la git update-refcommande. Pour supprimer le dernier commit, vous utiliseriez:

$ git update-ref HEAD HEAD^

Ou si vous n'êtes pas dans la branche dont vous ne pouvez pas supprimer le dernier commit:

$ git update-ref refs/heads/branch-name branch-name^

Vous pouvez également passer un sha1 si vous le souhaitez:

$ git update-ref refs/heads/branch-name a12d48e2

Consultez la documentation de la commande git-update-ref .

Sylvain Defresne
la source
@ Lavinia-Gabriela Dobrovolschi: c'est vrai, je n'étais pas familier avec la syntaxe exacte.
VonC
@VonC Vous pouvez spécifier le <ref> git update-ref <ref> <newvalue>comme étant la bonne branche, comme "refs / heads / master" au lieu de HEAD, par exemple. J'espère que je n'ai pas mal compris votre question.
Lavinia-Gabriela Dobrovolschi
@Sylvain: +1 bonne édition. @ Lavinia-Gabriela Dobrovolschi merci pour les précisions. C'est beaucoup plus pratique (si vous avez un accès direct au serveur distant, je présume).
VonC
3
Les exemples sont trompeurs en ce qui concerne l' branch-nameargument. Lors de l'utilisation update-refavec une «branche», vous devez absolument spécifier le nom de référence complet de la branche (c'est- refs/heads/à- dire précéder le nom court normal de la branche). Si vous utilisez simplement le nom court, vous finirez par créer / mettre $GIT_DIR/branch-nameà jour à la place de $GIT_DIR/refs/heads/branch-name. L'existence des deux branch-nameet refs/heads/branch-nameprovoquera des avertissements «refname… est ambigu».
Chris Johnsen
Cette réponse est beaucoup plus compliquée que celle proposée par Zach. Et sa solution fonctionne très bien.
Krystian
32

Si vous utilisez ce qui suit dans un dépôt nu:

git reset --soft <commit>

alors vous ne rencontrez pas les problèmes que vous avez en utilisant --hardet les --mixedoptions dans un dépôt nu puisque vous n'essayez pas de changer quelque chose que le dépôt nu n'a pas (c'est-à-dire l'arbre de travail et l'index). Dans votre cas spécifiquement, vous voudriez utiliser (à partir du dépôt nu):

git reset --soft HEAD^

Pour changer de branche sur le référentiel distant, procédez comme suit :

git symbolic-ref HEAD refs/heads/<branch_name>

Pour voir la branche actuellement sélectionnée, utilisez:

git symbolic-ref HEAD

https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html

Hazok
la source
3
Comment sélectionnez-vous la branche que vous souhaitez déplacer? Votre exemple fonctionne bien sur master mais git checkout other_branchne fonctionne pas dans un nu.
Gauthier
1
Hmmm ... Je me demande qui m'a voté contre. La question ne demandait pas comment changer de branche sur un dépôt distant, elle demandait comment réinitialiser sur un dépôt nu. Pour changer la branche par défaut dans un dépôt distant, utilisez git symbolic-ref HEAD refs / heads / <branch_name>.
Hazok
7

Le git push -fdevrait fonctionner correctement:
si vous clone qui repo nu, supprimer le dernier commit ( git reset --hard HEAD^comme vous le mentionnez, mais dans une pension non-nue local) et repoussage ( -f):

  • vous ne modifiez aucun SHA1 pour les autres commits précédant celui que vous supprimez.
  • vous êtes sûr de repousser le contenu exact du dépôt nu moins le commit supplémentaire (car vous venez de le cloner en premier).
VonC
la source
@ VonC Salut Von, je vous ai vu beaucoup de réponses sur Git alors je voulais vous demander ... J'étais curieux, pourquoi ne serait-ce pas git reset --soft <sha1>comme indiqué dans ma réponse ci-dessous la pratique recommandée pour déplacer HEAD sur un repo nu?
Hazok
Je suppose qu'une autre raison pour laquelle je demande est que l'utilisation de la réinitialisation logicielle pour les dépôts nus n'est pas une information facilement disponible et de nombreux forums semblent avoir des solutions de contournement inutilement complexes lorsqu'il semble que la réinitialisation logicielle est la meilleure pratique en raison du moins de frappe et du moins de chance pour erreur.
Hazok
2
@Zach: a reset --softdevrait fonctionner lorsqu'il est effectué directement sur un dépôt nu. Je soupçonne que cela est rarement fait car un dépôt nu est généralement un dépôt en amont (c'est-à-dire un dépôt vers lequel vous envoyez des données), et la plupart du temps, vous n'y avez pas d'accès local direct. Mais si vous le faites, alors ceci est certainement un autre bon exemple d' reset --softutilisation " " (comme dans stackoverflow.com/questions/5203535/… ) Donc +1 à votre réponse.
VonC
2

Vous pouvez également utiliser la notation git refspec et faire quelque chose comme ceci:

git push -f origin +<commit you want to revert to>:<destination_head | branch_name>

Cela force la mise à jour de la branche de destination (comme indiqué par la référence) vers le commit source comme indiqué par la +<object ref>pièce.

alup
la source
2
sauf quand il y a un acl sur la branche - ce qui est généralement le cas si vous "devez le faire sur le repo nu lui-même" ...
David Schmitt