Le projet Git a récemment publié la version 2.46.0 de Git. Jetons un coup d'œil aux points forts de cette version, comprenant des contributions de l'équipe Git de GitLab et de la communauté Git au sens large.
Outils pour migrer les backends de références
Dans la version Git 2.45.0 précédente, le format « reftable » est devenu le nouveau backend pour le stockage des références. Ce nouveau format de référence vise à améliorer les performances et l'efficacité des dépôts Git, en particulier lorsque le nombre de références devient très élevé. Si le backend « reftable » ne vous est pas encore familier, n'hésitez pas à consultez notre précédent article de blog consacré à la version 2.45.0 de Git dans lequel nous présentons ce nouveau format, ainsi que notre guide du débutant pour en savoir plus sur le fonctionnement des reftables.
Le backend « reftable » offre un format de stockage sur disque différent de l'ancien format de backend basé sur les fichiers. Par conséquent, l’utilisation du format « reftable » avec un dépôt existant, nécessite une conversion entre les différents formats. Pour cela, une nouvelle commande git-refs(1) a été introduite, incluant la sous-commande migrate
pour effectuer les migrations de backend de référence. Voici un exemple illustrant l'utilisation de cette commande :
# Initialize a new repository as “bare” so it does not contain reflogs.
$ git init --bare .
$ git commit --allow-empty -m "init"
# Populate repository with references in the files backend.
$ git branch foo
$ git branch bar
$ tree .git/refs
.git/refs
├── heads
│ ├── bar
│ ├── foo
│ ├── main
└── tags
# Perform reference migration to reftables format.
$ git refs migrate --ref-format=reftable
# Check that reftables backend is now in use.
$ tree .git/reftable
.git/reftable
├── 0x000000000001-0x000000000001-a3451eed.ref
└── tables.list
# Check the repository config to see the updated `refstorage` format.
$ cat config
[core]
repositoryformatversion = 1
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
[extensions]
refstorage = reftable
Une fois qu'un dépôt est migré, le format de stockage sur disque est mis à jour, permettant ainsi
l'utilisation du backend « reftable ». Les opérations Git dans le dépôt continuent de
fonctionner normalement et d'interagir avec les dépôts distants comme elles le faisaient auparavant. La migration n'a d'incidence que
sur la manière dont les références sont stockées en interne pour le dépôt. Si vous souhaitez revenir au backend « fichiers », vous pouvez le faire avec la même commande en spécifiant à la place --ref-format=files
.
L'outil de migration présente actuellement certaines limitations notables. Les reflogs dans un dépôt font partie du backend de gestion des références et nécessitent également une migration lors du changement de format. Malheureusement, l'outil n'est pas encore capable de convertir les reflogs entre les backends « fichiers » et les backends « reftable ». De plus, un dépôt avec des arbres de travail dispose en réalité de plusieurs ref stores et l'outil de migration ne prend pas encore en charge ce scénario. Par conséquent, si un dépôt contient des reflogs ou des arbres de travail, la migration des références n'est actuellement pas possible. Ces limitations pourraient être résolues dans les futures versions.
Les dépôts Git « bare » ne contiennent pas de reflogs, ce qui facilite leur migration. Pour migrer un dépôt « non bare » standard, les reflogs doivent d'abord être supprimés. Ainsi, il est possible de migrer tout dépôt dépourvu de reflog et d'arbre de travail. En tenant compte de ces limitations, cet outil de migration peut être très utile pour profiter des avantages du backend « reftable » dans vos dépôts existants.
Ce projet a été mené par Patrick Steinhardt.
Mises à jour des références symboliques transactionnelles
La commande git-update-ref(1)
permet de mettre à jour les références dans un dépôt Git. Ces mises à jour de références peuvent également être effectuées de manière atomique en bloc via des transactions, en utilisant la commande
git update-ref --stdin
pour transmettre les informations de mise à jour de références à stdin. Voici un exemple :
$ git init .
$ git branch -m main
$ git commit --allow-empty -m "foo" && git commit --allow-empty -m "bar"
# Retrieve the object ID of the two commits created.
$ git rev-parse main~ main
567aac2b3d1fbf0bd2433f669eb0b82a0348775e
3b13462a9a42e0a3130b9cbc472ab479d3ef0631
# Start transaction, provide update-ref instructions, and commit.
$ git update-ref --stdin <<EOF
> start
> create refs/heads/new-ref 3b13462a9a42e0a3130b9cbc472ab479d3ef0631
> update refs/heads/main 567aac2b3d1fbf0bd2433f669eb0b82a0348775e
> commit
> EOF
$ git for-each-ref
567aac2b3d1fbf0bd2433f669eb0b82a0348775e commit refs/heads/main
3b13462a9a42e0a3130b9cbc472ab479d3ef0631 commit refs/heads/my-ref
Dans cet exemple, une fois la transaction validée, une nouvelle branche est créée et pointe vers le commit « bar » tandis que la branche principale est mise à jour et pointe vers le commit « foo » précédent. La validation de la transaction exécute les mises à jour des références spécifiées de manière atomique. Si une mise à jour concernant une référence particulière échoue, la transaction est abandonnée et aucune mise à jour de références n'est effectuée.
Il convient de noter ici qu'aucune instruction quant à la prise en charge des mises à jour des références symboliques n'est disponible pour ces
transactions. Si un utilisateur souhaite mettre à jour une référence symbolique en même temps que d'autres références
de manière atomique dans une seule transaction, il n'existe pas d'outil pour le faire. Dans la
nouvelle version de Git, les instructions symref-create
, symref-update
, symref-delete
et
symref-verify
sont introduites pour fournir cette fonctionnalité.
# Create a symref that will be updated during the next operation.
$ git symbolic-ref refs/heads/symref refs/heads/main
# The --no-deref flag is required to ensure the symref itself is updated.
$ git update-ref --stdin --no-deref <<EOF
> start
> symref-create refs/heads/new-symref refs/heads/main
> symref-update refs/heads/symref refs/heads/new-ref
> commit
> EOF
$ git symbolic-ref refs/heads/symref
refs/heads/new-ref
$ git symbolic-ref refs/heads/new-symref
refs/heads/main
L'exemple ci-dessus illustre la création d'une nouvelle référence symbolique et la mise à jour d'une autre au cours d'une transaction. Ces nouvelles instructions pour les références symboliques peuvent désormais être combinées avec les instructions existantes afin de réaliser toutes sortes de mises à jour de références dans une seule transaction. Pour en savoir plus sur chacune de ces nouvelles instructions, consultez la documentation.
Ce projet a été mené par Karthik Nayak.
Améliorations de l'expérience utilisateur pour git-config(1)
La commande git-config(1) est utilisée dans Git pour visualiser et modifier les options de configuration, tant au niveau local (pour un dépôt spécifique) qu'au niveau global (pour l'ensemble de l'interface utilisateur). Les modes d'interaction avec la configuration peuvent être choisis explicitement à l'aide d'indicateurs spécifiques ou déterminés implicitement en fonction du nombre d'arguments fournis à la commande. Voici un exemple :
$ git config --list
# Explicit retrieval of username configuration
$ git config --get user.name
# Implicit retrieval of username configuration
$ git config user.name
# Explicit setting of username configuration
$ git config --set user.name "Sidney Jones"
# Implicit setting of username configuration
$ git config user.name "Sidney Jones"
# An optional third argument is also accepted. What do you think this does?
$ git config <name> [<value> [<value-pattern>]]
Globalement, l'interface utilisateur de git-config(1)
n'est pas cohérente avec le fonctionnement d'autres commandes Git plus récentes, où l'on utilise généralement des sous-commandes. Par exemple, git remote list
. Cette nouvelle version Git introduit les sous-commandes list
, get
, set
, unset
, rename-section
, remove-section
et edit
pour la commande config, tout en conservant l'ancienne syntaxe. Ce changement vise à améliorer l'expérience utilisateur en adaptant la commande config pour qu'elle suive des pratiques plus modernes et soit davantage alignée avec les autres commandes de Git. Par exemple :
$ git config list
$ git config get user.name
$ git config set user.name "Sidney Jones"
Ce projet a été mené par Patrick Steinhardt.
Correction de la régression des performances
Les opérations Git qui utilisent des attributs reposent sur la lecture des fichiers .gitattributes
présents dans l'arbre de travail du dépôt. Cela pose un problème pour les dépôts Git « bare » qui sont, par définition, dépourvus d'un arbre de travail. Pour contourner ce problème, Git dispose de la configuration attr.tree
, qui permet de définir un arbre source et de l'utiliser pour en extraire des attributs.
Dans la version 2.43.0 de Git, Git a commencé à utiliser par défaut l'arborescence de HEAD
comme source des attributs Git dans le cas de dépôts « bare ». Malheureusement, cette charge de travail supplémentaire liée à la recherche de fichiers d'attributs Git a eu de graves impacts sur les performances. En effet, à chaque recherche d'attribut, l'arbre source est parcouru dans son ensemble pour rechercher un fichier .gitattributes
associé, si attr.tree
est défini. Plus l'arbre source du dépôt est grand et profond, plus la régression des performances est évidente. Par exemple, des tests de performance réalisés sur le dépôt linux.git ont montré que
git-pack-objects(1) mettait 1,68 fois plus de temps à s'exécuter. Cela peut entraîner des ralentissements lors d'opérations de clonage ou de récupération.
# attr.tree set to HEAD as done by default in Git version 2.43.0.
Benchmark 1: git -c attr.tree=HEAD pack-objects --all --stdout </dev/null >/dev/null
Time (mean ± σ): 133.807 s ± 4.866 s [User: 129.034 s, System: 6.671 s]
Range (min … max): 128.447 s … 137.945 s 3 runs
# attr.tree is set to an empty tree to disable attribute lookup as done in Git versions prior to 2.43.0.
Benchmark 2: git -c attr.tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 pack-objects --all --stdout </dev/null >/dev/null
Time (mean ± σ): 79.442 s ± 0.822 s [User: 77.500 s, System: 6.056 s]
Range (min … max): 78.583 s … 80.221 s 3 runs
Les commandes Git les plus impactées étaient clone
, pull
, fetch
et diff
, particulièrement lorsqu'elles étaient utilisées sur des dépôts avec des arborescences volumineuses ou profondes. Par conséquent, dans Git 2.46.0, la configuration attr.tree
a été partiellement modifiée pour ne plus être définie sur HEAD
par défaut afin de remédier à la régression des performances. Pour en savoir plus, consultez ce fil de discussion.
Migration des tests unitaires
Historiquement, pour tester Git, les développeurs utilisaient des scripts shell pour réaliser des tests de bout en bout. Un framework de tests unitaires écrit en C a été récemment intégré au projet Git. Ce nouveau framework permet de tester en détail les implémentations à un niveau granulaire, tel que chaque appel de fonction, et complète les tests de bout en bout existants. Certains tests de bout en bout existants sont plus adaptés aux tests unitaires et sont donc de bons candidats pour le portage de tests.
Cette année, GitLab continu d'aider les contributeurs du Google Summer of Code (GSoC) qui travaillent sur le projet Git. Grâce aux efforts déployés dans le cadre de ces projets GSoC et à la contribution de la communauté Git au sens large, certains tests existants sont révisés et migrés vers le framework de tests unitaires. Pour la sortie de la nouvelle version Git 2.46.0, plusieurs contributions ont été apportées dans le but d'améliorer les tests dans le projet Git. Pour suivre l'avancement de ces projets de contributeurs GSoC, consultez les blogs de Chandra et Ghanshyam.
Correction du bundle URI
En général, lorsqu'un client récupère des données à partir d'un dépôt distant, tous les objets nécessaires sont envoyés dans un fichier groupé généré par le serveur distant. Pour éviter une partie de ce traitement, les serveurs peuvent choisir de proposer des bundles prêts à l'emploi, stockés séparément du serveur distant, qui contiennent des ensembles de références et d'objets dont le client peut avoir besoin. Le client peut d'abord récupérer ces bundles grâce à un mécanisme appelé bundle-uri.
Grâce à Xing Xin, un problème a été identifié et corrigé : Git, malgré le téléchargement de certains bundles, continuait de télécharger tous les objets et les références depuis le dépôt distant, comme si aucun bundle n'avait été récupéré. La raison de ce problème était que Git ne découvrait pas correctement l'ensemble des bundles téléchargés, ce qui entraînait la nécessité de récupérer les bundles suivants depuis le dépôt distant. Grâce à cette correction, les dépôts distants utilisant le mécanisme bundle-uri peuvent éviter d'avoir à effectuer un travail redondant et ainsi améliorer les performances.
En savoir plus
Cet article n'a mis en évidence que quelques-unes des contributions apportées par GitLab et la communauté Git au sens large pour cette nouvelle version. Vous pouvez approfondir ce sujet en lisant l'annonce officielle du projet Git. Consultez également nos précédents articles de blog sur les nouvelles versions de Git pour en découvrir davantage sur les contributions de l'équipe GitLab.