Git a été écrit par Linus Torvalds en 2005 en deux semaines parce qu'il était en désaccord avec la licence de BitKeeper, le système de versioning qu'utilisait le noyau Linux. Deux semaines. L'outil que vous utilisez tous les jours pour versionner votre infrastructure, vos configs, vos secrets mal anonymisés et vos fichiers .env commités par accident a été écrit en deux semaines par quelqu'un qui était en colère.
Ça explique beaucoup de choses.
Aujourd'hui Git est partout, tout le monde l'utilise, et la grande majorité des gens connaissent six commandes : clone, add, commit, push, pull, status. C'est suffisant pour survivre. Ce guide parle de ce qui vient après - les commandes qui vous feront passer de "je survis" à "je comprends ce qui se passe".
La config .git/config et ~/.gitconfig - poser les bases
Avant tout le reste, votre config globale :
git config --global user.name "Cyril Beaufrère"
git config --global user.email "cyril@rudeops.com"
git config --global core.editor "vim"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global push.autoSetupRemote true
pull.rebase true - git pull fait un rebase par défaut au lieu d'un merge. Votre historique reste linéaire, vous évitez les commits de merge inutiles du type "Merge branch 'main' into main". rebase.autoStash true - si vous avez des modifications non commitées quand vous faites un rebase, Git les stash automatiquement avant et les réapplique après. Fini les "cannot pull with rebase: You have unstaged changes".
push.autoSetupRemote true - git push sur une nouvelle branche configure automatiquement le tracking remote sans vous demander de taper git push --set-upstream origin ma-branche. Disponible depuis Git 2.37, si vous êtes sur une version plus ancienne c'est le moment de mettre à jour.
Les alias qui changent la vie
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD"
git config --global alias.wip "commit -am 'WIP'"
git config --global alias.undo "reset HEAD~1 --mixed"
git lg vous donne un graphe ASCII de votre historique avec toutes les branches - bien plus lisible que git log par défaut. git undo annule le dernier commit en gardant les modifications dans votre working directory. git wip commit tout en un coup pour sauvegarder avant de changer de branche en urgence.
Si vous vous demandez quels paramètres valent vraiment la peine d'être configurés, les core devs de Git ont répondu à cette question lors d'une discussion dont j'ai parlé dans la newsletter du lundi 24 mars 2025 : 9 paramètres, 3 alias, et un consensus surprenant sur ce qui devrait être les nouvelles valeurs par défaut de Git.
Le reflog - le filet de sécurité que personne ne connaît
Le reflog est probablement la fonctionnalité Git la plus sous-estimée. C'est un journal de tout ce que Git a fait sur votre HEAD - chaque commit, chaque checkout, chaque rebase, chaque reset.
git reflog
Sortie typique :
a3f2c1d HEAD@{0}: commit: Fix connection timeout
b8e4d2a HEAD@{1}: rebase (finish): returning to refs/heads/main
b8e4d2a HEAD@{2}: rebase (pick): Add radar feature
c9f1a3b HEAD@{3}: checkout: moving from feature/radar to main
d2e8b4c HEAD@{4}: commit: WIP radar implementation
Vous avez fait un git reset --hard et perdu des commits ? Le reflog les a. Vous avez rebasé et quelque chose s'est mal passé ? Le reflog a l'état avant le rebase.
# Récupérer un commit "perdu"
git checkout HEAD@{3}
# Ou créer une branche depuis un état précédent
git checkout -b rescue HEAD@{3}
# Revenir à l'état avant un rebase catastrophique
git reset --hard HEAD@{5}
Le reflog est local - il n'est pas pushé. Et il expire après 90 jours par défaut. Mais dans la fenêtre de 90 jours, vous pouvez récupérer à peu près n'importe quoi. C'est la différence entre "j'ai tout perdu" et "j'ai eu chaud".
Le rebase interactif - réécrire l'histoire proprement
Le rebase interactif est l'outil pour nettoyer votre historique avant de pousser. Pas pour réécrire l'histoire sur main - pour présenter un historique lisible au lieu de vos commits de debug et vos "fix typo" en cascade.
# Réécrire les 5 derniers commits
git rebase -i HEAD~5
# Réécrire depuis la divergence avec main
git rebase -i main
L'éditeur s'ouvre avec quelque chose comme :
pick a3f2c1d Add radar feature
pick b8e4d2a Fix bug in radar
pick c9f1a3b Fix typo
pick d2e8b4c Another fix
pick e1f4a2b Final fix I promise
Les commandes disponibles :
pick # garder le commit tel quel
reword # garder le commit, modifier le message
edit # s'arrêter pour modifier le contenu du commit
squash # fusionner avec le commit précédent, combiner les messages
fixup # fusionner avec le commit précédent, ignorer le message
drop # supprimer le commit
Ce qu'on fait en pratique :
pick a3f2c1d Add radar feature
squash b8e4d2a Fix bug in radar
fixup c9f1a3b Fix typo
fixup d2e8b4c Another fix
fixup e1f4a2b Final fix I promise
Résultat : un seul commit propre "Add radar feature" qui contient toutes les modifications. Votre historique sur main reste lisible. Vos collègues vous remercient silencieusement.
Attention - ne rebasez jamais des commits déjà pushés sur une branche partagée. Réécrire l'histoire d'une branche que d'autres ont pullé crée des divergences et des conflits douloureux. Le rebase interactif c'est pour vos commits locaux avant le premier push, ou sur une branche feature que vous êtes le seul à utiliser.
Git bisect - trouver le commit qui a tout cassé
Vous avez un bug en prod. Il n'était pas là il y a une semaine. Vous avez 200 commits depuis. git bisect fait une recherche binaire dans votre historique pour trouver le commit exact qui a introduit le bug.
# Démarrer la bissection
git bisect start
# Indiquer que le commit actuel est mauvais
git bisect bad
# Indiquer un commit connu comme bon
git bisect good v1.2.0
# Ou avec un hash
git bisect good a3f2c1d
Git checkout automatiquement un commit au milieu de l'intervalle. Vous testez. Vous dites à Git si c'est bon ou mauvais :
git bisect good # ce commit est ok
git bisect bad # ce commit a le bug
Git répète jusqu'à isoler le commit coupable. Sur 200 commits, vous trouvez le coupable en 8 étapes (log2(200) ≈ 8). Quand c'est trouvé :
# Git vous affiche le commit coupable
# Puis vous revenez à la normale
git bisect reset
Automatiser avec un script
Si vous pouvez écrire un script qui retourne 0 si c'est bon et 1 si c'est mauvais :
git bisect start
git bisect bad HEAD
git bisect good v1.2.0
git bisect run ./test-bug.sh
Git tourne le script automatiquement sur chaque commit. Vous revenez 10 minutes plus tard avec le commit coupable identifié, sans avoir rien fait. C'est presque trop bien.
Git worktree - plusieurs branches en parallèle
Le problème classique : vous êtes en plein milieu d'un développement, votre chef arrive avec un bug critique en prod à corriger maintenant. Vous faites quoi ? git stash ? Nouveau clone dans un autre dossier ? Les deux sont des hacks.
git worktree permet d'avoir plusieurs branches checkoutées simultanément dans des dossiers séparés, depuis le même dépôt local.
# Lister les worktrees existants
git worktree list
# Créer un nouveau worktree pour un hotfix
git worktree add ../rudeops-hotfix hotfix/connexion-timeout
# Créer un worktree sur une nouvelle branche
git worktree add -b feature/glossaire ../rudeops-glossaire main
Vous avez maintenant :
~/rudeops/- votre branche feature en cours~/rudeops-hotfix/- le hotfix, complètement indépendant
Vous corrigez le bug dans rudeops-hotfix/, vous poussez, vous revenez dans rudeops/ exactement là où vous étiez. Pas de stash, pas de clone, pas de contexte perdu.
# Supprimer un worktree quand c'est fini
git worktree remove ../rudeops-hotfix
Le setup avec un repo bare
Pour une utilisation maximale des worktrees, un pattern courant consiste à cloner en bare :
# Cloner en bare dans un dossier caché
git clone --bare git@github.com:cyril/rudeops.git .bare
echo "gitdir: ./.bare" > .git
# Créer les worktrees
git worktree add main main
git worktree add feature/radar feature/radar
Vous avez un dossier par branche, un seul historique central. Aucune branche n'est "la principale" - tout est un worktree. C'est le setup des gens qui jonglent en permanence entre plusieurs branches sans perdre leur calme. J'en ai parlé dans la newsletter du lundi 23 mars 2026, avec la méthode bare détaillée étape par étape.
Git stash - au-delà du stash basique
Tout le monde connaît git stash et git stash pop. Peu de gens savent ce qui vient après.
# Stash avec un message descriptif
git stash push -m "WIP radar feature - fix pending"
# Stash incluant les fichiers non trackés
git stash push -u -m "Nouveau composant radar"
# Stash un seul fichier
git stash push -m "Juste ce fichier" -- src/components/Radar.tsx
# Lister les stashs
git stash list
# stash@{0}: On main: WIP radar feature - fix pending
# stash@{1}: On feature/radar: Nouveau composant radar
# Appliquer un stash spécifique sans le supprimer
git stash apply stash@{1}
# Appliquer et supprimer
git stash pop stash@{1}
# Voir le contenu d'un stash
git stash show -p stash@{0}
# Créer une branche depuis un stash
git stash branch feature/from-stash stash@{0}
git stash branch est particulièrement utile : vous aviez commencé à travailler sur main, vous réalisez que ça devrait être une branche, vous créez la branche directement depuis le stash. Propre, sans copier-coller.
Git log - trouver ce qu'on cherche
git log par défaut est illisible. Avec les bons flags, c'est un outil de recherche puissant.
# Historique graphique compact
git log --oneline --graph --decorate --all
# Chercher dans les messages de commit
git log --grep="radar" --oneline
# Chercher dans le contenu des modifications
git log -S "time_namelookup" --oneline
# Commits d'un auteur
git log --author="Cyril" --oneline
# Commits sur un fichier spécifique
git log --follow --oneline -- src/components/Radar.tsx
# Commits entre deux dates
git log --after="2026-01-01" --before="2026-03-01" --oneline
# Voir ce qui a changé dans un commit
git show a3f2c1d
# Voir qui a modifié chaque ligne d'un fichier
git blame -L 10,30 src/components/Radar.tsx
git log -S (le pickaxe) est particulièrement puissant : il trouve tous les commits qui ont ajouté ou supprimé une chaîne de caractères spécifique. Vous cherchez quand une fonction a été supprimée, quand une variable a été introduite - le pickaxe le trouve.
git blame vous dit qui a écrit chaque ligne et dans quel commit. Utile pour comprendre le contexte d'un code bizarre. Résistez à l'envie de l'utiliser pour accuser vos collègues - git blame ne montre pas pourquoi, seulement qui et quand.
Git cherry-pick - prendre un commit sans prendre la branche
Vous avez un commit sur une branche feature qui corrige un bug, et vous avez besoin de ce fix sur main sans merger toute la branche.
# Cherry-pick d'un commit unique
git cherry-pick a3f2c1d
# Cherry-pick d'une plage de commits
git cherry-pick a3f2c1d..e1f4a2b
# Cherry-pick sans committer (pour modifier avant)
git cherry-pick -n a3f2c1d
# En cas de conflit
git cherry-pick --continue
git cherry-pick --abort
Cherry-pick crée un nouveau commit avec les mêmes modifications mais un hash différent. Le commit original reste sur sa branche d'origine. C'est une copie, pas un déplacement.
À utiliser avec parcimonie sur des branches long-lived - vous créez une divergence qui peut compliquer les merges futurs. Sur une branche de hotfix ponctuelle, c'est l'outil parfait.
Git reset vs git revert - ne pas confondre
La confusion la plus courante, avec des conséquences parfois catastrophiques.
git reset - rembobine l'historique local :
# Annuler le dernier commit, garder les modifications (mode par défaut)
git reset HEAD~1
git reset --mixed HEAD~1
# Annuler le dernier commit, garder les modifications dans le staging
git reset --soft HEAD~1
# Annuler le dernier commit, supprimer les modifications
git reset --hard HEAD~1
git reset réécrit l'historique. Sur des commits déjà pushés, c'est une très mauvaise idée sauf si vous êtes prêt à faire un git push --force et à avoir une conversation inconfortable avec vos collègues.
git revert - crée un nouveau commit qui annule les modifications :
# Créer un commit qui annule a3f2c1d
git revert a3f2c1d
# Annuler sans committer immédiatement
git revert -n a3f2c1d
# Annuler une plage de commits
git revert a3f2c1d..e1f4a2b
git revert ne réécrit pas l'historique. Il ajoute un commit. C'est la seule option safe sur des branches partagées ou des commits déjà pushés. Votre collègue qui a pullé votre branche ne se retrouvera pas avec des divergences incompréhensibles.
Règle simple : reset pour l'historique local non pushé, revert pour tout ce qui est déjà partagé.
.gitignore - ce qu'on oublie toujours
# Ignorer un fichier déjà tracké
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "Stop tracking .env"
# Ignorer globalement sur toute votre machine
git config --global core.excludesfile ~/.gitignore_global
Si vous avez commité des secrets par accident :
# Supprimer un fichier de tout l'historique (recommandé)
pip install git-filter-repo
git filter-repo --path .env --invert-paths
Après ça, git push --force sur toutes les branches et rotation immédiate de tous les secrets exposés. Le filtre nettoie votre repo local et pushé, mais les secrets commités doivent toujours être considérés comme compromis, même après nettoyage.
Pour auditer un repo existant et détecter les secrets déjà commités, Gitleaks fait le job - léger, rapide, lancez-le sur l'historique complet avant de rendre un repo public. J'en ai parlé dans la newsletter du lundi 6 janvier 2025.
À retenir
| Commande | Pour quoi |
|---|---|
git reflog | Retrouver des commits "perdus" |
git rebase -i HEAD~N | Nettoyer les N derniers commits |
git bisect start/good/bad | Trouver le commit coupable |
git worktree add ../dossier branche | Deux branches en parallèle |
git stash push -m "message" | Stash nommé |
git log -S "string" | Trouver quand une string a changé |
git cherry-pick hash | Copier un commit sur la branche courante |
git revert hash | Annuler un commit pushé proprement |
git rm --cached fichier | Arrêter de tracker un fichier |
FAQ
Quelle différence entre git merge et git rebase ?
merge crée un commit de fusion, préserve l'historique exact. rebase réapplique vos commits sur la branche cible, donne un historique linéaire. Sur des branches feature personnelles : rebase. Sur des branches partagées : merge. Les deux ont leur place, le dogmatisme dans un sens ou l'autre est inutile.
Comment annuler un git push --force catastrophique ?
Si quelqu'un avait pullé avant votre force push, leur reflog local a l'ancien état. Récupérez le hash auprès de ce collègue et faites un git push --force avec ce hash. Si personne n'avait pullé, votre propre reflog local a l'état avant le force push.
git pull --rebase ou git pull --merge ?
--rebase par défaut (via pull.rebase true dans la config). Votre historique reste linéaire, pas de commits de merge parasites. Si vous travaillez sur une branche longue avec plusieurs personnes qui pushent régulièrement, --merge peut être plus safe pour éviter les conflits de rebase répétés.
Comment voir les branches distantes supprimées côté remote ?
git fetch --prune supprime localement les références aux branches distantes qui n'existent plus. Ajoutez fetch.prune=true dans votre config globale pour que ce soit automatique à chaque fetch.
J'ai commité sur main par erreur, comment déplacer sur une branche ?
git branch ma-feature # créer la branche au commit actuel
git reset --hard origin/main # revenir main à l'état remote
git checkout ma-feature # aller sur la branche
Pour aller plus loin
- Pro Git - le livre officiel, gratuit, en français, exhaustif
- Oh Shit, Git! - les situations catastrophiques et comment s'en sortir
- Lazygit - mon favori : une interface terminal pour Git qui transforme la douleur en quelque chose de vaguement ergonomique. Mentionné plusieurs fois dans les newsletters, la dernière dans la newsletter du lundi 24 novembre 2025
- Gitleaks - détecter les secrets dans votre historique Git avant qu'il ne soit trop tard
- git-filter-repo - nettoyer l'historique proprement
man git-rebase,man git-bisect- les pages de manuel sont bien écrites pour une fois