Quelle est la différence entre «git reset» et «git checkout»?

440

J'ai toujours pensé git resetet git checkoutcomme la même chose, dans le sens où les deux ramènent le projet à un commit spécifique. Cependant, je pense qu'ils ne peuvent pas être exactement les mêmes, car cela serait redondant. Quelle est la différence réelle entre les deux? Je suis un peu confus, car le svn n'a svn coqu'à annuler le commit.

AJOUTÉE

VonC et Charles ont expliqué les différences entre git resetet git checkoutvraiment bien. Ma compréhension actuelle est que git resettous les changements reviennent à un commit spécifique, alors que se git checkoutprépare plus ou moins pour une branche. J'ai trouvé les deux diagrammes suivants très utiles pour arriver à cette compréhension:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

AJOUTÉ 3

À partir de http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , l'extraction et la réinitialisation peuvent émuler le rebase.

entrez la description de l'image ici

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

entrez la description de l'image ici

prosseek
la source
jetez un œil sur git-scm.com/blog/2011/07/11/reset.html
pedrorijo91
Re: "Est-ce mal ou trop simplifié?" Oui, ce premier diagramme est trompeur en ce qui concerne la différence entre le paiement et la réinitialisation. (Il peut être correct en ce qui concerne les -- filesvariantes; je ne suis pas sûr.) Ce diagramme donne l'impression que la principale différence est de savoir si elles affectent l'index ou le WD. Voir ma réponse à ce sujet. Les 2e et 3e diagrammes sont très utiles pour voir la vraie différence. Les 4e et 5e diagrammes sont utiles pour vérifier si vous comprenez ce que font ces commandes, mais ne vous aideront pas vraiment à y arriver.
LarsH
J'ai trouvé la section "Check it out" du "Git Tools Reset Demystified" pour donner le résumé le plus utile.
Josiah Yoder
1
prosseek: Si vous êtes d'accord avec @LarsH que le premier diagramme est trompeur, pouvez-vous le supprimer, s'il vous plaît?
Josiah Yoder
Veuillez noter que le paiement et la réinitialisation n'émulent que la 2e partie de la rebase, et des étapes supplémentaires (fournies dans l' think-like-a-git.netarticle lié ) sont nécessaires pour éviter la perte de données.
Cowlinator

Réponses:

198
  • git resetconcerne spécifiquement la mise à jour de l'index , le déplacement de HEAD.
  • git checkoutconcerne la mise à jour de l'arborescence de travail (vers l'index ou l'arborescence spécifiée). Il mettra à jour le HEAD uniquement si vous extrayez une branche (sinon, vous vous retrouvez avec un HEAD détaché ).
    (en fait, avec Git 2.23 Q3 2019, ce sera git restore, pas nécessairement git checkout)

Par comparaison, puisque svn n'a pas d'index, seule une arborescence de travail svn checkoutcopiera une révision donnée sur un répertoire séparé.
L'équivalent le plus proche de git checkout:

  • svn update (si vous êtes dans la même branche, c'est-à-dire la même URL SVN)
  • svn switch (si vous extrayez par exemple la même branche, mais à partir d'une autre URL de dépôt SVN)

Toutes ces trois modifications d'arbres de travail ( svn checkout, update, switch) ont une seule commande dans git: git checkout.
Mais puisque git a aussi la notion d'index (cette "zone de transit" entre le repo et l'arbre de travail), vous l'avez aussi git reset.


Thinkeye mentionne dans les commentaires l'article " Reset Demystified ".

Par exemple, si nous avons deux branches, ' master' et ' develop' pointant sur des validations différentes, et que nous sommes actuellement sur ' develop' (donc HEAD pointe dessus) et que nous couronsgit reset master , ' develop' lui-même va maintenant pointer vers le même commit que '' master' Est-ce que.

D'un autre côté, si nous courons à la place git checkout master, ' develop' ne bougera pas,HEAD lui-même le fera. HEADva maintenant pointer vers ' master'.

Donc, dans les deux cas, nous nous dirigeons HEADvers le point de s'engager A, mais la façon dont nous le faisons est très différente. resetdéplacera les HEADpoints de branche vers, checkout se déplace HEADpour pointer vers une autre branche.

http://git-scm.com/images/reset/reset-checkout.png

Sur ces points, cependant:

LarsH ajoute dans les commentaires :

Le premier paragraphe de cette réponse, cependant, est trompeur: " git checkout... ne mettra à jour le HEAD que si vous extrayez une branche (sinon, vous vous retrouvez avec un HEAD détaché)".
Pas vrai: git checkoutmettra à jour le HEAD même si vous extrayez un commit qui n'est pas une branche (et oui, vous vous retrouvez avec un HEAD détaché, mais il a quand même été mis à jour).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo souscrit aux commentaires :

@LarsH est correct.
La deuxième puce a une idée fausse de ce dans quoi se trouve HEAD ne mettra à jour la tête que si vous extrayez une branche.
HEAD va où que vous soyez, comme une ombre.
Vérifier une référence non-branche (par exemple, une balise), ou un commit directement, déplacera HEAD. La tête détachée ne signifie pas que vous vous êtes détaché de la TÊTE, cela signifie que la tête est détachée d'une référence de branche, que vous pouvez voir, par exemple,git log --pretty=format:"%d" -1 .

  • Les États chefs de file attachés commenceront par (HEAD -> :
  • détaché affichera toujours (HEAD, mais n'aura pas de flèche vers une branche réf.
VonC
la source
7
Je dirais qu'il git resets'agit de modifier le "label" de la branche et éventuellement de mettre à jour l'index ou l'arbre de travail comme effet secondaire. git checkoutconsiste à mettre à jour l'arborescence de travail et à changer de branche actuellement "sélectionnée" (la HEAD).
Mikko Rantalainen
2
@MikkoRantalainen nope. git resetest à 100% sur le HEAD. Il fonctionne même en mode HEAD détaché ( stackoverflow.com/a/3965714/6309 ), ce qui signifie où il n'y a pas de branche (!). git checkout fonctionne également en mode HEAD détaché, ou peut être utilisé pour extraire un SHA1 en mode HEAD détaché: là encore, aucune branche n'est impliquée dans ce cas.
VonC
3
Pour en savoir plus sur toutes les âmes perdues envoyées ici par un moteur de recherche, je pense que cela en vaut la peine: git-scm.com/blog/2011/07/11/reset.html
Thinkeye
2
@Thinkeye bonne référence. Je l'ai inclus, avec un extrait pertinent, dans la réponse pour plus de visibilité.
VonC
2
L'explication de Reset Demystified est excellente. Le premier paragraphe de cette réponse, cependant, est trompeur: "git checkout ... ne mettra à jour le HEAD que si vous retirez une branche (sinon, vous vous retrouvez avec un HEAD détaché)". Pas vrai ... git checkout mettra à jour le HEAD même si vous extrayez un commit qui n'est pas une branche (et oui, vous vous retrouvez avec un HEAD détaché, mais il a quand même été mis à jour). Peut-être que je comprends mal ce que vous entendez par «mise à jour»? git checkout a839e8fmet à jour HEAD pour pointer pour valider a839e8f.
LarsH
67

Dans leur forme la plus simple, resetréinitialise l'index sans toucher l'arborescence de travail, tout en checkoutmodifiant l'arborescence de travail sans toucher l'index.

Réinitialise l'index pour correspondre HEAD, l'arbre de travail reste seul:

git reset

Conceptuellement, cela extrait l'index dans l'arborescence de travail. Pour qu'il fasse réellement tout ce que vous devez utiliser -fpour le forcer à écraser les modifications locales. Il s'agit d'une fonction de sécurité pour vous assurer que le formulaire "sans argument" n'est pas destructeur:

git checkout

Une fois que vous commencez à ajouter des paramètres, il est vrai qu'il y a un certain chevauchement.

checkoutest généralement utilisé avec une branche, une balise ou un commit. Dans ce cas, il sera réinitialisé HEADet l'index de la validation donnée ainsi que l'exécution de l'extraction de l'index dans l'arborescence de travail.

En outre, si vous fournissez --hardà resetvous pouvez demanderreset de remplacer l'arbre de travail ainsi que la réinitialisation de l'index.

Si vous avez actuellement une branche extraite, il existe une différence cruciale entre resetet checkoutlorsque vous fournissez une autre branche ou un commit. resetchangera la branche actuelle pour pointer sur la validation sélectionnée tandis que checkoutlaissera la branche actuelle seule mais extraira la branche ou la validation fournie à la place.

Autres formes de resetetcommit impliquent la fourniture de chemins.

Si vous fournissez des chemins d'accès, resetvous ne pouvez pas fournir --hardet resetne modifierez que la version d'index des chemins d'accès fournis en version dans la validation fournie (ouHEAD si vous ne spécifiez pas de validation).

Si vous fournissez des chemins à checkout, comme resetcela mettra à jour la version d'index des chemins fournis pour correspondre au commit fourni (ou HEAD) mais il récupérera toujours la version d'index des chemins fournis dans l'arborescence de travail.

CB Bailey
la source
2
Il est faux de dire que "checkout" ne change pas l'index: il le change lorsqu'il est utilisé pour passer d'une branche à une autre.
wiki1000
Dans leur forme la plus simple, la réinitialisation réinitialise l'index sans toucher l'arborescence de travail, tandis que l'extraction modifie l'arborescence de travail sans toucher l'index. : Quelle est la confusion: |
Aditya Gupta
41

Un cas d'utilisation simple lors
de l'annulation d'une modification: 1. Utilisez reset si vous souhaitez annuler le transfert d'un fichier modifié.
2. Utilisez checkout si vous souhaitez annuler les modifications apportées aux fichiers non organisés.

John Doe
la source
1
Réponse parfaite. Je vous remercie.
user358591
11

La principale différence en bref est que reset la référence de branche actuelle est déplacée , tandis quecheckout contrairement à ce qui est le cas (elle déplace HEAD).

Comme l'explique le livre Pro Git sous Réinitialiser démystifié ,

La première chose à resetfaire est de déplacer vers quoi pointe HEAD . Ce n'est pas la même chose que de changer HEAD lui-même (c'est ce qui checkoutfait); reset déplace la branche vers laquelle HEAD pointe. Cela signifie que si HEAD est défini sur la masterbranche (c'est-à-dire que vous êtes actuellement sur la masterbranche), l'exécution git reset 9e5e6a4commencera en faisant masterremarquer 9e5e6a4. [non souligné dans l'original]

Voir aussi la réponse de VonC pour un texte très utile et un extrait du même article, que je ne reproduirai pas ici.

Bien sûr, il y a beaucoup plus de détails sur les effets checkoutet resetpeuvent avoir sur l'index et l'arbre de travail, selon les paramètres utilisés. Il peut y avoir beaucoup de similitudes et de différences entre les deux commandes. Mais comme je le vois, la différence la plus cruciale est de savoir s'ils déplacent la pointe de la branche actuelle.

LarsH
la source
2
Bonne rétroaction, en plus de ma réponse plus ancienne. +1
VonC
2

Les deux commandes (reset et checkout) sont complètement différentes.

checkout X N'EST PAS reset --hard X

Si X est un nom de branche, checkout Xchangera la branche actuelle tandis que reset --hard Xnon.

wiki1000
la source
2
Mais si X est un fichier ou un dossier, alors ce sont les mêmes.
Ted Bigham
1

brèves mnémoniques:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Филя Усков
la source