Date de la publication : 25 août 2025
Lecture : 14 min
Découvrez les dernières contributions de l'équipe Git de GitLab et de la communauté Git, notamment les optimisations de performances pour git-push(1) et git-fetch(1).
Le projet Git a récemment publié la version Git 2.51. En raison de l'été dans l'hémisphère nord et d'un développement plus lent, ce cycle de sortie de nouvelles versions a été plus court et a duré 8 semaines (au lieu des 12 semaines habituelles). Passons en revue certaines modifications notables de cette version, notamment les contributions de l'équipe Git de GitLab ainsi que de la communauté Git dans son ensemble.
git-push(1)
et git-fetch(1)
Les commandes git-push(1)
et git-fetch(1)
permettent aux utilisateurs de synchroniser les dépôts locaux et distants. Une partie de ces commandes consiste à mettre à jour les références dans le dépôt, ce qui peut prendre un temps considérable dans les dépôts comportant de nombreuses références, en particulier pour les utilisateurs qui travaillent avec de grands environnements de développement, des monorepos ou des dépôts avec des pipelines CI/CD étendus.
Les transactions de références Git peuvent inclure plusieurs mises à jour de références, mais elles suivent une approche « tout ou rien ». Si une seule mise à jour dans la transaction échoue, la transaction entière échoue, et aucune des mises à jour de références n'est appliquée. Cependant, les mises à jour de références dans git-push(1)
et git-fetch(1)
sont autorisées à échouer, ce qui permet aux dépôts de synchroniser un sous-ensemble de références même si un sous-ensemble différent a divergé. Pour faciliter ce comportement, Git crée une transaction distincte pour chaque mise à jour de référence afin que certaines transactions réussissent même si d'autres échouent.
La création d'une transaction distincte par mise à jour entraîne une surcharge opérationnelle importante, car chaque transaction comprend une phase d'initialisation et de finalisation, et vérifie s'il existe des noms de références contradictoires. Le backend « reftable » effectue également un compactage automatique à la fin de chaque transaction. De multiples transactions peuvent ainsi déclencher plusieurs compactages automatiques, ce qui peut augmenter considérablement la latence de la commande.
Dans Git 2.51.0, ces commandes utilisent désormais des mises à jour par lots au lieu de transactions distinctes afin de mettre à jour plusieurs références dans une seule transaction, tout en autorisant certaines mises à jour à échouer. Cette approche élimine le surcoût lié aux initialisations, vérifications et finalisations répétées et supporte mieux la montée en charge du nombre de références à mettre à jour, puisqu'une seule transaction est utilisée. Les performances du backend « reftable » en sont considérablement améliorées, et ce dernier surpasse désormais le backend « files ». Ces améliorations de performances s'appliquent de manière transparente pour les utilisateurs.
Pour git-fetch(1)
, nous constatons des performances 22x meilleures pour le backend « reftable » et 1,25x meilleures pour le backend « files » lorsque cette commande est utilisée dans un dépôt avec 10 000 références.
Benchmark 1: fetch: many refs (refformat = reftable, refcount = 10000, revision = master)
Time (mean ± σ): 3.403 s ± 0.775 s [User: 1.875 s, System: 1.417 s]
Range (min … max): 2.454 s … 4.529 s 10 runs
Benchmark 2: fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
Time (mean ± σ): 154.3 ms ± 17.6 ms [User: 102.5 ms, System: 56.1 ms]
Range (min … max): 145.2 ms … 220.5 ms 18 runs
Summary
fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD) ran
22.06 ± 5.62 times faster than fetch: many refs (refformat = reftable, refcount = 10000, revision = master)
Benchmark 1: fetch: many refs (refformat = files, refcount = 10000, revision = master)
Time (mean ± σ): 605.5 ms ± 9.4 ms [User: 117.8 ms, System: 483.3 ms]
Range (min … max): 595.6 ms … 621.5 ms 10 runs
Benchmark 2: fetch: many refs (refformat = files, refcount = 10000, revision = HEAD)
Time (mean ± σ): 485.8 ms ± 4.3 ms [User: 91.1 ms, System: 396.7 ms]
Range (min … max): 477.6 ms … 494.3 ms 10 runs
Summary
fetch: many refs (refformat = files, refcount = 10000, revision = HEAD) ran
1.25 ± 0.02 times faster than fetch: many refs (refformat = files, refcount = 10000, revision = master)
Pour git-push(1)
, nous constatons des performances 18x meilleures pour le backend reftable et 1,21x meilleures pour le backend « files » lorsque cette commande est utilisée dans un dépôt avec 10 000 références.
Benchmark 1: push: many refs (refformat = reftable, refcount = 10000, revision = master)
Time (mean ± σ): 4.276 s ± 0.078 s [User: 0.796 s, System: 3.318 s]
Range (min … max): 4.185 s … 4.430 s 10 runs
Benchmark 2: push: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
Time (mean ± σ): 235.4 ms ± 6.9 ms [User: 75.4 ms, System: 157.3 ms]
Range (min … max): 228.5 ms … 254.2 ms 11 runs
Summary
push: many refs (refformat = reftable, refcount = 10000, revision = HEAD) ran
18.16 ± 0.63 times faster than push: many refs (refformat = reftable, refcount = 10000, revision = master)
Benchmark 1: push: many refs (refformat = files, refcount = 10000, revision = master)
Time (mean ± σ): 1.121 s ± 0.021 s [User: 0.128 s, System: 0.975 s]
Range (min … max): 1.097 s … 1.156 s 10 runs
Benchmark 2: push: many refs (refformat = files, refcount = 10000, revision = HEAD)
Time (mean ± σ): 927.9 ms ± 22.6 ms [User: 99.0 ms, System: 815.2 ms]
Range (min … max): 903.1 ms … 978.0 ms 10 runs
Summary
push: many refs (refformat = files, refcount = 10000, revision = HEAD) ran
1.21 ± 0.04 times faster than push: many refs (refformat = files, refcount = 10000, revision = master)
Ce projet a été mené par Karthik Nayak.
La dernière version majeure de Git, la version 2.0, a été publiée il y a onze ans déjà. Bien que nous n'ayons pas de calendrier spécifique pour la prochaine version majeure de Git, la version 2.51.0 inclut déjà des décisions concernant Git 3.0.
La planification de la version Git 3.0 nous permet de prévoir et d'implémenter des changements rendant cette version incompatible avec les précédentes et de les communiquer à la communauté Git. En plus de la documentation, Git peut également être compilé avec ces changements incompatibles à des fins de test. Pour en savoir plus, consultez le document BreakingChanges.
La version Git 2.51.0 apporte des changements importants en préparation de Git 3.0.
Dans la version Git 2.45.0, le format « reftable » a été introduit comme nouveau backend pour stocker les références comme les branches ou les tags dans Git, afin de corriger de nombreux problèmes avec le backend « files » existant. Consultez notre guide du débutant sur le fonctionnement du format reftable pour obtenir plus d'informations sur le backend « reftable ».
La version Git 2.51.0 marque le passage à l'utilisation du format « reftable » par défaut dans Git 3.0 pour les dépôts nouvellement créés et configure également le changement d'un feature flag. Le format « reftable » offre les améliorations suivantes par rapport au backend « files » traditionnel :
Il est impossible de stocker deux références avec pour seule différence la casse sur des systèmes de fichiers qui ne tiennent pas compte de la casse avec le format « files ». Ce problème est courant sur les systèmes Windows et macOS. Étant donné que le backend « reftable » n'utilise pas de chemins de système de fichiers pour encoder les noms de références, ce problème n'a plus lieu d'être.
De même, macOS normalise les noms de chemins qui contiennent des caractères unicode. Vous ne pouvez donc pas stocker deux noms avec des caractères unicode qui sont encodés différemment avec le backend « files », mais ce n'est pas un problème avec le backend « reftable ».
La suppression de références avec le backend « files » nécessite que Git réécrive le fichier complet « packed-refs ». Dans les grands dépôts avec de nombreuses références, ce fichier peut facilement faire des dizaines de mégaoctets, voire des gigaoctets. Le backend « reftable » utilise des marqueurs « tombstone » pour les références supprimées et n'a donc pas à réécrire toutes ses données.
La maintenance du dépôt avec le backend « files » effectue généralement des repacks tout-en-un des références. Cette approche peut être assez coûteuse, et par conséquent, la maintenance est un compromis entre le nombre de références seules par fichier qui s'accumulent et ralentissent les opérations qui lisent les références, et la compression de ces références non compactées en un seul fichier « packed-refs ». Le backend « reftable » utilise le compactage géométrique après chaque écriture, ce qui amortit les coûts et garantit que le backend est toujours bien entretenu.
Les opérations qui écrivent plusieurs références à la fois ne sont pas atomiques avec le backend « files ». Par conséquent, Git peut voir des états intermédiaires lorsqu'il lit des références pendant qu'une transaction de référence est en cours de validation sur le disque.
L'écriture de nombreuses références à la fois est un processus lent avec le backend « files », car chaque référence est créée en tant que fichier séparé. Le backend « reftable » fournit des résultats considérablement meilleurs par rapport au backend « files ».
Le backend « reftable » utilise un format binaire avec compression de préfixe pour les noms de références. En conséquence, le format utilise moins d'espace par rapport au fichier « packed-refs ».
Ce projet a été mené par Patrick Steinhardt.
Le système de contrôle de version Git stocke les objets dans un système de fichiers adressable par contenu. Cela signifie qu'il utilise le hachage d'un objet pour adresser le contenu tel que les fichiers, les répertoires et les révisions, contrairement aux systèmes de fichiers traditionnels, qui utilisent des nombres séquentiels. L'utilisation d'une fonction de hachage présente les avantages suivants :
Vérifications faciles de l'intégrité, car un seul bit inversé modifierait complètement le résultat du hachage.
Recherche d'objets rapide, car ces derniers peuvent être indexés par leur hachage.
Les noms d'objets peuvent être signés, et des tiers peuvent faire confiance au hachage pour adresser l'objet signé et tous les objets qu'il référence.
La communication via le protocole Git et les méthodes de communication hors bande disposent d'une chaîne de caractères courte et fiable qui peut être utilisée pour adresser de manière fiable le contenu stocké.
Depuis sa création, Git a utilisé l'algorithme de hachage SHA-1. Cependant, des chercheurs en sécurité ont découvert quelques failles dans cet algorithme, en particulier l'attaque SHAttered, qui montre une collision de hachage SHA-1 réalisable en pratique. Nous sommes passés à l'utilisation d'une implémentation SHA-1 renforcée par défaut depuis Git 2.13.0. Cependant, SHA-1 reste un algorithme de hachage faible, et ce n'est qu'une question de temps avant que des attaques supplémentaires ne diminuent encore davantage sa sécurité.
SHA-256 a été identifié comme le successeur de SHA-1 fin 2018. Git 2.51.0 le marque comme l'algorithme de hachage par défaut à utiliser dans Git 3.0.
Ce projet a été mené par brian m. carlson.
git-whatchanged(1)
La commande git-whatchanged(1)
montre les logs avec les différences que chaque commit introduit. Bien que cette commande soit maintenant remplacée par git log --raw
, elle a été conservée pour des raisons historiques.
Git 2.51.0 oblige les utilisateurs de la commande à utiliser explicitement le flag --i-still-use-this
pour identifier tous les utilisateurs qui utilisent encore cette commande dépréciée, et marque également la commande pour suppression dans Git 3.0.
Ce projet a été mené par Junio C Hamano.
git switch
et git restore
ne sont plus en phase expérimentale
La commande git-checkout(1)
peut être utilisée dans plusieurs cas d'utilisation différents. Elle peut être utilisée pour changer la référence courante :
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
$ git checkout next
Switched to branch 'next'
Your branch is up to date with 'origin/next'.
Ou pour restaurer des fichiers :
$ echo "additional line" >> git.c
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: git.c
no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout git.c
Updated 1 path from the index
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Pour les nouveaux utilisateurs de Git, ces différentes possibilités peuvent être source de confusion. Dans Git 2.33.0, elles ont été divisées en deux nouvelles commandes, git-switch(1)
et git-restore(1)
.
La commande git-switch(1)
permet aux utilisateurs de basculer vers une branche spécifique :
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
$ git switch next
Switched to branch 'next'
Your branch is up to date with 'origin/next'.
Et la commande git-restore(1)
permet aux utilisateurs de restaurer les fichiers de l'arbre de travail :
$ echo "additional line" >> git.c
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: git.c
no changes added to commit (use "git add" and/or "git commit -a")
$ git restore git.c
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Ces deux commandes existent depuis 2019, mais étaient en phase expérimentale. Ce qui signifie que le projet Git ne garantissait pas la compatibilité avec les versions précédentes pour ces commandes, et le comportement pouvait changer à tout moment. L'objectif était initialement de stabiliser ces commandes après quelques nouvelles versions, mais cela n'a pas été le cas jusqu'à présent.
Cela a entraîné plusieurs discussions sur la liste de diffusion Git, où les utilisateurs se demandaient s'ils pouvaient commencer à utiliser ces nouvelles commandes, ou si celles-ci pourraient éventuellement disparaître à nouveau. Mais étant donné qu'aucun changement significatif n'a été proposé, et que certains utilisateurs utilisent déjà ces commandes, nous avons décidé de les retirer de leur phase expérimentale dans la version Git 2.51.
Ce projet a été mené par Justin Tobler.
git for-each-ref(1)
La commande git for-each-ref
est utilisée pour indiquer toutes les références présentes dans un dépôt. Comme elle fait partie de la couche de plomberie de Git, cette commande est fréquemment utilisée par les forges logicielles d'hébergement pour lister sur leur interface utilisateur les références qui existent dans le dépôt. Mais à mesure que les dépôts grandissent, il n'est pas réaliste de lister toutes les références à la fois, car les plus grands dépôts peuvent en contenir des millions ! À la place, les forges ont tendance à paginer les références.
Une lacune importante émerge ainsi : git-for-each-ref
ne sait pas ignorer les références des pages précédentes qui ont déjà été affichées. Par conséquent, cette commande peut devoir lister un grand nombre de références sans intérêt avant de commencer à indiquer les références requises pour la page actuelle. Ce processus est peu efficace et conduit à une latence plus élevée que nécessaire ou même à des délais d'attente dépassés.
Git 2.51.0 prend en charge une nouvelle option --start-after
pour git for-each-ref
, qui permet de paginer les données de sortie. Il est aussi possible de la combiner avec l'option --count
pour itérer sur un lot de références.
$ git for-each-ref --count=10
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-001
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-002
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-003
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-004
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-005
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-006
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-007
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-008
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-009
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-010
$ git for-each-ref --count=10 --start-after=refs/heads/branch-010
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-011
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-012
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-013
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-014
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-015
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-016
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-017
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-018
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-019
9751243fba48b34d29aabfc9784803617a806e81 commit refs/heads/branch-020
Ce projet a été mené par Karthik Nayak.
Prêt à découvrir ces améliorations ? Mettez à jour votre version Git et commencez à utiliser git switch
et git restore
dans vos workflows quotidiens.
Pour les utilisateurs de GitLab, ces améliorations de performances enrichiront automatiquement l'expérience de développement une fois la version de Git mise à jour.
Pour en savoir plus, consultez les notes de version officielles de Git 2.51.0 et explorez notre archive complète de le développement de Git.