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