cours/content/projet_programmation/2_git/index.md

9.8 KiB


title: "PdP: Git" date: 2024-01-17 tags: ["Internet", "Débit"] categories: ["Projet de programmation", "Cours"] mathjax: true

Les systèmes de contrôles de versions permettent de garder l'ensemble des changement effectués sur le code source, à plusieurs dévellopeurs de collaborer (via des opérations de merge) et de naviguer dans l'historique d'un projet. Ils existent depuis 1972 avec l'apparition de SCCS, il a été suivi de plusieurs autres logiciels depuis, open-sources ou propriétaires.

Quelques définitions

Gestion de l'historique

Il y a deux façons de voir l'historique dans un système de version:

  1. Organisé chronologiquement, immuable dans le sens ou il ne peut être réinscrit(les erreurs aussi...);
  2. Comme partie intégrante de la documentation. Ainsi il est possible de comprendre comment et pourquoi on en est arrivé là. Il est alors permis de le réécrire afin de le clarifier par exemple.

Définitions

Dépôt (repository): endroit ou est stockée l'historique complet d'un projet. Il contient l'ensemble des métadonnées du projet.

Copie de travail (working copy): une snapshot prise depuis le dépôt et sur laquelle travailler.

Les paragigmes : centralisé ou distribué.

Dans un environnement centralisé ou le serveur regroupe toutes les sources et faisant office de référentiel.

Dans un environnement distribué ou décentralisé, un système de connexion pair à pair est utilisé. Ainsi le dépôt est présent sur les machines des dévellopeurs et éventuellement su run ou plusiers serveurs.

git

C'est le système de gestion de version le plus utilisé. Il a été créé par Linux Torvald, créateur mainteneur du noyau Linux.

L'utilisation de git se fait d'abord en ligne de commande :

$ git --stat --after="yesterday" bugfix 
#     <options                 > <args>

La commande contient des options et des aguments en fonction des actions à effectuer. Git permet tout un ensemble de commandes, en voici quelques exemples:

# initialiser un nouveau dépôt
$ git init 

# ajouter un fichier
$ git add moncode.c

# effectuer un commit
$ git commit -m "Ajour de la fonctionnalité X"

Git propose une aide en ligne accessible via la commande help ou des manuel via lacommande man:

$ git help <commande>
# ou
$ git <commande> --help

# Et via les manuels
man git-<commande>

Il est possible de configurer git globalement (pour tous les projets) ou par projet. La configuration se fait en ligne de commande :

# configuration dans un projet, locale
$ git config --local user.name "John Doe"
$ git config --local user.email j.doe@anonymous.de
$ git config --local core.editor nvim

# configuration blobale
$ git config --global user.name "John Doe"
$ git config --global user.email j.doe@anonymous.de
$ git config --global core.editor nvim

La configuration locale prend le pas sur celle globale. La configuration est elle même stockée dans un fichier texte au format ini. La liste de toutes les clés de configuration définie s'obtient avec la commande git config --list.

L'index

Physiquement, lindex est un fichier stocké dans le répertoire .git à la racine du projet. Il contient une liste de chemin vers des ficiers avec leurs permissions et le condensat SHA1 de l'objet en question.

Les fichiers stockés dans notre index on 6 états répartis en 3 catégories :

  1. La copie de travail:
  • Untracked Files: les fichiers non suivis par git;
  • Unmodified Files: les fichiers suivis par git mais non modifiés;
  • Modified Files: les fichies suivis et modifiés.
  1. Métadonnées:
  • staging area: stocke l'ensemble des modifications temporaires et plannifiées pour le commit (dans .git/index);
  • local repository: garde l'intégralité de l'historique (dans .git/objects).
  1. Le réseau
  • Remote Repository: l'endroit où l'ensemble du travail des dévellopeurs est synchronisé.

L'état courant de l'index s'obtient avec la commande status. Il est possible de vois les 3 états de notre copie de travail, voici un exemple sur le dépôt de mes notes de cours:

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

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

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

Les deux commandes principales interagir avec l'index en ajoutant du contenu sont add et mv comme le montre le diagramme ci-dessous:

+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
| Untracked | | | Unmodified | | | Modified | | | Staging | | | Local repo | | | Remote repo |
+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
              |                |              |             |                |
      >-----------------(git add)-------------------->      |                |
              |                |              |             |                |
              |                |     >---(git add)--->      |                |
              |                |              |             |                |
              |       >-----------(git mv)----------->      |                |
              |                |              |             |                |
              |                |     >----(git mv)--->      |                |
              |                |              |             |                |

Les commandes rm et reset permettent de supprimer du contenu. git rm -r <dir> permet de supprimer récusivement un repertoire et
git rm --cached <file> supprime un élément des fichiers suivis sans pour autant supprimer le supprimer du disque:

+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
| Untracked | | | Unmodified | | | Modified | | | Staging | | | Local repo | | | Remote repo |
+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
              |                |              |             |                |
      <-----------------(git rm)---------------------<      |                |
              |                |              |             |                |
      <--------(git rm --force)--------<      |             |                |
              |                |              |             |                |
      <----(git rm)---<        |              |             |                |
              |                |              |             |                |
              |                |      <--(git reset)--<     |                |
              |                |              |             |                |
              |        <------(git reset --hard)------<     |                |

Ignorer des fichiers

Un projet peut contenir un ensemble de fichiers que ne doivent pas être suivi comme par exmeple les fichiers object issus de la compilation ou encore les binaires.

Git propose un mécanisme pour ignorer ces fichiers via un fichier que se soit globalement via ~/.config/git/ignore ou par projet avec .gitignore racine.

Voici un exemple:

# All .o files
*.o

# all the content into build/
**/build

# but the text file mus be tracked
!build/*.txt

Il est trs important de maintenir une liste à jour des fichiers ignorés afin de laisser le dépôt le plus propre possible. On évite ainsi le bruit initile dans notre dépôt et ainsi d'oublier de mettre dans le stage un fichier importan noyé dans la liste des fichier non-suivi.

Gestion de l'historique

Chaque commit est identifié par un condensat SHA1 calculé sur l'arbre des chagements (arbre de Merkel). L'historique des changements effectués est accessible par la commande git log. Voici quelques exemples:

# version courte ...
$ git log --oneline

# version courte avec des stats
$ git log --oneline --stat

# en version patch
$ git log --patch

Écrire des messages de commit cohérent permet de garder un historique propre et de documenter les changements effectués. Un commit peut contenir plusieurs lignes cependant la première doit être inférieure à 50 lignes, il est conseillé de limiter les suivantes à 72 caractères. doivent avoir 72 caractères

Se balader dans l'historique

La commande checkout permet de se ballader dans l'historique alors que commit permet de rajouter un point dans l'historique. *git c

+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
| Untracked | | | Unmodified | | | Modified | | | Staging | | | Local repo | | | Remote repo |
+-----------+ | +------------+ | +----------+ | +---------+ | +------------+ | +-------------+
              |                |              |             |                |
              |                |              |      >--(git commit)-->      |
              |                |              |             |                |
              |                |     >-------(git commit --all)------->      |
              |                |              |             |                |
              |       <-----------(git checkout HEAD)-----------------<      |
              |                |              |             |                |
              |       <--------(git checkout)--------<      |                |
              |                |              |             |                |

Les branches, tags

Pour les branches, ous en utilisons une les dès que nous initialisons notre dépôt, souvent appelée master ou main. Elle représentent une référence vers une suite de commits. Cette référence évolue lors de l'ajout de commit.

Un tag est lui une référence vers un commit précis qui n'évolue pas.