tp2-historique.tex 8.03 KB
Newer Older
1
2
\documentclass[a4paper,10pt]{article}

3
\usepackage{header}
4
5
6

\date{2017}
\author{Sylvain Bouveret, Grégory Mounié}
7
\title{Git -- Gestion de l'historique}
8
9
10
11
12
13

\sloppy

\begin{document}
\maketitle

14
15
Ce document peut être téléchargé depuis l'adresse suivante :
\begin{center}
16
  \url{\gitlabpages/\jobname.pdf}
17
\end{center}
18
19
20

\section{Introduction}

21
La clarté de l'historique est un préalable à la production de logiciel
22
de qualité. Dans cette session nous allons~:
23
\begin{itemize}
24
25
26
\item nettoyer d'abord un petit historique~;
\item rechercher un commit par bissection dans un historique de grande
  taille.
27
28
\end{itemize}

29
Pour cette session, les différents exercices peuvent être réalisés
30
31
32
33
seuls.

\section{Nettoyage d'un historique}

34
35
36
37
38
39
40
41
42
Le nettoyage de l'historique change les commits. Cela signifie
qu'\textbf{il faut réaliser ce nettoyage avant de publier les commits}
et qu'ils ne soient récupérés dans un autre dépot. En effet, sinon les deux
historiques seront incohérents et git ne pourra plus gérer les opérations
de fusion.

Dans ce TP, nous nettoyerons l'historique d'un dépot déjà publié, ce
qui ne faut jamais faire en pratique.

43
44
45
\subsection{Mise en place}

Cloner le dépot suivant contenant un historique perfectible:
46
47
48
\begin{minted}{console}
$ git clone git@gitlab.ensimag.fr:git/dumb-project.git
\end{minted}
49

50
Observer l'historique, par exemple avec~:
51
52
53
\begin{minted}{console}
$ git log --graph -c --pretty=full
\end{minted}
54
55
56

\subsection{Reconstruire l'historique}

57
58
59
Vous pouvez observer dans cet historique un certain nombre de
problèmes~: coquilles dans les messages de commit, commits qui sont
visiblement mal séparés ou redondants, etc.
60

61
Tout ce que vous avez à faire est d'utiliser la commande
62
\mintinline{bash}{git rebase -i} pour reconstruire l'historique à votre
63
64
65
convenance. Procédez par petits pas plutôt que de tout faire d'un
coup. Git vous permet de faire plusieurs reconstructions d'historique
à la suite. Pour remonter au commit d'origine, vous pouvez utiliser~:
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
\begin{minted}{console}
$ git rebase -i --root
\end{minted}

Cela affichera votre éditeur préféré, celui configuré par défaut, avec le contenu suivant:
\begin{minted}{ini}
pick 27f44e5 Initial revision
pick 8900bfb Add diff, test it, and test add better.
pick 2612865 Rename diff to sub
pick 48a2fa4 Rename diff to sub in tests too
pick df7eae8 add fnuctino f

# Rebasage de df7eae8 sur f223221 (5 commandes)
#
# Commandes :
#  p, pick <commit> = utiliser le commit
#  r, reword <commit> = utiliser le commit, mais reformuler son message
#  e, edit <commit> = utiliser le commit, mais s'arrêter pour le modifier
#  s, squash <commit> = utiliser le commit, mais le fusionner avec le précédent
#  f, fixup <commit> = comme "squash", mais en éliminant son message
#  x, exec <commit> = lancer la commande (reste de la ligne) dans un shell
#  b, break = s'arrêter ici (on peut continuer ensuite avec 'git rebase --continue')
#  d, drop <commit> = supprimer le commit
#  l, label <label> = étiqueter la HEAD courante avec un nom
#  t, reset <label> = réinitialiser HEAD à label
#  m, merge [-C <commit> | -c <commit>] <label> [# <uniligne>]
#          créer un commit de fusion utilisant le message de fusion original
#          (ou l'uniligne, si aucun commit de fusion n'a été spécifié).
#          Utilisez -c <commit> pour reformuler le message de validation.
#
# Vous pouvez réordonner ces lignes ; elles sont exécutées de haut en bas.
#
# Si vous éliminez une ligne ici, LE COMMIT CORRESPONDANT SERA PERDU.
#
# Cependant, si vous effacez tout, le rebasage sera annulé.
#
\end{minted}
Sinon, à la place de l'option \mintinline{bash}{--root}, vous pouvez
104
également utiliser un numéro de commit particulier.
105

106
107
108
109
110
111
112
113
Nous vous proposons de faire les modifications suivantes:
\begin{enumerate}
\item découper le deuxième commit en deux ou trois morceaux
\item fusionner le troisième et quatrième commit avec l'option de
  votre choix
\item reformuler le message du dernier commit
\end{enumerate}

Grégory Mounié's avatar
Grégory Mounié committed
114
115
116
117
Pour séparer un commit en plusieurs morceaux, le plus simple est
d'arrêter le rebase sur le commit à séparer pour une édition (edit),
de le défaire (avec reset), puis d'enregistrer les nouveaux commits
avant de continuer.
118
119
120
121
122
123
124
125
126
127
128
\begin{minted}{console}
$ git rebase -i --root
# mettre le commit à séparer à "edit"
# et demander aussi les autres modifications
$ git reset HEAD^
$ git add ...
$ git commit ...
$ git add ...
$ git commit ...
$ git rebase --continue
\end{minted}
Grégory Mounié's avatar
Grégory Mounié committed
129

130
\section{Recherche par bissection}
131

132
133
134
Afin d'illustrer le principe de la recherche par bissection, nous
allons récupérer un dépôt de grande taille~: celui de Git
lui-même. Récupérez le dépôt du projet en le clonant~:
135
136
137
\begin{minted}{console}
$ git clone https://github.com/git/git.git
\end{minted}
138

139
L'une des fonctionnalités qui a été ajoutée à Git est la possibilité
140
141
142
de synchroniser un dépôt avec Mediawiki. Mais quand donc cette
fonctionnalité a-t-elle été introduite ? Nous allons faire une
recherche dans l'historique.
143

144
145
146
Tout d'abord, vérifiez que cette fonctionnalité est bien présente dans
la version actuelle du projet. Le plus simple pour cela est de tester
l'existence du répertoire \lstinline{contrib/mw-to-git}.
Grégory Mounié's avatar
Grégory Mounié committed
147
\begin{minted}{sh}
148
[ -d contrib/mw-to-git ] && echo "Le répertoire existe" || echo "Le répertoire n'existe pas"
Grégory Mounié's avatar
Grégory Mounié committed
149
\end{minted}
150
151

Nous allons débuter la recherche par bissection~:
Grégory Mounié's avatar
Grégory Mounié committed
152
153
154
\begin{minted}{console}
$ git bisect start
\end{minted}
155
156
157
158
159
160
161
162
163

Git bissect est un outil plutôt utilisé pour remonter à l'origine de
problèmes dans les programmes (plutôt que pour savoir quand telle ou
telle fonctionnalité a été introduite). Le raisonnement à adopter est
donc le suivant~: la fonctionnalité Mediawiki est nocive
(\textit{bad})~; nous cherchons à remonter au premier commit dans
lequel cette fonctionnalité nocive est apparue.

Nous partons de la tête de la branche master. Comme nous avons pu le
Grégory Mounié's avatar
Grégory Mounié committed
164
vérifier préalablement, le répertoire \mintinline{bash}{contrib/mw-to-git}
165
166
167
168
existe bien dans l'état actuel. C'est donc qu'il faut remonter dans
l'historique pour trouver le premier commit dans lequel ce répertoire
a été versionné. Pour cela, nous disons à git que ce commit est
mauvais~:
Grégory Mounié's avatar
Grégory Mounié committed
169
170
171
\begin{minted}{console}
$ git bisect bad
\end{minted}
172

173
174
175
176
Ensuite, il faut remonter (manuellement pour cette fois-ci) à un
commit antérieur. Remontons à la version 1.0.0 de git, et testons si
la fonctionnalité est déjà présente ou non. Normalement, elle ne
devrait pas l'être, donc nous marquons ce commit comme \texttt{good}~:
Grégory Mounié's avatar
Grégory Mounié committed
177
178
179
180
181
182
\begin{minted}{console}
$ git checkout v1.0.0
$ [ -d contrib/mw-to-git ] && echo "Le répertoire existe" || echo "Le répertoire n'existe pas"
Le répertoire existe
$ git bisect good
\end{minted}
183
184
185
186
187
188
189
190
191
192
193
194

La suite est semi-automatique. Après avoir réfléchi un petit moment,
git va vous proposer un commit intermédiaire. À vous de déterminer si
le répertoire est présent ou pas. S'il est présent, il faut marquer ce
commit comme \texttt{bad}. Sinon, il faut le marquer comme
\texttt{good}.

Après quelques itérations, vous devriez tomber sur le commit ayant
permis l'apparition de cette fonctionnalité. Qui en est responsable~?
Est-ce un bon exemple de message de commit~?

Terminez l'exercice en revenant à la position initiale~:
Grégory Mounié's avatar
Grégory Mounié committed
195
196
197
\begin{minted}{console}
$ git bisect reset
\end{minted}
198
199

\section{Pour conclure\dots{}}
200

201
202
203
204
205
206
207
208
209
210
211
Vous avez appris dans ce TP à maîtriser l'historique de vos
dépôts. Vous avez vu comment on peut utiliser la bissection pour
rechercher à quel moment une fonctionnalité a été introduite. Vous
avez également vu comment réécrire l'histoire (\emph{sur un dépôt
  local uniquement}) en utilisant \texttt{rebase}. Attention, en
rebasant, vous modifiez l'historique de votre dépôt, donc vous pouvez
potentiellement perdre des informations sur les états
intermédiaires\footnote{En fait, en général rien n'est vraiment perdu
  dans git, tout peut être retrouvé lorsque l'on connaît les bons
  numéros de commits ou alors les noms des références permettant de
  s'y retrouver. Mais ça peut être plus compliqué...}.
212
213
214
215
216
217
218
219
220


\end{document}


%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End: