Aide-mémoire Git pour mathématicien(ne)s

par Damien Mégy

Table des matières

Cette entrée est un aide-mémoire sur (les bases de) git, pour éviter de devoir googler en permanence et de tomber sur des articles interminables et complètement creux écrits par des IA. Elle peut aussi servir d'introduction très basique pour les collègues/étudiants/stagiaires qui veulent découvrir git.

Git est un outil très efficace de gestion de versions. Il n'est sans doute pas indispensable pour un matheux mais peut aider à éviter des choses un peu embarassantes comme ci-dessous :

Le Git du pauvre

On peut revenir en arrière pour un seul fichier et gérer différentes versions d'un document en même temps, la version "expérimentale" et la version "officielle".

Git simplifie aussi la collaboration sur des projets avec un grand nombre de fichiers (bases de données d'exercices, projets de livres ou de polycopiés etc), avec un mode de fonctionnement symétrique (chacun travaille sur les documents en permanence) ou asymétrique (seule une personne a le droit de "valider" des changements, mais tout lemonde peut en proposer, par exemple, là aussi, pour des bases de données d'exercices comme http://exo7.emath.fr/).

Pour commencer : création d'un 'dépôt' (repo) et créations de points de sauvegarde ("commits")

Pour initialiser le versionnage sur un répertoire, ouvrir un terminal sur ce répertoire et faire :

git init

Ceci va créer un sous-dossier nommé .git qui contiendra tout l'historique. Ce dossier spécial ne doit absolument pas être modifié/bougé.

Optionnel mais conseillé : .gitignore (dès le début)

Sauvegarder systématiquement tous les fichiers du dossier avec git n'est peut-être pas la meilleure idée : on veut peut-être exclure certains fichiers (fichiers .aux et .log etc très courants en LaTeX, ou fichiers système comme les .DS_Store et autres Thumbs.db que l'on ne veut pas sauvegarder). D'autre part, tout ce qui est sauvegardé sera peut-être par la suite rendu public, si l'on met le dépot en ligne sur le site github.com, par exemple.

On peut donc décider que certains fichiers ou dossiers seront exclus systématiquement. Pour cela, il faut créer un fichier texte dont le nom est .gitignore (il n'y a vraiment rien avant le point) et le remplir en indiquant les fichiers à ignorer, par exemple

.DS_Store
*.aux
*.log
*.fls

Dans certains contextes, on peut ne pas sauvegarder les pdfs, mais uniquement les fichiers source, par exemple pour gagner de la place (?). Dans ce cas on peut rajouter *.pdf au fichier .gitignore. Mais les pdfs ne pèsent pas si lourd que ça et ça peut être utile d'avoir une sauvegarde du pdf à un instant t en plus des sources.

On peut aussi décider d'exclure des sous-dossiers entiers des sauvegardes, par exemple des dossiers contenant un très grand nombre de scans de livres (ahem) servant de références pour un cours et n'ayant pas vocation à être rendu public lors d'une mise en ligne ultérieure. Pour cela, ajouter dirname/ pour exclure ce sous-dossier, ou **/dirname/ pour exclure tout sous-ddosier ayant ce nom, à tout niveau de profondeur. Enfin, si l'on veut autoriser un seul fichier dans un sous-dossier, il faudra ajouter les deux lignes dirname/* puis !dirname/myfile.

Il existe des fichiers .gitignore tout prêts. Par exemple pour un dossier contenant des fichiers LaTeX, on peut simplement prendre le fichier suivant https://gitignore.org/TeX puis compléter suivant ses besoins.

Création d'une sauvegarde complète du dossier

Pour créer un "point de sauvegarde" dans son travail, on peut faire ceci :

git add -A
git commit -m "Description de ce qui a changé"

(Pour le tout premier commit, l'usage est de mettre un message de description du type "premier commit".)

Ceci va créer un instantané de tout le dossier du dépôt tel qu'il est actuellement (y compris les fichiers modifiés, supprimées, ou ajoutés) et le sauvegarder. Il sera ensuite possible de visualiser cet instané et de restaurer tout ou partie du dossier tel qu'il l'était au oment de la création de cet instantané.

⚠️ Si l'on oublie le -m "message", git va ouvrir un éditeur de texte dans le terminal pour écrire le message. Par exemple, Vim. Il faut alors savoir enregistrer un fichier et quitter Vim !

À quoi sert git add? Que se passe-t-il si je l'oublie ? La commande git add -A ajoute tous les fichiers modifiés/créés / supprimés à une liste d'attente de modifications qui vont être validées. La commande git commit ne valide et ne crée une sauvegarde que des changements qui sont en liste d'attente de validation. (Le nom technique de cette liste d'attente est la staging area ou l'index, voir discussion technique dans les prochaines sections.) Par conséquent, si on n'utilise pas git add, rien n'est ajouté à la la liste d'attente, et donc lors du commit, git indique "nothing to commit".

Ne puis-je pas faire add et commit en une seule ligne de commande ? Il y a git commit -am "mon message", mais cela n'ajoute pas les fichiers nouvellement créés depuis l'ancienne sauvegarde, juste les fichiers modifiés qui existaient précédemment, ou les fichiers supprimés.

Création de sauvegardes partielles

Si depuis la précédente sauvegarde on a travaillé sur plusieurs fichiers, qui sont dans des états d'avancement inégaux (certains finis, d'autres bien avancés, d'autres à l'état de brouillon, potentiellement avec des erreurs de compilation etc), alors faire une sauvegarde complète du dépôt n'est pas conseillé : le point de sauvegarde va être un peu pénible à exploiter car les différences seront difficilement lisibles.

Si l'on a touché à plusieurs fichiers mais que les modifications sont indépendantes, on peut préférer créer un point de sauvegarde uniquement avec les modifications d'un fichier précis. Par exemple si l'on a travaillé sur exercice1.tex et exercice2.tex, que le premier fichier est prêt à être sauvegardé (énoncé terminé) mais que le second est encore un brouillon et a encore besoin de quelques retouches pour être sauvegardé dans un état acceptable, on peut faire :

git add exercice1.tex
git commit -m "énoncé exo1 terminé"

On peut ensuite continuer à travailler sur les deux fichiers (ajout de la correction de l'exercice 1, et exercice 2 dans un état sauvegardable, par exemple sans erreurs de compilation), puis sauvegarder à nouveau uniquement l'exercice 1 et l'exercice 2 séparément :

git add exercice1.tex
git commit -m "corrigé exo1 terminé"
git add exercice2.tex
git commit -m "brouillon exo2, à terminer"

En pratique, pour des petits projets (dépôt d'un cours avec un fichier pour les notes de cours, et quelques fichiers pour les feuilles d'exercices, ou dépôt pour l'écriture d'une article), on peut tout-à-fait fonctionner uniquement avec des sauvegardes complètes et utiliser git add -A.

L'utilisation de commandes plus avancées, git add -u, git add -p etc est discutée plus bas.

Il est déconseillé d'inclure dans les sauvegardes (les commits) des fichiers contenant des erreurs (de maths, de syntaxe...) : il vaut mieux attendre un peu et sauvegarder quelque chose de propre. Un commit doit être une sauvegarde utile et exploitable en cas de problème.

Étiqueter un commit pour le retrouver plus facilement

Si une étape est particulièrement importante et qu'on veut pouvoir la retrouver facilement (finalisation d'un chapitre, première ou N-ème soumission d'un article, version mise en ligne/imprimée/envoyée à telle personne etc), on peut ajouter une étiquette à notre dernier commit l'aide de la commande:

git tag v1

Ici, le nom de l'étiquette (du 'tag') est v1. Il n'y a pas de guillemets. On peut utiliser des noms d'étiquettes un peu plus informatifs : git tag soumission1, ou git tag 2026-02-15-v1-arxiv etc.

On peut ensuite afficher la liste des tags à l'aide de git tag, ce qui est ensuite utile pour comparer des versions entre elles, restaurer des fichiers etc.

Réparations de petits oublis, fautes de frappe ou erreurs de manipulation

  • Une faute d'orthographe dans le message de description d'un "commit" ? Pas de panique, on peut modifier le message du commit comme ceci: git commit --amend -m "Message qui remplace l'ancien".
  • Envie d'annuler le dernier commit, sans toucher au dossier ? git reset HEAD~1 (Les fichiers sont inchangés, le travail n'est pas perdu, mais la dernière sauvegarde est supprimée (grosso-modo). Cette commande vide aussi le "staging area", tout ce qui avait été "ajouté" avec git add devra l'être à nouveau. Bref ceci remet git à l'état où il l'était juste après la sauvegarde précédente, mais conserve le travail effectué depuis.)

POINT D'ÉTAPE : Ceci conclut le guide d'utilisation ultra-basique de Git, à savoir la création de sauvegardes complètes ou partielles et la modification élémenentaire ou suppression de sauvegardes. Rien de tout ça n'a eu d'effet sur les fichiers eux-mêmes. Dans la suite, on va voir comment utiliser les différentes sauvegardes effectuées pour :

  1. Visualiser l'état du projet à un instant t;
  2. restaurer tout ou partie du dossier dans un état correspondant à une des sauvegardes précédente;
  3. étudier plus en profondeur le fonctionnement de Git, l'utilisation de la staging area etc.

Visualisation des sauvegardes, comparaison entre plusieurs sauvegardes

Cette section présente quelques commandes simples pour voir et comparer l'historique du dépôt, ou de fichiers séparés.

UTILISATION D'UNE INTERFACE GRAPHIQUE CONSEILLÉE

On décrit ci-dessous les commandes à taper dans un terminal, mais en réalité, il existe des logiciels proposant une interface graphique très agréable permettant de visualiser rapidement les changements entre différentes versions, surtout en présence de branches et de contributions par différents utilisateurs etc.

Comparer la version courante avec la version du dernier commit

git diff HEAD monfichier.tex

Ceci montre les changements opérés sur le fichier entre l'état actuel et la dernière version validée. (En rouge pour les lignes supprimées et vert pour les lignes ajoutées.)

On peut faire défiler les changements en appuyant sur la touche espace, et quitter en tapant 'q'.

Ou, pour tout le dossier:

git diff HEAD

Ceci va montrer tous les changements dans tous les fichiers ayant été modifiés.

On peut aussi comparer avec l'avant-dernier commit avec git diff HEAD~1 monfichier.tex , ou avec N commits antérieurs à l'aide de git diff HEAD~N monfichier.tex.

Enfin, si on veut comparer avec un commit ayant une étiquette (un tag), on peut taper :

git diff monetiquette monfichier

On peut aussi comparer non pas l'état actuel du fichier, mais l'état dans l'index, etc. On peut également utiliser les identifiants uniques des commits, ou tout pointeur vers un commit (HEAD, HEAD~1, HEAD~2 etc et les tags sont des cas particuliers de pointeurs vers des commits, les branches en sont d'autres). Voir plus bas pour une discussion plus avancée, cette section se voulant toujours une section d'introduction.

Explications plus détaillées sur le fonctionnement de Git

Vocabulaire

Le mot technique pour un "point de sauvegarde" est "commit" (ou : "validation" dans les version francophones de certains logiciels comme gitlab). Les commits ont des messages descriptifs mais ils sont identifiés par un identifiant unique, leur "sha", une suite de chiffres et de lettres.

Dans la suite, <commit> désigne un identifiant de commit, donc son SHA-1 ou SHA-256 complet, ou bien les 6 (ou 7, ou 10) premiers caractères de ce hash, qui suffisent souvent à git, ou bien une référence à un commit comme HEAD~ pour le dernier commit, ou HEAD~1 pour l'avant-dernier, ou HEAD~2 etc ou le nom d'une branche (une branche est juste un pointeur mobile sur un commit), ou un tag (idem, mais fixe).

Traduction Anglais vers Français

Traduction du vocabulaire de base avec explications minimales. Il manque le vocabulaire relatif aux branches, aux remotes et au travail en collaboration (merge, conflits etc). Ces points seront abordés dans les sections suivantes.

Terme Git Traduction française Explication courte
Repository / Repo Dépôt L’endroit où Git stocke l’historique complet et les objets du projet
Working tree Répertoire de travail Les fichiers locaux sur le disque, ceux sur lesquels l'utilisateur travaille
Commit Commit / Validation Instantané des fichiers versionnés à un certain instant
Staging / Index Zone de staging / Index Zone intermédiaire pour préparer les fichiers à committer
HEAD HEAD / Pointeur actuel Pointeur vers commit courant ou référence vers la branche active

Modifications de l'index (staging area), sans toucher au répertoire de travail ni aux commits

Ajouter des fichiers à l'index

Ajouter tout:

git add .

Un seul fichier:

git add monfichier

Plusieurs fichiers:

git add fichier1 fichier2

Ajouter des listes de fichiers :

git add fichier{3..7}.txt
git add *.tex

Plus fin : ajouter seulement une partie d'un fichier (on peut dire oui à certaines lignes, non à d'autres):

git add -p fichier

Retirer des choses de l'index, par exemple annuler un malencontreux git add .

git restore --staged .

Ceci vide l'index, on revient à l'état juste après le dernier commit.

Pour n'enlever qu'un seul fichier de l'index :

git restore --staged intro.tex

Pour en enlever deux :

git restore --staged chapitre3.tex chapitre5.tex

Pour enlever une série :

git restore --staged chapitre{4..7}.tex

Etc.

Visualiser ce qui a été staged ou pas, comparer l'état de l'index, du répertoire de travail et du dernier commit (HEAD)

Vue d'ensemble : git status

Ceci affiche quelque chose comme:

Changes to be committed:
  modified:   fichier1.txt

Changes not staged for commit:
  modified:   fichier2.txt

Untracked files:
  fichier3.txt

Visualisation des différences entre les trois zones

voir la différence entre Commande
Le répertoire de travail et l'index git diff
L'index et HEAD (dernier commit) git diff --staged
Le répertoire de travail et HEAD git diff HEAD

Schéma récapitulatif:

flowchart LR WD["Répertoire de travail (Working Directory/Tree)"] IDX["Index (Staging Area)"] HEAD["HEAD = dernier Commit"] WD <--> |git diff| IDX IDX <--> |git diff --staged| HEAD WD <--> |git diff HEAD| HEAD

Modification des commits, sans toucher au répertoire de travail

Annuler un commit

Pour revenir juste avant le dernier commit, de sorte que les fichiers qui étaient dans l'index le restent :

git reset --soft HEAD~1

Ou alors, revenir au commit précédent et tout désindexer:

git reset HEAD~1

Ces opérations ne suppriment pas vraiment le dernier commit : elles font en fait pointer HEAD vers l'avant-dernier commit. Le dernier commit est toujours là mais il est en quelque sorte orphelin. Il est récupérable pendant un certain temps avec des commandes spéciales mais git finira par l'effacer automatiquement pour économiser de la mémoire. En première approximation, on peut quand même dire qu'on a bien supprimé le commit et qu'il est dans une "corbeille" qui est régulièrement vidée par git.

Modifier le message du dernier commit

git commit --amend -m "Message corrigé"

Ou alors git commit --amend qui ouvre l'éditeur (vi a priori?) pour modifier le message. Pour modifier un commit plus ancien, c'est plus délicat, voir sections ultérieures avec rebase.

Ajouter un tag à un commit (pour le retrouver facilement)

Pour retrouver plus facilement un commit, marquer le commit correspondant à une release ou à la version publiée de l'article etc :

git tag -a v1.0 -m "Version 1.0"

Pour tagger un autre commit:

git tag -a v1.0 <commit> -m "Version 1.0"

Le message -m "Version 1.0" est facultatif.

Supprimer l'intégralité de l'historique

Il suffit d'effacer le dossier .git par exemple avec rm -rf .git. On peut ensuite réinitialiser le dépôt si l'on veut.

Supprimer un fichier déjà versionné de l'historique futur

Scénario Un fichier (par exemple un fichier .aux) a été ajouté, commité et poussé sur GitHub. Il ne doit plus être présent dans le dépôt.

Objectif

  • Supprimer le fichier du dépôt distant
  • Le conserver en local
  • Éviter qu’il soit de nouveau versionné

À éviter Ajouter le fichier dans .gitignore seul : cela n’a aucun effet sur les fichiers déjà suivis. Le fichier reste présent dans le dépôt et continue d’être versionné.

Solution

  1. Modifier le fichier .gitignore :
*.aux
*.log
  1. Supprimer le fichier incriminé des fichiers suivis, ajouter le gitignore, commit et push :
git rm --cached chemin/vers/fichier.aux
git add .gitignore
git commit -m "Remove file from repo and ignore it"
git push

Résultat

  • Le fichier est supprimé du dépôt (et de GitHub)
  • Il reste présent en local
  • Il ne sera plus suivi ni ajouté dans les prochains commits

Remarque Le fichier reste présent dans l’historique Git. Pour le supprimer complètement, il faut réécrire l’historique (ex : git filter-repo).

Modifications du répertoire de travail : récupération d'anciennes versions etc

La commande restore permet de ... restaurer une zone (par défaut : --worktree, le répertoire de travail) à un état précédent en se basant sur l'état d'une deuxième zone, précisée par --source=??, la source par défault était l'index.

Par exemple, on peut restaurer le répertoire de travail (tout, ou juste certaines fichiers) à partir de l'index, ou du dernier commit, ou d'un commit plus ancien.

Annuler les modifications et remettre le répertoire à l'état de l'index :

git restore fichier.txt

Pour tout:

git restore .

On peut mettre des --worktree pour préciser que la destination est le répertoire de travail mais c'est inutile. La source est l'index par défaut.

Le travail unstaged sur les fichiers sera perdu.

Annuler les modifications et revenir à l'état lors du commit précédent:

Juste pour un fichier :

git restore --source=HEAD fichier.txt

Pour tout:

git restore --source=HEAD .
  1. Le travail sur les fichiers restaurés sera perdu.
  2. Auparavant, on utilisait checkout mais depuis git v2.23 on utilise restore pour récupérer des fichiers et switch pour changer de branche. Voir section ultérieure sur les branches.
  3. Noter que l'index est intact.

Remettre un fichier à l'état où il l'était après un autre commit plus lointain

git restore --source=<commit> fichier.txt

Attention ceci ne touche pas à l'index, si le fichier était déjà dans l'index, il faudra mettre à jour l'index avant de commiter la version récupérée:

git add fichier.txt
git commit -m "Restore old version"

Ou alors, on peut restaurer une vieille version ET modifier l'index d'un seul coup :

git restore --source <commit> --staged fichier.txt

Et pour tout restaurer comme après un certain commit:

git restore --source <commit> .

(En cours d'écriture) Utilisation des branches

(En cours d'écriture) Utilisation des remotes (sauvegarde distante sur github / gitlab)

(En cours d'écriture) Travail avec collaborateurs