Plan pour un atelier sur la gestion de versions, en prenant Git comme référentiel.
Sommaire |
Les systèmes de gestion de versions (VCS)
- Qu'est-ce qu'un VCS ?
- À quoi ça sert ?
- Gestion de code source
- Documents littéraires
- Gestion de configuration
- …
- Principes majeurs :
- Le dépôt
- La copie de travail
- Les commits
- Les merges et les conflits
- VCS centralisés (CVCS) et décentralisés (DVCS).
- Principe des CVCS (exemple de Subversion).
- Principe comparé des DVCS (exemple de Git).
- Comparatif des deux solutions.
- Les CVCS sont plus simples à utiliser de manière basique.
- Différences en termes d'espace disque, pour différents usages :
- Subversion stocke la dernière révision récupérée sur le serveur et une copie de travail −> avantage pour des fichiers binaires changeant souvent et les très gros dépôts.
- Git stocke chaque version de chaque fichier, sous forme compressée.
- Différences en termes de fonctionnalités, à peu près pour les mêmes raisons :
- Hors ligne, Subversion peut comparer les modifications de la copie de travail par rapport à la dernière version récupérée du serveur. Impossible d'avoir l'historique hors ligne.
- Git peut tout comparer, tout afficher, etc.
- Git permet de réorganiser et modifier des commits, faire facilement des branches dans tous les sens, etc.
Au cœur de Git
- Organisation interne d'un dépôt Git : présentation du système de fichier copy on write qu'est Git.
- Les types d'objets :
- blob,
- tree,
- commit,
- tag.
- L'index (ou staging area)
- Commiter seulement certains fichiers.
- Commiter des morceaux (hunks) de fichiers.
- Modifier l'historique
- Modifier l'ordre des commits.
- Séparer un commit en plusieurs commits plus petits.
- Combiner plusieurs commits en un seul commit plus gros.
- Modifier des fichiers dans un commit, modifier un message de commit.
Il est important d'insister sur le fait que la manière de travailler avec Git est (ou peut être) radicalement différente de celle que l'on emploie avec un CVCS, justement parce qu'il est possible de modifier l'historique : on peut se permettre de commiter souvent, de faire des erreurs que l'on va corriger ensuite, etc.
Travaux pratiques
L'idée est de reprendre les éléments théoriques exposés plus haut et de voir concrètement comment on traite chaque problématique.
Création d'un dépôt
À partir de rien :
git init nom_du_dépôt
ou :
mkdir nom_du_dépôt cd nom_du_dépôt git init
À partir d'un dépôt existant :
git clone adresse_du_dépôt
Enregistrer des modifications
Ajouter un fichier non versionné, ou marquer pour commit un fichier modifié :
git add
On peut aussi ajouter des fichiers en mode interactif, y compris ajouter partiellement des modifications sur un fichier, en utilisant l'option -i :
git add -i
Démarquer un fichier :
git reset
Supprimer un fichier (utiliser --cached pour ne pas le supprimer de la copie de travail) :
git rm
Commiter les modifications enregistrées :
git commit
Commiter toutes les modifications :
git commit -a
Annuler les modifications sur le fichier « fichier » :
git checkout fichier
Observer les changements
Quelles sont les modifications de la copie de travail ?
git status
Voir l'historique de la branche courante :
git log
Voir l'historique de tout le dépôt :
git log --all
Essayez aussi les options suivantes de git log : -p, --stat, --pretty=oneline, --graph
Interfaces graphiques
Deux interfaces graphiques intéressantes sont fournies avec Git. Gitk permet de visualiser l'historique des changements sur une branche, ou sur toutes les branches du dépôt avec l'option --all :
gitk --all
Git GUI permet de préparer les commits en mode graphique, en visualisant les changements sur chaque fichier. Il est par exemple plus pratique que git add -i pour marquer partiellement un fichier pour commit.
git gui
Branches
Note : en faisant des expériences sur les branches, n'hésitez pas à observer le dépôt avec gitk --all ou git log --graph --pretty=oneline --all
Voir la liste des branches locales :
git branch
Voir la liste des branches distantes :
git branch -r
Voir la liste de toutes les branches :
git branch -a
Créer une nouvelle branche au même point que la branche courante :
git branch nom_de_la_branche
Changer de branche (si l'on passe l'identifiant d'un commit, une branche temporaire sera créée) :
git checkout branche_ou_commit
Créer une nouvelle branche (éventuellement à partir d'une autre branche ou d'un commit), et se placer dessus :
git checkout -b nom_de_la_branche [ branche_ou_commit ]
Ajouter les commits de la branche « dev » à la branche « master » de manière à avoir un historique linéaire (git se placera automatiquement sur la branche master) :
git rebase dev master
Merger la branche dev dans la branche master (en créant un commit de merge ayant deux parents) :
git checkout master git merge dev
Supprimer une branche :
git branch -d nom_de_la_branche
Sauvegarder les changements de manière temporaire (stash)
Pour nettoyer la copie de travail de tout changement (par exemple pour permettre le changement de branche) :
git stash
Les modifications seront sauvegardées dans une sorte de commit temporaire (visible par exemple dans gitk --all).
Il est possible d'appeler git stash plusieurs fois. On peut visualiser la liste des changements sauvegardés :
git stash list
Pour réappliquer la dernière sauvegarde, on utilise git stash apply (ce qui conservera la sauvegarde) ou git stash pop (ce qui la supprimera), éventuellement avec l'option --index pour restaurer l'index (changements marqués pour commit) :
git stash pop git stash pop --index git stash apply git stash apply --index
Pour supprimer la dernière sauvegarde sans l'appliquer :
git stash drop
Pour appliquer ou supprimer non pas le dernier état sauvegardé mais une sauvegarde antérieure, il faut noter son numéro dans git stash list et l'indiquer à la suite de la commande. Par exemple, pour supprimer l'état numéro 1 (le deuxième plus récent donc) :
git stash drop stash@\{1\}
Modifier l'historique du dépôt
Avertissement : il est déconseillé de modifier un dépôt public, à moins d'être sûr que personne ne travaille dessus. Toutes les personnes ayant obtenu une copie du dépôt devront le copier à nouveau.
Il est possible de modifier le dernier commit grâce à l'option --amend de git commit :
git commit --amend
Il faut préalablement avoir apporté et marqué des modifications à la copie de travail (git add, git rm…). Si ce n'est pas le cas, git commit --amend permettra simplement de modifier le message de commit.
Il est également possible de modifier l'ordre des commits, de modifier des commits antérieurs, de fusionner ou diviser des commits, etc. La commande maîtresse est alors git rebase avec l'option -i ; il faut indiquer la somme de contrôle SHA-1 du commit parent du premier commit sur lequel on veut travailler.
git rebase -i SHA1
Git nous présentera alors un éditeur de texte, et nous permettra de marquer les modifications que l'on veut effectuer (des indications sont données en commentaire dans ce fichier texte).
Par exemple, pour modifier un commit, il faudra le marquer « edit » (ou simplement « e »), enregistrer le fichier texte et quitter l'éditeur. On utilisera ensuite git commit --amend comme vu précédemment, puis git rebase --continue pour terminer.
