Voilà un aide mémoire pour retrouver comment corriger quelques unes des erreurs que l’on peut faire avec git
.
En local
Attention : on ne parle ici que de corrections locales, c’est-à-dire qui n’ont pas été poussées dans le dépôt.
Avant le commit
On a ajouté par erreur un ou plusieurs fichiers dans l’index, on les enlève en faisant :
$ git checkout -- fichier1 fichier2 ...
Si on veut carrément tout des-indexer :
$ git reset HEAD
Modification du dernier commit
La commande suivante modifie le message du dernier commit et ajoute les fichiers présents dans l’index :
$ git commit --amend -m "mon message modifié"
Si on ne précise pas le message, l'éditeur s’ouvre et on peut soit garder le même message, soit corriger l’ancien (typo par exemple).
Annuler le(s) dernier(s) commit(s)
Pour revenir en arrière, et annuler par exemple le dernier commit :
$ git reset HEAD^1
Plus généralement :
$ git reset <commit>
Il y a trois modes :
--soft
remet les fichiers dans l’index comme avant le commit, les modifications locales sont conservées ;--mixed
(mode par défaut) récupère les fichiers dans la copie de travail, mais les modifications locales sont conservées ;--hard
récupère l'état au moment du commit : les modifications locales sont perdues.
Il faut noter qu’on peut récupérer un seul fichier :
$ git reset <commit> <fichier>
Pour corriger un commit plus ancien
Il s’agit ici de revenir sur un commit qui n’est pas le dernier, par exemple pour corriger le message, modifier ou ajouter des fichiers, mais sans perdre les commit qu’on a fait depuis.
$ git rebase --interactive <commit>^
Le ^
(signifie -1) et permet de se placer sur le commit
juste avant de celui qu’on veut modifier.
L'éditeur s’ouvre avec la liste des commit :
il faut remplacer pick pour edit devant celui qu’on veut modifier,
ou par reword
si on veut juste modifier le message.
Si on a choisi edit, on se retrouve alors dans une branche REBASE
et l’on peut faire les modifications que l’on souhaite,
puis on met à jour le commit
(ne pas mettre --no-edit
si on veut modifier le message) :
$ git commit -a --amend --no-edit
Et on rejoue les autres commit à partir de cette version modifiée :
$ git rebase --continue
Échanger deux commits
$ git rebase --interactive <commit>
Dans l'éditeur, on laisse pick
, mais on peut changer l’ordre des lignes.
Si on a des modification en cours, on peut toujours les sauver avant :
$ git stash
et les restaurer après :
$ git stash pop
Fusionner plusieurs commits (avec rebase)
Ça peut aussi se faire avec le commande rebase
,
mais il faut cette fois remplacer pick par squash
sur une ou plusieurs lignes consécutives.
Supposons qu’on ait:
o - (HEAD, master) fix2
o - fix1
o - new feature
o - (origin/master, origin/HEAD) ...
mais on veut ne pousser qu’un seul commit tout propre. On va faire :
git rebase -i HEAD~3
L'éditeur s’ouvre alors avec les trois derniers commit, et il faut cette fois remplacer pick par squash pour les deux commits que l’on souhaite fusionner:
pick xxx new feature
squash yyy fix1
squash zzz fix2
L'éditeur s’ouvre alors avec la liste des anciens messages de commit et il faut saisir le nouveau message.
S’il y a des conflits,
ils se corrigent à l’aide de successions de git add
et git rebase --continue
,
ou bien on peut abandonner l’opération avec git rebase --abort
.
Fusionner plusieurs commits (avec reset)
Quand on fait un pull request
,
il arrive souvent qu’il y ait des demandes de corrections avant l’intégration.
A la fin,
on peut avoir envie de tout remettre sous la forme d’un seul commit
.
Voilà comment faire :
$ git checkout nouveau_dev # doit être pareil que origin/nouveau_dev
$ git status # doit être propre
$ git reset --soft <commit> # le commit juste avant le début de nouveau_dev
$ git commit -m 'message'
$ git push -f origin nouveau_dev
Et hop : ça a du effacer tous les commits de cette branche et le remplacer par un seul, tout propre.
Sur un dépôt privé
Quand on utilise un dépôt privé à soi tout seul, on peut se permettre de faire
tout ce qui a été dit au sujet des modifications locales.
Il faut juste utiliser -f
pour pousser ça sur le dépôt
sans que git
ne râle :
$ git push -f private_repo branch
Sur un dépôt public
Sur un dépôt public, utilisé par d’autre, il est fortement déconseillé de
réécrire l’histoire, c’est-à-dire de modifier les commits existants.
Dans ce cas, le mieux est de refaire un ou plusieurs commits pour annuler
l’erreur. On peut pour cela s’aider avec la commande revert
qui construit le commit correspondant.
Si par exemple on part de la situation:
A -- B -- C -- D -- E (HEAD)
Pour annuler C
, on fait :
$ git revert HEAD~2
On va avoir avoir (en local) :
A -- B -- C -- D -- E -- F
avec F
qui est dans le même état que E
si on n’avait pas fait C
.
Pour annuler plusieurs commits, on peut faire :
$ git revert HEAD~5..HEAD
Il ne reste plus qu'à pousser ce nouveau commit dans le dépôt.
Si on veut voir ce qui se passe avant de faire le nouveau commit,
on peut utiliser l’option -n
.
Documentation
Voir aussi :
- Git : déménagement d'un dépôt
- Git rebase : pour diviser un commit
- Git submodule
- Git : pour extraire de l'information
- Git bisect : pour trouver l'origine d'une régression
- Git tag : pour nommer des versions
- Git archive : exporter du contenu
- Git subtree : créer un nouveau dépôt à partir du répertoire d'un autre dépôt
- Git : au sujet des pull requests
- Git : les branches
- Git diff : voir les différences
- Git clean : grand nettoyage
- Git : aide mémoire de base
- Afficher un pourcentage dans une page HTML
- VNC : Virtual Network Computing
- Git : déménagement d'un dépôt
- Quelques liens au sujet de l'analyse statique
- Ocaml: mon principal langage de développement
- Disque dur externe
- Les profiles dans Firefox
- Cryptographie et mail sous Android
- Quelques liens au sujet du C
- Git rebase : pour diviser un commit