Mise à jour : 25 avril 2025

Lecture : 12 min

Git : 20 ans d'histoire

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

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 Git
  • update-cache pour ajouter des fichiers à l'index
  • write-tree pour créer un nouvel arbre à partir des éléments de l'index
  • read-tree pour lire un objet arbre
  • commit-tree pour créer un commit à partir d'un arbre
  • cat-file pour lire un objet spécifique dans un fichier temporaire

Notez 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.

Créer un commit

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 :

  1. Mettre à jour l'index en appelant update-cache pour chaque fichier que vous souhaitiez ajouter.
  2. Écrire un nouvel arbre en appelant write-tree pour prendre le contenu que vous aviez ajouté à l'index.
  3. Configurer les variables d'environnement pour indiquer à Git que vous en étiez l'auteur.
  4. Créer un objet de commit en appelant 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.

Apporter des modifications

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é :

  • Il était impossible de passer facilement d'un commit à un autre.
  • Il était impossible d'afficher les logs.
  • Il n'y avait pas de branches, de tags ou même de références. Les utilisateurs devaient manuellement conserver une trace des ID d'objet.
  • Il était impossible de synchroniser deux dépôts. Par conséquent, les utilisateurs devaient utiliser rsync(1) pour synchroniser les répertoires .dircache.
  • Il était impossible de fusionner des modifications.

Git 0.99

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 :

  • Git avait commencé à suivre différentes branches de développement à l'aide de références, ce qui, dans la grande majorité des cas, dispensait les utilisateurs de suivre les ID d'objets manuellement.
  • Un nouveau protocole distant permettait désormais à deux dépôts d'échanger des objets entre eux.
  • Le répertoire .dircache avait été renommé .git.
  • Il était désormais possible de fusionner des fichiers uniques entre eux.

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) :

  • Les outils de « plomberie » sont les commandes de bas niveau qui accèdent au dépôt Git sous-jacent.
  • Les outils de « porcelaine » sont des scripts shell qui encapsulent les commandes de « plomberie » pour fournir une interface utilisateur plus conviviale et performante.

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 passe la main

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.

Git 1.0

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.

Dépôts distants

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.

Image de marque de Git

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 :

trois signes moins rouges au-dessus de trois signes plus verts, référence visuelle inspirée de la sortie de

Le site web git-scm.com voit quant à lui le jour en 2008 :

page de destination pour git-scm.com en 2006

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 :

site web git remanié en 2012

Cette refonte du site arbore le nouveau logo rouge-orange conçu par Jason Long, qui est encore utilisé aujourd'hui :

logo git

Git 2.0

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.

Comportement par défaut de 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 :

  • Refuser d'agir et vous inviter à préciser l'objet de votre push.
  • Effectuer un push de la branche actuellement extraite.
  • Effectuer un push de la branche actuellement extraite, mais uniquement s'il détectait une branche correspondante dans le dépôt distant.
  • Effectuer un push de toutes vos branches disposant d'un équivalent dans le dépôt distant.

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.

La communauté Git à l'honneur

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 :

  • Accumulé 56 721 commits depuis Git 2.49.0
  • Reçu des contributions de plus de 2 000 personnes différentes.
  • Publié 60 nouvelles versions majeures.

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.

L'avenir de 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 :

  • la modernisation d'un code base vieillissant
  • la mise à l'échelle face à la croissance continue des monorepos
  • la gestion plus efficace des fichiers binaires volumineux

Sur le plan communautaire :

  • l'amélioration de la convivialité de Git
  • la promotion de la communauté Git pour garantir la pérennité du projet

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.

En savoir plus sur Git

Votre avis nous intéresse

Cet article de blog vous a plu ou vous avez des questions ou des commentaires ? Partagez vos réflexions en créant un nouveau sujet dans le forum de la communauté GitLab.

Plus de 50 % des entreprises du classement Fortune 100 font confiance à GitLab

Commencez à livrer des logiciels de meilleurs qualité plus rapidement

Découvrez comment la plateforme DevSecOps intelligente

peut aider votre équipe.