Chapitre 9. Appendix A: Les lacunes de Git

Git présente quelques problèmes que j’ai soigneusement cachés. Certains peuvent être résolus par des scripts et des hooks, d’autres nécessitent une réorganisation ou une redéfinition du projet et pour les quelques rares ennuis restants, il vous suffit d’attendre. Ou mieux encore, de donner un coup de main.

Les faiblesses de SHA1

Avec le temps, les spécialistes de cryptographie découvrent de plus en plus de faiblesses de SHA1. À ce jour, la découverte de collisions d’empreintes semble à la portée d’organisations bien dotées. Et d’ici quelques années, peut-être que même un simple PC aura assez de puissance de calcul pour corrompre de manière indétectable un dépôt Git.

Heureusement Git aura migré vers une fonction de calcul d’empreintes de meilleure qualité avant que de futures recherches détruisent SHA1.

Microsoft Windows

Git sur Microsoft Windows peut être jugé encombrant :

  • Cygwin est un environnement de type Linux dans Windows proposant un portage de Git.
  • Git pour Windows est un autre choix nécessitant beaucoup moins de place. Néanmoins quelques commandes doivent encore être améliorées.

Des fichiers sans relation

Si votre projet est très gros et contient de nombreux fichiers sans relation entre eux et changeant constamment, Git peut être plus défavorisé que d’autres systèmes puisque les fichiers pris séparément ne sont pas pistés. Git piste les changement de l’ensemble du projet, ce qui est habituellement bénéfique.

Une solution consiste à découper votre projet en plusieurs parties, chacune réunissant des fichiers en relation entre eux. Utilisez git submodule si vous souhaitez conserver tout cela dans un seul dossier.

Qui modifie quoi ?

Certains systèmes de gestion de versions vous oblige à marquer explicitement un fichier avant de pouvoir le modifier. Bien que particulièrement ennuyeux puisque pouvant impliquer une communication avec un serveur central, cela présente deux avantages :

  1. Les diffs sont plus rapides puisque seuls les fichiers marqués doivent être examinés.
  2. Quelqu’un peut savoir qui travaille sur un fichier en demandant au serveur central qui l’a marqué pour modification.

Avec quelques scripts appropriés, vous pouvez obtenir la même chose avec Git. Cela nécessite la coopération du développeur qui doit exécuter un script particulier avant toute modification d’un fichier.

L’historique d’un fichier

Puisque Git enregistre les modifications de manière globale au projet, la reconstruction de l’historique d’un seul fichier demande plus de travail qu’avec un système de gestion de versions qui traque les fichiers individuellement.

Ce surplus est généralement négligeable et en vaut la peine puisque cela permet aux autres opérations d'être incroyablement efficaces. Par exemple, git checkout est plus rapide que cp -a et un delta de versions globale au projet se compresse mieux qu’une collection de delta fichier par fichier.

Le clone initial

La création d’un clone est plus coûteuse que l’extraction de code des autres systèmes quand il y a un historique conséquent.

Ce coût initial s’avère payant dans le temps puisque la plupart des opérations futures s’effectueront rapidement et hors-ligne. En revanche, dans certains situations, il est préférable de créer un clone superficiel grâce à l’option --depth (qui limite la profondeur de l’historique). C’est plus rapide mais le clone ainsi créé offre des fonctionnalités réduites.

Les projets versatiles

Git a été conçu pour être rapide au regard de la taille des changements. Les humains font de petits changement de version en version. Une correction de bug en une ligne ici, une nouvelle fonctionnalité là, un commentaire amendé ailleurs… Mais si vos fichiers changent radicalement à chaque révision alors, à chaque commit, votre historique grossit d’un poids équivalent à celui de votre projet.

Il n’y a rien qu’un système de gestion de versions puisse faire pour éviter cela, mais les utilisateurs de Git en souffrent plus puisque chaque clone contient habituellement l’historique complet.

Il faut rechercher les raisons de ces changements radicaux. Peut-être faut-il changer les formats des fichiers. Des modifications mineures ne devraient modifier que très peu de chose dans très peu de fichiers.

Peut-être qu’une base données ou une solution d’archivage est-elle plus adaptée comme solution qu’un système de gestion de versions. À titre d’exemple, un système de gestion de versions n’est certainement pas bien taillé pour gérer des photos prises périodiquement par une webcam.

Si les fichiers doivent absolument se transformer constamment et s’il faut absolument les gérer par version, une possibilité peut être une utilisation centralisée d’un dépôt Git. Chacun ne crée qu’un clone superficiel ne contenant qu’un historique récent voire inexistant du projet. Évidemment de nombreux outils Git ne seront plus utilisables et les corrections devront être fournies sous forme de patches. C’est sans doute acceptable sans en savoir plus sur les raisons réelles de la conservation de l’historique de nombreux fichiers instables.

Un autre exemple serait un projet dépendant d’un firmware qui prend la forme d’un énorme fichier binaire. L’historique de ce firmware n’intéresse pas les utilisateur et les mises à jour se compressent difficilement et donc les révisions de ce firmware vont faire grossir inutilement le dépôt.

Dans ce cas, le code source devrait être stocké dans le dépôt Git et les fichiers binaires conservés séparément. Pour rendre la vie meilleure, on peut distribuer un script qui utilisera un clone Git pour le code et rsync ou un clone Git superficiel pour le firmware.

Compteur global

Certains systèmes de gestion de versions centralisés gère un entier positif qui augmente à chaque commit accepté. Git fait référence à un changement par son empreinte ce qui est mieux pour de nombreuses raisons.

Mais certains aiment voir ce compteur. Par chance, il est très facile d'écrire un script qui se déclenchera à chaque mise à jour du dépôt Git central et incrémentera un compteur, peut-être dans un tag, qu’il associera à l’empreinte du dernier commit.

Chaque clone peut gérer un tel compteur mais c’est probablement sans intérêt puisque seul le compteur du dépôt central compte.

Les dossiers vides

Les sous-dossiers vides ne peuvent pas être suivis. Placez-y des fichiers sans intérêt pour remédier à ce problème.

Cette limitation n’est pas une fatalité due à la conception de Git mais un choix de l’implémentation actuelle. Avec un peu de chance, si de nombreux utilisateurs le demandent, cette fonctionnalité pourrait être ajoutée.

Le premier commit

Un informaticien typique compte à partir de 0 plutôt que de 1. Malheureusement, concernant les commits, Git n’adhère pas à cette convention. Plusieurs commandes ne fonctionnent pas avant le tout premier commit. De plus, certains cas limites doivent être gérés spécifiquement : par exemple, un rebasage vers une branche avec un commit initial différent.

Git bénéficierait à définir le commit zéro : dès la création d’un dépôt, HEAD serait défini comme la chaîne contenant 20 octets nuls. Ce commit spécial représenterait un arbre vide, sans parent, qui serait présent dans tous les dépôts Git.

Ainsi l’appel à git log, par exemple, pourrait indiquer à l’utilisateur qu’aucun commit n’a été fait au lieu de se terminer par une erreur fatale. Il en serait de même pour les autres outils.

Le commit initial serait un descendant implicite de ce commit zéro.

Mais ce n’est pas le cas et donc certains problèmes peuvent se poser. Si plusieurs branches avec des commits initiaux différents sont fusionnées alors le rebasage du résultat requiert de nombreuses interventions manuelles.

Bizarreries de l’interface

Étant donné deux commits A et B, le sens des expressions "A..B" et "A…B" diffère selon que la commande attend deux extrémités ou un intervalle. Voir git help diff et git help rev-parse.