Projet

Général

Profil

GitBonnesPratiques » Historique » Version 53

Daniel Dehennin, 07/02/2012 15:24
Correction de listes

1 40 Daniel Dehennin
{{toc}}
2 1 Redmine Admin
3 40 Daniel Dehennin
h1. Les bonnes pratiques c’est quoi ?
4 1 Redmine Admin
5 40 Daniel Dehennin
Ce document n’est pas une référence git, nous n’allons pas réécrire le
6 40 Daniel Dehennin
"progit book":http://progit.org/book/fr, ni les autres références disponibles sur Internet.
7 1 Redmine Admin
8 40 Daniel Dehennin
Nous allons partir du principe qu’un minimum de connaissance de l’outil git est acquis, notamment 
9 42 Daniel Dehennin
le "démarrage rapide":http://progit.org/book/fr/ch1-0.html et les "bases de git":http://progit.org/book/fr/ch2-0.html du livre "progit book":http://progit.org/book/fr.
10 1 Redmine Admin
11 40 Daniel Dehennin
Nous allons essayer de décrire ici une méthodologie de travail basée sur le
12 40 Daniel Dehennin
système de gestion de version décentralisé "git":https://fr.wikipedia.org/wiki/Git avec les objectifs suivants :
13 1 Redmine Admin
14 40 Daniel Dehennin
* Communiquer entre développeur
15 40 Daniel Dehennin
* S’y retrouver dans ses développements, ou comment gérer des ajouts fonctionnels et des corrections de bug en parallèle
16 40 Daniel Dehennin
* Publier des modifications clairement identifiables et analysables, par des humains et des outils de tests automatiques
17 35 Daniel Dehennin
18 41 Daniel Dehennin
Ce document ne représente en rien _LA_ bonne méthode de travail, il s’agit juste d’une façon de faire,
19 41 Daniel Dehennin
appuyée par l’expérience d’autres personnes que l’on trouve un peu partout sur Internet.
20 1 Redmine Admin
21 41 Daniel Dehennin
Il est tout à fait possible de trouver autant, voir plus, de références prônant un point de vue opposé ou orthogonal au mien.
22 14 Klaas TJEBBES
23 35 Daniel Dehennin
24 1 Redmine Admin
h1. De la méthode agile
25 35 Daniel Dehennin
26 35 Daniel Dehennin
Comme il est défini dans le "manifeste agile":https://fr.wikipedia.org/wiki/Manifeste_agile#Les_4_valeurs, la première valeur est
27 1 Redmine Admin
« Les individus et leurs interactions ».
28 35 Daniel Dehennin
29 35 Daniel Dehennin
Afin de travailler correctement en équipe, il faut communiquer, et
30 35 Daniel Dehennin
l’outil de gestion de version "git":https://fr.wikipedia.org/wiki/Git, utilisé à EOLE, peut-être un excellent
31 23 Redmine Admin
outil de communication.
32 23 Redmine Admin
33 35 Daniel Dehennin
34 23 Redmine Admin
h1. De l’écriture des "ChangeLog":https://fr.wikipedia.org/wiki/ChangeLog
35 35 Daniel Dehennin
36 35 Daniel Dehennin
Afin de communiquer avec les autres membres d’une équipe sur le
37 35 Daniel Dehennin
travail que chacun effectue, l’écriture d’un ChangeLog, ou plus
38 35 Daniel Dehennin
précisément d’un « commit message » dans la littérature en anglaise
39 35 Daniel Dehennin
(qui pourrait être traduit par « message de consignation ») se doit
40 1 Redmine Admin
d’être fait correctement(sic).
41 35 Daniel Dehennin
42 23 Redmine Admin
Que penser d’un message comme « "typo":http://dev-eole.ac-dijon.fr/projects/eole-sso/repository/revisions/f2e5c52482c896b84e57333ba61654286b856f02 » ou encore « "correction d'une coquille":http://dev-eole.ac-dijon.fr/projects/cdc/repository/revisions/0dc6d59ca9c5294790ae1ebe0b035d8a3296ed22 » ?
43 35 Daniel Dehennin
44 1 Redmine Admin
Nous pouvons établir une règle simple et souple, par exemple :
45 35 Daniel Dehennin
46 23 Redmine Admin
Un message de commit comprend :
47 35 Daniel Dehennin
48 23 Redmine Admin
* Une première ligne résumant le pourquoi du patch ;
49 35 Daniel Dehennin
* Une description longue optionnelle permettant d’expliciter le
50 1 Redmine Admin
  contexte du résumé donné en première ligne ;
51 34 Bruno Boiget
* Une liste de fichier et leur modification.
52 35 Daniel Dehennin
53 35 Daniel Dehennin
Une ligne vide sépare les différentes parties : la première est
54 23 Redmine Admin
obligatoire et la troisième est optionnelle pour les changements triviaux
55 35 Daniel Dehennin
56 14 Klaas TJEBBES
Par exemple :
57 1 Redmine Admin
58 35 Daniel Dehennin
<pre>
59 1 Redmine Admin
  Le répertoire /usr/share/eole/noyau/ est nécessaire (Fixes: #2405).
60 35 Daniel Dehennin
61 1 Redmine Admin
  * debian/dirs: Création du répertoire.
62 1 Redmine Admin
</pre>
63 1 Redmine Admin
64 35 Daniel Dehennin
<pre>
65 35 Daniel Dehennin
  Simplification de la gestion des noyaux (ref: #2406).
66 35 Daniel Dehennin
  
67 35 Daniel Dehennin
  * creole/fonctionseole.py: Suppression du code effectué par
68 35 Daniel Dehennin
    eole-kernel-version depuis sa version 2.3-eole37~2.
69 1 Redmine Admin
    Renommage de la variable 'boot_ok' en 'need_boot'.
70 1 Redmine Admin
</pre>
71 35 Daniel Dehennin
72 1 Redmine Admin
Cela impose la règle suivante :
73 35 Daniel Dehennin
74 1 Redmine Admin
« Ne jamais utiliser l’option "-m" de la commande "git commit" »
75 1 Redmine Admin
76 35 Daniel Dehennin
77 1 Redmine Admin
h1. De la cohérence de l’histoire du monde
78 35 Daniel Dehennin
79 35 Daniel Dehennin
Un système de gestion de version permet avant tout de conserver un
80 14 Klaas TJEBBES
livre d’histoire d’un projet.
81 35 Daniel Dehennin
82 35 Daniel Dehennin
Dans les premiers systèmes de gestion de version, cette histoire était
83 35 Daniel Dehennin
centralisée. Il fallait avoir le droit d’écrire dans le « livre des
84 35 Daniel Dehennin
comptes et légendes » afin d’y ajouter un morceau, impossible donc de
85 1 Redmine Admin
réécrire l’histoire sans être tout puissant sur le registre.
86 35 Daniel Dehennin
87 35 Daniel Dehennin
Grâce aux systèmes décentralisés comme "git":https://fr.wikipedia.org/wiki/Git, tout le monde peut avoir
88 35 Daniel Dehennin
une copie privée de l’histoire publique d’un projet, pour cela il
89 1 Redmine Admin
suffit de « cloner » l’histoire originale :
90 1 Redmine Admin
91 35 Daniel Dehennin
<pre>
92 14 Klaas TJEBBES
  moi@work:~/src$ git clone git://far-far.away.example.net/bidule.git
93 14 Klaas TJEBBES
</pre>
94 35 Daniel Dehennin
95 35 Daniel Dehennin
À partir de là il est possible de vouloir y ajouter ses propres
96 1 Redmine Admin
morceaux, et cela sans rien demander à personne.
97 35 Daniel Dehennin
98 35 Daniel Dehennin
On modifie le projet et on consigne les nouveaux événements dans
99 35 Daniel Dehennin
notre copie locale de l’histoire du projet :
100 1 Redmine Admin
101 35 Daniel Dehennin
<pre>
102 35 Daniel Dehennin
  moi@work:~/src/bidule(master)$ $EDITOR src/bidule.c # On modifie un fichier du projet
103 35 Daniel Dehennin
  moi@work:~/src/bidule(master)$ git add src/bidule.c # On ajoute un événement à enregistrer dans le livre d’histoire
104 1 Redmine Admin
  moi@work:~/src/bidule(master)$ git commit # On consigne ce nouvel événement
105 1 Redmine Admin
</pre>
106 35 Daniel Dehennin
107 35 Daniel Dehennin
Mais l’histoire, c’est un sujet sensible. On ne badine pas avec
108 1 Redmine Admin
l’histoire et on ne la réécrit sous aucun prétexte.
109 35 Daniel Dehennin
110 35 Daniel Dehennin
Peu importe si la vérité est ailleurs, l’important c’est que tout le
111 1 Redmine Admin
monde soit d’accord sur la même version des faits.
112 35 Daniel Dehennin
113 35 Daniel Dehennin
Si un plaisantin modifie l’histoire et la publie à tout vent, il y
114 17 Gérald Schwartzmann
aura conflit.
115 35 Daniel Dehennin
116 1 Redmine Admin
Nous allons donc édicter la règle suivante :
117 35 Daniel Dehennin
118 16 Gaston TJEBBES
« On ne réécrit pas l’histoire connue »
119 35 Daniel Dehennin
120 35 Daniel Dehennin
Cela sous entend donc que nous pouvons réécrire comme il nous plaît
121 35 Daniel Dehennin
toute l’histoire qui nous est privée, c’est à dire inconnue de tous
122 1 Redmine Admin
les autres.
123 35 Daniel Dehennin
124 1 Redmine Admin
Mais dès qu’un événement est rendu public, ça n'est plus possible.
125 8 Gaston TJEBBES
126 35 Daniel Dehennin
127 8 Gaston TJEBBES
h1. Trop de pull, c’est trop chaud !
128 35 Daniel Dehennin
129 35 Daniel Dehennin
Que se passe-t-il si un jour nous souhaitons apprendre les nouvelles
130 8 Gaston TJEBBES
histoires de par le monde ?
131 35 Daniel Dehennin
132 35 Daniel Dehennin
Que ce passe-t-il si un jour nous souhaitons partager nos petites
133 1 Redmine Admin
histoires avec le reste du monde ?
134 35 Daniel Dehennin
135 35 Daniel Dehennin
La plupart du temps, la réponse donnée à ces questions commence par
136 1 Redmine Admin
quelque chose comme « fais-toi donc un pull ».
137 35 Daniel Dehennin
138 11 Gaston TJEBBES
Cela se traduit, en terme git, par :
139 1 Redmine Admin
140 35 Daniel Dehennin
<pre>
141 1 Redmine Admin
  moi@work:~/src/bidule(master)$ git pull
142 1 Redmine Admin
</pre>
143 35 Daniel Dehennin
144 1 Redmine Admin
Cela est strictement équivalent aux deux commandes suivantes :
145 1 Redmine Admin
146 35 Daniel Dehennin
<pre>
147 35 Daniel Dehennin
  moi@work:~/src/bidule(master)$ git fetch origin
148 1 Redmine Admin
  moi@work:~/src/bidule(master)$ git merge origin/master
149 1 Redmine Admin
</pre>
150 35 Daniel Dehennin
151 35 Daniel Dehennin
Mais il existe quelques soucis avec cette méthode, la première étant
152 29 Joël Cuissinat
« qu’une histoire entre en conflit avec l’une des vôtres ».
153 35 Daniel Dehennin
154 35 Daniel Dehennin
Un autre problème est que cette méthode « mélange » littéralement
155 35 Daniel Dehennin
l’histoire publique avec vos histoires privées, même s’il n’y a pas de
156 35 Daniel Dehennin
conflit, il peut-être difficile de savoir si le résultat aura un sens
157 1 Redmine Admin
ou non.
158 1 Redmine Admin
159 35 Daniel Dehennin
Dans git, chaque commit a une généalogie, le parent du commit que je
160 1 Redmine Admin
m’apprête à faire est le dernier commit enregistré dans le dépôt.
161 35 Daniel Dehennin
162 21 Joël Cuissinat
Lors d’un pull sur un dépôt contenant des modifications, git créé un
163 41 Daniel Dehennin
commit ayant deux parents dont le seul but est de mélanger la généalogie.
164 37 Daniel Dehennin
165 41 Daniel Dehennin
Il est donc préférable d’utiliser la méthode décomposée en deux commandes.
166 37 Daniel Dehennin
167 37 Daniel Dehennin
Cela permet de vérifier au préalable si des changements
168 37 Daniel Dehennin
sont à intégrer, et lesquels, avec les commandes suivantes :
169 37 Daniel Dehennin
170 37 Daniel Dehennin
* ChangeLog des différences
171 38 Daniel Dehennin
<pre>
172 37 Daniel Dehennin
  moi@work:~/src/bidule(master)$ git log master..origin/master
173 37 Daniel Dehennin
</pre>
174 44 Fabrice Barconnière
* Liste des fichiers modifiés
175 38 Daniel Dehennin
<pre>
176 37 Daniel Dehennin
  moi@work:~/src/bidule(master)$ git diff --stat master..origin/master
177 37 Daniel Dehennin
</pre>
178 37 Daniel Dehennin
* Modification du code
179 38 Daniel Dehennin
<pre>
180 37 Daniel Dehennin
  moi@work:~/src/bidule(master)$ git diff master..origin/master
181 21 Joël Cuissinat
</pre>
182 35 Daniel Dehennin
183 21 Joël Cuissinat
Mais cela n’empêche nullement :
184 35 Daniel Dehennin
185 35 Daniel Dehennin
* D’être potentiellement désastreux : chaque « fusion » (merge) et
186 35 Daniel Dehennin
  « consignation » de « fusion » (merge commit) sont à la charge de
187 21 Joël Cuissinat
  chaque développeur ;
188 35 Daniel Dehennin
* Votre histoire devient illisible. Elle intègre tout un tas de
189 21 Joël Cuissinat
  « fusion » inexplicables ;
190 35 Daniel Dehennin
* Retrouver à quel moment précis et quel modification a entraîné un
191 35 Daniel Dehennin
  changement de comportement devient impossible du fait des
192 1 Redmine Admin
  « fusions »
193 1 Redmine Admin
194 1 Redmine Admin
Tout mélanger dans la même branche, qui devient alors un tronc, pose
195 1 Redmine Admin
des soucis quant à la lecture de l’histoire du projet.
196 21 Joël Cuissinat
197 21 Joël Cuissinat
198 35 Daniel Dehennin
199 21 Joël Cuissinat
h1. Pour s’y retrouver, il faut s’accrocher aux branches
200 35 Daniel Dehennin
201 35 Daniel Dehennin
Une branche est une ligne d’histoire divergente d’un projet, leur
202 44 Fabrice Barconnière
utilisation dans git est très simple et légère.
203 35 Daniel Dehennin
204 1 Redmine Admin
La création d’une branche peut se faire de deux façons :
205 35 Daniel Dehennin
206 35 Daniel Dehennin
# Créer une branche que j’utiliserais plus tard :
207 40 Daniel Dehennin
<pre>
208 1 Redmine Admin
  moi@work:~/src/projet(master)$ git branch mabranche
209 40 Daniel Dehennin
  moi@work:~/src/projet(master)$ # on commit dans la branche « master »
210 40 Daniel Dehennin
</pre>
211 40 Daniel Dehennin
# Créer une branche et commencer à travailler dedans :
212 40 Daniel Dehennin
<pre>
213 40 Daniel Dehennin
  moi@work:~/src/projet(master)$ git checkout -b mabranche
214 40 Daniel Dehennin
  moi@work:~/src/projet(mabranche)$ # on commit dans la branche « mabranche »
215 35 Daniel Dehennin
</pre>
216 35 Daniel Dehennin
217 41 Daniel Dehennin
Chacune de ces commandes permet de définir, en dernier argument, le point de départ de la nouvelle branche.
218 35 Daniel Dehennin
219 1 Redmine Admin
Par défaut ce point de départ est le dernier commit de la branche courante.
220 35 Daniel Dehennin
221 1 Redmine Admin
Tout les commit effectués sur cette branche sont localisés à cette branche.
222 1 Redmine Admin
223 35 Daniel Dehennin
Cela permet de se focaliser sur une activité :
224 1 Redmine Admin
225 1 Redmine Admin
* Sans risquer d’impacter la vision que les autres ont de l’histoire ;
226 1 Redmine Admin
* Sans se soucier de ce qui peut arriver sur les autres branches ;
227 1 Redmine Admin
* Sans fusionner les modifications de la branche principale dans la
228 35 Daniel Dehennin
  branche courante.
229 1 Redmine Admin
230 41 Daniel Dehennin
Il faut travailler ensuite à intégrer cette nouvelle histoire à la ligne principale.
231 1 Redmine Admin
232 35 Daniel Dehennin
h2. Les voies du temps sont interpénétrables
233 35 Daniel Dehennin
234 41 Daniel Dehennin
C’est le principe utilisé par le pull, ce qui est nommé dans la littérature le « merge workflow ».
235 36 Daniel Dehennin
236 41 Daniel Dehennin
Ce qui est fait lors d’un @git pull@ entre une branche locale et une branche sur un dépôt distant,
237 41 Daniel Dehennin
« remote » en jargon git, est applicable entre deux branches d’un dépôt local.
238 35 Daniel Dehennin
239 41 Daniel Dehennin
En pratique, on se positionne sur la branche qui doit intégrer les modifications d’une autre,
240 41 Daniel Dehennin
par exemple une branche publique, et on fusionne la branche privée de développement dans cette branche publique :
241 1 Redmine Admin
242 1 Redmine Admin
<pre>
243 36 Daniel Dehennin
  moi@work:~/src/projet(master)$ git merge mabranche
244 1 Redmine Admin
</pre>
245 35 Daniel Dehennin
246 1 Redmine Admin
Pour ensuite publier ces modifications par @git push@.
247 35 Daniel Dehennin
248 35 Daniel Dehennin
Ceci induit les mêmes inconvénients que l’utilisation des pull.
249 35 Daniel Dehennin
250 41 Daniel Dehennin
Lorsque l’on passe du temps à travailler sur une branche privée, 
251 41 Daniel Dehennin
il est tentant de « fusionner » régulièrement une branche publique de référence, afin de se mettre à jour.
252 35 Daniel Dehennin
253 41 Daniel Dehennin
Mais cette pratique ne fait que rendre illisible l’histoire privée de cette branche.
254 35 Daniel Dehennin
255 35 Daniel Dehennin
Cela rend très difficile la relecture de chaque modification apportée
256 35 Daniel Dehennin
par cette branche car son histoire n’est plus simplement une suite
257 1 Redmine Admin
logique d’étapes afin d’arriver à un résultat voulu.
258 35 Daniel Dehennin
259 1 Redmine Admin
h2. On ne construit que sur les épaules de géants
260 35 Daniel Dehennin
261 35 Daniel Dehennin
Il existe une autre approche à la problématique généalogique des
262 1 Redmine Admin
commits, nommé dans la littérature « rebase workflow ».
263 35 Daniel Dehennin
264 35 Daniel Dehennin
Ce principe utilise la réécriture de l’historique, par conséquent,
265 1 Redmine Admin
elle ne peut être utilisée que sur des commits non publiés.
266 35 Daniel Dehennin
267 1 Redmine Admin
Le principe est le même que le greffage en botanique :
268 35 Daniel Dehennin
269 35 Daniel Dehennin
# On coupe la branche ;
270 1 Redmine Admin
# On la greffe sur une autre.
271 35 Daniel Dehennin
272 45 Fabrice Barconnière
En pratique, c’est surtout utilisé pour préparer l’intégration de nos
273 1 Redmine Admin
modifications dans une branche publique.
274 35 Daniel Dehennin
275 1 Redmine Admin
C’est un peu le miroir du « merge workflow ».
276 35 Daniel Dehennin
277 35 Daniel Dehennin
Dans le « merge workflow », la fusion se fait sur la branche publique
278 1 Redmine Admin
et les conflits sont gérés dans l’histoire de la branche publique.
279 35 Daniel Dehennin
280 35 Daniel Dehennin
Dans le « rebase workflow », c’est l’inverse, tout se fait dans la
281 1 Redmine Admin
branche que l’on souhaite intégrer à la branche publique.
282 35 Daniel Dehennin
283 35 Daniel Dehennin
La procédure est décomposée comme suit :
284 35 Daniel Dehennin
285 35 Daniel Dehennin
# Mise de côté de tous les commits de la branche depuis sa création :
286 35 Daniel Dehennin
  on revient dans le tronc de développement (branche privée) à la
287 35 Daniel Dehennin
  version sur laquelle notre branche est basée ;
288 35 Daniel Dehennin
# Intégration de tous les changements de la branche publique survenus
289 35 Daniel Dehennin
  depuis ;
290 35 Daniel Dehennin
# Application de tous les commits mis de côté, il faut gérer les
291 35 Daniel Dehennin
  éventuels conflits.
292 35 Daniel Dehennin
293 35 Daniel Dehennin
Avant la procédure, la branche privée était basée sur la branche
294 45 Fabrice Barconnière
publique à un certain instant dans le passé.
295 35 Daniel Dehennin
296 35 Daniel Dehennin
Après la procédure, la branche privée est basée sur le dernier commit
297 35 Daniel Dehennin
de la branche publique.
298 35 Daniel Dehennin
299 35 Daniel Dehennin
On a donc changé la base de la branche, d’où le nom de cette méthode.
300 35 Daniel Dehennin
301 35 Daniel Dehennin
Tout cela se fait simplement par :
302 1 Redmine Admin
303 35 Daniel Dehennin
<pre>
304 1 Redmine Admin
  moi@work:~/src/projet(mabranche)$ git rebase master
305 1 Redmine Admin
</pre>
306 35 Daniel Dehennin
307 35 Daniel Dehennin
Il est possible de faire fréquemment des rebases des branches privées
308 45 Fabrice Barconnière
par rapport à la branche publique où seront intégrées les
309 1 Redmine Admin
modifications.
310 35 Daniel Dehennin
311 35 Daniel Dehennin
On minimise ainsi les conflits ou, plus précisément, on les dilue dans
312 1 Redmine Admin
le temps.
313 35 Daniel Dehennin
314 35 Daniel Dehennin
Ce principe de rebase est à utiliser, au moins avant l’intégration à
315 35 Daniel Dehennin
la branche publique, afin d'avoir une histoire plus propre de la
316 1 Redmine Admin
branche et ce en fusionnant certains commits.
317 35 Daniel Dehennin
318 45 Fabrice Barconnière
Dans ce cas on ne rebase pas par rapport à une branche publique, mais
319 19 Joël Cuissinat
par rapport à un commit de la branche privée.
320 35 Daniel Dehennin
321 35 Daniel Dehennin
Par exemple, ne pas avoir un commit ajoutant une fonctionnalité et les
322 19 Joël Cuissinat
30 suivants qui corrigent les inévitables erreurs typographiques.
323 19 Joël Cuissinat
324 35 Daniel Dehennin
325 1 Redmine Admin
h1. « Le blabla c’est bien, mais en pratique ? » par moi©®™
326 35 Daniel Dehennin
327 1 Redmine Admin
h2. Puisque je vous dis que les branches ça ne coûte rien !
328 35 Daniel Dehennin
329 36 Daniel Dehennin
Dans git, une branche est simplement un fichier dans l’arborescence du
330 1 Redmine Admin
répertoire @.git/refs/heads/@.
331 35 Daniel Dehennin
332 35 Daniel Dehennin
Ce fichier contient l’identifiant du dernier commit de cette branche,
333 35 Daniel Dehennin
c’est le "SHA1":http://fr.wikipedia.org/wiki/SHA1 du contenu de l’objet (les détails sont accessibles dans
334 1 Redmine Admin
"Les tripes de Git":http://progit.org/book/fr/ch9-0.html).
335 35 Daniel Dehennin
336 36 Daniel Dehennin
L’identifiant de commit référence un fichier dans l’arborescence du
337 1 Redmine Admin
répertoire @.git/objects/@, avec :
338 35 Daniel Dehennin
339 35 Daniel Dehennin
* les deux premiers caractères (1 octet noté en hexadécimal) sont le
340 1 Redmine Admin
  nom d’un sous répertoire ;
341 1 Redmine Admin
* le reste des caractères sont le nom du fichier.
342 35 Daniel Dehennin
343 35 Daniel Dehennin
Connaître l’identifiant du dernier commit est suffisant pour remonter
344 1 Redmine Admin
l’arbre généalogique.
345 35 Daniel Dehennin
346 35 Daniel Dehennin
Faire une nouvelle branche se résume donc à créer un fichier ne
347 1 Redmine Admin
contenant qu’un identifiant.
348 35 Daniel Dehennin
349 1 Redmine Admin
On créé une branche dédiée pour le développement à faire :
350 35 Daniel Dehennin
<pre>
351 1 Redmine Admin
  moi@work:~/src/projet(master)$ git checkout -b issue/42 master
352 1 Redmine Admin
</pre>
353 35 Daniel Dehennin
354 1 Redmine Admin
h2. Le clonage déontologiquement correcte
355 35 Daniel Dehennin
356 35 Daniel Dehennin
Afin de tester nos modifications avant publication, nous pouvons
357 35 Daniel Dehennin
copier les fichiers sur une machine de test, par quelque moyen que ce
358 1 Redmine Admin
soit.
359 35 Daniel Dehennin
360 35 Daniel Dehennin
Un de ces moyens, et le plus simple dans notre cas, est d’utiliser
361 1 Redmine Admin
git.
362 35 Daniel Dehennin
363 1 Redmine Admin
Étant donné que :
364 35 Daniel Dehennin
365 35 Daniel Dehennin
* Nous souhaitons tester les modifications apportées par le
366 1 Redmine Admin
  développement enregistré dans une branche non publiée ;
367 35 Daniel Dehennin
* Nous ne souhaitons pas publier cette branche privée tant que tout ne
368 1 Redmine Admin
  sera pas propre ;
369 35 Daniel Dehennin
370 1 Redmine Admin
Nous allons créer une copie conforme de notre dépôt, sur la machine de test.
371 35 Daniel Dehennin
372 1 Redmine Admin
Le fonctionnement est simple, un dépôt git, qu’il soit sur un serveur
373 1 Redmine Admin
http ou dans notre répertoire, peut servir de base à un clone.
374 35 Daniel Dehennin
375 1 Redmine Admin
Et un clone, ça peut se faire par "SSH":http://fr.wikipedia.org/wiki/SSH.
376 35 Daniel Dehennin
377 2 samuel morin
Nous avons besoin :
378 35 Daniel Dehennin
379 1 Redmine Admin
* D’une machine de test ;
380 53 Daniel Dehennin
* D’un accès "SSH":http://fr.wikipedia.org/wiki/SSH sur cette machine ;
381 53 Daniel Dehennin
* De l’outil git installé sur cette machine.
382 35 Daniel Dehennin
383 35 Daniel Dehennin
Aucun fichier ne sera éditer sur cette machine, cela évite de
384 1 Redmine Admin
s’éparpiller.
385 35 Daniel Dehennin
386 35 Daniel Dehennin
Nous mettrons à jour ce dépôt par des pull, ce qui ne posera aucun
387 35 Daniel Dehennin
soucis comme expliqué plus haut du fait qu’il n’y aura aucune
388 1 Redmine Admin
modification locale à la machine de test.
389 1 Redmine Admin
390 35 Daniel Dehennin
<pre>
391 35 Daniel Dehennin
  moi@work:~/src/projet(master)$ ssh user@test-machine
392 35 Daniel Dehennin
  user@test-machine:~$ git clone ssh://moi@work/home/moi/src/projet && cd projet
393 1 Redmine Admin
  user@test-machine:~/projet(master)$ git checkout -b issue/42 origin/issue/42
394 1 Redmine Admin
  user@test-machine:~/projet(issue/42)$ # On est prêt
395 1 Redmine Admin
</pre>
396 1 Redmine Admin
397 1 Redmine Admin
On garde un shell sur la machine de test, on y reviendra souvent, à
398 1 Redmine Admin
moins d’être très fort et de tout réussir du premier coup.
399 35 Daniel Dehennin
400 1 Redmine Admin
h2. Les commits, c’est radioactif ?
401 1 Redmine Admin
402 1 Redmine Admin
Un commit, c’est un instantané du code à un instant « T ».
403 1 Redmine Admin
404 1 Redmine Admin
Si nous souhaitons tester l’impact de chaque commit sur un projet, il
405 1 Redmine Admin
est préférable que chacun d’eux soit fonctionnel.
406 1 Redmine Admin
407 1 Redmine Admin
Par exemple, si on modifie le nom d’une fonction ou d’une variable, on
408 46 Fabrice Barconnière
doit, dans le même commit, modifier toutes les utilisations de l’ancien
409 35 Daniel Dehennin
nom.
410 1 Redmine Admin
411 35 Daniel Dehennin
Chaque commit se doit d’être le plus « atomique » possible.
412 1 Redmine Admin
413 1 Redmine Admin
h2. Cycle de développement et tests
414 1 Redmine Admin
415 1 Redmine Admin
# On code :
416 1 Redmine Admin
<pre>
417 47 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ ${EDITOR} src/bidule.py
418 35 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git add src/bidule.py
419 35 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git commit
420 35 Daniel Dehennin
</pre>
421 35 Daniel Dehennin
# On nettoie la machine de test :
422 40 Daniel Dehennin
<pre>
423 40 Daniel Dehennin
  user@test-machine:~/projet(issue/42)$ make uninstall
424 40 Daniel Dehennin
</pre>
425 40 Daniel Dehennin
# On met à jour le dépôt de la machine de test :
426 35 Daniel Dehennin
<pre>
427 40 Daniel Dehennin
  user@test-machine:~/projet(issue/42)$ git pull origin
428 40 Daniel Dehennin
</pre>
429 40 Daniel Dehennin
# On met en place la nouvelle version du code à tester :
430 35 Daniel Dehennin
<pre>
431 40 Daniel Dehennin
  user@test-machine:~/projet(issue/42)$ make install
432 40 Daniel Dehennin
</pre>
433 48 Daniel Dehennin
# On test, si des problèmes persistent, on boucle sur 1 et on peut même utiliser un [[GitTrucsEtAstuces#Tu-balises-quand-tu-commit|petit truc]] pour s’y retrouver dans toutes ces itérations.
434 35 Daniel Dehennin
435 40 Daniel Dehennin
h2. Publication du développement
436 40 Daniel Dehennin
437 41 Daniel Dehennin
# On détermine le nombre de modification de notre branche par rapport à la branche « master »:
438 35 Daniel Dehennin
<pre>
439 41 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git log --oneline master..HEAD | wc -l
440 41 Daniel Dehennin
5
441 41 Daniel Dehennin
</pre>
442 41 Daniel Dehennin
# On nettoie notre histoire privée, dans notre exemple, à partir du 5e commit avant la fin:
443 41 Daniel Dehennin
<pre>
444 41 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git rebase -i HEAD~5
445 40 Daniel Dehennin
</pre>
446 35 Daniel Dehennin
# On rebase sur la dernière version de la branche publique :
447 40 Daniel Dehennin
<pre>
448 40 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git fetch origin
449 40 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git rebase origin/master
450 40 Daniel Dehennin
</pre>
451 35 Daniel Dehennin
# On intègre à la branche publique :
452 40 Daniel Dehennin
<pre>
453 40 Daniel Dehennin
  moi@work:~/src/projet(issue/42)$ git checkout master
454 40 Daniel Dehennin
  moi@work:~/src/projet(master)$ git merge issue/42
455 40 Daniel Dehennin
</pre>
456 49 Daniel Dehennin
# On tag un numéro de version, dans cet exemple, nous utilisons un "timestamp":http://fr.wikipedia.org/wiki/Timestamp :
457 40 Daniel Dehennin
<pre>
458 40 Daniel Dehennin
  moi@work:~/src/projet(master)$ git tag -s -m "release/$(date +%Y%m%d.%H%M)" release/$(date +%Y%m%d.%H%M)
459 40 Daniel Dehennin
</pre>
460 35 Daniel Dehennin
# On publie :
461 40 Daniel Dehennin
<pre>
462 40 Daniel Dehennin
  moi@work:~/src/projet(master)$ git push origin
463 40 Daniel Dehennin
</pre>
464 35 Daniel Dehennin
465 35 Daniel Dehennin
466 1 Redmine Admin
h1. Webographie
467 35 Daniel Dehennin
468 52 Daniel Dehennin
* *L'ancienne page GitBonnesPratiques est ici http://dev-eole.ac-dijon.fr/projects/eole/wiki/RecueilGit*
469 50 Daniel Dehennin
* "Afficher le status de git dans la ligne de commande BASH":http://volnitsky.com/project/git-prompt/
470 50 Daniel Dehennin
* "Le prompt Bash qui change la vie avec Git":http://www.git-attitude.fr/2010/07/14/le-prompt-bash-qui-change-la-vie-avec-git/
471 43 Daniel Dehennin
* "Avoiding Git Disasters: A Gory Story":http://www.randyfay.com/node/89
472 35 Daniel Dehennin
* "A rebase workflow":http://www.randyfay.com/node/91
473 35 Daniel Dehennin
* "Simpler Rebasing (avoiding unintentional merge commits)":http://randyfay.com/node/103
474 35 Daniel Dehennin
* "A git workflow for agile teams":http://reinh.com/blog/2009/03/02/a-git-workflow-for-agile-teams.html
475 35 Daniel Dehennin
* "The case for git rebase":http://darwinweb.net/articles/the-case-for-git-rebase
476 35 Daniel Dehennin
* "Pro git book":http://progit.org/book/ch5-3.html
477 35 Daniel Dehennin
* "Maintaining a project":http://progit.org/book/ch5-3.html
478 35 Daniel Dehennin
* "Packaging software using Git":http://www.golden-gryphon.com/software/misc/packaging.html
479 1 Redmine Admin
* "Packaging with git":http://wiki.debian.org/PackagingWithGit/