HOWTO · Git
Utiliser `git reset --soft` en conservant les modifications indexées
Apprenez à utiliser `git reset --soft` pour déplacer la branche vers un commit antérieur tout en conservant les modifications indexées, puis à les vérifier avant de poursuivre votre travail.
Sur cette page
Utilisez git reset --soft <target> pour déplacer la pointe de la branche actuelle vers un commit antérieur tout en laissant l’index et l’arbre de travail inchangés. Les modifications apportées par les commits dépassés restent donc indexées, prêtes à être examinées puis validées à nouveau. Cette méthode est utile pour regrouper des commits récents ou modifier leurs messages sans perdre leur contenu.
Ce que modifie git reset --soft
Une réinitialisation logicielle déplace HEAD et la pointe de la branche actuelle vers le commit indiqué. Elle ne modifie ni l’index de staging ni les fichiers de l’arbre de travail. Les modifications comprises entre l’ancienne pointe et la cible sont donc indexées par rapport à cette nouvelle cible. La commande agit sur la branche actuellement extraite ; elle ne déplace pas toutes les branches qui pointent vers l’ancien commit.
Indiquez toujours une cible lorsque vous voulez déplacer l’historique. Si vous l’omettez, Git utilise HEAD et la branche ne bouge pas. Le travail déjà indexé ou non indexé reste également en place. Examinez ensuite le diff indexé afin de savoir exactement ce que contiendra un prochain commit.
Choisir le commit cible de la réinitialisation
Examinez l’historique récent avec git log --oneline. Choisissez le commit qui doit devenir la nouvelle pointe de la branche actuelle et vérifiez son sujet ou son hash avant de lancer la réinitialisation. Par exemple, HEAD~1 désigne le premier parent du commit actuel, c’est-à-dire le commit précédent sur la ligne d’historique actuelle. HEAD~2 remonte de deux étapes en suivant les premiers parents. Vous pouvez aussi désigner la cible par le nom d’une branche, d’une étiquette ou par le hash d’un commit.
La cible est le commit à conserver comme pointe, et non celui à supprimer. Une réinitialisation vers HEAD~1 fait reculer la branche d’un commit et laisse indexées les modifications du commit précédent. Si l’historique n’est pas linéaire, vérifiez la cible dans le journal au lieu de supposer qu’une expression de parent numérotée désigne le commit voulu.
Réinitialiser des commits en conservant les modifications indexées
Pour réinitialiser un seul commit, examinez d’abord le journal, puis exécutez git reset --soft HEAD~1. Pour regrouper plusieurs commits récents, utilisez une cible antérieure adaptée, par exemple git reset --soft HEAD~3. L’index et l’arbre de travail sont préservés ; les modifications de ces commits peuvent donc être réunies dans un nouveau commit.
Exécutez cet exemple. Le code et les libellés ou sorties qu’il affiche restent en anglais :
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
cd "$work_dir"
git init -q
git config user.name "Example User"
git config user.email "example@example.com"
printf 'first version\n' > note.txt
git add note.txt
git commit -qm "Add note"
printf 'second version\n' > note.txt
git commit -qam "Update note"
git reset --soft HEAD~1
git status --short
L’exemple se termine sans erreur et affiche M note.txt, ce qui confirme que la modification reste indexée après la réinitialisation logicielle.
Vérifier les modifications indexées
Après la réinitialisation, utilisez git status pour confirmer que les fichiers voulus sont indexés. Utilisez git diff --cached pour examiner le patch indexé exact avant de créer un autre commit. L’option --cached compare l’index à HEAD, qui est désormais la cible sélectionnée. Si les modifications affichées ne sont pas celles que vous attendiez, arrêtez-vous et vérifiez la cible ainsi que le diff avant de valider.
Lorsque le patch indexé est correct, créez un commit de remplacement avec git commit -m "Describe the combined change". Pour modifier plutôt le commit le plus récent, git commit --amend le remplace ; vérifiez soigneusement le contenu indexé et le message du commit avant de confirmer. Une réinitialisation logicielle ne crée pas automatiquement de commit et ne modifie pas les messages de commit.
Comparaison de --soft avec --mixed et --hard
Les trois modes de réinitialisation déplacent la pointe de la branche actuelle vers la cible, mais traitent différemment l’index et l’arbre de travail :
git reset --soft <target>déplace la pointe de la branche et laisse l’index ainsi que l’arbre de travail inchangés. Les modifications des commits concernés restent indexées.git reset --mixed <target>déplace la pointe de la branche et met l’index en accord avec la cible, tout en laissant les fichiers de l’arbre de travail inchangés. Les modifications des commits dépassés ne sont plus indexées.--mixedest le mode par défaut si aucun mode n’est précisé.git reset --hard <target>déplace la pointe de la branche et met l’index ainsi que les fichiers suivis de l’arbre de travail en accord avec la cible. Les modifications suivies absentes de la cible peuvent être perdues ; utilisez ce mode uniquement si c’est bien le résultat voulu.
En général, les modes de réinitialisation laissent intacts les fichiers non suivis sans rapport avec l’opération. Toutefois, git reset --hard peut supprimer un fichier ou un répertoire non suivi s’il empêche l’écriture d’un chemin suivi présent dans la cible. Choisissez --soft si vous voulez conserver les modifications indexées pour créer un commit de remplacement ; choisissez --mixed si vous voulez les examiner comme modifications non indexées. N’utilisez pas --hard à la place d’une réinitialisation logicielle.
Quand utiliser git reset --soft en toute sécurité
La réinitialisation logicielle convient à la modification d’un historique local récent, par exemple pour regrouper plusieurs commits en un seul ou préparer leurs modifications pour un autre commit. Avant de l’exécuter, vérifiez la branche actuelle et la cible avec git status et git log --oneline. Ensuite, examinez git status et git diff --cached avant de valider, afin de ne pas inclure par erreur des modifications indexées sans rapport.
Si les commits ont déjà été partagés, déplacer la branche réécrit l’historique sur lequel d’autres personnes ont peut-être fondé leur travail. Coordonnez-vous avant de modifier un historique partagé ; pour annuler une modification publique tout en préservant l’historique, un revert est généralement plus adapté. Une réinitialisation logicielle ne modifie que le dépôt local jusqu’à ce que vous poussiez ensuite vos changements, mais pousser un historique réécrit peut perturber vos collaborateurs. Gardez la cible et le diff indexé bien en tête, et évitez le push forcé comme suite systématique.