Aller au contenu
Développement medium

Branches distantes et tracking

12 min de lecture

origin/main n'est pas une branche distante : c'est un marqueur local mis à jour par git fetch. Cette confusion est la source de nombreuses erreurs, branches qui « ne se mettent pas à jour », pushs rejetés, upstreams manquants. Ce guide vous explique la mécanique des branches distantes, vous montre comment les synchroniser, lire leur état et configurer vos upstreams correctement.

Prérequis : Les branches Git en bref et Merge et résolution de conflits.

  • Comprendre origin/main et le mécanisme de tracking branch
  • Distinguer fetch et pull pour synchroniser votre dépôt local
  • Pousser une branche locale vers le remote et configurer le suivi
  • Supprimer une branche distante proprement après fusion

Les trois lignes du tableau désignent des objets de nature différente, et c'est là que naît la confusion. Les deux premières sont des pointeurs stockés dans votre dépôt local : main et origin/main vivent tous les deux sur votre disque, dans .git/refs/. La troisième n'est pas un pointeur du tout, c'est une relation enregistrée dans .git/config qui dit à Git quelle référence distante comparer à quelle branche locale. Retenez la colonne « Modifiable ? » : elle explique pourquoi un commit sur origin/main est impossible.

TypeExempleDescriptionModifiable ?
Branche localemain, feature/loginPointeur sur vos commits locauxOui
Référence distanteorigin/main, origin/developCopie locale de l'état du remote, mise à jour par fetchNon (lecture seule)
Upstreamorigin/main lié à mainLe remote + branche que suit votre branche localeCe n'est pas un pointeur

Concrètement :

Votre machine Serveur (GitHub)
───────────────────────────── ─────────────────
main → commit A main → commit A
origin/main → commit A (copie locale, mise à jour par fetch)
Après git fetch (quelqu'un a pushé B sur le serveur) :
main → commit A main → commit B
origin/main → commit B ← la copie est mise à jour
votre main est en retard de 1 commit

Quand vous clonez un dépôt, Git :

  1. Télécharge tous les objets (commits, arbres, blobs)
  2. Crée des références distantes pour chaque branche du remote (ex. origin/main, origin/develop)
  3. Crée une branche locale main qui suit origin/main
  4. Vous place sur main
Remote (GitHub) : Local après clone :
main → C3 origin/main → C3
develop → C5 origin/develop → C5
main → C3 (tracking origin/main)
HEAD → main

Le nom origin est la convention par défaut pour le remote principal. Ce n'est qu'un alias configurable.

Les branches de forme origin/main, origin/develop sont des remote-tracking branches. Elles sont en lecture seule : vous ne pouvez pas faire de commit dessus directement.

Fenêtre de terminal
# Voir toutes les branches (locales + distantes)
git branch -a

Sortie :

* main
feature/auth
remotes/origin/main
remotes/origin/develop
remotes/origin/feature/auth

Les remotes/origin/... sont les références distantes. Elles sont mises à jour uniquement par git fetch ou git pull.

git fetch télécharge les nouveaux commits du remote et met à jour les références distantes, sans modifier vos branches locales :

Fenêtre de terminal
git fetch origin
Avant fetch : Après fetch :
origin/main → C3 origin/main → C5 (mis à jour)
main → C3 + C4 (local) main → C3 + C4 (inchangé)

Votre branche main locale n'a pas bougé. Pour intégrer les changements distants :

Fenêtre de terminal
# Option 1 : merge
git merge origin/main
# Option 2 : rebase (historique linéaire)
git rebase origin/main

La seule vraie différence tient dans la troisième colonne. git pull n'est pas une commande plus complète que git fetch, c'est git fetch suivi immédiatement d'une opération d'intégration que vous n'avez pas vue arriver. La conséquence pratique est qu'un git pull peut vous déposer en plein conflit de fusion alors que vous vouliez seulement savoir si le remote avait bougé. Le comportement de git pull dépend aussi de la configuration pull.rebase, ce qui rend son effet dépendant de la machine sur laquelle on travaille.

CommandeActionModifie la branche locale ?
git fetchTélécharge les commits distantsNon
git pullgit fetch + git mergeOui
git pull --rebasegit fetch + git rebaseOui

Une tracking branch (branche de suivi) est une branche locale liée à une branche distante. Cette liaison permet à Git d'afficher des informations comme « 2 commits d'avance, 1 commit de retard ».

Le cas courant est celui d'un collègue qui a poussé une branche que vous voulez reprendre. Après un git fetch, la référence origin/feature/api existe chez vous mais aucune branche locale ne lui correspond. Les deux commandes ci-dessous créent cette branche locale et enregistrent le lien en une seule opération ; la seconde n'est possible que si un seul remote possède une branche de ce nom, sans quoi Git refuse plutôt que de choisir.

Fenêtre de terminal
# Créer et suivre une branche distante existante
git switch --track origin/feature/api
# Raccourci (si le nom n'existe qu'en remote) :
git switch feature/api

Sortie :

Switched to a new branch 'feature/api'
branch 'feature/api' set up to track 'origin/feature/api'.

Cette variante sert quand la branche locale existe déjà, typiquement parce que vous l'avez créée avant de savoir qu'elle vivait aussi sur le remote. git branch -u ne modifie aucun commit : il écrit deux lignes dans .git/config et rien d'autre. Si la référence distante visée n'existe pas, Git refuse avec fatal: the requested upstream branch ... does not exist plutôt que de créer une configuration cassée.

Fenêtre de terminal
git branch -u origin/feature/auth
# ou
git branch --set-upstream-to=origin/feature/auth

git branch -vv est la commande de contrôle à retenir : elle affiche en une fois, pour chaque branche locale, son dernier commit, son upstream entre crochets et l'écart avec lui. Une branche sans crochets n'a pas d'upstream ; c'est elle qui produira le message d'erreur au prochain git pull.

Fenêtre de terminal
git branch -vv

Sortie :

feature/auth a1b2c3d [origin/feature/auth: ahead 2] Ajouter JWT
* main i7j8k9l [origin/main] Merge PR #42
fix/header e4f5g6h [origin/fix/header: behind 1] Corriger z-index
  • ahead 2 : vous avez 2 commits locaux non poussés
  • behind 1 : le remote a 1 commit que vous n'avez pas
  • Pas d'indication : synchronisé
Fenêtre de terminal
git push -u origin feature/login

Le -u (ou --set-upstream) crée la branche sur le remote et configure le tracking. Les push suivants n'ont besoin que de :

Fenêtre de terminal
git push

Cette commande existe surtout pour un cas précis : migrer un dépôt d'un hébergeur vers un autre, où l'on veut effectivement tout transférer d'un coup. Dans le travail quotidien elle est rarement le bon geste, parce qu'elle n'exclut rien et ne demande pas confirmation.

Fenêtre de terminal
git push --all origin

Après le merge d'une PR, supprimez la branche distante pour garder un remote propre :

Fenêtre de terminal
git push origin --delete feature/login
To git@github.com:mon-orga/api-meteo.git
- [deleted] feature/login

Cette commande supprime la branche sur le serveur et la référence origin/feature/login dans votre dépôt. Elle ne touche pas à votre branche locale, qui existe toujours : c'est pourquoi la vérification doit se faire sur les seules références distantes, avec git branch -r et non git branch -a.

Fenêtre de terminal
git branch -r | grep feature/login
# Aucun résultat = suppression réussie côté remote

N'oubliez pas de supprimer la branche locale aussi :

Fenêtre de terminal
git branch -d feature/login

Si Git répond error: the branch 'feature/login' is not fully merged, c'est que la branche porte des commits absents de la branche courante. Vérifiez avec git log main..feature/login --oneline avant d'employer git branch -D, qui supprime sans contrôle.

Si vous travaillez sur un fork, vous avez généralement deux remotes :

Fenêtre de terminal
# Ajouter le dépôt original comme remote "upstream"
git remote add upstream https://github.com/original/repo.git
# Vérifier les remotes
git remote -v

Pour synchroniser votre fork :

Fenêtre de terminal
git fetch upstream
git switch main
git merge upstream/main
git push origin main

Presque toutes ces situations viennent d'un décalage entre ce que vous croyez savoir du remote et ce que vos références locales contiennent réellement. Le premier réflexe est donc git fetch --prune, qui rafraîchit les références et supprime celles dont la branche n'existe plus côté serveur ; relisez ensuite git branch -vv. Le message exact renvoyé par Git est votre meilleur point d'entrée dans ce tableau, la première colonne reprend les formulations littérales.

SymptômeCause probableSolution
There is no tracking information for the current branchPas de tracking configurégit branch -u origin/ma-branche
! [rejected] (non-fast-forward) ou (fetch first)Remote a divergégit pull --rebase puis git push
git branch -a liste une branche distante supprimée sur le serveurRéférence obsolète non nettoyéegit fetch --prune pour nettoyer
fatal: the requested upstream branch ... does not existUpstream visé absent après suppression ou faute de frappegit fetch --prune puis vérifier avec git branch -r
ahead N, behind MDésynchronisation locale/remotegit pull --rebase pour rattraper le retard, puis git push
  • origin/main est une référence locale, pas la branche distante elle-même
  • git fetch met à jour les références distantes sans toucher à vos branches
  • git pull = git fetch + git merge (ou --rebase)
  • git push -u crée la branche distante et configure le tracking
  • git branch -vv montre ahead/behind pour chaque branche
  • git push origin --delete supprime une branche sur le remote

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn