Git, gestionnaire de version décentralisée
Fonctionnement de Git
Présentation de Git
Git est un gestionnaire de version décentralisée. Il a été créé par Linus Torvarlds également créateur
du noyau Linux. Ce projet est sous licence GPL et est principalement développé en C avec également un peu
de Shell et de Perl, notamment pour les "hook scripts".
Git est dès à présent utilisé par de nombreux projets. Certains d'entre eux ont migré vers Git récemment.
Nous pouvoir par exemple citer :
- Kernel.org : Le kernel Linux
- VLC : Le lecteur multimédia
- Samba : Pour le partage de fichiers Windows/Linux
- X.org : Le serveur graphique
Pourquoi Git ?
A l'origine, Linus Torvarlds à développé Git pour proposer une alternative libre a un gestionnaire de version décentralisée baptisé BitKeeper. Git s'est désormais imposé dans ce domaine pour plusieurs raisons :
- Sa rapidité
- Sa robustesse
Grâce a git, n'importe qui est en mesure de :
- Cloner un repository
- Effectuer/Commiter des changements en local
- Générer des patchs
- Envoyer ses changements "upstream" si il en a les droits
- Suivre le développement "upstream"
Parmi ses autres avantages, nous pouvons également citer :
- Les identifiants universels de commits (SHA1), permettant ainsi d'identifier un objet git de façon unique. Que ce soit un fichier, un répertoire, un commit etc.
- Il est multi-protocole, les échanges entre repository peuvent se faire via http(s), ssh, rsync, ou encore en utilisant le protocole Git lui même.
- Un stockage des objets efficace grâce a la compression. Permettant ainsi de sauver beaucoup d'espace disque
- Tout le monde dispose du repository entier, et peut ainsi consulter les logs et/ou changements entre les révisions sans qu'il soit nécessaire de se connecter a un serveur maître.
- Et enfin, git est très efficace pour la gestion de branches de développement.
Structure d'un repository git
Voici les différents objets stockés dans un repository git.

Nous avons donc :
- Les blobs, qui représente en réalité un fichier, ou plutôt une version bien précise d'un fichier
- Les trees, qui sont en fait des répertoires, contenant des objets blobs, comme dans tout système de fichiers
- Les commits, le nom parle de lui même
- Les tags, un tag peut être associé à un commit, afin de l'identifier plus simplement
Recherchons dans un premier temps un commit sur lequel fonder notre exemple. Pour cela lançons la commande git-log qui nous affiche les commits du projet, choisissons en un par son identifiant SHA1.

Une fois notre commit exemple choisit, analysons sont contenu par le biais de la commande git-cat-file avec l'option "-p". Cette commande de git est en quelque sorte une commande de bas niveau, nous permettant d'analyser le contenu brut d'un objet git.

Dans le contenu de ce commit, nous pouvons dans un premier temps remarquer une référence à un commit parent, ce qui parait plutôt logique pour un gestionnaire de version. Et enfin ce qui nous intéresse le plus, la référence tree, qui est en fait une référence sur un répertoire contenant les objets de notre commit.
Affichons maintenant les informations sur le contenu de ce tree :

Ce tree contient bien entendu des blobs (fichiers), et également d'autre trees (répertoires), comme tout bon système de fichiers. Sélectionnons l'identifiant d'un blob, et affichons son contenu, toujours par le biais de la commande git-cat-file.

Nous avons maintenant le contenu du fichier. Il s'agit en fait du contenu du fichier "ChangeLog" dans son état au moment du commit que nous avons sélectionné. Affichons maintenant le contenu actuel du fichier, pour voir si des changements ont été effectués entre temps.

Le contenu actuel du fichier est similaire au contenu lors du commit sélectionné. Comme précisé précédemment, git utilise avec une grande efficacité la compression afin de limiter au maximum la taille de ses objets, et par conséquent la taille du repository. Lors de sa création, un fichier n'est pas compressé. Cependant, git se chargera de la compression lors de transferts. L'utilisateur peut aussi choisir d'effectuer une passe de compression de son repository via la commande git-repack. Cela ne présente pas d'avantage autre que celui de réduire la consommation d'espace disque, puisque pour les transferts entre repository, la compression est utilisée par défaut, comme précisé précédemment.
Le répertoire .git
Dans le répertoire .git nous trouvons les fichiers/répertoires suivants :
- config/ : contient des fichiers relatifs à la configuration de l'environnement git, comme par exemple des informations sur le développeur (son nom, son email ...)
- objetcs/* : c'est dans ce répertoire que sont stockés tous les objets git (commits, tags, trees, blobs)
- ref/heads/* : contient les informations sur les branches locales du repository
- logs/* : contient les messages de logs
- refs/remotes/* : contient les informations relatives aux branches distantes, c'est à dire les branches du repository depuis lequel nous avons cloné le projet. Si c'est un projet nouveau, alors il n'y a pas de branches distantes
- index : fichier contenant des informations sur l'état du prochain commit (voir plus bas)
- HEAD : fichier contenant des informations sur la branche actuelle de l'utilisateur
Le fichier index
Le fichier index représente le prochain commit de l'utilisateur. Lorsqu'un utilisateur
modifie, ou ajoute un nouveau fichier, il faut qu'il l'ajoute à l'index pour qu'il soit
commité.
Pour une meilleure compréhension, voici un exemple d'utilisation du fichier d'index. Nous
avons donc notre repository, sur lequel nous n'avons pas encore fait de modifications non
commitées. Nous pouvons le vérifier par le biais de la commande "git-status" :
alk@macbook PackageKit % git status # On branch master nothing to commit (working directory clean)
Effectuons maintenant des modifications sur les fichiers ChangeLog et AUTHORS, et consultons le retour de la commande git-status après ces modifications.
alk@macbook PackageKit % vim ChangeLog alk@macbook PackageKit % vim AUTHORS alk@macbook PackageKit % git status # On branch master # Changed but not updated: # (use "git add..." to update what will be committed) # # modified: AUTHORS # modified: ChangeLog # no changes added to commit (use "git add" and/or "git commit -a")
Nous pouvons constater que git s'est bien rendu compte que les fichiers avaient été modifiés. Cependant, il prévient l'utilisateur que ces changements ne seront pas commité lors du prochain git-commit tant qu'ils n'auront pas été ajoutés à l'index.
Pour tester, ajoutons un des deux fichiers à l'index.
alk@macbook PackageKit % git add ChangeLog alk@macbook PackageKit % git status # On branch master # Changes to be committed: # (use "git reset HEAD..." to unstage) # # modified: ChangeLog # # Changed but not updated: # (use "git add ..." to update what will be committed) # # modified: AUTHORS #
Nous avons ajouté le fichier ChangeLog à l'index. Cela signifie que tous les changements apportés à ce fichier seront commités lors du prochain git-commit, alors que ceux apportés au fichier AUTHORS (non ajouté à l'index) ne seront pas pris en compte.