1. Concept de branche
Une branche Git n'est rien d'autre qu'un pointeur léger vers un commit. Contrairement à SVN où une branche est une copie complète du projet, une branche Git ne coûte que 41 octets (un fichier contenant le hash SHA-1 du commit cible).
HEAD — où vous vous trouvez
HEAD est un pointeur spécial qui indique le commit (ou la branche) sur lequel
vous vous trouvez actuellement. Quand vous commitez, la branche active avance automatiquement.
┌──────────────────────────────────────────────────────────┐
│ │
│ Commit A ──→ Commit B ──→ Commit C │
│ ↑ │
│ main ← HEAD │
│ │
│ (HEAD pointe sur main, qui pointe sur commit C) │
└──────────────────────────────────────────────────────────┘
Pourquoi utiliser des branches ?
| Cas d'usage | Branche recommandée |
|---|---|
| Développer une nouvelle fonctionnalité | feature/nom-fonctionnalite |
| Corriger un bug en production | hotfix/description-bug |
| Préparer une release | release/1.2.0 |
| Expérimenter une idée | experiment/mon-idee |
| Code principal stable | main ou master |
| Intégration continue | develop |
Diagramme : branches parallèles
A ──→ B ──→ C ──→ D ──→ G (main)
↘ ↗
E ──→ F (feature/login)
Chaque lettre = un commit
G = commit de merge (deux parents : D et F)
Git branch — lister les branches
# Lister les branches locales
git branch
# Lister avec le hash du dernier commit
git branch -v
# Lister les branches déjà mergées dans main
git branch --merged main
# Lister les branches NON mergées
git branch --no-merged
2. Créer et naviguer
Créer une branche
# Créer une branche (reste sur la branche courante)
git branch feature/login
# Créer une branche et basculer dessus (syntaxe moderne - Git 2.23+)
git switch -c feature/dashboard
# Ancienne syntaxe (toujours valide)
git checkout -b feature/dashboard
# Créer une branche à partir d'un commit spécifique
git branch hotfix/crash a3f8c1d
Naviguer entre les branches
# Basculer sur une branche existante (moderne)
git switch main
# Ancienne syntaxe
git checkout main
# Revenir à la branche précédente (comme cd - en bash)
git switch -
# Basculer vers un commit détaché (detached HEAD)
git switch --detach a3f8c1d
Lister toutes les branches (locales + distantes)
# Toutes les branches locales et distantes
git branch -a
# Exemple de sortie :
* feature/login ← branche courante (étoile)
main
remotes/origin/main
remotes/origin/develop
Comparaison switch vs checkout
| Action | git switch (moderne) | git checkout (classique) |
|---|---|---|
| Changer de branche | git switch nom | git checkout nom |
| Créer + basculer | git switch -c nom | git checkout -b nom |
| Revenir en arrière | git switch - | git checkout - |
| Detached HEAD | git switch --detach hash | git checkout hash |
switch pour les branches, restore pour les fichiers.
git checkout faisait les deux, ce qui créait de la confusion.
3. Merge
Le merge intègre les changements d'une branche dans une autre. Git choisit automatiquement la stratégie de merge selon la situation.
Fast-Forward Merge
Quand la branche cible n'a pas divergé depuis la création de la feature branch, Git avance simplement le pointeur — pas de commit de merge créé.
# Situation initiale (pas de divergence) :
A ──→ B ──→ C (main)
↓
D ──→ E (feature/login)
# Après : git switch main && git merge feature/login
A ──→ B ──→ C ──→ D ──→ E (main, feature/login)
(simple avancée du pointeur — fast-forward)
# Commande de merge fast-forward
git switch main
git merge feature/login
# → Fast-forward
3-Way Merge (merge commit)
Quand les deux branches ont divergé (main a avancé depuis la création de la feature branch), Git crée un commit de merge avec deux parents.
# Situation avec divergence :
A ──→ B ──→ C ──→ D (main)
↓
E ──→ F (feature/navbar)
# Après : git merge feature/navbar
A ──→ B ──→ C ──→ D ──→ G (main)
↗
E ──→ F (feature/navbar)
(G = commit de merge avec 2 parents : D et F)
# Forcer un merge commit même si fast-forward possible
git merge --no-ff feature/navbar
# Message personnalisé pour le commit de merge
git merge --no-ff -m "merge: intégrer feature/navbar" feature/navbar
Fast-Forward vs No-FF — comparaison
| Aspect | Fast-Forward | --no-ff (Merge commit) |
|---|---|---|
| Historique | Linéaire (propre) | Avec branches visibles |
| Commit de merge | Non créé | Créé systématiquement |
| Traçabilité | Plus difficile | Claire (on voit les features) |
| git revert d'une feature | Difficile (commits éparpillés) | Facile (revert du merge commit) |
| Recommandé pour | Branches courtes, solo | Équipes, features complètes |
git merge --no-ff ou
les Pull Requests (GitHub/GitLab) qui créent automatiquement un merge commit.
Cela garde une trace claire de chaque feature intégrée.
4. Résolution de conflits
Un conflit survient quand deux branches ont modifié les mêmes lignes d'un même fichier. Git ne peut pas décider automatiquement quelle version garder.
Exemple de conflit
# Situation : les deux branches ont modifié navbar.js
git switch main
git merge feature/navbar
# Auto-merging navbar.js
CONFLICT (content): Merge conflict in navbar.js
Automatic merge failed; fix conflicts and then commit the result.
Marqueurs de conflit dans le fichier
// navbar.js après conflit :
function initNavbar() {
<<<<<<< HEAD
// Version de main
setTheme('dark');
addMenuItems(['Accueil', 'Contact']);
=======
// Version de feature/navbar
setTheme('light');
addMenuItems(['Accueil', 'Blog', 'Contact']);
>>>>>>> feature/navbar
}
Comprendre les marqueurs
| Marqueur | Signification |
|---|---|
<<<<<<< HEAD | Début de la version de votre branche courante (HEAD) |
======= | Séparateur entre les deux versions |
>>>>>>> feature/navbar | Fin de la version de la branche mergée |
Étapes de résolution
// ① Ouvrir le fichier en conflit dans votre éditeur
// ② Choisir la version correcte (ou combiner les deux) :
function initNavbar() {
setTheme('dark'); // ← gardé de HEAD
addMenuItems(['Accueil', 'Blog', 'Contact']); // ← gardé de feature
}
// ③ Supprimer TOUS les marqueurs (<<<, ===, >>>)
# ③ Marquer le conflit comme résolu
git add navbar.js
# ④ Vérifier qu'il ne reste pas de conflits
git status
# ⑤ Créer le commit de merge
git commit -m "merge: résoudre conflit navbar.js — combiner thème et menu"
Abandonner un merge
# Annuler le merge en cours (revenir à l'état avant merge)
git merge --abort
Outils visuels de merge
# Ouvrir l'outil de merge configuré
git mergetool
# Configurer VS Code comme outil de merge
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
git diff --check
pour vérifier qu'il ne reste aucun marqueur avant de committer.
5. Supprimer et renommer
Supprimer une branche mergée
# Supprimer une branche locale (déjà mergée = safe)
git branch -d feature/login
# Vérifier quelles branches sont mergées dans main
git branch --merged main
Forcer la suppression
# Supprimer une branche NON mergée (perte de commits potentielle !)
git branch -D feature/abandon
# ⚠️ -D est équivalent à --delete --force
# Les commits "perdus" restent dans git reflog pendant 30 jours
Renommer une branche
# Renommer la branche courante
git branch -m nouveau-nom
# Renommer une branche spécifique
git branch -m ancien-nom nouveau-nom
# Cas pratique : renommer master en main
git branch -m master main
Supprimer une branche distante
# Supprimer la branche sur origin (distant)
git push origin --delete feature/login
# Nettoyer les références distantes obsolètes
git fetch --prune
Bonnes pratiques de nommage
| Préfixe | Usage | Exemple |
|---|---|---|
feature/ | Nouvelle fonctionnalité | feature/user-auth |
fix/ | Correction de bug | fix/login-crash |
hotfix/ | Correctif urgent en prod | hotfix/security-xss |
release/ | Préparation de version | release/2.1.0 |
chore/ | Maintenance, refactoring | chore/update-deps |
docs/ | Documentation | docs/api-guide |
test ou temp.
6. Branches distantes
Les branches distantes (remote-tracking branches) sont des références locales
qui reflètent l'état des branches sur le dépôt distant (origin).
Elles ont le format origin/nom-branche.
Récupérer les changements distants
# Fetch : télécharger les changements SANS merger
git fetch origin
# Fetch d'une branche spécifique
git fetch origin feature/login
# Pull : fetch + merge automatique
git pull origin main
# Pull en rebase (historique linéaire)
git pull --rebase origin main
Pousser une branche
# Pousser et créer le tracking automatique
git push -u origin feature/login
# Une fois le tracking configuré
git push
# Pousser sur une branche distante différente
git push origin feature/login:feature/login-v2
Différence fetch vs pull
| Commande | Ce qui se passe | Modifie votre Working Dir |
|---|---|---|
git fetch origin |
Télécharge les commits distants dans origin/main, etc. |
Non — sûr à tout moment |
git pull origin main |
Fetch + merge de origin/main dans la branche courante |
Oui — peut créer des conflits |
Branches de tracking
# Voir le tracking de toutes les branches
git branch -vv
# Exemple de sortie :
* feature/login a3f8c1d [origin/feature/login: ahead 2] feat: ajouter form
main 7b2e4a9 [origin/main] feat: page accueil
# "ahead 2" = 2 commits locaux non poussés
# "behind 3" = 3 commits distants non récupérés
Récupérer une branche distante en local
# Créer une branche locale qui track la branche distante
git switch -c feature/login origin/feature/login
# Raccourci (Git 2.23+)
git switch feature/login
# Ancienne syntaxe
git checkout --track origin/feature/login
Workflow typique avec remote
# 1. Créer et basculer sur une nouvelle branche
git switch -c feature/mon-widget
# 2. Développer (add + commit)
git add .
git commit -m "feat: ajouter widget météo"
# 3. Pousser et ouvrir une Pull Request
git push -u origin feature/mon-widget
# 4. Après merge de la PR, nettoyer
git switch main
git pull origin main
git branch -d feature/mon-widget
git push origin --delete feature/mon-widget