47 votes

Y a-t-il une différence entre "git reset --hard hash" et "git checkout hash" ?

Alors que reset y checkout ont des usages différents la plupart du temps, je ne vois pas quelle différence il y a entre ces deux-là.

Il y en a probablement un, sinon personne n'aurait pris la peine d'ajouter une --hard option pour faire quelque chose de la base checkout peut faire.

Peut-être y a-t-il une différence dans la façon dont vous verrez l'histoire ?

1 votes

J'ai abordé ce sujet dans une mise à jour de ma réponse à l'une de vos questions précédentes - regardez l'art ascii près du sommet, en particulier là où il est écrit "Digression : ...". (même si j'aimerais bien être plus représenté pour répondre à nouveau à cette question ici)

0 votes

Je pense que vous pouvez poster votre réponse ici et gagner en réputation. Si quelqu'un recherche cette connaissance particulière, il ne trouvera pas l'autre message. Celui-ci vise un sujet très spécifique, et il mérite d'avoir sa propre page. BTW, il semble que vous soyez mon mentor Git :-) harigato, senseï !

1 votes

Mais si je comprends bien, la différence est que reset déplace la branche et non le checkout.

64voto

Jefromi Points 127932

Cette réponse est essentiellement tirée de ma réponse à une question précédente : La réinitialisation git en langage clair .

Les deux sont très différents. Ils aboutissent au même état pour votre index et votre arbre de travail, mais l'historique et la branche actuelle qui en résultent ne sont pas les mêmes.

Supposons que votre historique ressemble à ceci, avec la branche master actuellement extraite :

- A - B - C (HEAD, master)

et tu cours git reset --hard B . Vous obtiendrez ceci :

- A - B (HEAD, master)      # - C is still here, but there's no
                            # branch pointing to it anymore

Vous obtiendrez cet effet si vous utilisez --mixed o --soft aussi - la seule différence est ce qui arrive à votre arbre de travail et à votre index. Dans le --hard Dans ce cas, l'arbre de travail et l'index correspondent B .

Maintenant, supposons que vous couriez git checkout B à la place. Tu auras ça :

- A - B (HEAD) - C (master)

Vous vous êtes retrouvé dans un état d'HEAD détaché. HEAD l'arbre de travail, l'index de toutes les correspondances B comme pour le hard reset, mais la branche master a été laissée en place à l'adresse suivante C . Si vous faites un nouveau commit D à ce stade, vous obtiendrez ceci, qui n'est probablement pas ce que vous voulez :

- A - B - C (master)
       \
        D (HEAD)

Donc, vous utilisez checkout pour, eh bien, vérifier ce commit. Vous pouvez le modifier, faire ce que vous voulez, mais vous avez laissé votre branche derrière vous. Si vous voulez que la branche soit déplacée aussi, vous utilisez reset.

7 votes

+1 comme d'habitude. Ce fil ( marc.info/?l=git&m=120955970704567&w=2 ) a également ajouté un effet secondaire : si vous êtes au milieu d'une fusion (par exemple lorsqu'il y a des conflits de fusion, ou après que git merge --no-commit ), git reset --hard oublie la fusion, mais git checkout -f ne le fait pas ; par conséquent, une git commit après cette dernière créerait un commit de fusion, ce qui n'est généralement pas ce que vous voulez.

15voto

Jakub Narębski Points 87537

Si la documentation fournie avec Git ne vous aide pas, jetez un coup d'oeil à Une référence visuelle de Git par Mark Lodato.

En particulier, si vous comparez git checkout <non-branch> con git reset --hard <non-branch> (en lien direct) :

git checkout master~3
(source : <a href="http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png" rel="nofollow noreferrer">github.com </a>)

git reset --hard master~3

Notez que dans le cas de git reset --hard master~3 vous laissez derrière vous une partie du DAG de révisions - certains commits ne sont référencés par aucune branche. Ceux-ci sont protégés pendant (par défaut) 30 jours par la fonction reflog ; ils seraient finalement élagués (supprimés).

6voto

hasenj Points 36139

git-reset hash définit la référence de la branche au hachage donné, et éventuellement la vérifie, avec --hard .

git-checkout hash définit l'arbre de travail au hash donné ; et à moins que hash soit un nom de branche, vous vous retrouverez avec une tête détachée.

En fin de compte, git s'occupe de 3 choses :

                   working tree (your code)
-------------------------------------------------------------------------
                     index/staging-area
-------------------------------------------------------------------------
      repository (bunch of commits, trees, branch names, etc)

git-checkout par défaut ne met à jour que l'index et l'arbre de travail, et peut optionnellement mettre à jour quelque chose dans le référentiel (avec la commande -b option)

git-reset par défaut ne fait que mettre à jour le référentiel et l'index, et optionnellement l'arbre de travail (avec la commande --hard option)

Vous pouvez penser au dépôt comme ceci :

 HEAD -> master

 refs:
    master -> sha_of_commit_X
    dev -> sha_of_commit_Y

 objects: (addressed by sha1)

    sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A ....

git-reset manipule ce vers quoi pointent les références de la branche.

Supposons que votre histoire ressemble à ceci :

           T--S--R--Q [master][dev]
          / 
   A--B--C--D--E--F--G [topic1]
                   \
                    Z--Y--X--W [topic2][topic3]

Gardez à l'esprit que les branches sont juste des noms qui avancent automatiquement lorsque vous livrez.

Vous avez donc les branches suivantes :

 master -> Q
 dev -> Q
 topic1 -> G
 topic2 -> W
 topic3 -> W

Et votre branche actuelle est topic2 c'est-à-dire que le HEAD pointe vers le sujet 2.

HEAD -> topic2

Ensuite, git reset X réinitialisera le nom topic2 pour pointer vers X ; ce qui signifie que si vous faites un commit P sur la branche topic2, les choses ressembleront à ceci :

           T--S--R--Q [master][dev]
          / 
   A--B--C--D--E--F--G [topic1]
                   \
                    Z--Y--X--W [topic3]
                           \
                            P [topic2]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X