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:
- A - B - C (HEAD, master)
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à:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
Digression: c'est différent d'une caisse. Si vous couriez git checkout B
, vous obtiendriez ceci:
- A - B (HEAD) - C (master)
Vous vous êtes retrouvé dans un état HEAD détaché. HEAD
, arbre de travail, indexer toutes les correspondances B
, mais la branche principale a été laissée à C
. Si vous effectuez un nouveau commit D
à ce stade, vous obtiendrez ceci, ce qui n'est probablement pas ce que vous voulez:
- A - B - C (master)
\
D (HEAD)
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 validation C
. Il est toujours dans le référentiel, et vous pouvez le trouver en regardant git reflog show HEAD
ou git 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 simple git 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: des git reset --hard
moyens git 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écuter reset --hard
.
--mixed
est la valeur par défaut, c'est à git reset
dire git 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 comme changes 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 vous git 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 comme git reset --merge
(sens git 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'origine HEAD
, 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^
et HEAD~1
) que vous mentionnez est simplement un raccourci pour spécifier les commits, sans avoir à utiliser un nom de hachage comme 3ebe3f6
. 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 de HEAD~1
et signifie le premier parent du commit. HEAD~2
signifie le premier parent du premier parent de la validation. Pensez HEAD~n
à "n s'engage avant HEAD" ou "l'ancêtre de la nième génération de HEAD".
HEAD^
(ou HEAD^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).
- Les
^
et les ~
opérateurs peuvent être enfilées ensemble, comme dans HEAD~3^2
le second parent de l'ancêtre de la troisième génération de HEAD
, HEAD^^2
, le second parent du premier parent HEAD
, ou même HEAD^^^
, ce qui équivaut à HEAD~3
.