4.2 — Git en profondeur
🎯 Objectif : ne plus avoir peur de Git. Comprendre ce qu’est un commit, savoir réécrire l’historique proprement, et toujours pouvoir récupérer un travail perdu.
À l'issue de cet axe, tu sauras :
- Expliquer ce qu'est un commit (un snapshot, pas un diff)
- Distinguer merge, rebase, cherry-pick et savoir quand utiliser chacun
- Récupérer un commit perdu avec git reflog
- Choisir entre GitFlow, GitHub Flow et trunk-based
- Écrire des messages de commit selon Conventional Commits
Débutant
Le modèle mental — un graphe de snapshots
Section intitulée « Le modèle mental — un graphe de snapshots »Un commit n’est pas un diff. C’est un snapshot complet de tous les fichiers à un instant donné, identifié par un hash SHA-1.
flowchart RL
C4["c4: f3a2... (HEAD, main)<br/>fix bug auth"]
C3["c3: 9b1e...<br/>add login form"]
C2["c2: 2d8a...<br/>scaffold app"]
C1["c1: e7c4...<br/>initial commit"]
C4 --> C3 --> C2 --> C1 Chaque commit contient :
- Un hash unique (SHA-1).
- Un pointeur vers son parent (ou plusieurs en cas de merge).
- L’arbre des fichiers à ce moment.
- Métadonnées : auteur, message, date.
Une branche est juste un pointeur mobile vers un commit. main pointe vers le dernier commit de main. Quand tu fais un commit, le pointeur avance.
La zone de travail — 4 états
Section intitulée « La zone de travail — 4 états »Un fichier dans Git peut être dans 4 endroits :
flowchart LR
WD[Working Directory<br/>fichiers édités] -->|git add| Staging[Staging area<br/>index]
Staging -->|git commit| Local[Local repo<br/>commits]
Local -->|git push| Remote[Remote repo<br/>GitHub/GitLab]
Remote -->|git fetch| Local
Remote -->|git pull| WD Voir l’état
Section intitulée « Voir l’état »git status # vue d'ensemblegit diff # diff working dir vs staginggit diff --staged # diff staging vs dernier commitgit log --oneline -10 # 10 derniers commitsgit log --graph --oneline --all # graphe visuel des branchesWorkflow quotidien — les 10 commandes essentielles
Section intitulée « Workflow quotidien — les 10 commandes essentielles »# Configurer (une fois)git config --global user.name "Ton Nom"git config --global user.email "ton@email.com"git config --global init.defaultBranch maingit config --global pull.rebase false
# Démarrergit clone <url> # cloner un repogit init # nouveau repo
# Travaillergit checkout -b feat/login # créer + basculer sur une branchegit status # qu'est-ce que j'ai modifié ?git add fichier.js # stage un fichiergit add . # stage tout (avec précaution !)git commit -m "feat: add login form" # créer un commitgit push -u origin feat/login # pousser et tracker la branche
# Mettre à jourgit fetch # récupérer les changements distants (sans merger)git pull # fetch + mergegit pull --rebase # fetch + rebase (historique plus propre)Branches — créer, basculer, fusionner
Section intitulée « Branches — créer, basculer, fusionner »Créer / basculer
Section intitulée « Créer / basculer »git branch # liste les branches localesgit branch -a # locales + distantesgit checkout -b feat/login # créer + basculer (Git < 2.23)git switch -c feat/login # même chose, syntaxe modernegit switch main # revenir sur maingit switch - # retourner sur la précédenteFusionner — merge vs rebase
Section intitulée « Fusionner — merge vs rebase »Tu as travaillé sur feat/login, pendant que main a évolué. Comment intégrer ?
Option 1 — Merge
Section intitulée « Option 1 — Merge »git switch maingit pullgit merge feat/loginCrée un commit de merge qui a deux parents.
gitGraph
commit id: "A"
commit id: "B"
branch feat/login
checkout feat/login
commit id: "L1"
commit id: "L2"
checkout main
commit id: "C"
merge feat/login id: "M" ✅ Préserve l’historique réel. ❌ Historique « complexe » à long terme (beaucoup de commits de merge).
Option 2 — Rebase
Section intitulée « Option 2 — Rebase »git switch feat/logingit rebase main # rejoue les commits de feat/login après maingit switch maingit merge feat/login # fast-forward, pas de merge commitgitGraph
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "L1'"
commit id: "L2'" ✅ Historique linéaire, lisible. ❌ Réécrit l’historique : dangereux sur des branches partagées !
Squash — un seul commit pour la PR
Section intitulée « Squash — un seul commit pour la PR »Quand ta branche a 12 commits « wip », « fix », « re-fix », tu veux les fusionner en 1 seul commit propre avant de pousser :
git rebase -i main# Dans l'éditeur, garde "pick" sur le 1er, change les autres en "squash" ou "s"Ou directement à la PR : la plupart des plateformes (GitHub, GitLab) ont un bouton « Squash and merge ».
Les outils avancés à connaître
Section intitulée « Les outils avancés à connaître »git stash — mettre de côté
Section intitulée « git stash — mettre de côté »Tu travailles sur une feature, on te demande de fixer un bug urgent ailleurs :
git stash # sauvegarde le working dir et le nettoiegit switch maingit switch -c fix/urgent# ... travail urgent ...git switch feat/logingit stash pop # restaure ton travailgit cherry-pick — appliquer un commit ailleurs
Section intitulée « git cherry-pick — appliquer un commit ailleurs »Tu as un fix sur feat/login qui doit aussi aller sur main immédiatement :
git switch maingit cherry-pick <hash-du-commit>git reflog — la machine à remonter le temps
Section intitulée « git reflog — la machine à remonter le temps »« J’ai perdu mon commit ! » Non, tu ne l’as jamais vraiment perdu. Git garde un historique de toutes tes manipulations pendant ~90 jours.
git reflog# 1a2b3c HEAD@{0}: reset: moving to HEAD~1# 4d5e6f HEAD@{1}: commit: feat: add awesome feature# ...
git reset --hard 4d5e6f # récupère le commit perduC’est ton filet de sécurité ultime. Si tu te plantes — git reset --hard, git rebase cassé, etc. — reflog te sauve.
git bisect — trouver le commit qui a introduit un bug
Section intitulée « git bisect — trouver le commit qui a introduit un bug »Recherche binaire dans l’historique :
git bisect startgit bisect bad # le commit actuel est casségit bisect good v1.2.0 # cette version marchait# Git checkout un commit au milieu# Tu testes, puis :git bisect good # ou bad selon le résultat# Répète jusqu'à trouver le coupablegit bisect resetgit worktree — plusieurs branches en parallèle
Section intitulée « git worktree — plusieurs branches en parallèle »Tu veux travailler sur une feature et un fix simultanément, sans stash :
git worktree add ../mon-repo-fix fix/urgent# Tu as maintenant 2 dossiers, 2 branches activesStratégies de branching
Section intitulée « Stratégies de branching »GitHub Flow — simple et efficace
Section intitulée « GitHub Flow — simple et efficace »gitGraph
commit id: "v1.0"
branch feat/login
checkout feat/login
commit id: "wip"
commit id: "ok"
checkout main
merge feat/login id: "PR fusionnée"
branch fix/bug
checkout fix/bug
commit id: "fix"
checkout main
merge fix/bug mainest toujours déployable.- Chaque feature/fix → une branche.
- PR → review → merge sur main.
- Déploiement après chaque merge (continuous deployment).
Pour 90 % des équipes web modernes, c’est le bon choix.
Trunk-based development
Section intitulée « Trunk-based development »Encore plus radical : tout le monde commit directement sur main (avec feature flags pour cacher l’incomplet). Pour les équipes très matures avec excellente CI/CD.
GitFlow — l’historique
Section intitulée « GitFlow — l’historique »Plus complexe : main, develop, feature/*, release/*, hotfix/*. Surdimensionné pour la plupart des projets web modernes, encore utilisé sur certains projets avec releases trimestrielles.
Conventional Commits
Section intitulée « Conventional Commits »Format normalisé pour les messages de commit :
<type>[scope optionnel]: description courte
[corps optionnel : pourquoi]
[footer optionnel : BREAKING CHANGE, Refs #123]Types courants :
| Type | Usage |
|---|---|
feat | Nouvelle fonctionnalité |
fix | Correction de bug |
docs | Documentation seulement |
style | Formatage (pas de logique) |
refactor | Réorganisation sans changement fonctionnel |
perf | Amélioration de perf |
test | Ajout/correction de tests |
build | Système de build, dépendances |
ci | Configuration CI |
chore | Maintenance |
Exemples :
feat(auth): add password reset flow
Lien vers issue #145.
BREAKING CHANGE: l'endpoint /reset-password est devenu /auth/reset-passwordfix: prevent crash when user has no avatar
Returns a default avatar URL instead of throwing.
Refs #234Pourquoi c’est utile :
- Les changelogs se génèrent automatiquement (
standard-version,changesets). - Le versioning sémantique se déduit (
feat→ minor,fix→ patch,BREAKING CHANGE→ major). - L’historique se survole en un coup d’œil.
Bonnes pratiques
Section intitulée « Bonnes pratiques »Faire des commits petits et atomiques
Section intitulée « Faire des commits petits et atomiques »Un commit = un changement logique cohérent. Pas « Save de fin de journée ».
Mauvais :
- 47 fichiers changés en 1 commit- "wip"Bon :
- feat(auth): add login form- feat(auth): add password validation- test(auth): cover login error cases- docs(auth): document JWT expirationTu pourras revenir en arrière sur une partie sans perdre les autres. Les PR sont plus reviewables.
.gitignore
Section intitulée « .gitignore »Ce qu’il faut ignorer :
node_modules/.env.env.*.localdist/build/.DS_StoreThumbs.db.vscode/ # ← discutable, certains aiment versionner.idea/*.logcoverage/Ce qui ne doit jamais être commit :
- Mots de passe, clés API, JWT secrets.
- Fichiers binaires lourds (préfère Git LFS).
- Dossiers
node_modules/(régénérables).
Si tu as commit un secret par erreur
Section intitulée « Si tu as commit un secret par erreur »# C'est URGENT. Le secret est dans l'historique distant.# 1. Révoquer le secret immédiatement (rotate API key, etc.)# 2. Réécrire l'historique avec git-filter-repo ou BFG Repo-Cleaner# 3. Force-push (avec accord équipe — change l'historique pour tout le monde)Ne pas se contenter d’un nouveau commit qui supprime le fichier. Le secret reste dans l’historique. Toujours révoquer d’abord.
Auto-évaluation
Section intitulée « Auto-évaluation »Pour aller plus loin
Section intitulée « Pour aller plus loin »- Pro Git — Scott Chacon (gratuit, en français) : git-scm.com/book/fr/v2
- Oh Shit, Git!?! — ohshitgit.com — comment se sortir des situations classiques
- Learn Git Branching — learngitbranching.js.org — visualisations interactives
- Conventional Commits — conventionalcommits.org
Suite : 4.3 — Gestion de paquets — npm, semver, lockfiles, monorepos.