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