Les branches Git : git branch pour créer, changer et supprimer une branche
Dans Git, une branche est un simple pointeur léger vers un commit, et HEAD indique la branche sur laquelle vous vous trouvez. git branch liste, crée, renomme et supprime les branches, git switch permet de passer de l'une à l'autre, et git switch -c nom crée une branche et s'y place immédiatement.
Qu'est-ce qu'une branche Git ?
Une branche Git n'est pas une copie du projet, mais un petit fichier contenant le hash d'un seul commit. Créer une branche prend une fraction de seconde et ne consomme presque pas d'espace, car Git ne duplique rien : toutes les branches pointent vers les mêmes objets de la base du dépôt. Quand vous faites un commit, le pointeur de la branche courante avance simplement sur le nouveau commit.
Cela change la façon de les voir. Inutile de les craindre ou de les économiser : une branche dédiée pour chaque tâche, correctif ou expérimentation, c'est la pratique normale. Si l'expérience échoue, on supprime la branche et l'historique principal reste propre.
Vous pouvez constater par vous-même qu'une branche n'est qu'un fichier :
$ cat .git/refs/heads/main
8b7d4e2a9f1c0d3e5b6a7c8d9e0f1a2b3c4d5e6f
(Dans les gros dépôts, une partie des références est compactée dans .git/packed-refs, le fichier peut donc ne pas exister — le principe reste le même.)
HEAD dans Git : où vous vous trouvez
HEAD est le pointeur vers ce qui est actuellement extrait dans votre répertoire de travail. En général, HEAD ne pointe pas vers un commit, mais vers une branche :
$ cat .git/HEAD
ref: refs/heads/main
La chaîne est donc : HEAD → main → commit. Un nouveau commit prend pour parent le commit visé par HEAD, puis Git avance la branche vers laquelle pointe HEAD. C'est pour cela que les commits « atterrissent » dans la branche courante.
Si vous vous placez directement sur un commit ou un tag (git switch --detach v1.0 ou git checkout 3f2a1c9), HEAD pointe directement vers le commit. On appelle cet état un detached HEAD (HEAD détachée). Consulter le code dans cet état ne pose aucun problème, mais les nouveaux commits ne sont rattachés à aucune branche et on les perd facilement après avoir changé de branche. Si vous commencez à modifier quelque chose, créez une branche sur place : git switch -c fix-from-old-version.
Dans les expressions, HEAD sert de point de repère pratique : HEAD~1 désigne le commit précédent, HEAD~3 celui d'il y a trois commits, HEAD^2 le second parent d'un commit de merge.
Lister les branches : git branch
git branch # branches locales, la courante est marquée d'un *
git branch -v # avec le dernier commit de chacune
git branch -vv # avec l'upstream et l'avance/le retard
git branch -r # branches distantes (origin/...)
git branch -a # toutes les branches
git branch --show-current # uniquement le nom de la branche courante
Exemple de sortie de git branch -vv :
feature/login 4c1e2d7 [origin/feature/login: ahead 2] Formulaire de connexion
* main 8b7d4e2 [origin/main] Mettre à jour le README
old-spike 1a9b3c0 Expérimentation avec le cache
On voit ici que feature/login contient deux commits non poussés, que main est identique au serveur et que old-spike n'a aucune contrepartie sur le serveur.
Pour filtrer les branches : git branch --merged (déjà fusionnées dans la branche courante — candidates à la suppression), git branch --no-merged (pas encore fusionnées) et git branch --list 'feature/*' (par motif).
Créer une branche Git
Il y a deux façons de faire. git branch crée la branche mais vous laisse sur la branche courante :
git branch feature/login # à partir du commit courant
git branch hotfix v1.2.0 # à partir d'un tag
git branch review 3f2a1c9 # à partir d'un commit précis
Le plus souvent, on veut créer la branche et s'y placer aussitôt. C'est le rôle de git switch -c (apparu dans Git 2.23) ou de son ancien équivalent git checkout -b :
git switch -c feature/login
git switch -c hotfix origin/main # nouvelle branche à partir de l'état à jour du serveur
Une bonne habitude avant de créer une branche pour une tâche : mettre la base à jour. git fetch, puis git switch -c feature/x origin/main. Ainsi, la branche part du code actuel et non de votre main locale qui n'a pas été mise à jour depuis longtemps.
Comment nommer ses branches
Les conventions les plus répandues dans les équipes : un préfixe selon le type de travail et une courte description avec des tirets — feature/user-avatar, fix/login-timeout, chore/update-deps, parfois avec le numéro de ticket : feature/SHOP-142-cart. Sont interdits : les espaces, ~ ^ : ? * [, deux points consécutifs et la terminaison .lock.
Changer de branche : git switch
git switch main # aller sur une branche existante
git switch - # revenir à la branche précédente
git switch feature/login # s'il n'y a pas de branche locale mais qu'il existe origin/feature/login,
# Git crée la branche locale et la lie à la branche distante
Lors du changement de branche, Git remplace les fichiers du répertoire de travail par la version de la branche cible. Les modifications non commitées vous suivent si elles n'entrent pas en conflit avec la branche cible. Sinon, Git refuse :
error: Your local changes to the following files would be overwritten by checkout:
app.js
Please commit your changes or stash them before you switch branches.
Solutions : commiter, mettre de côté avec git stash (puis récupérer avec git stash pop) ou transférer volontairement les modifications en tentant une fusion : git switch -m main. L'option --discard-changes jette les modifications — ne l'utilisez que si vous êtes certain de ne pas en avoir besoin.
Pourquoi git switch plutôt que checkout ? Checkout sait à la fois changer de branche et écraser des fichiers, ce qui rend les erreurs faciles. Switch ne fait qu'une chose — il gère les branches — et il est donc plus sûr. La comparaison détaillée entre checkout, switch et restore fait l'objet d'un article à part.
Renommer une branche
git branch -m new-name # renommer la branche courante
git branch -m old-name new-name # renommer n'importe quelle branche
git branch -M main # idem, en écrasant une branche existante
Si la branche existait déjà sur le serveur, le renommage reste local. Poussez la nouvelle et supprimez l'ancienne :
git push -u origin new-name
git push origin --delete old-name
Supprimer une branche Git
git branch -d feature/login # supprime uniquement si la branche est fusionnée
git branch -D old-spike # suppression forcée
git push origin --delete feature/login # supprimer sur le serveur
-d protège contre la perte de travail : si la branche contient des commits absents de la branche courante (ou de son upstream), Git refuse avec le message « The branch 'x' is not fully merged ». -D supprime sans poser de question. Impossible de supprimer la branche courante — changez d'abord de branche.
Supprimé une branche par erreur ? Les commits ne disparaissent pas tout de suite. Retrouvez le hash du dernier commit de la branche dans git reflog et recréez-la : git branch old-spike 1a9b3c0.
Les références obsolètes vers des branches distantes qui n'existent plus sur le serveur se nettoient avec git fetch --prune.
Lier une branche locale à une branche distante
Une branche locale peut avoir un upstream — une branche distante avec laquelle elle est comparée et synchronisée. Il permet à git push et git pull de fonctionner sans arguments, et à git status d'afficher « ahead/behind ».
git push -u origin feature/login # lors du premier push
git branch --set-upstream-to=origin/main main # pour une branche existante
git branch --unset-upstream # supprimer le lien
Fusionner des branches : l'essentiel
On crée des branches pour les fusionner ensuite. Quand le travail est prêt, placez-vous sur la branche cible et fusionnez-y la vôtre :
git switch main
git merge feature/login
Si main n'a pas avancé depuis la création de la branche, Git fait un fast-forward : il déplace simplement le pointeur de main sur le dernier commit de la branche, sans commit de merge. Si les deux branches ont reçu de nouveaux commits, c'est une fusion à trois voies : Git trouve l'ancêtre commun, compare les deux côtés et crée un commit de merge à deux parents. En équipe, la fusion se fait généralement via une pull request sur le serveur ; en local, on se contente de récupérer la main à jour.
Aide-mémoire des branches
| Tâche | Commande |
|---|---|
| Lister les branches | git branch -vv |
| Créer une branche | git branch nom |
| Créer et s'y placer | git switch -c nom |
| Changer de branche | git switch nom |
| Revenir à la précédente | git switch - |
| Renommer | git branch -m ancien nouveau |
| Supprimer une branche fusionnée | git branch -d nom |
| Forcer la suppression | git branch -D nom |
| Supprimer sur le serveur | git push origin --delete nom |
| Branches supprimables | git branch --merged |
| Restaurer une branche supprimée | git reflog, puis git branch nom hash |
Erreurs fréquentes des débutants
- Travailler directement sur main. Si les commits sont faits mais pas encore poussés, créez une branche à l'endroit actuel (
git branch feature/x), puis ramenezmainà l'état du serveur :git reset --hard origin/main(vérifiez que tout est bien commité). - Branche créée depuis une main obsolète. Faites d'abord
git fetchet créez la branche à partir deorigin/main. - Commits en detached HEAD. Créez une branche avant de changer de branche ; si c'est déjà fait, retrouvez les commits dans
git reflog. - Branches qui vivent trop longtemps. Plus une branche vit isolée, plus la fusion est douloureuse. Récupérez régulièrement
mainet intégrez votre travail par petites portions.
Les branches dans le travail en équipe
Les processus varient d'une équipe à l'autre, mais on retrouve presque toujours l'un de ces deux modèles. Dans GitHub Flow, il y a une seule branche longue durée, main, toujours prête à être déployée, et des branches de fonctionnalité courtes, fusionnées via pull request après revue et passage de la CI. Git Flow ajoute develop, des branches de release et des branches de hotfix ; ce modèle est plus lourd et convient aux produits avec des releases versionnées et peu fréquentes.
Quel que soit le modèle, les règles communes s'appliquent : une branche = une tâche, une branche vit quelques jours et non des mois, elle est mise à jour avec la main fraîche avant la pull request, et elle est supprimée en local comme sur le serveur après la fusion. La branche principale est protégée dans les paramètres du dépôt : push direct et force push interdits, fusion uniquement après revue.
Visualiser l'historique des branches
Le plus simple pour comprendre comment les branches s'articulent est de regarder le graphe : git log --oneline --graph --all dessine toutes les branches et leurs points de divergence directement dans le terminal. Pour voir les commits présents dans une branche mais pas encore dans main, utilisez git log main..feature/login, et pour la différence de fichiers, git diff main...feature/login (les trois points comparent avec l'ancêtre commun, c'est-à-dire qu'ils n'affichent que les modifications propres à la branche).
En résumé
Une branche Git est un pointeur bon marché vers un commit, HEAD est un pointeur vers la branche courante. git branch gère les branches (liste, création, renommage, suppression), git switch permet de passer de l'une à l'autre, et git switch -c fait les deux à la fois. Les branches, HEAD, le fast-forward et la fusion à trois voies sont expliqués sur des exemples concrets dans le cours Git.
Questions fréquentes
Combien de branches peut-on créer dans Git ?
Pratiquement autant que vous voulez : chaque branche est une référence de quelques dizaines d'octets, il n'y a donc aucune limite de taille.
Les commits sont-ils supprimés avec la branche ?
Pas immédiatement. Les commits qui ne sont plus référencés sont conservés encore un certain temps et restent accessibles via git reflog jusqu'à ce que le ramasse-miettes les supprime (par défaut, pas avant 30 jours pour les entrées de reflog inaccessibles).
Comment savoir à partir de quelle branche la branche courante a été créée ?
Git ne stocke pas cette information : une branche ne connaît que son commit. Vous pouvez trouver l'ancêtre commun avec main grâce à la commande git merge-base HEAD main.
Quelle différence entre une branche et un tag ?
Une branche avance à chaque nouveau commit, alors qu'un tag reste définitivement attaché à un seul commit et sert à marquer les releases.
Pourquoi main et pas master ?
Ce n'est que le nom de la branche par défaut. Beaucoup de plateformes sont passées à main ; vous pouvez définir le nom pour les nouveaux dépôts avec git config --global init.defaultBranch main.
Ce sujet est traité en détail avec de la pratique dans le cours « Git de zéro à développeur confirmé ».
Voir le cours