Introduction

Un SGV (VCS) enregistre des informations afin de pouvoir récupérer des versions antérieures de fichiers. Git est des SGV les plus populaires. Il a été développé par Linus Torvalds (le fondateur du noyau Linux).

L’objectif de ce cours est d’aborder les principes fondamentaux de Git, et de présenter l’essentiel des commandes pour travailler localement (sans forge) :

  • indexer les fichiers et créer des instantanés ;
  • gérer les branches et résoudre les conflits ;

Quelques commandes additionnelles pour la gestion des étiquettes et le remisage sont également présentées. Pour approfondir, se référer à la documentation :

Principe de fonctionnement de Git

Les instantanés

A chaque validation (commit), Git crée un instantané (snapshot), c’est-à-dire une copie de l’arborescence et du contenu des fichiers du projet.

Chaque instantané fait référence à celui à partir qui le précède, ce qui permet de retrouver l’historique des validations.

C’est dans le dossier .git situé à la racine du projet qu’est enregistrée la “base de donnée” de Git, en particuliers les références et

Les trois états et zones

Git gère trois états dans lesquels les fichiers peuvent résider :

  • modifié : le fichier n’est présent que dans le répertoire de travail, (c’est-à-dire dans l’arborescence des fichiers du projet) ;
  • indexé : le fichier est copié et référencé dans l’index (staging-area) pour être pris en compte lors du prochain instantané ;
  • validé : le fichier est enregistré dans un instantané (repository).

L’utilisation standard de Git se passe comme suit :

  1. modification des fichiers du répertoire de travail ;
  2. indexation des fichiers à prendre en compte pour le prochain instantané ;
  3. validation (création d’un nouvel instantané).

Remarque : l’indexation peut paraître superflue, mais elle sert à choisir précisément quels fichiers modifiés seront inclus dans l’instantané, de sorte que chaque validation ne porte que sur un point précis (une fonctionnalité additionnelle, un correctif…).

Les commandes de base

Cette section présente les commandes essentielles pour utiliser Git au quotidien sur un dépôt local.

Configuration de Git

Il faut configurer Git pour définir :

  • son identité : git config --global user.email "user@domain.org" et git config --global user.name "Prénom NOM" ;
  • le nom de la branche principale (“master” → “main”) : git config --global init.defaultBranch main ;
  • la commande pour lancer l’éditeur de code (“vi” par défaut) : git config --global core.editor "geany"
  • l’utile alias git tree : git config --global alias.tree "log --oneline --decorate --all --graph"

Cette configuration est globale (commune à tous les projets) et enregistrée dans le fichier .gitconfig à la racine du dossier personnel de l’utilisateur.

Initialisation d’un projet avec Git

Pour activer le SGV Git pour un projet, il y a deux principales approches :

  • cloner un projet (“dépôt”) depuis une forge (cf git clone URL_Dépôt) ;
  • initialiser Git localement : se placer dans le dossier racine d’un projet et saisir la commande git init.

L’initialisation de Git est matérialisée par la présence d’un dossier (caché) .git à la racine du projet.

Inspection et statut

Ces commandes permettent d’inspecter l’état du dépôt, son historique et les modifications en cours.

  • git status : affiche l’état de la copie de travail ; montre quels fichiers sont modifiés, lesquels sont indexés et ceux non suivis par Git.
  • git diff : afficher les différences entre deux versions des fichiers ;
    • git diff : montre les modifications des fichiers qui ne sont pas encore indexés ;
    • git diff --staged : montre les modifications des fichiers qui sont déjà indexés.
  • git log [--oneline] : affiche l’historique des commits ; en cas de problèmes d’affichage, configurer le paginateur : git config --global core.pager "less -r" ;
  • git log --graph --all --decorate : affiche l’historique des commits sous forme de graphe, montrant les branches et les fusions. Cf alias git tree.

Le cycle de vie d’un fichier : indexer et valider

C’est le flux de travail de base de Git : modifier les fichiers, les indexer, puis valider les changements.

  • git add fichier_ou_répertoire : ajoute un fichier à l’index pour qu’il soit pris en compte lors du prochain commit.
  • git add -A : indexe tous les fichiers modifiés, supprimés ou nouveaux du projet, à l’exception de ceux référencés dans le fichier .gitignore.
  • git commit -m "Message descriptif." : crée un instantané des fichiers indexés.

Il est courant de vouloir que Git ignore certains fichiers ou dossiers : fichiers de compilation, bibliothèques externes… Pour cela, il faut les indiquer dans le fichier .gitignore à la racine du projet ; exemples :

*.o
build/
vendor/
node_modules/

Annuler et corriger

Il est parfois nécessaire d’annuler une commande Git ou de restaurer la version précédente d’un fichier.

  • git restore fichier : annule les modifications non indexées d’un fichier et le restaure à l’état du dernier commit ; action irréversible.
  • git restore --staged fichier : désindexe un fichier (pour annuler un git add).
  • git reset HEAD~1 : supprime le dernier commit (sans changer l’état du dossier de travail).
  • git reset --hard : rétablit l’état du dernier commit ; action irréversible.

Gestion des fichiers : renommer et supprimer

Pour que Git puisse suivre les changements de noms ou les suppressions, il faut utiliser ses commandes dédiées :

  • git mv ancien_nom nouveau_nom : renomme ou déplace un fichier.
  • git rm <fichier> : supprime un fichier du projet et de l’index.

Les branches

Présentation

Les branches sont l’un des concepts les plus puissants de Git. Elles permettent de travailler sur des fonctionnalités ou des corrections de bugs de manière isolée, sans impacter la ligne de développement principale.

Règle d’organisation : une fonctionnalité (ou un correctif) = une branche.

Une fois le travail dans une branche terminé, il faut l’intégrer à une autre branche. Il y a pour cela deux stratégies principales : la fusion et le rebasage.

Créer, basculer et supprimer

  • git branch : liste les branches ; celle avec un astérisque (*) est la branche active.
  • git branch nom_branche : créé une nouvelle branche.
  • git switch nom_branche : bascule sur une autre branche.
  • git switch -c nom_branche : crée et bascule sur une nouvelle branche
  • git branch -d nom_branche : supprime une branche.

La Fusion

La fusion intègre l’historique d’une branche dans une autre en créant un “commit de fusion”. Exemple, pour intégrer à la branche “main” le contenu de la branche “feature" :

git switch main
git merge feature

Selon l’état des branches l’une par rapport à l’autre, la fusion s’opère :

  • en fast-forward : Si “main” n’a pas évolué depuis la création de la branche “feature”, Git y ajoute les commits de la branche “feature" ; ‘historique reste linéaire.
  • avec un merge commit : Si les deux branches ont évolué, Git crée un commit spécial qui a deux parents, marquant la fusion.

Le Rebasage

Le rebasage permet de créer un historique plus “propre” et linéaire. L’idée est de déplacer les commits de votre branche “par-dessus” le dernier commit de la branche cible, comme si vous aviez commencé à travailler à partir de ce point.

# On veut rebaser les commits de "feature" sur le dernier commit de "main"
git switch feature
git rebase main

# On peut ensuite aller sur "main" et fusionner "feature" en fast-forwards
git switch main
git merge feature
gir branch -d feature

Les conflits

Un conflit survient lorsque deux modifications incompatibles sont fusionnées, par exemple, si la même ligne d’un fichier a été modifiée dans deux branches différentes, Git ne peut pas savoir qu’elle version conserver.

Un fichier en conflit est modifié pour inclure des marqueurs spéciaux ; exemple

int x;          //contenu commun aux deux versions
<<<<<<< HEAD
x = x + 10;     //contenu dans la branche destination
=======
x = x + 15;     //contenu dans la branche fusionnée
>>>>>>> nom_branche_fusionnée

Pour résoudre un conflit :

  1. Éditer le fichier en conflit et analysez les différences.

  2. Supprimer les marqueurs de conflit (<<<<<<<, =======, >>>>>>>) et conserver la version souhaitée ; exemple :

    int x; //contenu commun aux deux versions x = x + 15; //contenu dans la branche fusionnée

  3. Une fois le fichier enregistré, l’indexer (cf git add).

Une fois tous les conflits résolus, finaliser la fusion avec git commit (ou git rebase --continue).

Autres fonctionnalités

Les étiquettes

Les étiquettes permettent d’ajouter des labels à certains commits — des numéros de version notamment.

  • git tag : liste tous les tags existants.
  • git tag nom_tag : ajoute une étiquette au le dernier commit.
  • git tag -d nom_tag : supprime un tag.

Le remisage

Le remisage permet de mettre temporairement de côté le travail non indexé et non validé, pour disposer d’une copie de travail “propre”, prérequis à certaines opérations (qui se plaindront si ce n’est pas le cas).

  • git stash : met de côté toutes les modifications (indexées ou non) et nettoie la copie de travail.
  • git stash pop : récupère le travail mis en attente.