Série Git - Fonctionnement (2/5)
Comment Git fonctionne ?
Après avoir présenté Git et ses avantages, nous allons nous concentrer dans ce deuxième article sur la manière dont Git fonctionne.
1 Les états de fichiers
Comme nous l’évoquions dans le premier chapitre de cette série, Git suit les modifications apportées aux fichiers du projet. Ainsi, chacun d’eux est considéré dans un des 4 états ci-dessous :
Untracked
(non suivi) : Fichier qui n’est pas suivi par Git et dont les versions ne sont pas historisées.Unmodified
(non modifié) : Fichier suivi dont la version courante n’a pas été modifiée par rapport au dernier point de validation.Modified
(modifié) : Fichier suivi dont la version courante a été modifiée par rapport au dernier point de validation.Staged
(indexé) : Fichier suivi dont les modifications de la version courante seront référencées dans le prochain point de validation.
Les passages d’un état à l’autre peuvent être décrit par le schéma ci-dessous :
2 Les zones de travail
Pour son fonctionnement local, Git considère essentiellement 3 zones de travail :
Working directory
: Dossier de travail où se trouvent les sources.Staging area
: Emplacement temporaire où sont stockées les versions avant commit.Local repository (dossier .git)
: Historique des modifications.
À noter qu’en plus des 3 zones de travail décritent ci-dessous, il en existe 2 autres :
remote
: Copie locale des répos distants (lorsque vous synchronisez votre projet avec GitHub, GitLab ou tout autre serveur Git distant).stash
: Emplacement temporaire permettant de “mettre de côté” les fichiers à l’état modifiés.
Local repository (dossier .git)
est théoriquement “immuable” !git filter-branch
ou BFG Repo-Cleaner
).
3 Le fichier .gitignore
Le fichier .gitignore
est un fichier permettant d’exclure certains fichiers du suivi.
Il joue le rôle de filtre lors des commandes git
.
Exemples de cas d’usage :
- Fichiers de configuration ;
- Fichiers binaires ;
- Fichiers avec des données sensibles ;
- Etc.
Exemple de contenu de fichier .gitignore
:
|
|
Bonnes pratiques :
- N’utiliser qu’un seul “.gitignore” à la racine de repo
- Privilégier l’utilisation du chemin complet plutôt que seulement le nom du fichier
4 Les commits
Les commits constituent la base du fonctionnement de Git. Ils consistent en des points d’arrêt dans l’historique des modifications apportées aux fichiers. Chaque commit est stocké de manière “définitive” dans le repository.
Les commits sont souvent représentés comme un graphe orienté, chacun des noeuds de ce graphe représentant un commit :
Chaque commit contient les informations suivantes :
- Modifications apportées aux fichiers suivis par rapport à la version précédente
- La référence du précédent commit
- Les infos (nom/email) de l’auteur et la date
- Les infos (nom/email) du committer et la date (Permet de distinguer la dernière modif d’un commit en cas de réécriture d’historique via
amend
ourebase
.) - Le commentaire associé au commit
Chacun de ces commits est référencé par un hash
unique.
Exemple de hash : 6c78e246f967a554d1b9bbc64573f12ad9e9e32c
(hash raccourci : 6c78e24
).
5 Les pointeurs
Afin de faciliter la bascule entre les commits et les branches, Git dispose des pointeurs. Ces pointeurs agissent comme des alias faisant référence à des hash de commit.
Il existe plusieurs types de pointeurs :
HEAD
- Les branches
- Les tags
5.1 Le pointeur HEAD
Le pointeur HEAD
est un pointeur vers le commit courant.
Cela veut donc dire que lorsque vous vous déplacez dans l’historique (avec la commande git checkout
), le pointeur HEAD
va pointer vers un commit différent.
Par défaut, celui-ci est positionné sur le dernier commit d’une branche.
Le pointeur HEAD
a pour avantage de permettre des références relatives.
Exemples :
HEAD
représente le commit courant.HEAD~
etHEAD~1
représentent l’avant-dernier commit.HEAD~~
etHEAD~2
représentent l’avant avant-dernier commit.
5.2 Les branches
Comme dit précédemment, les branches ne sont techniquement que des pointeurs vers des commits. Leur objectif est d’isoler les commits durant la phase de développement pour ne pas impacter les autres développeurs.
Sur le graphe ci-dessus, nous pouvons constater les deux branches main
et feature
représentées :
Bien que la branche main
(anciennement master
) soit souvent considérée comme une branche particulière, puisque créée par défaut, son fonctionnement est exactement le même que pour les autres branches.
À l’exception de certaines branches comme la branche main
(ou develop
dans le cas de l’utilisation de Git flow
), les branches n’ont généralement qu’une existence temporaire et ont vocation à être fusionnées avec la ou les branches principales.
À noter que comme pour le pointeur HEAD
, le pointeur de la branche va être mis à jour à chaque commit pour pointer vers le dernier.
5.3 Les tags
Une fois encore, les tags ne sont que des pointeurs vers un commit au même titre que les branches ou le pointeur HEAD
.
L’unique différence avec eux est que les tags sont des pointeurs “permanents” vers un commit.
Cela veut donc dire qu’un tag ne change pas de destination lors d’un nouveau commit.
Les tags sont la plupart du temps utilisés pour représenter les versions d’un développement.
6 Les remotes
Comme expliqué en introduction, Git
est un outil distribué.
Les remotes correspondent donc à des copies distantes du répertoire.
Exemples de remote :
- GitHub
- Gitlab
L’objectif d’un remote comme GitLab est de servir d’interface entre les développeurs pour mettre en commun les modifications opérées.
Il permet aussi l’ajout de fonctionnalités de type gestion des partages, des issues
, des pull request
, etc.