Je suis toujours confus avec cela, voici donc un cas de test de rappel; disons que nous avons ce bash
script à tester git
:
set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email test@test.com
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt
À ce stade, la modification n'est pas mise en scène dans le cache, tout git status
comme:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
Si à partir de ce point, nous le faisons git checkout
, le résultat est le suivant:
$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean
Si au contraire nous le faisons git reset
, le résultat est:
$ git reset HEAD -- b.txt
Unstaged changes after reset:
M b.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
Donc, dans ce cas - si les modifications ne sont pas échelonnées, git reset
cela ne fait aucune différence, tout en git checkout
écrasant les modifications.
Maintenant, disons que le dernier changement par rapport au script ci-dessus est mis en scène / mis en cache, c'est-à-dire que nous l'avons également fait git add b.txt
à la fin.
Dans ce cas, git status
à ce stade est:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: b.txt
Si à partir de ce point, nous le faisons git checkout
, le résultat est le suivant:
$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean
Si au contraire nous le faisons git reset
, le résultat est:
$ git reset HEAD -- b.txt
Unstaged changes after reset:
M b.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b.txt
no changes added to commit (use "git add" and/or "git commit -a")
Donc, dans ce cas - si les modifications sont échelonnées, elles git reset
feront essentiellement des changements échelonnés en changements non échelonnés - alors qu'elles git checkout
écraseront complètement les changements.
git reset HEAD <filename> ; git checkout -- <filename>
HEAD^^
pour 2 validations à partir de la plus récente, ouHEAD^^^
pour 3 validations de retour. Vous pouvez également utiliserHEAD~2
, ouHEAD~3
, ce qui devient plus pratique si vous souhaitez revenir en arrière, tandis queHEAD^2
signifie "le deuxième parent de cette validation"; en raison des validations de fusion, une validation peut avoir plusieurs validations précédentes, donc avecHEAD^
un nombre sélectionne lequel de ces parents, tandis qu'avecHEAD~
un nombre sélectionne toujours le premier parent mais ce nombre de validations revient. Voirgit help rev-parse
pour plus de détails.