Quelle est la différence entre git reset --mixed, --soft et --hard?

741

Je cherche à diviser un commit et je ne sais pas quelle option de réinitialisation utiliser.

Je regardais la page En clair, que fait "git reset"? , mais j'ai réalisé que je ne comprenais pas vraiment ce qu'est l'index git ou la zone de transit et donc les explications n'ont pas aidé.

En outre, les cas d'utilisation --mixedet --softla même chose me semblent dans cette réponse (lorsque vous souhaitez corriger et recommencer). Quelqu'un peut-il le décomposer encore plus? Je me rends compte que --mixedc'est probablement l'option, mais je veux savoir pourquoi . Enfin, qu'en est-il --hard?

Quelqu'un peut-il me donner un exemple de flux de travail de la façon dont la sélection des 3 options se produirait?

Michael Chinen
la source
1
Je vais modifier ma réponse sur cette autre question pour essayer de la clarifier un peu.
Cascabel
La réponse de @mkarasek est assez bonne, mais on peut aussi être intéressé à jeter un œil à cette question .
brandizzi
3
Note à moi: En général , soft: stage everything, mixed: unstage everything, hard: ignore everythingjusqu'à la commettras je réinitialisation de.
user1164937
un autre bon article par David Zychavec une explication claire - davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

Réponses:

1491

Lorsque vous modifiez un fichier dans votre référentiel, la modification est initialement non mise en scène. Pour le valider, vous devez le mettre en scène, c'est-à-dire l'ajouter à l'index, en utilisant git add. Lorsque vous effectuez une validation, les modifications qui sont validées sont celles qui ont été ajoutées à l'index.

git reset change, au minimum, où la branche actuelle (HEAD ) pointe. La différence entre --mixedet --softest de savoir si votre index est également modifié ou non. Donc, si nous sommes en branche masteravec cette série de commits:

- A - B - C (master)

HEADpointe vers Cet l'index correspond C.

Lorsque nous exécutons git reset --soft B, master(et donc HEAD) pointe maintenant vers B, mais l'index a toujours les changements de C;git statusles montrera comme mis en scène. Donc, si nous exécutons git commità ce stade, nous obtiendrons un nouveau commit avec les mêmes modifications que C.


D'accord, alors à partir d'ici encore:

- A - B - C (master)

Faisons maintenant git reset --mixed B. (Remarque: --mixedest l'option par défaut). Encore une fois, masteret HEADpointez sur B, mais cette fois, l'index est également modifié pour correspondre B. Si nous exécutons git commità ce stade, rien ne se passera puisque l'index correspond HEAD. Nous avons toujours les changements dans le répertoire de travail, mais comme ils ne sont pas dans l'index,git status montrent comme non organisés. Pour les valider, vous le feriez git addet vous vous engagez ensuite comme d'habitude.


Et enfin, --hardc'est la même chose que --mixed(cela change votre HEADindex et), sauf que cela --hardmodifie également votre répertoire de travail. Si nous sommes arrivés Cet exécutés git reset --hard B, les modifications ajoutées C, ainsi que toutes les modifications non validées que vous avez, seront supprimées et les fichiers de votre copie de travail correspondront à la validation B. Comme vous pouvez définitivement perdre des modifications de cette façon, vous devez toujours exécuter git statusavant d'effectuer une réinitialisation matérielle pour vous assurer que votre répertoire de travail est propre ou que vous êtes d'accord avec la perte de vos modifications non validées.


Et enfin, une visualisation: entrez la description de l'image ici

mkarasek
la source
45
En d'autres termes, --soft supprime le dernier commit, --mix supprime le dernier commit et ajoute, --hard supprime le dernier commit, add et toutes les modifications que vous avez apportées aux codes, ce qui est le même avec git checkout HEAD
James Wang
11
@eventualEntropy Vous pouvez récupérer toutes les modifications validées avec le reflog; les modifications non validées qui sont supprimées avec reset --harddisparaissent à jamais.
mkarasek
2
@Robert Ni l'un ni l'autre; --mixedmodifie votre index mais pas votre répertoire de travail, donc toutes les modifications locales ne sont pas affectées.
mkarasek
3
Peut être utile pour les personnes visuelles qui utilisent git sur un terminal avec une couleur: 1.'git reset --soft A 'et vous verrez les trucs de B et C en vert (par étapes) 2.'git reset --mixed A' et vous verrez voir les trucs de B et C en rouge (non monté) 3.'git reset --hard A 'et vous ne verrez plus les changements de B et C n'importe où (ce sera comme s'ils n'avaient jamais existé)
timhc22
2
@ user1933930 1 et 3 vous laisseront avec - A - B - C′, où C ′ contient les mêmes modifications que C (avec un horodatage différent et éventuellement un message de validation). 2 et 4 vous laisseront avec - A - D, où D contient les changements combinés de B et C.
mkarasek
216

En termes simples:

  • --soft: annuler les modifications, les modifications sont laissées par étapes ( index ).
  • --mixed (par défaut) : annuler les modifications + annuler l'étape , les modifications sont laissées dans l' arborescence de travail .
  • --hard: annuler l'engagement + annuler l'étape + supprimer les modifications, il ne reste plus rien.
Mo Ali
la source
8
meilleure réponse car la réponse utilise des termes techniques pour fournir une réponse complète qui est aussi la plus concise
Trevor Boyd Smith
1
Lorsque j'ai validé un fichier (non poussé) et que j'ai un fichier non suivi nouvellement créé, alors git reset --hard ne fait rien? Ce n'est que lorsque je mets en scène le fichier non suivi qu'il le supprime de mon répertoire de travail.
Michael
1
@Nikhil Pouvez-vous expliquer où cette réponse est fausse?
Ned Batchelder,
1
@NedBatchelder Aucun de ces points n'est correct: comme un engagement ne se produit jamais lorsque ces commandes sont utilisées.
Nikhil
1
@Nikhil Peut-être que vous voulez dire que l'engagement d'origine existe toujours, ce qui est vrai. Mais la branche a été modifiée de sorte que la validation ne fait plus partie de la branche. Sommes-nous d'accord là-dessus?
Ned Batchelder
69

Veuillez noter qu'il s'agit d'une explication simplifiée conçue comme une première étape pour chercher à comprendre cette fonctionnalité complexe.

Peut être utile pour les apprenants visuels qui souhaitent visualiser à quoi ressemble l'état de leur projet après chacune de ces commandes:


Pour ceux qui utilisent Terminal avec la couleur activée (git config --global color.ui auto):

git reset --soft A et vous verrez les trucs de B et C en vert (mis en scène et prêts à s'engager)

git reset --mixed A (ou git reset A ) et vous verrez les trucs de B et C en rouge (non mis en scène et prêts à être mis en scène (vert) puis validés)

git reset --hard A et vous ne verrez plus les changements de B et C n'importe où (ce sera comme s'ils n'avaient jamais existé)


Ou pour ceux qui utilisent un programme GUI comme «Tower» ou «SourceTree»

git reset --soft A et vous verrez les trucs de B et C dans la zone des "fichiers intermédiaires" prêts à être validés

git reset --mixed A(ou git reset A) et vous verrez les trucs de B et C dans la zone des "fichiers non mis en scène" prêts à être déplacés vers mis en scène puis validés

git reset --hard A et vous ne verrez plus les changements de B et C n'importe où (ce sera comme s'ils n'avaient jamais existé)

timhc22
la source
1
Au mieux, cela est trompeur: votre réponse se lit comme si elle git resetne changeait que l'apparence de git statusla sortie de.
jub0bs
3
Je vois votre point de vue, mais je ne suis pas d'accord parce qu'en tant qu'apprenant visuel, voir à quoi mon projet «ressemblait» après avoir utilisé les 3 commandes m'a finalement aidé à comprendre ce qu'ils faisaient!
timhc22
Je l'ai vu plus comme une sorte d'idée de «git for dummies» pour aider les gens à comprendre ce qui se passe réellement. Pouvez-vous imaginer comment il pourrait être amélioré pour ne pas être trompeur
timhc22
8
Non, nous n'avons pas besoin de changer cette réponse. Il fournit une "feuille de triche" pratique. Pensez-y: doux = vert, mélangé = rouge, dur = rien (signifie disparu)! Comme c'est facile à retenir! Pour les débutants qui ne comprennent même pas ce que ces couleurs signifient vraiment, ils en savent trop peu sur git, et ils vont de toute façon prendre des leçons difficiles, et ce n'est PAS la faute de @unegma! BTW, je viens de voter pour cette réponse pour contrecarrer ce précédent downvote. Bon travail, @unegma!
RayLuo
5
Cela a servi de grand résumé supplémentaire pour mieux comprendre le fonctionnement interne pendant que je les lis ailleurs. Je vous remercie!
spex
24

Toutes les autres réponses sont grandes, mais je trouve qu'il valait mieux les comprendre en éliminant les fichiers en trois catégories: unstaged, staged, commit:

  • --hard devrait être facile à comprendre, il restaure tout
  • --mixed (par défaut) :
    1. unstagedfichiers: ne pas changer
    2. staged fichiers: déplacer vers unstaged
    3. commit fichiers: déplacer vers unstaged
  • --soft:
    1. unstagedfichiers: ne pas changer
    2. stagedfichiers: ne pas changer
    3. commit fichiers: déplacer vers staged

En résumé:

  • --softl'option déplacera tout (sauf les unstagedfichiers) dansstaging area
  • --mixed l'option déplacera tout dans unstaged area
Hansen W
la source
22

Voici une explication de base pour les utilisateurs de TortoiseGit:

git reset --softet --mixedlaissez vos fichiers intacts.

git reset --hardmodifier réellement vos fichiers pour qu'ils correspondent au commit que vous avez réinitialisé.

Dans TortoiseGit, le concept de l'index est très masqué par l'interface graphique. Lorsque vous modifiez un fichier, vous n'avez pas à exécuter git addpour ajouter la modification à la zone / index de transfert. Lorsqu'il s'agit simplement de modifications de fichiers existants qui ne changent pas les noms de fichiers, git reset --softet qui --mixedsont les mêmes! Vous ne remarquerez une différence que si vous avez ajouté de nouveaux fichiers ou renommé des fichiers. Dans ce cas, si vous exécutez git reset --mixed, vous devrez ajouter à nouveau vos fichiers liste des fichiers non versionnés .

James Lawruk
la source
Cette réponse est très floue concernant la différence entre le doux et le mixte. et est même dédaigneux en le déclarant. La réponse suivante est plus claire à ce sujet. stackoverflow.com/questions/2530060/…
barlop
2
En tant qu'utilisateur de Github Desktop qui a également le même comportement, cette réponse me permet de comprendre pourquoi je reste confus à propos de --mixedet --soft.
Chen Li Yong,
20

Dans ces cas, j'aime un visuel qui peut, espérons-le, expliquer cela:

git reset --[hard/mixed/soft] :

entrez la description de l'image ici

Donc, chaque effet diffère

  1. Difficile => WorkingDir + Index + HEAD
  2. Mixte => Index + TETE
  3. Soft => HEAD uniquement (index et répertoire de travail inchangés).
Tomer Ben David
la source
15

Trois types de regrets

Beaucoup de réponses existantes ne semblent pas répondre à la question réelle. Ils concernent ce que font les commandes, pas ce que vous (l'utilisateur) voulez - le cas d'utilisation . Mais c'est ce que le PO a demandé!

Il pourrait être plus utile de décrire la description en termes de ce que vous regrettez précisément au moment où vous donnez une git resetcommande. Disons que nous avons ceci:

A - B - C - D <- HEAD

Voici quelques regrets possibles et que faire à leur sujet:

1. Je regrette que B, C et D ne soient pas un engagement.

git reset --soft A. Je peux maintenant valider immédiatement et hop, toutes les modifications depuis A sont un commit.

2. Je regrette que B, C et D ne soient pas dix commits.

git reset --mixed A. Les validations ont disparu et l'index est de retour à A, mais la zone de travail ressemble toujours à ce qu'elle était après D. Alors maintenant, je peux ajouter et valider dans un tout autre groupe.

3. Je regrette que B, C et D se soient produits sur cette branche ; Je souhaite que je m'étais branchée après A et qu'ils s'étaient produits sur cette autre branche.

Créez une nouvelle branche otherbranch, puis git reset --hard A. La branche actuelle se termine maintenant en A, avec otherbranchson origine.

(Bien sûr, vous pouvez également utiliser une réinitialisation matérielle car vous souhaitez que B, C et D ne se soient jamais produits du tout.)

mat
la source
5

Vous n'avez pas à vous forcer à vous souvenir des différences entre eux. Pensez à la façon dont vous avez réellement effectué un commit.

1.Faites quelques changements.

2. ajoutez git.

3.gc -m "J'ai fait quelque chose"

Doux, Mixte et Difficile est le moyen qui vous permet de renoncer aux opérations que vous avez effectuées de 3 à 1.

Doux "fait semblant" de ne jamais voir que vous avez fait "gc -m".

Mixte "fait semblant" de ne jamais voir que vous avez fait "git add".

Difficile de «faire semblant» de ne jamais voir que vous avez modifié le fichier.

qinmu2127
la source
4

Avant d'entrer dans ces trois options, il faut comprendre 3 choses.

1) Histoire / TETE

2) Stade / index

3) Répertoire de travail

reset --soft: Historique modifié, HEAD modifié, Le répertoire de travail n'est pas modifié.

reset --mixed: l'historique a changé, HEAD a changé, le répertoire de travail a été modifié avec des données non mises en scène.

reset --hard: Historique modifié, HEAD modifié, Le répertoire de travail est modifié avec des données perdues.

Il est toujours prudent d'utiliser Git --soft. On devrait utiliser une autre option dans une exigence complexe.

Suresh Sharma
la source
3

Il y a un certain nombre de réponses ici avec une idée fausse sur git reset --soft. Bien qu'il existe une condition spécifique dans laquelle git reset --softne changera que HEAD(à partir d'un état de tête détaché), généralement (et pour l'utilisation prévue), il déplace la référence de branche que vous avez actuellement extraite. Bien sûr, il ne peut pas le faire si vous n'avez pas extrait une branche (d'où la condition spécifique où git reset --softne changera queHEAD ).

J'ai trouvé que c'était la meilleure façon de penser git reset. Vous ne vous déplacez pas seulement HEAD( tout fait cela ), vous déplacez également la référence de branche , par exemple master. Ceci est similaire à ce qui se passe lorsque vous exécutez git commit(la branche actuelle se déplace avec HEAD), sauf qu'au lieu de créer (et de passer à) un nouveau commit, vous passez à un précédent commit .

C'est le point de resetchanger une branche en autre chose qu'un nouveau commit, pas de changer HEAD. Vous pouvez le voir dans l'exemple de documentation:

Annuler une validation, ce qui en fait une branche de sujet

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. Vous avez fait quelques commits, mais réalisez qu'ils étaient prématurés pour être dans la branche "master". Vous voulez continuer à les polir dans une branche de sujet, alors créez une branche "sujet / essuyer" hors de la TÊTE actuelle.
  2. Rembobinez la branche principale pour vous débarrasser de ces trois commits.
  3. Passez à la branche "sujet / essuyer" et continuez à travailler.

Quel est l'intérêt de cette série de commandes? Vous voulez déplacer une branche , ici master, donc pendant que vous avez mastervérifié, vous exécutezgit reset .

La réponse la plus votée ici est généralement bonne, mais j'ai pensé l'ajouter pour corriger les nombreuses réponses avec des idées fausses.

Changez de succursale

git reset --soft <ref>: Remet à zéro le pointeur de branchement pour la branche a vérifié la validation , à la référence spécifiée, <ref>. Les fichiers de votre répertoire de travail et de votre index ne sont pas modifiés. S'engager à partir de cette étape vous ramènera directement à l'endroit où vous étiez avant la git resetcommande.

Modifiez également votre index

git reset --mixed <ref>

ou équivalent

git reset <ref>:

Fait ce que --softfait ET réinitialise également l'index pour qu'il corresponde à la validation à la référence spécifiée. Tandis que git reset --soft HEADne fait rien (car il dit déplacer la branche extraite vers la branche extraite), git reset --mixed HEADou de manière équivalente git reset HEAD, est une commande courante et utile car elle réinitialise l'index à l'état de votre dernier commit.

Modifiez également votre répertoire de travail

git reset --hard <ref>: fait ce que --mixedfait ET écrase également votre répertoire de travail. Cette commande est similaire à git checkout <ref>, sauf que (et c'est le point crucial à propos de reset) toutes les formes de git resetdéplacement de la branche refHEAD pointées par la .

Une note sur "telle ou telle commande déplace la TÊTE":

Il n'est pas utile de dire qu'une commande déplace le HEAD. Toute commande qui change où vous vous trouvez dans votre historique de commit déplace le HEAD. Voilà ce que l' HEAD est , un pointeur à l' endroit où vous êtes. HEADc'est vous , et ainsi vous bougerez quand vous le ferez.

De Novo
la source
2
"déplacer la branche ref": bon point. J'ai dû mettre à jour stackoverflow.com/a/5203843/6309 .
VonC
1

Une réponse courte dans quel contexte les 3 options sont utilisées:

Pour conserver les modifications actuelles dans le code mais pour réécrire l'historique des validations:

  • soft: Vous pouvez tout valider à la fois et créer un nouveau commit avec une nouvelle description (si vous utilisez torotise git ou n'importe quelle autre interface graphique, c'est celui-ci à utiliser, car vous pouvez toujours cocher les fichiers que vous voulez dans le commit et en faire plusieurs valide de cette façon avec différents fichiers. Dans Sourcetree, tous les fichiers sont organisés pour validation.)
  • mixed: Vous devrez ajouter à nouveau les fichiers individuels à l'index avant de faire des commits (dans Sourcetree, tous les fichiers modifiés ne seront pas mis en scène)

Pour perdre également vos modifications dans le code:

  • hard: vous ne réécrivez pas seulement l'historique, mais vous perdez également toutes vos modifications jusqu'au point que vous réinitialisez
Nickpick
la source
Je ne deviens pas doux et mélangé dans ce cas. Si vous devez vous engager, qu'est-ce qui a été annulé? êtes-vous en train de valider le retour ou de recommencer les changements (pour revenir à l'état d'origine?)
John Little
Recommencer les changements. Il n'y aura pas de reverse commit.
Nickpick
1

La différence de base entre les différentes options de la commande git reset est la suivante.

  • --soft: réinitialise uniquement le HEAD au commit que vous sélectionnez. Fonctionne essentiellement de la même manière que git checkout mais ne crée pas un état de tête détaché.
  • --mixed (option par défaut): réinitialise le HEAD au commit que vous sélectionnez dans l'historique et annule les modifications de l'index.
  • --hard: réinitialise le HEAD au commit que vous sélectionnez dans l'historique, annule les modifications dans l'index et annule les modifications dans votre répertoire de travail.
Vishwas Abhyankar
la source
1

--soft: Indique à Git de réinitialiser HEAD sur un autre commit, donc l'index et le répertoire de travail ne seront en aucun cas modifiés. Tous les fichiers modifiés entre le HEAD d'origine et la validation seront organisés.

--mixed: Tout comme le soft, cela réinitialisera HEAD dans un autre commit. Il réinitialisera également l'index pour qu'il corresponde tandis que le répertoire de travail ne sera pas touché. Toutes les modifications resteront dans le répertoire de travail et apparaîtront comme modifiées, mais pas par étapes.

--hard: Cela réinitialise tout - il réinitialise HEAD à un autre commit, réinitialise l'index pour le faire correspondre et réinitialise le répertoire de travail pour le faire correspondre également.

La principale différence entre --mixedet --softest de savoir si votre index est également modifié ou non. Vérifiez plus à ce sujet ici .

Nesha Zoric
la source
0

La réponse de mkarasek est excellente, en termes simples, nous pouvons dire ...

  • git reset --soft: définissez le HEADsur la validation prévue, mais conservez vos modifications par rapport aux dernières validations
  • git reset --mixed : c'est la même chose que git reset --soft mais la seule différence est qu'il annule vos modifications par rapport aux dernières validations
  • git reset --hard: définissez votre HEADsur la validation que vous spécifiez et réinitialisez toutes vos modifications par rapport aux dernières validations, y compris les modifications non validées.
Vivek Maru
la source