J'ai vu des articles intéressants expliquant les subtilités git reset
.
Malheureusement, plus j'en lis, plus il apparaît que je ne le comprends pas complètement. Je viens d'un arrière-plan SVN et Git est un tout nouveau paradigme. Je suis devenu mercurial facilement, mais Git est beaucoup plus technique.
Je pense que git reset
c'est proche hg revert
, mais il semble qu'il y ait des différences.
Alors qu'est-ce que git reset
ça fait exactement ? Veuillez inclure des explications détaillées sur:
- les options
--hard
,--soft
et--merge
; - l'étrange notation que vous utilisez avec
HEAD
commeHEAD^
etHEAD~1
; - cas d'utilisation concrets et flux de travail;
- conséquences sur la copie de travail, le
HEAD
et votre niveau de stress global.
Réponses:
En général,
git reset
la fonction de est de prendre la branche courante et de la réinitialiser pour pointer ailleurs, et éventuellement de ramener l'index et l'arbre de travail. Plus concrètement, si votre branche master (actuellement extraite) est comme ceci:et vous vous rendez compte que vous voulez que maître pointe vers B, pas C, vous allez le
git reset B
déplacer là:Digression: c'est différent d'une caisse. Si vous couriez
git checkout B
, vous obtiendriez ceci:Vous vous êtes retrouvé dans un état HEAD détaché.
HEAD
, arbre de travail, indexer toutes les correspondancesB
, mais la branche principale a été laissée àC
. Si vous effectuez un nouveau commitD
à ce stade, vous obtiendrez ceci, ce qui n'est probablement pas ce que vous voulez:Rappelez-vous que reset ne fait pas de commit, il met simplement à jour une branche (qui est un pointeur vers un commit) pour pointer vers un autre commit. Le reste n'est que des détails de ce qui arrive à votre index et à votre arbre de travail.
Cas d'utilisation
Je couvre plusieurs des principaux cas d'utilisation
git reset
dans ma description des différentes options dans la section suivante. Il peut vraiment être utilisé pour une grande variété de choses; le fil conducteur est que tous impliquent la réinitialisation de la branche, de l'index et / ou de l'arbre de travail pour pointer / correspondre à un commit donné.Choses à faire attention
--hard
peut vous faire vraiment perdre du travail. Il modifie votre arbre de travail.git reset [options] commit
peut vous faire (en quelque sorte) perdre des commits. Dans l'exemple de jouet ci-dessus, nous avons perdu la validationC
. Il est toujours dans le référentiel, et vous pouvez le trouver en regardantgit reflog show HEAD
ougit reflog show master
, mais il n'est plus accessible depuis aucune branche.Git supprime définitivement ces validations au bout de 30 jours, mais d'ici là, vous pouvez récupérer C en pointant à nouveau une branche vers lui (
git checkout C; git branch <new branch name>
).Arguments
En paraphrasant la page de manuel, l'utilisation la plus courante est de la forme
git reset [<commit>] [paths...]
, qui réinitialisera les chemins d'accès donnés à leur état à partir de la validation donnée. Si les chemins ne sont pas fournis, l'arborescence entière est réinitialisée et si la validation n'est pas fournie, elle est considérée comme étant HEAD (la validation actuelle). C'est un modèle commun à toutes les commandes git (par exemple checkout, diff, log, bien que la sémantique exacte varie), donc cela ne devrait pas être trop surprenant.Par exemple,
git reset other-branch path/to/foo
réinitialise tout dans chemin / vers / foo à son état dans l'autre branche,git reset -- .
réinitialise le répertoire actuel à son état dans HEAD, et un simplegit reset
réinitialise tout à son état dans HEAD.L'arborescence de travail principale et les options d'index
Il existe quatre options principales pour contrôler ce qui arrive à votre arborescence de travail et à votre index pendant la réinitialisation.
Rappelez-vous, l'index est la «zone de transit» de git - c'est là que les choses se passent lorsque vous dites que vous vous préparez
git add
à vous engager.--hard
fait tout correspondre au commit que vous avez réinitialisé. C'est probablement le plus facile à comprendre. Tous vos changements locaux sont bouleversés. Une utilisation primaire souffle dans votre travail , mais pas de commutation commits: desgit reset --hard
moyensgit reset --hard HEAD
, par exemple ne changent pas la branche , mais se débarrasser de tous les changements locaux. L'autre consiste simplement à déplacer une branche d'un endroit à un autre et à synchroniser l'index / l'arbre de travail. C'est celui qui peut vraiment vous faire perdre du travail, car il modifie votre arbre de travail. Soyez très sûr de vouloir jeter le travail local avant d'en exécuterreset --hard
.--mixed
est la valeur par défaut, c'est àgit reset
diregit reset --mixed
. Il réinitialise l'index, mais pas l'arborescence de travail. Cela signifie que tous vos fichiers sont intacts, mais toutes les différences entre le commit d'origine et celui que vous réinitialisez apparaîtront comme des modifications locales (ou fichiers non suivis) avec le statut git. Utilisez-le lorsque vous réalisez que vous avez commis de mauvaises validations, mais que vous souhaitez conserver tout le travail que vous avez effectué afin de pouvoir le corriger et le recommencer. Pour valider, vous devrez à nouveau ajouter des fichiers à l'index (git add ...
).--soft
ne touche pas l'index ou l' arbre de travail. Tous vos fichiers sont intacts comme avec--mixed
, mais toutes les modifications apparaissent commechanges to be committed
avec l'état git (c'est-à-dire archivées en préparation pour la validation). Utilisez-le lorsque vous réalisez que vous avez commis de mauvaises validations, mais le travail est tout bon - tout ce que vous avez à faire est de le réengager différemment. L'index n'est pas modifié, vous pouvez donc valider immédiatement si vous le souhaitez - le commit résultant aura le même contenu que celui où vous étiez avant de réinitialiser.--merge
a été ajouté récemment et vise à vous aider à abandonner une fusion qui a échoué. Cela est nécessaire car vousgit merge
permettra en réalité de tenter une fusion avec un arbre de travail sale (avec des modifications locales) tant que ces modifications se trouvent dans des fichiers non affectés par la fusion.git reset --merge
réinitialise l'index (comme--mixed
- toutes les modifications apparaissent comme des modifications locales), et réinitialise les fichiers affectés par la fusion, mais laisse les autres seuls. J'espère que cela rétablira tout ce qu'il était avant la mauvaise fusion. Vous l'utiliserez généralement commegit reset --merge
(sensgit reset --merge HEAD
) parce que vous voulez seulement réinitialiser la fusion, pas déplacer la branche. (HEAD
n'a pas encore été mis à jour, car la fusion a échoué)Pour être plus concret, supposons que vous avez modifié les fichiers A et B et que vous essayez de fusionner dans une branche qui a modifié les fichiers C et D. La fusion échoue pour une raison quelconque et vous décidez de l'annuler. Vous utilisez
git reset --merge
. Cela ramène C et D à leur état d'origineHEAD
, mais laisse vos modifications à A et B seules, car elles ne faisaient pas partie de la tentative de fusion.Vouloir en savoir davantage?
Je pense que
man git reset
c'est vraiment très bon pour cela - peut-être avez-vous besoin d'un peu de sens de la façon dont git fonctionne pour qu'ils s'enfoncent vraiment. En particulier, si vous prenez le temps de les lire attentivement, ces tableaux détaillant les états des fichiers dans l'index et l'arborescence de travail pour toutes les différentes options et cas sont très utiles. (Mais oui, ils sont très denses - ils transmettent énormément d'informations ci-dessus sous une forme très concise.)Étrange notation
La "notation étrange" (
HEAD^
etHEAD~1
) que vous mentionnez est simplement un raccourci pour spécifier les commits, sans avoir à utiliser un nom de hachage comme3ebe3f6
. Il est entièrement documenté dans la section "spécification des révisions" de la page de manuel de git-rev-parse, avec de nombreux exemples et la syntaxe associée. Le caret et le tilde signifient en réalité des choses différentes :HEAD~
est l'abréviation deHEAD~1
et signifie le premier parent du commit.HEAD~2
signifie le premier parent du premier parent de la validation. PensezHEAD~n
à "n s'engage avant HEAD" ou "l'ancêtre de la nième génération de HEAD".HEAD^
(ouHEAD^1
) signifie également le premier parent du commit.HEAD^2
signifie le deuxième parent du commit . N'oubliez pas qu'une validation de fusion normale a deux parents - le premier parent est la validation fusionnée et le deuxième parent est la validation qui a été fusionnée. En général, les fusions peuvent avoir arbitrairement de nombreux parents (fusion de poulpe).^
et les~
opérateurs peuvent être enfilées ensemble, comme dansHEAD~3^2
le second parent de l'ancêtre de la troisième génération deHEAD
,HEAD^^2
, le second parent du premier parentHEAD
, ou mêmeHEAD^^^
, ce qui équivaut àHEAD~3
.la source
N'oubliez pas qu'en
git
vous avez:HEAD
pointeur , qui vous indique sur quel commit vous travaillezPar ordre croissant de dangerosité:
--soft
se déplaceHEAD
mais ne touche pas la zone de préparation ou l'arbre de travail.--mixed
déplaceHEAD
et met à jour la zone de transfert, mais pas l'arborescence de travail.--merge
déplaceHEAD
, réinitialise la zone de transit et essaie de déplacer toutes les modifications de votre arborescence de travail dans la nouvelle arborescence de travail.--hard
déplaceHEAD
et ajuste votre zone de préparation et votre arbre de travail au nouveauHEAD
, jetant tout.--soft
lorsque vous souhaitez passer à un autre commit et corriger les choses sans "perdre votre place". Il est assez rare que vous en ayez besoin.-
-
Utilisez
--mixed
(qui est la valeur par défaut) lorsque vous souhaitez voir à quoi ressemblent les autres validations, mais vous ne voulez pas perdre les modifications que vous avez déjà.À utiliser
--merge
lorsque vous souhaitez vous déplacer vers un nouvel emplacement mais incorporer les modifications que vous avez déjà dans l'arborescence de travail.Utilisez
--hard
pour tout effacer et commencer une nouvelle ardoise au nouveau commit.la source
reset --merge
. Il n'effectue pas de fusion à trois. C'est vraiment uniquement pour réinitialiser les fusions conflictuelles, comme décrit dans la documentation. Vous voudrez utilisercheckout --merge
pour faire ce dont vous parlez. Si vous souhaitez également déplacer la branche, je pense que la seule façon est de faire un suivi / réinitialiser pour la faire glisser.reset --merge
avec une cible en plus (par défaut)HEAD
, car dans les cas en plus d'interrompre une fusion conflictuelle, cela va jeter informations que vous pourriez autrement enregistrer.git reset
etgit reset -- .
.Le post Reset Demystified dans le blog Pro Git donne une explication très simple sur
git reset
etgit checkout
.Après toutes les discussions utiles en haut de cet article, l'auteur réduit les règles aux trois étapes simples suivantes:
la source
Lorsque vous validez quelque chose à git, vous devez d'abord mettre en scène (ajouter à l'index) vos modifications. Cela signifie que vous devez git ajouter tous les fichiers que vous souhaitez inclure dans ce commit avant que git les considère comme faisant partie du commit. Jetons d'abord un coup d'œil sur l'image d'un dépôt git:
donc, c'est simple maintenant. Nous devons travailler dans le répertoire de travail, créer des fichiers, des répertoires et tout. Ces modifications sont des modifications non suivies. Pour les faire suivre, nous devons les ajouter à git index en utilisant la commande git add . Une fois qu'ils sont ajoutés à git index. Nous pouvons maintenant valider ces modifications, si nous voulons le pousser vers le dépôt git.
Mais tout à coup, nous avons appris en validant que nous avons un fichier supplémentaire que nous avons ajouté dans l'index n'est pas nécessaire pour pousser dans le référentiel git. Cela signifie que nous ne voulons pas de ce fichier dans l'index. Maintenant, la question est de savoir comment supprimer ce fichier de l'index git, puisque nous avons utilisé git add pour les mettre dans l'index, il serait logique d'utiliser git rm ? Faux! git rm supprimera simplement le fichier et ajoutera la suppression à l'index. Alors que faire maintenant:
Utilisation:-
Il efface votre index, laisse votre répertoire de travail intact. (simplement décortiquer tout).
Il peut être utilisé avec un certain nombre d'options. Il existe trois options principales à utiliser avec git reset: --hard, --soft et --mixed . Ceux-ci affectent la réinitialisation de get en plus du pointeur HEAD lors de la réinitialisation.
Tout d'abord, --hard réinitialise tout. Votre répertoire actuel serait exactement le même que si vous aviez suivi cette branche tout au long. Le répertoire de travail et l'index sont modifiés pour ce commit. C'est la version que j'utilise le plus souvent. git reset --hard est quelque chose comme svn revert .
Ensuite, l'opposé complet, —soft , ne réinitialise pas l'arborescence de travail ni l'index. Il déplace uniquement le pointeur HEAD. Cela laisse votre état actuel avec des modifications différentes de la validation vers laquelle vous basculez en place dans votre répertoire, et «par étapes» pour la validation. Si vous effectuez un commit localement mais n'avez pas poussé le commit vers le serveur git, vous pouvez réinitialiser le commit précédent et recommencer avec un bon message de commit.
Enfin, --mixed réinitialise l'index, mais pas l'arborescence de travail. Ainsi, les modifications sont toujours là, mais ne sont pas "mises en scène" et devraient être git ajoutées ou git commit -a . nous l'utilisons parfois si nous avons commis plus que ce que nous voulions avec git commit -a, nous pouvons annuler le commit avec git reset --mixed, ajouter les choses que nous voulons valider et simplement les valider.
Différence entre git revert et git reset : -
En termes simples, git reset est une commande pour "corriger les erreurs non validées" et git revert est une commande pour "corriger les erreurs commises " .
Cela signifie que si nous avons fait une erreur dans un changement et que nous nous sommes engagés et poussés de la même manière pour git repo, alors git revert est la solution. Et si dans le cas où nous avons identifié la même erreur avant de pousser / valider, nous pouvons utiliser git reset pour résoudre le problème.
J'espère que cela vous aidera à vous débarrasser de votre confusion.
la source
git reset HEAD
par défaut?--hard
,--soft
ou--mixed
? Grande réponse btw.git reset --hard
vous perdrez certaines données. Et il y a un point qui pourrait être faux (bien que je ne sois pas sûr à 100% ... J'apprends toujours!): Parler de--mixed
vous dit que "nous utilisons parfois cela si nous nous engageons plus que ce que nous voulions avec git commit -a". Vouliez-vous dire: "si nous avons mis en scène plus que ce que nous voulionsgit stage .
"? Si vous l'avez vraiment commis, je pense qu'il est trop tard (comme vous le dites à la fin, git reset est une commande pour "corriger les erreurs non validées")TL; DR
VERSION PLUS LONGUE
Mais c'est évidemment simpliste d'où les nombreuses réponses assez verbeuses. Il était plus logique pour moi de poursuivre la lecture
git reset
dans le contexte de l'annulation des changements. Par exemple, voyez ceci:Depuis https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
et ça
Depuis https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations
la source
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
(ougit 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ésgit reset --mixed A
(ougit 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ésgit 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é)la source
Checkout pointe la tête vers un commit spécifique.
Reset pointe une branche sur un commit spécifique. (Une branche est un pointeur vers une validation.)
Soit dit en passant, si votre tête ne pointe pas vers une validation qui est également pointée par une branche, vous avez une tête détachée.(s'est avéré être faux. Voir les commentaires ...)la source