Une introduction à Git


November 04, 2015

En l’espace de quelque années, Git s’est imposé comme le standard pour la gestion des versions logicielles. Le projet Git a été initié en 2005 par Linus Torvald pour gérer les sources du noyau Linux. Git repose sur une architecture distribuée : chaque copie locale d’un dépôt contient l’intégralité de l’historique du projet.

Un dépôt (repository en anglais) se matérialise sous la forme d’un répertoire caché nommé .git dans lequel Git stocke l’historique du projet. Git représente en interne cet historique sous la forme d’un graphe (plus précisement un graphe acyclique orienté). Chaque noeud de ce graphe correspond à un état du projet à un instant donné. Dans le language de Git, ces “photographies” s’appellent des commits.

Git acyclic graph

A chaque commit sont associés :

  • un message de description
  • la date et l’auteur du commit
  • un lien vers le ou les commits précédents
  • une signature de contrôle de 160 bit (SHA-1).

Cette signature identifie le commit de façon unique et garantit de façon cryptographique l’intégrité des données. Elle est le plus souvent représentée sous forme hexadecimale.

Pour optimiser l’espace disque, Git ne stocke pas l’ensemble des fichiers pour chaque commit. Seules les différences avec l’état précédent sont stockées. Notons que Git est très efficace pour manipuler des fichiers texte. Il l’est beaucoup moins pour les fichiers binaires pour lesquels les différences entre les versions successives sont plus gourmandes en mémoire.

Un peu de pratique

Dans Git, une branche est simplement un pointeur sur un commit. La branche par défaut est nommée master.

Git acyclic graph

Ajoutons un fichier dans notre dépôt:

$ echo 'hello' > hello.txt

La commande git status permet de vérifier l’état du répertoire de travail :

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	hello.txt

nothing added to commit but untracked files present (use "git add" to track)

Git a détecté un changement entre l’état du dernier commit celui du répertoire de travail. Nous allons demander à Git de suivre l’état du fichier hello.txt:

$ git add hello.txt
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   hello.txt

A ce stade, notre fichier se trouve dans une zone d’indexation (staging area en anglais). Nous allons à présent commiter nos modifications :

$ git commit -m 'ajout du fichier hello'
[master 34551d7] ajout du fichier hello
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

Git acyclic graph

On observe que le pointeur de la branche master s’est déplacé vers le commit nouvellement créé. Le pointeur HEAD correspond à l’état du répertoire de travail. Il est possible de remettre le répertoire de travail dans l’état dans lequel il se trouvait avant l’ajout de notre fichier. Pour cela, nous allons déplacer le pointeur HEAD vers le commit précédent:

$ git checkout 1901058
Note: checking out '1901058'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 1901058... badge style

On observe que le fichier hello.txt a bien disparu de notre espace de travail.

Git acyclic graph

Création d’une branche

Nous allons à présent créer une branche que nous appellerons test:

$ git checkout -b test
Switched to a new branch 'test'

Git acyclic graph

$ git checkout -b test
Switched to a new branch 'test'

Nous écrivons bonjour dans un fichier nommé hello.txt et commitons nos changements:

$ echo 'bonjour' > hello.txt
$ git add hello.txt
$ git commit -am 'ajout de bonjour dans hello.txt'
[test 04b8214] ajout de bonjour dans hello.txt
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

Git acyclic graph

Fusion des branches

Supposons que nous voulions à présent intégrer les changements de notre branche test sur la branche master. Pour cela, nous allons nous placer sur la branche master puis appliquer la commande git merge:

$ git checkout master
$ git merge test
Auto-merging hello.txt
CONFLICT (add/add): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.

Git nous indique qu’il ne peut pas fusionner les deux branches automatiquement. Il y a en effet un conflit entre les deux versions du fichier hello.txt qu’il faut résoudre manuellement. Git a modifié le fichier hello.txt pour nous faciliter le travail :

<<<<<<< HEAD
hello
=======
bonjour
>>>>>>> test

Nous éditons donc le fichier pour ne conserver que bonjour et commitons le résultat:

$ git commit -am 'merge test into master'
[master 6af5e9e] merge test into master

Git acyclic graph