Introduction
Les objets sont immuables et nommés par hachage. Les références sont les noms mutables et lisibles par l'humain qui pointent vers eux. Chaque branche, tag, branche de tracking distant et HEAD est une ref.
Où vivent les refs
Les refs sont des fichiers (ou des entrées dans le fichier packed-refs) sous .git/refs/ :
.git/refs/heads/<name>: branches locales..git/refs/tags/<name>: tags..git/refs/remotes/<remote>/<name>: branches de tracking distant..git/HEAD: la ref courante.
Chaque ref non symbolique est un fichier d'une ligne contenant un hachage :
cat .git/refs/heads/main
# a1b2c3d4...
Lister les refs
git for-each-ref
git for-each-ref refs/tags/
git for-each-ref --format='%(refname:short) %(objectname:short) %(subject)'
git show-ref
Refs symboliques
Une ref symbolique pointe vers une autre ref au lieu d'un hachage. HEAD est l'exemple canonique :
cat .git/HEAD
# ref: refs/heads/main
git symbolic-ref HEAD
git symbolic-ref refs/remotes/origin/HEAD
Lire les refs en sécurité
Passez toujours par la plomberie plutôt que de lire les fichiers :
git rev-parse HEAD
git rev-parse main
git rev-parse origin/main
git rev-parse v1.0.0^{commit}
La plomberie gère uniformément les refs packées, les refs symboliques et les recherches de refs.
Mettre à jour les refs
git update-ref refs/heads/feature/login <sha>
git update-ref -d refs/heads/feature/login # supprimer
git update-ref refs/heads/feature/login <new> <old> # CAS
La forme à trois arguments est compare-and-set ; elle refuse si la valeur courante diffère.
Refs packées
Pour la performance, Git peut packer plusieurs refs dans un seul fichier .git/packed-refs. git pack-refs --all fait cela ; les écritures futures vont toujours dans des fichiers libres jusqu'au prochain pack.
Syntaxe des refspecs
Les remotes utilisent des refspecs pour mapper entre refs locales et distantes :
+refs/heads/*:refs/remotes/origin/*
Le + en tête signifie « mise à jour forcée ». Cette ligne unique est ce qui fait que git fetch peuple refs/remotes/origin/.
Le backend reftable
Git moderne (2.45+) fournit un format alternatif de stockage de refs appelé reftable, développé à l'origine pour JGit. Reftable stocke des millions de refs efficacement dans un format binaire à structure de log et supporte des transactions atomiques sur de nombreuses refs à la fois. Activez sur un nouveau dépôt :
git init --ref-format=reftable
git rev-parse --show-ref-format
Pour la plupart des utilisateurs, le format classique loose+packed reste très bien. Reftable brille sur les serveurs et sur d'énormes monorepos avec des centaines de milliers de refs (par ex. une ref par pull request).
Hiérarchies de refs personnalisées
Les refs n'ont pas à vivre sous les quatre namespaces standards. Les outils qui ont besoin de leurs propres noms utilisent des hiérarchies personnalisées sous refs/ :
refs/notes/*:git notes.refs/stash:git stash.refs/replace/*:git replace.refs/bisect/*: état degit bisect.refs/pull/*/headetrefs/merge-requests/*/head: fournisseurs d'hébergement.
git for-each-ref refs/notes/
git for-each-ref refs/replace/
Vous pouvez créer les vôtres tant que le nom est une ref valide (pas de double-points, pas d'espaces, pas de tiret en tête).
Erreurs fréquentes
Éditer les fichiers de refs à la main et finir avec un problème de saut de ligne final ou un fichier à moitié écrit. Utilisez git update-ref. Confondre refs/heads/main, main et refs/main ; git rev-parse --symbolic-full-name résout tout nom court vers sa forme canonique. Nommer une branche et un tag identiquement ; les outils préfèrent alors le tag, créant une confusion subtile. Enfin, supprimer .git/packed-refs pour « nettoyer » ; cela supprime des refs qui n'étaient pas aussi loose. Passez toujours par Git.