Guide d'utilisation de Git en français
Guide d'utilisation de Git en français
Sommaire
1. Présentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2. Ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3. Simulateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4. Gestion de versions (VCS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.1. Notion de version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2. VCS vs DVCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.3. Logiciels de gestion de versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
5. Fonctionnement interne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
6. Les commandes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
7. Premier pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
7.1. Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
7.2. Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
8. Les commandes de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
8.1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
8.2. Initialiser un dépôt git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
8.3. Travailler avec git. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
8.3.1. Ajouter un nouveau fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.3.2. Modifier un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
8.3.3. Ignorer des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
8.3.4. Visualiser des différences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
8.3.5. Effacer des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
8.3.6. Nettoyer son répertoire de travail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.3.7. Déplacer/Renommer des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
8.3.8. Visualiser l’historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
8.3.9. Annuler des actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
8.3.10. Étiqueter des versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.3.11. Publier une version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.3.12. Utiliser le mode interactif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
8.4. Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9. Les branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9.1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
9.2. Travailler avec les branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9.3. Rebaser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9.4. Retour sur le fonctionnement interne. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
9.5. Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10. Git hébergé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
1
10.1. Notion de dépôt distant. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
10.2. Création d’un dépôt distant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
10.3. Cloner un dépôt distant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
10.4. Exemple détaillé : développeur seul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
10.5. Branche de suivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
10.6. Travailler dans GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
10.7. Pull Request et Révision de code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
10.8. Travail collaboratif. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
11. La fusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
11.1. Stratégies de fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
11.2. Le conflit de fusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
12. Workflow git et Gitflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
13. Environnement de développement intégré (EDI ou IDE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
13.1. Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
14. Les outils graphiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
1. Présentation
Git est un logiciel de gestion de versions décentralisé (DVCS). C’est un logiciel libre créé par Linus
Torvalds en 2005. Il s’agit maintenant du logiciel de gestion de versions le plus populaire devant
Subversion (svn) qu’il a remplacé avantageusement.
2. Ressources
• Manuel de référence
• Wikipedia Git
2
• Git Handbook sur Github
3. Simulateurs
ExplainGit est un simulateur permettant d’expérimenter visuellement le résultat des commandes
qui agissent directement sur le dépôt Git. Il ne simule ni le répertoire de travail ni l’espace d’index,
mais uniquement le dépôt.
• (fr) : [Link]
• (en) : [Link]
Un gestionnaire de version est donc un système (un outil logiciel) qui enregistre l’évolution d’un
fichier (ou d’un ensemble de fichiers) au cours du temps dans un historique. Il permet de ramener
un fichier à un état précédent, de ramener le projet complet à un état précédent, de visualiser les
3
changements au cours du temps, de voir qui a modifié quelque chose et quand, et plus encore …
Les fichiers ainsi versionnés sont mis à dispositions sur un dépôt (repository). C’est un espace de
stockage géré par un logiciel de gestion de versions.
Essentiellement utilisée dans le développement logiciel, elle concerne surtout la gestion des codes
source.
diff
Compare des fichiers ligne à ligne
patch
Utilise la différence entre deux fichiers pour passer d’une version à l’autre.
Exemple :
diff en action :
$ cat [Link]
toto :
Hello wordl!
$ cat [Link]
toto :
Bonjour le monde !
4
patch en action :
$ cat [Link]
toto :
Bonjour le monde !
La première ligne de la sortie de diff indique les numéros de ligne qui contiennent
des différences et le type de modifications qui ont été apportées. Le c indique que
le contenu a été remplacé, sinon a pour un ajout et d pour une suppression.
Les caractères > et < dans la sortie pointent dans la direction du fichier dans lequel
se trouve le contenu. Ainsi, pour la commande ci-dessus, le < fait référence aux
lignes de [Link] et > fait référence aux lignes de [Link].
Le principe est donc le suivant : on passera de la version N à la version N+1 en appliquant une
modification M. Un logiciel de gestion de versions applique ou retire ces modifications une par une
pour fournir la version du fichier voulue.
• conserve l’historique (les révisions successives) du projet dans un seul dépôt (repository) qui fait
référence : possibilités de revenir en arrière, de voir les changements ;
• facilite la collaboration entre les intervenants : chacun travaille avec son environnement,
plusieurs personnes travaillent sur les mêmes fichiers simultanément ;
Un DVCS (Distributed Version Control) offre les mêmes services qu’un VCS sur une architecture
décentralisée (ou distribuée).
5
La plupart des opérations de Git sont locales.
• Logiciels propriétaires : ClearCase (IBM©), Visual Source Safe et Team Foundation Server
(Microsoft©), …
5. Fonctionnement interne
Git a été conçu comme un système de fichiers versionnés.
Par bien des aspects, vous pouvez considérer Git comme un simple système
de fichiers.
Git possède deux structures de données : une base d’objets et un cache de répertoires.
• l’objet blob (binary large object), qui représente le contenu d’un fichier ;
6
• l’objet tree (arbre), qui décrit une arborescence de fichiers. Il est constitué d’une liste d’objets
de type blobs et des informations qui leur sont associées, tel que le nom du fichier et les
permissions. Il peut contenir récursivement d’autres trees pour représenter les sous-répertoires
;
• l’objet commit (résultat de l’opération du même nom signifiant « valider une transaction »), qui
correspond à une arborescence de fichiers (tree) enrichie de métadonnées comme un message
de description, le nom de l’auteur, etc. Il pointe également vers un ou plusieurs objets commits
parents pour former un graphe d’historiques ;
• l’objet tag (étiquette) qui est une manière de nommer arbitrairement un commit spécifique
pour l’identifier plus facilement. Il est en général utilisé pour marquer certains commits, par
exemple par un numéro ou un nom de version.
Une couche intermédiaire, utilisant des index (les sommes de contrôle), établit un lien entre les
objets de la base et l’arborescence des fichiers.
Git indexe les fichiers d’après leur somme de contrôle calculée avec la fonction de hachage SHA-1
qui génère un « hash » (une clé) de 160 bits.
sha1sum en action :
$ sha1sum [Link]
b6c3339dcaa25beabff0af919a49e8c44d800dab [Link]
$ sha1sum [Link]
0610e586db143df27558d98a5bd4c2c792b0bf28 [Link]
Dans Git, il est possible d’utiliser une empreinte SHA-1 courte (au moins 4
caractères) lorsqu’elle ne correspond pas à plusieurs commits. En règle générale,
entre 8 et 10 caractères sont largement suffisants pour assurer l’unicité dans un
projet. Par exemple, en février 2019, le noyau Linux avait de plus de 875 000
commits et presque sept millions d’objets dont les empreintes SHA sont uniques à
partir des 12 premiers caractères.
Git enregistre chaque révision dans un fichier en tant qu’objet blob unique.
En général, les objets blobs sont stockés dans leur intégralité en utilisant la
compression de la zlib.
Une différence majeure entre Git et les autres VCS (comme Subversion) réside dans l’historique. La
7
plupart des autres systèmes gèrent une liste de modifications de fichiers (des différences). Git ne
fait pas ça : il stocke un instantané (un commit) de la représentation de tous les fichiers du projet
dans une structure hiérarchisée. Pour être efficace, si les fichiers n’ont pas changé, Git ne stocke pas
le fichier à nouveau mais seulement une référence vers celui-ci.
6. Les commandes
Git est un ensemble de commandes indépendantes dont les principales sont :
• git add ajoute le contenu du répertoire de travail dans la zone d’index pour le prochain commit
;
• git status montre les différents états des fichiers du répertoire de travail et de l’index ;
• git commit enregistre dans la base de données (le dépôt) un nouvel instantané avec le contenu
des fichiers qui ont été indexés puis fait pointer la branche courante dessus ;
• git checkout permet de basculer de branche et d’en extraire le contenu dans le répertoire de
travail ;
• git log affiche la liste des commits effectués sur une branche ;
8
• git fetch récupère toutes les informations du dépôt distant et les stocke dans le dépôt local ;
• git pull récupère les dernières modifications distantes du projet et les fusionne dans la
branche courante ;
• git stash stocke de côté un état non commité afin d’effectuer d’autres tâches.
Liens :
• Git CHEATSHEET
Obtenir de l’aide :
$ git help
$ git --help
$ man git
7. Premier pas
Objectif
7.1. Installation
Sous GNU/Linux Ubuntu :
$ git --version
git version 2.17.1
gitk est une interface graphique pour git. C’est un paquet optionnel !
Sous Mac OS X :
9
Sous Windows :
7.2. Configuration
Configuration du compte :
Activation de la coloration :
etc …
$ cat $HOME/.gitconfig
[color]
diff = auto
status = auto
branch = auto
[user]
name = tvaira
email = tvaira@[Link]
10
Visualiser la configuration
Lien : [Link]
Le mode « cache » conserve en mémoire les identifiants pendant un certain temps. Aucun mot de
passe n’est stocké sur le disque et les identifiants sont oubliés après 15 minutes par défaut.
L’assistant cache accepte une option --timeout <secondes> qui modifie la période de maintien en
mémoire (par défaut, 900, soit 15 minutes).
Découvrir les commandes de base nécessaires pour utiliser avec Git en local :
On abordera aussi :
8.1. Introduction
La fonction principale de Git est de suivre les différentes versions d’un projet. Un projet est un
ensemble de fichiers.
11
Le commit est l’élément central de Git. Un commit (ou instantané) représente un ensemble cohérent
de modifications sur le projet.
$ mkdir tp-git-sequence-1
mkdir: création du répertoire 'tp-git-sequence-1'
$ cd ./tp-git-sequence-1
$ git init
Dépôt Git vide initialisé dans $HOME/tp-git-sequence-1/.git/
Cela crée un nouveau sous-répertoire nommé .git qui contient tous les fichiers nécessaires au
dépôt :
$ ls -al
...
drwxrwxr-x 7 tv tv 4096 juil. 28 10:58 .git
$ tree -L 1 .git
.git
├── config # configuration des préférences
├── description # description du projet
├── HEAD # pointeur vers la branche courante
├── hooks # pre/post actions hooks
├── index # l'index
├── logs # historique
├── objects # les objets (commits, trees, blobs, tags)
└── refs # pointeurs vers les branches
...
• l’index ou zone de transit (staging area) : un simple fichier (ici .git/index) qui stocke les
informations concernant ce qui fera partie du prochain instantané (commit)
12
• le dépôt local (local repository) : répertoire (ici .git) qui stocke tout l’historique des
instantannés (commits) et les méta-données du projet
On peut considérer qu’il existe une quatrième zone nommée "remise" qui s’utilise
avec la commande git stash.
• on indexe les fichiers modifiés, ce qui ajoute des instantanés de ces fichiers dans la zone d’index
(staging area) ;
• on valide les modifications, ce qui a pour effet de basculer les instantanés des fichiers de l’index
dans le dépôt local (local repository).
Lien : [Link]
• non suivi ou non versionné (untracked) : aucun instantané existe pour ce fichier
• modifié (modified) : modifié depuis le dernier instantané mais n’a pas été indexé
13
• indexé (staged) : modifié et ajouté dans la zone d’index
Pour obtenir l’état des fichiers du répertoire de travail (working directory), on utilise (très souvent)
la commande git status :
$ git status
Sur la branche master
Aucun commit
rien à valider (créez/copiez des fichiers et utilisez "git add" pour les suivre)
$ git status -s
$ git status -b
$ git status --long
$ git status -v
master (ou main) désigne la branche principale (cf. Travailler avec les branches).
14
Création d’un fichier vide :
$ touch [Link]
$ git status -s
?? [Link]
$ git status
Sur la branche master
Aucun commit
[Link]
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents
(utilisez "git add" pour les suivre)
git add est une commande multi-usage, elle peut être utilisée pour :
• ou pour d’autres actions telles que marquer comme résolus des conflits de fusion de fichiers.
15
Ajout d’un fichier dans l’index :
$ git status -s
A [Link]
$ git status -v
Sur la branche master
Aucun commit
$ vim [Link]
16
// TODO Indiquer ce que fait le programme
int main()
{
// TODO Afficher un message de bienvenue
return 0;
}
$ git status -s
M [Link]
$ git status
Sur la branche master
Modifications qui ne seront pas validées :
(utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git checkout -- <fichier>..." pour annuler les modifications dans la
copie de travail)
modifié : [Link]
aucune modification n'a été ajoutée à la validation (utilisez "git add" ou "git commit
-a")
Avant d’indexer le fichier modifié, il est plus prudent de vérifier son utilisation :
Fabrication de l’exécutable :
$ g++ -c [Link]
$ ls -l
-rw-rw-r-- 1 tv tv 119 juil. 28 20:46 [Link]
-rw-rw-r-- 1 tv tv 1232 juil. 28 20:48 bienvenue.o
$ ./bienvenue
17
$ git status -s
M [Link]
?? bienvenue
?? bienvenue.o
$ git status -v
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
modifié : [Link]
bienvenue
bienvenue.o
Il apparaît souvent que certains types de fichiers présents dans la copie de travail ne doivent pas
être ajoutés au dépôt :
18
$ git status
Sur la branche master
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
bienvenue
bienvenue.o
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents
(utilisez "git add" pour les suivre)
Ici, ce sont les fichiers issus de la fabrication (exécutable, fichiers objets, …).
Pour simplement les ignorer dans git, il faut les ajouter dans un fichier spécial .gitignore :
$ touch .gitignore
$ echo '*.[oa]' >> .gitignore
$ echo '*~' >> .gitignore
$ git status
Sur la branche master
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
.gitignore
bienvenue
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents
(utilisez "git add" pour les suivre)
$ echo 'bienvenue' >> .gitignore
$ git status
Sur la branche master
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
.gitignore
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents
(utilisez "git add" pour les suivre)
19
$ git add .gitignore
$ git commit -m "Ajout du fichier .gitignore"
[master af1dcc8] Ajout du fichier .gitignore
1 file changed, 3 insertions(+)
create mode 100644 .gitignore
Vérification :
$ git status
Sur la branche master
rien à valider, la copie de travail est propre
bienvenue
bienvenue.o
$ ls bienvenue*
bienvenue [Link] bienvenue.o
Liens :
• gitignore
En complément de git status, on utilisera la commande git diff pour visualiser les lignes exactes
qui ont été ajoutées, modifiées ou effacées :
20
On modifie le programme principal :
$ vim [Link]
#include <iostream>
int main()
{
std::cout << "Bienvenue le monde !" << std::endl;
return 0;
}
$ g++ -c [Link]
$ g++ bienvenue.o -o bienvenue
$ ./bienvenue
Bienvenue le monde !
$ git status -s
M [Link]
La commande git diff compare le contenu du répertoire de travail avec la zone d’index. Cela
affiche les modifications réalisées mais non indexées :
21
Voir les différences avec l’index :
$ git diff
diff --git a/[Link] b/[Link]
index d315a70..e8d46fe 100644
--- a/[Link]
+++ b/[Link]
@@ -1,8 +1,10 @@
-// TODO Indiquer ce que fait le programme
+// Affiche un message de bienvenue
+
+#include <iostream>
int main()
{
- // TODO Afficher un message de bienvenue
+ std::cout << "Bienvenue le monde !" << std::endl;
return 0;
}
On indexe le fichier :
Et :
$ git diff
Aucune différence
La commande git diff --staged compare les fichiers indexés et le dernier instantané (commit).
Cela affiche les modifications indexées qui feront partie de la prochaine validation :
Contenu de l’index :
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
modifié : [Link]
22
Voir les différences avec le dernier commit :
int main()
{
- // TODO Afficher un message de bienvenue
+ std::cout << "Bienvenue le monde !" << std::endl;
return 0;
}
On valide :
Et :
Aucune différence
$ git status
Sur la branche master
rien à valider, la copie de travail est propre
$ cat [Link]
23
// Affiche un message de bienvenue
#include <iostream>
int main()
{
std::cout << "Bienvenue le monde !" << std::endl;
return 0;
}
La commande git diff <commit> sert à visualiser les modifications présentes dans le répertoire de
travail par rapport au <commit> indiqué. On peut aussi utiliser la référence HEAD pour le comparer au
commit le plus récent.
HEAD est une référence symbolique pointant vers l’endroit (un commit) où l’on se
trouve dans l’historique. Si on fait un commit, HEAD se déplacera. HEAD~ désigne le
premier ancêtre de la pointe de la branche actuelle. HEAD~ est l’abréviation de
HEAD~1. HEAD~<n> désigne le n-ième ancêtre. HEAD^ désigne le premier parent
immédiat de la pointe de la branche actuelle. HEAD^ est l’abréviation de HEAD^1.
HEAD^2 désigne le deuxième parent lorsqu’il y a un commit de fusion. Pour un
commit avec un seul parent, HEAD~ et HEAD^ signifient la même chose. cf. Exemple de
déplacement avec HEAD
Les développeurs utilisent aussi des outils graphiques ou externes pour visualiser les différences.
Dans ce cas, il faut utiliser git difftool au lieu de git diff.
24
$ git difftool --tool-help
'git difftool --tool=<tool>' may be set to one of the following:
araxis
kompare
meld
vimdiff
vimdiff2
vimdiff3
...
Meld en action :
La commande git blame annote les lignes de n’importe quel fichier avec des informations : le
commit du dernier changement avec son auteur et l’horodatage.
25
$ git blame [Link]
47170829 (tvaira 2021-07-28 21:30:16 +0200 1) // Affiche un message de bienvenue
47170829 (tvaira 2021-07-28 21:30:16 +0200 2)
47170829 (tvaira 2021-07-28 21:30:16 +0200 3) #include <iostream>
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 4)
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 5) int main()
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 6) {
47170829 (tvaira 2021-07-28 21:30:16 +0200 7) std::cout << "Bienvenue le monde !"
<< std::endl;
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 8)
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 9) return 0;
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 10) }
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 11)
Pour effacer un fichier de Git, il faut l’effacer dans la zone d’index puis valider. La commande git
rm réalise cette action mais efface aussi ce fichier de la copie de travail.
Pour conserver le fichier dans la copie de travail, il faut utiliser l’option --cached.
Il existe une mesure de sécurité pour empêcher un effacement accidentel lorsqu’un fichier a été
modifié et indexé. Il est alors possible de forcer son élimination avec l’option -f.
$ touch README
$ ls -l README
-rw-rw-r-- 1 tv tv 0 juil. 31 11:49 README
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
26
Suppression forcée d’un fichier :
$ git rm README
error: le fichier suivant a des changements indexés :
README
(utilisez --cached pour garder le fichier, ou -f pour forcer la suppression)
$ git rm README -f
rm 'README'
$ git status
Sur la branche master
rien à valider, la copie de travail est propre
$ ls -l README
ls: impossible d'accéder à 'README': Aucun fichier ou dossier de ce type
$ touch README
$ ls -l README
-rw-rw-r-- 1 tv tv 0 juil. 31 11:52 README
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
27
Suppression d’un fichier de l’index :
$ git status
Sur la branche master
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
README
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents
(utilisez "git add" pour les suivre)
$ ls -l README
-rw-rw-r-- 1 tv tv 0 juil. 31 11:52 README
28
Suppresion d’un fichier du dépôt :
$ git rm README
rm 'README'
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
supprimé : README
$ git status
Sur la branche master
rien à valider, la copie de travail est propre
$ ls -l README
ls: impossible d'accéder à 'README': Aucun fichier ou dossier de ce type
Par défaut, la commande git clean ne va supprimer que les fichiers non-suivis qui ne sont pas
ignorés (cf. .gitignore).
• -x : supprime aussi les fichiers ignorés (-X supprime seulement les fichiers ignorés)
29
git clean en action :
$ touch hello
$ git clean -n
Supprimerait hello
$ git clean
fatal: [Link] à true par défaut et ni -i, -n ou -f fourni ; refus de
nettoyer
$ git clean -f
Suppression de hello
Il est (souvent) impossible de récupérer le contenu des fichiers après un git clean.
Une option plus sécurisée consisterait à "remiser" l’ensemble avec git stash --all.
Lien : [Link]
La commande git mv permet de renommer un fichier. Cela évite de faire successivement les
commandes mv, git rm et git add.
$ touch README
$ git add README
$ git commit -m "Ajout README"
[master f937b30] Ajout README
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README
30
Renommage d’un fichier du dépôt :
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
$ ls -l README*
-rw-rw-r-- 1 tv tv 0 juil. 31 11:59 [Link]
$ vim [Link]
# Bienvenue
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
modifié : [Link]
31
Renommage d’un fichier dans l’index :
$ git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
$ ls -l README*
-rw-rw-r-- 1 tv tv 52 juil. 31 12:02 README
$ cat README
# Bienvenue
Après avoir créé plusieurs instatanés (commits), il est possible de consulter l’historique avec la
commande git log. C’est une commande importante et puissante disposant de nombreuses options.
Par défaut, git log affiche les commits réalisés en ordre chronologique inversé. Cela signifie que les
commits les plus récents apparaissent en premier. Sinon, on utilisera l’option --reverse.
• git log --oneline Affiche chaque commit sur une seule ligne
• git log -- <fichier> Affiche uniquement les commits contenant le fichier spécifié
• git log <depuis>..<jusqu'à> Affiche les validations qui se produisent entre deux commits en
utilisant une référence comme un ID de validation, un nom de branche, HEAD ou tout autre type
32
de référence de révision.
Il est possible d’appliquer des critères de recherche avec les options --author,
--grep et -S. Voir aussi : --since, --after, --until et --before.
Historique complet :
$ git log
commit bb6ef9fbb54b4aa856bbd6effbc30601d38acffb (HEAD -> master)
Author: tvaira <tvaira@[Link]>
Date: Sat Jul 31 12:05:07 2021 +0200
Renommage README
commit 948859bdcac73aff903fa13fe340658dae6c4922
Author: tvaira <tvaira@[Link]>
Date: Sat Jul 31 12:00:32 2021 +0200
Renommage [Link]
commit f937b306dfb405a77a26688bf8aecf0312d33799
Author: tvaira <tvaira@[Link]>
Date: Sat Jul 31 11:59:57 2021 +0200
Ajout README
commit 357d00546a9968556fafd680b1721b37d58bb70f
Author: tvaira <tvaira@[Link]>
Date: Sat Jul 31 11:56:26 2021 +0200
Suppression README
commit e60cc7eae4f55b7cb4c53c20827f904697308898
Author: tvaira <tvaira@[Link]>
Date: Sat Jul 31 11:55:48 2021 +0200
Ajout README
commit 47170829ef8654ec28f6d3b74d00b2a0baeaefa9
Author: tvaira <tvaira@[Link]>
Date: Wed Jul 28 21:30:16 2021 +0200
commit af1dcc83807624005b76a1ca5d7e790ce6f1737a
Author: tvaira <tvaira@[Link]>
Date: Wed Jul 28 21:03:28 2021 +0200
commit 973e4f7d830313e4ac9b08a332db767cdf28941f
33
Author: tvaira <tvaira@[Link]>
Date: Wed Jul 28 20:55:12 2021 +0200
commit bb344f417dbbf7f6725b24b293af2909bad6a519
Author: tvaira <tvaira@[Link]>
Date: Wed Jul 28 20:33:06 2021 +0200
commit 973e4f7d830313e4ac9b08a332db767cdf28941f
Author: tvaira <tvaira@[Link]>
Date: Wed Jul 28 20:55:12 2021 +0200
34
Avec les différences :
$ git log -p
...
int main()
{
- // TODO Afficher un message de bienvenue
+ std::cout << "Bienvenue le monde !" << std::endl;
return 0;
}
...
35
Affichage sous forme de graphe :
Affichage personnalisé :
La commande git blame annote les lignes de n’importe quel fichier avec des informations : le
commit du dernier changement avec son auteur et l’horodatage :
36
$ git blame [Link]
47170829 (tvaira 2021-07-28 21:30:16 +0200 1) // Affiche un message de bienvenue
47170829 (tvaira 2021-07-28 21:30:16 +0200 2)
47170829 (tvaira 2021-07-28 21:30:16 +0200 3) #include <iostream>
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 4)
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 5) int main()
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 6) {
47170829 (tvaira 2021-07-28 21:30:16 +0200 7) std::cout << "Bienvenue le monde !"
<< std::endl;
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 8)
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 9) return 0;
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 10) }
973e4f7d (tvaira 2021-07-28 20:55:12 +0200 11)
Il est possible de modifier le dernier commit (plutôt de le remplacer complètement par un nouveau
commit) avec la commande git commit --amend.
$ vim README
# Bienvenue
37
Modification du dernier commit :
Vérification :
On peut aussi annuler des modifications dans la zone d’index et la zone de travail :
• git checkout -- <fichier> pour annuler les modifications dans la copie de travail
git reset peut être une commande dangereuse, notamment avec l’option --hard.
De manière générale, il est déconseillé de modifier l’historique dans le cas d’un
travail collaboratif. La version 2.25.0 de Git a introduit une nouvelle commande :
git restore. C’est fondamentalement une alternative à git reset.
Pour annuler un commit, on peut l’inverser (revert) : git revert crée un commit
qui applique l’exact opposé des modifications introduites par le commit ciblé.
38
8.3.10. Étiqueter des versions
Git donne la possibilité d’étiqueter un certain état dans l’historique. On l’utilise pour marquer (tag)
les états de publication comme des versions (1.0 par exemple).
Git utilise deux types principaux d’étiquettes : légères et annotées (avec l’option -
a). Une étiquette légère est considérée comme un pointeur sur un commit
spécifique. Par contre, les étiquettes annotées sont stockées en tant qu’objets à part
entière dans la base de données de Git.
$ git tag
1.0
La version 1.0
...
Il est possible d’étiqueter après coup. Pour cela, il faut spécifier le commit en fin de
commande : git tag -a v1.2 <commit>
Pour publier une version, il est nécessaire de créer une archive à partir d’un instantané
(généralement une étiquette de version).
# Exemple :
# git archive --prefix=src-directory-name tag --format=zip > `git describe master`.zip
N’oubliez pas d’ajouter l’option --prefix (et de préciser votre nom comme
indentifiant) avant de rendre une archive de TP !!!
39
Il est possible de recopier le dépôt avec la commande : cp -Rf tp-git-sequence-1
<destination>. Git fournit aussi la commande git clone. Mais en pratique, on
utilisera plutôt des dépôts hébergés (GitHub, GitLab, Bitbucket, …).
Git propose quelques scripts qui "guident" les opérations en ligne de commande avec l’option -i ou
--interactive.
• git add --interactive : pour choisir les fichiers ou les parties d’un fichier à incorporer à un
commit
• git clean --interactive : pour choisir les fichiers qui seront supprimés du répertoire de travail
Git ne possède pas d’outil de modification d’historique mais, il est possible d’utiliser l’outil rebase en
mode interactif pour :
• Écraser un commit
• Diviser un commit
• Supprimer un commit
Il est également possible de prendre une série de commits et de les rassembler en un seul avec
l’outil de rebasage interactif :
40
HEAD est une référence symbolique pointant vers l’endroit (un commit) où l’on se
trouve dans l’historique. Si on fait un commit, HEAD se déplacera. HEAD~ désigne le
premier ancêtre de la pointe de la branche actuelle. HEAD~ est l’abréviation de
HEAD~1. HEAD~<n> désigne le n-ième ancêtre. HEAD^ désigne le premier parent
immédiat de la pointe de la branche actuelle. HEAD^ est l’abréviation de HEAD^1.
HEAD^2 désigne le deuxième parent lorsqu’il y a un commit de fusion. Pour un
commit avec un seul parent, HEAD~ et HEAD^ signifient la même chose. cf. Exemple de
déplacement avec HEAD
Ajout README
#Suppression README
#Ajout README
41
# Ceci est le message de validation numéro 4 :
#Renommage [Link]
#Renommage README
#Modification README
Vérification :
42
8.4. Conclusion
Cycle de travail
• git status
• git log …
9. Les branches
Objectif
9.1. Introduction
En général, les gestionnaires de version (VCS) proposent une gestion de branches. Créer une
branche signifie diverger de la ligne principale de développement et continuer à travailler sans
impacter cette ligne.
La branche par défaut dans Git s’appelle master ou main. Au fur et à mesure des validations, la
branche master pointe vers le dernier des commits réalisés. À chaque validation, le pointeur de la
branche master avance automatiquement.
La branche master ou main n’est pas une branche spéciale. Elle est identique à
toutes les autres branches. La seule raison pour laquelle chaque dépôt en a une est
que la commande git init la crée par défaut.
D’un point de vue technique, une branche dans Git est simplement un pointeur déplaçable vers un
commit.
Pour créer une nouvelle branche, on utilise la commande git branch <nom-branche>. Cela crée
simplement un nouveau pointeur vers le commit courant.
Git connaît la branche actuelle avec le pointeur spécial appelé HEAD. Dans Git, il s’agit simplement
d’un pointeur sur la branche locale où l’on se trouve.
Pour l’instant, on se trouve toujours sur la branche master. En effet, la commande git branch n’a fait
que créer une nouvelle branche et elle n’a pas fait basculer la copie de travail vers cette branche.
43
Pour basculer sur une branche existante, il suffit d’exécuter la commande git checkout <nom-
branche>. Cela déplace HEAD pour le faire pointer vers la branche <nom-branche>.
Il est habituel de créer une nouvelle branche et de vouloir basculer sur cette nouvelle branche en
même temps : pour cela on exécutera la commande git checkout -b <nouvelle-branche> (voir aussi
git switch).
Il est important de noter que lorsque l’on change de branche avec Git, les fichiers
du répertoire de travail sont modifiés. Si la copie de travail ou la zone d’index
contiennent des modifications non validées qui sont en conflit avec la branche à
extraire, Git n’autorisera pas le changement de branche. Le mieux est donc d’avoir
une copie de travail propre au moment de changer de branche.
Une fois le travail réalisé (terminé et testé) dans la branche, il est prêt à être fusionné dans la
branche master. On réalise ceci au moyen de la commande git merge.
À présent que le travail a été fusionné, on n’a plus besoin de la branche. On peut la supprimer avec
l’option -d de la commande git branch.
En gardant une branche master ou main saine, on conserve ainsi une version du logiciel prête à être
livrée à tout instant puisqu’on ne fusionne (merge) dedans que lorsque le développement d’une
branche est bien terminé.
Liens :
44
$ git branch -vv
* master 7cbe84f Ajout README
$ git branch
fonction-bienvenue
* master
$ git branch
* fonction-bienvenue
master
$ touch fonction-bienvenue.h
$ touch [Link]
$ vim fonction-bienvenue.h
#ifndef FONCTION_BIENVENUE_H
#define FONCTION_BIENVENUE_H
void afficherBienvenue();
#endif // FONCTION_BIENVENUE_H
$ vim [Link]
45
#include "fonction-bienvenue.h"
#include <iostream>
void afficherBienvenue()
{
std::cout << "Bienvenue le monde !" << std::endl;
}
$ vim [Link]
#include "fonction-bienvenue.h"
int main()
{
afficherBienvenue();
return 0;
}
On crée un Makefile :
$ touch Makefile
$ vim Makefile
46
TARGET := bienvenue
MODULE := fonction-bienvenue
CXX = g++ -c
LD = g++ -o
RM = rm -f
CXXFLAGS = -Wall -std=c++11
LDFLAGS =
all : $(TARGET)
.PHONY: clean
clean:
$(RM) *.o
cleanall:
$(RM) *.o $(TARGET)
On teste le travail :
$ make
Fabrication du programme : bienvenue
g++ -c -Wall -std=c++11 [Link]
g++ -c -Wall -std=c++11 [Link]
g++ -o bienvenue bienvenue.o fonction-bienvenue.o
./bienvenue
Bienvenue le monde !
47
$ git status
Sur la branche fonction-bienvenue
Modifications qui ne seront pas validées :
(utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git checkout -- <fichier>..." pour annuler les modifications dans la
copie de travail)
modifié : [Link]
Makefile
[Link]
fonction-bienvenue.h
aucune modification n'a été ajoutée à la validation (utilisez "git add" ou "git commit
-a")
$ git status
Sur la branche fonction-bienvenue
Modifications qui seront validées :
(utilisez "git reset HEAD <fichier>..." pour désindexer)
48
Vérification :
$ git status
Sur la branche fonction-bienvenue
rien à valider, la copie de travail est propre
$ ls -l
-rwxrwxr-x 1 tv tv 9008 août 11 14:08 bienvenue
-rw-rw-r-- 1 tv tv 140 août 11 14:14 [Link]
-rw-rw-r-- 1 tv tv 1432 août 11 14:08 bienvenue.o
-rw-rw-r-- 1 tv tv 2816 août 11 14:08 fonction-bienvenue.o
-rw-rw-r-- 1 tv tv 63 août 11 10:11 README
$ git status
Sur la branche master
rien à valider, la copie de travail est propre
Fusion :
49
Lors de la fusion (merge), Git a simplement déplacé le pointeur (vers l’avant) : le
commit 7cbe84f vers c8824fc. Lorsque l’on cherche à fusionner un commit qui peut
être atteint en parcourant l’historique depuis le commit d’origine, Git se contente
d’avancer le pointeur car il n’y a pas de travaux divergents à fusionner. Ceci
s’appelle un fast-forward (avance rapide).
50
Vérification :
$ ls -l
-rwxrwxr-x 1 tv tv 9008 août 11 14:08 bienvenue
-rw-rw-r-- 1 tv tv 122 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 1432 août 11 14:08 bienvenue.o
-rw-rw-r-- 1 tv tv 135 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 117 août 11 14:16 fonction-bienvenue.h
-rw-rw-r-- 1 tv tv 2816 août 11 14:08 fonction-bienvenue.o
-rw-rw-r-- 1 tv tv 459 août 11 14:16 Makefile
-rw-rw-r-- 1 tv tv 63 août 11 10:11 README
$ make
Fabrication du programme : bienvenue
g++ -c -Wall -std=c++11 [Link]
g++ -c -Wall -std=c++11 [Link]
g++ -o bienvenue bienvenue.o fonction-bienvenue.o
$ ./bienvenue
Bienvenue le monde !
Avant :
Après :
51
9.3. Rebaser
En utilisant le rebasage, il est possible de conserver un historique linéaire après une fusion.
La commande git rebase permet de changer la « base » (le commit de départ) de la branche
courante. La nouvelle « base » devient le dernier commit de la branche passée en argument de la
commande.
Git a « rejoué » chacun des commits de la branche dev sur la tête de la branche master.
52
9.4. Retour sur le fonctionnement interne
Le répertoire de travail et dépôt local tp-git-sequence-1 actuel :
53
$ ls -l
-rwxrwxr-x 1 tv tv 9008 août 11 14:17 bienvenue
-rw-rw-r-- 1 tv tv 122 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 1432 août 11 14:17 bienvenue.o
-rw-rw-r-- 1 tv tv 135 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 117 août 11 14:16 fonction-bienvenue.h
-rw-rw-r-- 1 tv tv 2816 août 11 14:17 fonction-bienvenue.o
-rw-rw-r-- 1 tv tv 459 août 11 14:16 Makefile
-rw-rw-r-- 1 tv tv 111 août 11 17:17 [Link]
Le dépôt local contient l’historique des instantanés (commits). C’est une base de "données" (d’objets)
qui peut contenir n’importe quel type d’objets (commit, tree, blob et tag). Git utilise des index
(somme de contrôle calculée avec la fonction de hachage SHA-1) pour référencer les objets de la
base.
L’objet commit correspond à une arborescence de fichiers (tree) enrichie de métadonnées comme
un message de description, le nom de l’auteur, etc.
Il pointe également vers un ou plusieurs objets commits parents pour former un graphe :
54
Son objet commit parent :
L’objet tree décrit une arborescence de fichiers. Il est constitué d’une liste d’objets de type blobs (et
des informations qui leur sont associées, tel que le nom du fichier et les permissions). Il peut
contenir d’autres objets trees pour représenter les sous-répertoires.
L’objet blob (binary large object) représente le contenu d’un fichier. Git enregistre chaque révision
dans un fichier en tant qu’objet blob unique.
int main()
{
// TODO Afficher un message de bienvenue
return 0;
}
55
L’objet tag est une manière de nommer arbitrairement un commit spécifique pour l’identifier plus
facilement. Il est en général utilisé pour marquer certains commits, par exemple par un numéro ou
un nom de version. Un objet tag contient un nom d’objet (simplement nommé object), un type
d’objet (ici commit), un nom de tag, le nom du « taggeur » et un message :
La version 1.0
9.5. Conclusion
Dans Git, créer, développer, fusionner et supprimer des branches plusieurs fois par jour est un
travail "normal".
• les branches au long cours : ce sont des branches ouvertes en permanence pour les différentes
phases du cycle de développement.
• les branches thématiques : une branche thématique est une branche ayant une courte durée de
vie créée et utilisée pour une fonctionnalité ou une tâche particulière (un correctif par
exemple). On y réalise quelques commits et on supprime la branche immédiatement après
l’avoir fusionnée dans la branche principale. Les branches thématiques sont utiles quelle que
soit la taille du projet.
56
De nombreux développeurs travaillent avec Git en utilisant une méthode de
développement basée sur les branches (cf. Workflow git et Gitflow).
Cycle de travail
• Créer une branche thématique et basculer dessus (git branch <branche> puis git checkout
<branche> ou git checkout -b <branche>)
• git status
• git log …
Il est possible d’héberger des projets Git sur un site externe dédié à l’hébergement.
Liste : [Link]
Quelques hébergeurs :
57
• GitLab est un logiciel libre de forge basé sur Git proposant les fonctionnalités de wiki, un
système de suivi des bugs, l’intégration continue et la livraison continue. Site officiel :
[Link]
Ressources :
• Hello World
• Tutoriels
Des commandes spécifiques seront utilisées pour synchroniser les dépôts local et distant :
• git push publie ("pousse") les nouvelles révisions du dépôt local sur le dépôt distant ;
58
• git fetch récupère l’ensemble des changements (qui n’ont pas déjà été rapatriés localement)
présents sur le serveur et met à jour la base de donnée locale (le dépôt local). Elle ne modifie
pas le répertoire de travail.
• git pull consiste essentiellement en un git fetch immédiatement suivi par un git merge dans
la plupart des cas. Le répertoire de travail peut donc être modifié.
59
Il y a deux façons de récupérer un dépôt Git :
• soit le dépôt local est déjà existant (git init) et il faut donc le relier à un dépôt distant (git
remote add origin [Link]
• soit le dépôt distant existe et il faut le copier (git clone) pour obtenir un dépôt local
• créé un répertoire du nom du dépôt existant, initialisé avec un répertoire .git à l’intérieur,
60
• tire l’historique,
• crée un pointeur sur l’état actuel de la branche main et l’appelle localement origin/main
• crée également une branche locale main qui démarre au même endroit que la branche main
distante
main (ou master) et origin sont des noms donnés par défaut.
Clonage du dépôt :
État du dépôt :
$ cd tp-cplusplus/
$ ls -l
-rw-rw-r-- 1 tv tv 50 août 11 20:17 [Link]
$ cat [Link]
# tp-cplusplus
TP C++ - Deuxième année BTS SNIR
$ git remote -v
origin [Link] (fetch)
origin [Link] (push)
61
On suppose qu’un compte sur GitHub a été créé.
On se connecte :
• SSH
62
• Étape n°1 : générer des clés SSH
$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for ~/.ssh/id_ed25519:
Identity added: ~/.ssh/id_ed25519 (tvaira@[Link])
Accès en SSH :
• HTTPS
63
Il faut maintenant créer un jeton d’accès personnel à utiliser à la place du mot de
passe ([Link]
account-and-data-secure/creating-a-personal-access-token)
Accès en HTTPS :
• GitHub CLI
64
Lien : [Link]
Sous GNU/Linux Ubuntu, on put installer gh avec la commande sudo snap install gh
$ tldr gh
- Locally check out the branch of a pull request, given its number:
gh pr checkout pr_number
65
Avant d’utiliser gh, il faut s’authentifier : gh auth login
66
À la fin, GitHub fournit les indications en fonction de la situation :
67
Il est possible alors de l’ajouter comme dépôt distant pour le dépôt local de l’ordinateur de travail et
de synchroniser les deux emplacements.
Il faut renommer la branche master en main (l’option -M est un raccourci pour les options --move et
--force) :
68
$ git push -u origin main
Décompte des objets: 21, fait.
Delta compression using up to 12 threads.
Compression des objets: 100% (17/17), fait.
Écriture des objets: 100% (21/21), 2.32 KiB | 395.00 KiB/s, fait.
Total 21 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To [Link]:tvaira/[Link]
* [new branch] main -> main
La branche 'main' est paramétrée pour suivre la branche distante 'main' depuis
'origin'.
$ git pull
Déjà à jour.
L’option --set-upstream (alias -u) crée une référence qui permettra ensuite
d’utiliser git push et git pull directement sans argument.
$ git remote -v
origin git@[Link]:tvaira/[Link] (fetch)
origin git@[Link]:tvaira/[Link] (push)
$ vim README
# Bienvenue
69
$ git status
Sur la branche main
Votre branche est en avance sur 'origin/main' de 1 commit.
(utilisez "git push" pour publier vos commits locaux)
$ git push
Décompte des objets: 3, fait.
Delta compression using up to 12 threads.
Compression des objets: 100% (3/3), fait.
Écriture des objets: 100% (3/3), 352 bytes | 352.00 KiB/s, fait.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To [Link]:tvaira/[Link]
c8824fc..470794d main -> main
$ git status
Sur la branche main
Votre branche est à jour avec 'origin/main'.
$ git pull
Déjà à jour.
Dans GitHub :
70
GitHub traite automatique le format Markdown si l’extension du fichier est .md. Ce
qui n’est pas le cas içi ! Il faudra donc renommer le fichier [Link].
Et c’est mieux :
71
On re-synchronise les deux emplacements :
Avant :
$ ls -l
-rwxrwxr-x 1 tv tv 9008 août 11 14:17 bienvenue
-rw-rw-r-- 1 tv tv 122 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 1432 août 11 14:17 bienvenue.o
-rw-rw-r-- 1 tv tv 135 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 117 août 11 14:16 fonction-bienvenue.h
-rw-rw-r-- 1 tv tv 2816 août 11 14:17 fonction-bienvenue.o
-rw-rw-r-- 1 tv tv 459 août 11 14:16 Makefile
-rw-rw-r-- 1 tv tv 111 août 11 17:03 README
72
Récupère les modifications du dépôt distant :
$ git pull
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
Dépaquetage des objets: 100% (2/2), fait.
Depuis [Link]:tvaira/tp-git-sequence-1
470794d..c479e51 main -> origin/main
Mise à jour 470794d..c479e51
Fast-forward
README => [Link] | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename README => [Link] (100%)
Après :
$ ls -l
-rwxrwxr-x 1 tv tv 9008 août 11 14:17 bienvenue
-rw-rw-r-- 1 tv tv 122 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 1432 août 11 14:17 bienvenue.o
-rw-rw-r-- 1 tv tv 135 août 11 14:16 [Link]
-rw-rw-r-- 1 tv tv 117 août 11 14:16 fonction-bienvenue.h
-rw-rw-r-- 1 tv tv 2816 août 11 14:17 fonction-bienvenue.o
-rw-rw-r-- 1 tv tv 459 août 11 14:16 Makefile
-rw-rw-r-- 1 tv tv 111 août 11 17:17 [Link]
73
$ git push --tags
Décompte des objets: 1, fait.
Écriture des objets: 100% (1/1), 154 bytes | 154.00 KiB/s, fait.
Total 1 (delta 0), reused 0 (delta 0)
To [Link]:tvaira/[Link]
* [new tag] 1.0 -> 1.0
Dans le cadre d’un travail collaboratif, on pourra aussi décider d’utiliser des
branches locales privées que l’on ne souhaite pas partager.
L’extraction d’une branche locale à partir d’une branche distante crée automatiquement une
branche de suivi (c’est l’option par défaut --track de la commande git checkout). Si la branche
distante n’existe pas encore, il faudra utiliser l’option -u ou --set-upstream-to pour créer le suivi.
• git push sélectionne automatiquement le serveur vers lequel pousser les modifications.
• git pull récupère toutes les références distantes et fusionne automatiquement la branche
distante correspondante dans la branche actuelle.
74
On souhaite modifier la fonction afficherBienvenue() pourqu’elle soit plus "générique" en
recevant en argument le message à afficher. Pour cela on créer une branche qui va permettre
de réaliser ce travail de manière isolée.
$ git branch -v
* main c479e51 [origin/main] Renommage [Link]
$ git branch -v
main c479e51 [origin/main] Renommage [Link]
* modification-fonction c479e51 Renommage [Link]
75
On "travaille" sur le code :
$ vim fonction-bienvenue.h
#ifndef FONCTION_BIENVENUE_H
#define FONCTION_BIENVENUE_H
#include <string>
#endif // FONCTION_BIENVENUE_H
$ vim [Link]
#include "fonction-bienvenue.h"
#include <iostream>
$ vim [Link]
76
// Affiche un message de bienvenue
#include "fonction-bienvenue.h"
int main()
{
afficherMessage("Bienvenue le monde !");
return 0;
}
On teste :
$ make rebuild
$ ./bienvenue
Bienvenue le monde !
Vérification :
$ git branch -v
main c479e51 [origin/main] Renommage [Link]
* modification-fonction ce00d34 Modification afficherBienvenue en afficherMessage
77
On crée une branche de suivi :
78
Vérification :
$ git ls-remote
From git@[Link]:tvaira/[Link]
c479e51a64712908cf823b053b72d75a015d2cf8 HEAD
c479e51a64712908cf823b053b72d75a015d2cf8 refs/heads/main
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 refs/heads/modification-fonction
79
À partir d’ici, il y a deux possibilités pour fusionner la branche dans la branche
principale. Dans le cadre d’un travail collaboratif, on pourrait (devrait ?) créer une
Pull Request (une demande modification) comme l’indique le message "Create a
pull request for 'modification-fonction' on GitHub …" (cf. Pull Request et Révision de
code). Pull Request peut être traduit par « Proposition de révision » (PR). C’est
l’action qui consiste à demander au détenteur du dépôt de référence de prendre en
compte des modifications d’un autre dépôt (fork ou local).
Dans une situation "Développeur seul", cela n’a pas d’intérêt donc on peut
continuer sur le dépôt local pour faire la fusion (merge) puis la "publier" (push) sur
le dépôt distant.
80
On fusionne la branche modification-fonction dans main :
81
Vérification :
$ git status
Sur la branche main
Votre branche est en avance sur 'origin/main' de 1 commit.
(utilisez "git push" pour publier vos commits locaux)
82
$ git push
Total 0 (delta 0), reused 0 (delta 0)
To [Link]:tvaira/[Link]
c479e51..ce00d34 main -> main
Vérification :
83
On peut visualiser le commit de fusion :
On supprime la branche locale (c’est une branche thématique) : (l’option -D force la suppression)
84
Vérification :
85
Vérification :
$ git ls-remote
From git@[Link]:tvaira/[Link]
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 HEAD
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 refs/heads/main
...
86
Sur GitHub, on peut créer des versions livrables "release" :
87
Au final, l’état du projet sur GitHub est le suivant :
88
Les branches qui ont été fusionnées (ou pas) :
Pour éviter de conserver en local des anciennes branches généralement fusionnées, on les nettoye
avec :
Le prévisualiser :
89
Et terminer en réalisant le commit :
Le commit ayant été réalisé directement sur le dépôt distant, il n’est pas (encore) disponible sur le
dépôt local :
$ git status
Sur la branche main
Votre branche est en retard sur 'origin/main' de 1 commit, et peut être mise à jour en
avance rapide.
(utilisez "git pull" pour mettre à jour votre branche locale)
On peut mettre à jour le dépôt local et le répertoire de travail directement avec la commande git
pull (équivalente à git fetch suivi d’un git merge) :
$ git pull
Mise à jour 3cf9129..73c7f78
Fast-forward
[Link] | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
90
Vérification :
$ cat [Link]
# Bienvenue
Programme C++ qui affiche le message "Bienvenue le monde !" en utilisant la fonction
`afficherBienvenue()`.
## La fonction afficherBienvenue
```cpp
#ifndef FONCTION_BIENVENUE_H
#define FONCTION_BIENVENUE_H
#include <string>
#endif // FONCTION_BIENVENUE_H
```
```cpp
#include "fonction-bienvenue.h"
#include <iostream>
```cpp
// Affiche un message de bienvenue
#include "fonction-bienvenue.h"
int main()
{
afficherBienvenue();
return 0;
}
```
91
Lire : [Affichage avec cout]([Link] et
[Saisie avec cin en C++]([Link] en C++.
92
$ git tag -a 1.2 -m 'La version 1.2'
GitHub a popularisé le principe de Pull Request et les autres système Git hébergés
l’utilisent aussi : Bitbucket Cloud, GitLab (Merge Request), …
Lien : Collaborating with pull requests
Les Pull Requests sont un mécanisme permettant à un développeur d’informer les membres de
l’équipe qu’il a terminé un « travail » (une fonctionnalité, une version livrable, un correctif, …) et de
proposer sa contribution au dépôt central.
Pull Request peut être traduit par « Proposition de révision » (PR) : c’est-à-dire une
demande de modification ou de contribution.
Principe :
Une fois que sa branche de suivi est prête, le développeur crée ou ouvre (Open) une Pull Request.
Tous les développeurs du projet seront informées du fait qu’ils doivent réviser le code puis le
fusionner (merge) dans la branche principale (main ou master) ou dans une branche de
développement (develop).
Pendant cette révision de code, les développeurs peuvent discuter de la fonctionnalité (commenter
le code, poser des questions, …) et proposer des adaptations de la fonctionnalité en publiant des
commits de suivi.
93
Les Pull Requests offrent cette fonctionnalité dans une interface Web à côté des
dépôts GitHub ou Bitbucket. Cette interface affiche une comparaison des
changements, permet l’échange entre développeurs et fournit une méthode simple
pour réaliser la fusion (merge) du code quand il est prêt.
Les Pull Requests peuvent être utilisées avec le workflow Gitflow (un modèle de branches strict
conçu autour de la livraison du projet).
Liens :
Avant de faire un git push sur une branche de suivi, il faut peut être nettoyer son historique local
(une série de commits dans la branche) afin de pouvoir proposer quelque chose de propre et
d’utilisable. Avant de publier la branche, il est conseillé d’effectuer un rebasage interactif avec git
rebase -i. On a alors une totale liberté pour nettoyer, réécrire, annuler, regrouper les commits
locaux avant de les partager (git push) sur le dépôt distant.
Sur la branche actuelle depuis la dernière synchronisation : git rebase -i @{upstream} (ou git
rebase -i origin/feature ou git rebase -i HEAD~n).
Par exemple :
94
Lorsque l’on développe seul, une branche de suivi peut servir de sauvegarde sur
un dépôt distant. Dans le cadre d’un travail collaboratif, cela devient une branche
de partage.
Il est possible que le git push soit refusé en raison d’une branche de suivi obsolète (un travail a été
poussé entre-temps) : entre la dernière synchronisation entrante (git pull) et le moment où on
souhaite effectuer un git push, un autre développeur a publié des changements (des commits). La
branche distante (par exemple origin/feature) est donc maintenant plus avancée que sa copie
locale.
Un git pull provoquerait une fusion avec une divergence mais on souhaite conserver un
historique linéaire au sein d’une branche : car ce n’est réalité qu’un problème de séquencement
dans le travail sur la branche.
On va demander à git pull de faire un rebase au lieu d’une fusion (merge) en utilisant git pull
--rebase.
Bonus : Supprimer toutes ses modifications et commits locaux et récupérer un dépôt distant «
propre »
95
$ git fetch origin
$ git reset --hard origin/main
11. La fusion
11.1. Stratégies de fusion
Les différentes stratégies de fusion :
• Avance rapide (Fast Forward) : c’est la fusion utilisée par défaut par git merge si c’est possible.
Git déplace les commits de la branche feature vers la branche destination main si il n’y a pas eu
de nouveaux commits sur cette branche. En réalité, Git déplace simplement le pointeur vers
l’avant. On peut réaliser cette fusion avec l’option --ff-only.
• Commit de fusion : lorsque l’historique de développement a divergé, git merge réalise une
fusion à trois sources (three-way merge) en utilisant les deux commits au sommet des deux
branches (C4 et C5) ainsi que leur plus proche ancêtre commun (C2) pour créer un nouveau
commit (C6). On peut réaliser cette fusion avec l’option --no-ff.
96
• Squash : on obtient un nouveau commit qui regroupe tous les commits de la branche. Pour
réaliser cette fusion, il faut ajouter l’option --squash.
97
Dans GitHub :
98
Dans Bitbucket :
Cette situation peut se produire dans le cadre d’un travail collaboratif mais,
rarement en Développeur seul.
On s’aperçoit que le fichier [Link] n’a pas été modifié (nom de fonction incorrect) lors de la
modification de la fonction (un oubli !) :
$ cat [Link]
# Bienvenue
Il faut donc faire un correctif. Pour cela, on va créer une branche thématique (dans GitHub pour
changer) :
99
La branche correctif-readme est créée sur le dépôt distant mais elle n’est pas encore disponible sur
le dépôt local :
$ git ls-remote
From git@[Link]:tvaira/[Link]
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 HEAD
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 refs/heads/correctif-readme
ce00d3449aa40aa44d51effcc66c796eb9b2ed20 refs/heads/main
...
Il faut donc récupèrer les informations du dépôt distant et les rapatrier dans le dépôt local :
$ git fetch
Depuis [Link]:tvaira/tp-git-sequence-1
* [nouvelle branche] correctif-readme -> origin/correctif-readme
100
On bascule sur la branche correctif-readme qui sera automatiquement défini comme une branche
de suivi :
$ vim [Link]
# Bienvenue
101
Vérification :
Maintenant, on va basculer sur la branche principale pour créer une nouvelle branche thématique
modification-fonction pour modifier la fonction (et remettre un peu d’ordre dans le code !) :
102
Basculement sur la branche thématique :
On modifie le projet :
$ vim fonction-bienvenue.h
#ifndef FONCTION_BIENVENUE_H
#define FONCTION_BIENVENUE_H
#include <string>
#endif // FONCTION_BIENVENUE_H
$ vim [Link]
#include "fonction-bienvenue.h"
#include <iostream>
$ vim [Link]
103
// Affiche un message de bienvenue
#include "fonction-bienvenue.h"
int main()
{
afficherBienvenue();
return 0;
}
$ vim [Link]
# Bienvenue
Programme C++ qui affiche le message "Bienvenue le monde !" en utilisant la fonction
`afficherBienvenue()`.
On teste :
$ make rebuild
Fabrication du programme : bienvenue
rm -f *.o
g++ -c -Wall -std=c++11 [Link]
g++ -c -Wall -std=c++11 [Link]
g++ -o bienvenue bienvenue.o fonction-bienvenue.o
$ ./bienvenue
Bienvenue le monde !
104
Vérification :
On rebascule la branche principale et on peut voir qu’il y a maintenant une divergence dans
l’historique :
105
$ git log --graph --decorate --oneline --all
* f909007 (modification-fonction) Modification de la fonction afficherBienvenue() qui
affiche le message "Bienvenue le monde !" par défaut
| * 3d4fa0d (HEAD -> main, correctif-readme) Modification [Link]
|/
* ce00d34 (tag: 1.1, origin/main, origin/correctif-readme) Modification
afficherBienvenue en afficherMessage
* c479e51 Renommage [Link]
* 470794d Modification du fichier README
...
Très utile :
$ git status
Sur la branche main
Votre branche est en avance sur 'origin/main' de 1 commit.
(utilisez "git push" pour publier vos commits locaux)
modifié : [Link]
modifié : [Link]
modifié : fonction-bienvenue.h
106
$ cat [Link]
# Bienvenue
<<<<<<< HEAD
Programme C++ qui affiche "Bienvenue le monde !" en utilisant la fonction
`afficherMessage()`.
=======
Programme C++ qui affiche le message "Bienvenue le monde !" en utilisant la fonction
`afficherBienvenue()`.
>>>>>>> modification-fonction
Lorsque Git rencontre un conflit au cours d’une fusion, il l’indique dans les fichiers
concernés avec des délimiteurs (<<<<<<<, ======= et >>>>>>>) qui marquent les deux
côtés du conflit.
Pour résoudre le conflit, il faut choisir une partie ou l’autre ou bien fusionner les deux contenus "à
la main" :
$ vim [Link]
# Bienvenue
Programme C++ qui affiche le message "Bienvenue le monde !" en utilisant la fonction
`afficherBienvenue()`.
107
$ git add [Link]
$ git status
Sur la branche main
Votre branche est en avance sur 'origin/main' de 1 commit.
(utilisez "git push" pour publier vos commits locaux)
Tous les conflits sont réglés mais la fusion n'est pas terminée.
(utilisez "git commit" pour terminer la fusion)
modifié : [Link]
modifié : [Link]
modifié : [Link]
modifié : fonction-bienvenue.h
$ git commit
[main 3cf9129] Merge branch 'modification-fonction' into main
108
Attention, le dépôt distant n’est plus synchronisé :
$ git status
Sur la branche main
Votre branche est en avance sur 'origin/main' de 3 commits.
(utilisez "git push" pour publier vos commits locaux)
$ git push
Décompte des objets: 12, fait.
Delta compression using up to 12 threads.
Compression des objets: 100% (12/12), fait.
Écriture des objets: 100% (12/12), 1.25 KiB | 425.00 KiB/s, fait.
Total 12 (delta 7), reused 0 (delta 0)
remote: Resolving deltas: 100% (7/7), completed with 3 local objects.
To [Link]:tvaira/[Link]
ce00d34..3cf9129 main -> main
109
On peut finir par un nettoyage des branches thématiques qui ne servent plus :
Un workflow git est une méthode, un processus de travail, une recette ou une recommandation sur
la façon d’utiliser git pour accomplir un travail de manière cohérente et productive.
Il n’existe pas de processus standardisé sur la façon d’interagir avec git. Il est important de
110
s’assurer que l’équipe de projet est d’accord sur la façon dont le flux de modifications sera
appliqué. Un workflow git doit donc être défini.
• workflow centralisé
• workflow Gitflow
Le workflow Gitflow définit un modèle de branchement strict conçu autour de la version du projet.
Ce workflow n’ajoute pas de nouveaux concepts ou commandes. Gitflow permet de gérer les bugs
(issues), les nouvelles fonctionnalités (features) et les versions (releases) en attribuant des rôles très
spécifiques à différentes branches et définit comment et quand elles doivent interagir.
◦ La branche master stocke l’historique des versions officielles. Tous les commits de cette
branche sont étiquetés avec un numéro de version (tags).
◦ La branche develop est créée à partir de la branche master. Elle sert de branche d’intégration
pour les fonctionnalités. Cette branche contiendra l’historique complet du projet.
◦ Les branches features-xxxx permettent de travailler sur des nouvelles fonctionnalités. Elles
sont créées directement à partir de la branche develop et une fois le travail fini, fusionnées
vers la branche develop.
◦ Les branches release-xxxx permettent de travailler sur une livraison (généralement des
tâches dédiées à la documentation). On les crée à partir de develop puis on les fusionne dans
master en leur attribuant un numéro de version (tag).
111
◦ Les branches hotfix-xxxx permettent de publier rapidement (hot) une correction (fix) depuis
la branche master. Ces branches seront ensuite fusionnées vers la branche master et develop.
En projet BTS SN, les branches (feature, release et hotfix) seront créées dans Jira à
partir d’un ticket. Les fusions seront réalisées lors d’une revue de code en utilisant
les Pull Requests dans GitHub ou Bitbucket.
112
Correction d’un bug :
113
Installation de Visual Studio Code :
• Download
• Setup
• Getting Started
Liens :
• [Link]
• [Link]
114
Il existe de nombreuses extensions pour faciliter l’utilisation de Git dont Git Extension Pack qui
comprend :
• Git History
• Project Manager
• GitLens
• gitignore
115
Et quelques autres :
• GitHub Repositories
• Git Graph
• Git Blame
• gitflow
En standard :
116
Il existe également de nombreuses autres applications :
• TortoiseGit : logiciel libre pour Windows reprenant les éléments d’interface de TortoiseSVN (un
classique) ;
• …
• SourceTree : un logiciel propriétaire gratuit pour Windows © et macOS © édité par Atlassian ;
117
• GitEye : un client graphique pour Windows ©, macOS © et Linux
$ cd ~/Téléchargements/
$ wget -c [Link]
linux.x86_64.zip
$ mkdir /tmp/GitEye
$ unzip -d /tmp/GitEye ~/Téléchargements/GitEye-2.2.0-linux.x86_64.zip
118
Thierry Vaira - <tvaira@[Link]> - version v0.2 - 23/08/2021 - [Link]
119