Mise à jour : 25 avril 2025
Lecture : 12 min
Revivez les débuts du projet Git, avec le tout premier commit, découvrez les particularités des premières versions et replongez dans la confusion qu'a provoquée le changement du comportement par défaut de git-push(1).
Le projet Git vient de fêter ses 20 ans et depuis, bien des choses ont changé : si le design conceptuel de Git est resté globalement le même, la manière dont les utilisateurs s'en servent, elle, a considérablement évolué. Git est au cœur de notre travail chez GitLab et nous sommes fiers d'être liés à son histoire.
Remontez le temps avec nous pour retracer les grandes étapes de son évolution.
Le premier commit a été effectué le 7 avril 2005 par Linus Torvalds, le créateur du noyau Linux : e83c5163316 (Initial revision of "git", the information manager from hell, 2005-04-07)
.
Comme vous pouvez le constater, ce commit ne contient pas beaucoup de fichiers :
$ git ls-tree e83c5163316
100644 blob a6bba79ba1f46a1bbf7773449c3bd2bb9bf48e8b Makefile
100644 blob 27577f76849c09d3405397244eb3d8ae1d11b0f3 README
100644 blob 98a32a9ad39883c6d05a000a68511d4b1ee2b3c7 cache.h
100644 blob 74a0a234dd346fff51c773aa57d82fc4b83a8557 cat-file.c
100644 blob 840307af0cfaab31555795ce7175d5e9c9f981a0 commit-tree.c
100644 blob 25dc13fe101b219f74007f3194b787dd99e863da init-db.c
100644 blob c924a6e0fc4c36bad6f23cb87ee59518c771f936 read-cache.c
100644 blob 1b47742d8cbc0d98903777758b7b519980e7499e read-tree.c
100644 blob b8522886a15db861508fb6d03d4d88d6de912a4b show-diff.c
100644 blob 5085a5cb53ee52e1886ff6d46c609bdb2fc6d6cd update-cache.c
100644 blob 921f981353229db0c56103a52609d35aff16f41b write-tree.c
Outre l'infrastructure de compilation, le premier commit fournit sept commandes principales :
init-db
pour initialiser un nouveau dépôt Gitupdate-cache
pour ajouter des fichiers à l'indexwrite-tree
pour créer un nouvel arbre à partir des éléments de l'indexread-tree
pour lire un objet arbrecommit-tree
pour créer un commit à partir d'un arbrecat-file
pour lire un objet spécifique dans un fichier temporaireNotez que la commande git
n'existait pas encore à ce moment-là. Il fallait dès lors les exécuter directement.
Pour vous montrer un exemple concret, créons un nouveau dépôt :
$ mkdir repo
$ cd repo
$ init-db
defaulting to private storage area
$ ls -a
. .. .dircache
Cela peut surprendre : il n'y a pas de répertoire .git
, mais un répertoire .dircache
. Ce dernier représentait une zone de stockage privée.
Git distinguait alors deux types d'espaces de stockage des objets : un espace « privé » et un espace « partagé ». Ceux-ci regroupaient tous vos objets Git : vos commits et vos blobs, par exemple.
Par défaut, init-db
créait un espace de stockage des objets privé qui n'était utilisé que pour le répertoire géré dans lequel il avait été créé. L'espace de stockage des objets « partagé », quant à lui, permettait de centraliser les objets communs à plusieurs répertoires, ce qui évitait d'avoir à les stocker deux fois.
Nous disposons maintenant d'un dépôt, mais comment procéder pour créer un commit ? Autant vous dire que ce n'est pas aussi simple qu'avec la commande actuelle git add . && git commit
. À l'époque, vous deviez :
update-cache
pour chaque fichier que vous souhaitiez ajouter.write-tree
pour prendre le contenu que vous aviez
ajouté à l'index.commit-tree
.Créons un commit dans le dépôt pour illustrer ce processus :
$ echo content-1 >file-a
$ update-cache file-a
$ echo content-2 >file-b
$ update-cache file-b
$ write-tree
3f143dfb48f2d84936626e2e5402e1f10c2050fb
$ export COMMITTER_NAME="Patrick Steinhardt"
$ export [email protected]
$ echo "commit message" | commit-tree 3f143dfb48f2d84936626e2e5402e1f10c2050fb
Committing initial tree 3f143dfb48f2d84936626e2e5402e1f10c2050fb
5f8e928066c03cebe5fd0a0cc1b93d058155b969
Certes, ce processus n'est pas très pratique, mais il fonctionne ! Découvrons maintenant le commit généré :
$ cat-file 5f8e928066c03cebe5fd0a0cc1b93d058155b969
temp_git_file_rlTXtE: commit
$ cat temp_git_file_rlTXtE
tree 3f143dfb48f2d84936626e2e5402e1f10c2050fb
author Patrick Steinhardt <[email protected]> Wed Mar 26 13:10:16 2025
committer Patrick Steinhardt <[email protected]> Wed Mar 26 13:10:16 2025
commit message
Notez que cat-file
n'a pas affiché le contenu directement, mais l'a d'abord écrit
dans un fichier temporaire. Toutefois, le contenu du fichier ressemblait déjà en tous points à
celui des commits actuels.
Maintenant que nous avons des fichiers, comment pouvons-nous obtenir leur statut ? Vous l'aviez peut-être deviné, en utilisant show-diff
:
$ show-diff
file-a: ok
file-b: ok
$ echo modified-content >file-a
$ show-diff
--- - 2025-03-26 13:14:53.457611094 +0100
+++ file-a 2025-03-26 13:14:52.230085756 +0100
@@ -1 +1 @@
-content-1
+modified-content
file-a: 46d8be14cdec97aac6a769fdbce4db340e888bf8
file-b: ok
Étonnamment, la commande show-diff
permettait déjà de générer des diffs entre l'ancien et le nouvel état des fichiers modifiés ! Et pour l'anecdote, Git accomplissait cette tâche en exécutant simplement l'outil Unix diff(1).
En somme, tout était encore rudimentaire, mais suffisant pour assurer le suivi de l'historique. À ce stade, Git était encore très limité :
.dircache
.La version 0.99 de Git a été la première à entrer en phase de test. Celle-ci a été publiée seulement deux mois après le commit initial, mais contenait déjà 1 076 commits. Près de 50 développeurs différents ont participé à son développement. À ce stade, Linus Torvalds était encore le principal contributeur, talonné de près par Junio Hamano, qui est aujourd'hui le chargé de maintenance.
De nombreuses améliorations avaient été mises en place depuis le premier commit :
.dircache
avait été renommé .git
.Mais le changement le plus marquant a sans doute été l'arrivée de
la commande principale git
et de ses nombreuses sous-commandes. C'est aussi à cette occasion
qu'est née la distinction entre les commandes dites de « plomberie » (plumbing) et de « porcelaine » (porcelain) :
Cette distinction existe encore aujourd'hui, comme expliqué dans
git(1)
, mais avec
la réécriture en C de nombreuses commandes de « porcelaine » initialement en shell, la frontière entre ces deux catégories a commencé à s'estomper significativement.
Linus Torvalds n'a jamais créé Git par passion pour les systèmes de contrôle de version, mais parce qu'il était nécessaire de remplacer BitKeeper pour le développement du noyau Linux. Dès le départ, il n'avait pas l'intention d'en assurer la maintenance indéfiniment, mais juste le temps de trouver quelqu'un de confiance pour reprendre le flambeau.
Et cette personne fut Junio Hamano. Junio a rejoint Git une semaine à peine après le premier commit de Linus Torvalds et comptait déjà plusieurs centaines de commits dans l'historique au moment de la sortie de la version 0.99. Ainsi, le 26 juillet 2005, Linus Torvalds l'a désigné comme nouveau chargé de maintenance du projet Git. Même si Linus Torvalds a continué à contribuer à Git, son implication s'est progressivement réduite, ce qui n'a rien de surprenant, vu ses responsabilités à la tête du projet Linux.
A ce jour, Junio Hamano dirige toujours le projet Git.
La première version majeure de Git est sortie le 21 décembre 2005 par Junio Hamano. Fait intéressant : pas moins de 34 nouvelles versions ont été publiées entre la version 0.99 et la version 1.0 : 0.99.1 à 0.99.7, 0.99.7a à 0.99.7d, 0.99.8 à 0.99.8g, et 0.99.9 jusqu'à 0.99.9n.
Parmi les évolutions majeures depuis la version 0.99, l'une des plus importantes a sans doute été l'introduction de la commande git-merge(1)
pour fusionner deux arbres. Un changement radical par rapport à la version précédente, dans laquelle chaque merge devait être effectuée manuellement, fichier par fichier.
Un autre changement majeur a été l'introduction de la notation abrégée pour les dépôts distants. Git savait déjà communiquer avec eux, mais jusque-là, les utilisateurs devaient entrer l'URL complète à chaque récupération de modifications. Ce processus était plutôt contraignant, car dans la grande majorité des cas, les utilisateurs interagissaient toujours avec le même dépôt distant.
Aujourd'hui, vous connaissez probablement le fonctionnement des dépôts distants,
mais à l'époque, le mécanisme était encore très différent. Il n'existait pas de commande git-remote(1)
pour les gérer. Ils n'étaient même pas stockés
dans votre fichier.git/config
file. À vrai dire, lorsque les dépôts distants ont fait leur apparition dans
la version 0.99.2, Git ne disposait même pas encore de fichiers de configuration.
Pour les configurer, il fallait créer un fichier dans le
répertoire .git/branches
, un mécanisme qui semble aujourd'hui plutôt contre-intuitif. Mais
il fonctionne encore aujourd'hui :
$ git init repo --
Initialized empty Git repository in /tmp/repo/.git/
$ cd repo
$ mkdir .git/branches
$ echo https://gitlab.com/git-scm/git.git >.git/branches/origin
$ git fetch origin refs/heads/master
Et ce n'est pas tout ! Le répertoire a été renommé en « dépôts distants » dès la version 0.99.5 de Git. Aujourd'hui, il existe donc trois méthodes distinctes pour configurer des dépôts distants dans un client Git actuel.
Mais soyons honnêtes : la plupart d'entre vous n'ont sans doute jamais eu à utiliser .git/branches
ni .git/remotes
,
deux mécanismes devenus obsolètes en 2005 et 2011,
respectivement. Ces répertoires seront d'ailleurs définitivement supprimés dans la version Git 3.0.
En 2007, Git créé son premier logo. Le terme « logo » est peut-être un peu excessif : il ne s'agissait en réalité que de trois signes moins rouges au-dessus de trois signes plus verts, une référence visuelle directement inspirée de la sortie de git diff
:
Le site web git-scm.com voit quant à lui le jour en 2008 :
En 2012, le site web de Git est remanié par Scott Chacon et Jason Long et son design ne changera que très peu par la suite :
Cette refonte du site arbore le nouveau logo rouge-orange conçu par Jason Long, qui est encore utilisé aujourd'hui :
Dès la version 1.0, Git ressemblait déjà fortement à la version d'aujourd'hui, c'est pourquoi nous allons faire un grand saut dans le temps et passer directement à une autre étape clé de son histoire : Git 2.0. Publiée environ dix ans après Git 1.0, cette version a été la première à introduire délibérément des changements non compatibles avec les versions précédentes dans les workflows principaux.
git-push(1)
Le changement le plus déroutant de cette version a sans doute été
l'ajustement du comportement par défaut de la commande git-push(1)
.
Si vous réalisiez un push dans un dépôt distant sans en indiquer explicitement l'objet, Git pouvait réagir de plusieurs façons :
Aujourd’hui, le comportement par défaut de Git suit la stratégie dite « simple », c'est-à-dire la troisième option mentionnée ci-dessus. Mais avant Git 2.0, le comportement par défaut était la stratégie de « correspondance », soit la dernière option.
La stratégie de « correspondance » était nettement plus risquée. Avant le push, vous deviez toujours vous assurer que vous vouliez vraiment effectuer un push de toutes vos branches locales disposant d'un équivalent dans le dépôt distant. Dans le cas contraire, vous risquiez d'envoyer des modifications par erreur. C'est pourquoi Git a opté pour la stratégie dite « simple », afin de limiter les risques et de faciliter la prise en main pour les nouveaux utilisateurs.
git-add(1)
Le comportement par défaut de git-add(1)
vis-à-vis des fichiers supprimés
a lui aussi connu une évolution importante. Avant Git 2.0, la commande git-add(1)
ne
prenait pas en compte les fichiers supprimés : il fallait les ajouter manuellement
avec git-rm(1)
pour qu'ils soient inclus dans un commit. À partir de la version 2.0, la commande git-add(1)
détecte également les suppressions de fichiers et les ajoute à l’index.
Nous n'allons pas entrer dans les détails du fonctionnement actuel de Git : vous l'utilisez probablement déjà au quotidien, et dans le cas contraire, de nombreux tutoriels existent pour bien débuter. Prenons plutôt un moment pour célébrer et remercier la communauté Git, qui a permis à ce système de rester aussi performant après deux décennies.
Au fil du temps, Git a :
Le projet Git continue aussi de se renouveler grâce à l'arrivée régulière de nouveaux contributeurs, notamment par le biais des programmes Google Summer of Code et Outreachy. Ce sont eux qui assurent la pérennité du projet Git.
Git s'est clairement imposé comme le grand gagnant dans la course aux systèmes de contrôle de version. Il domine largement le marché et il est rare aujourd'hui de voir un projet open source qui n'utilise pas Git. C'est bien la preuve que Git a su faire les bons choix.
Cela dit, le développement de Git est loin d'être terminé et de nombreux défis restent à relever. Sur le plan technique :
Sur le plan communautaire :
Le travail ne s'arrête pas là et chez GitLab, nous sommes fiers de contribuer activement à faire en sorte que Git reste un système de contrôle de version de référence pour les vingt années à venir.