Mercurial > evolve
comparison docs/tutorial/slides.md @ 3376:aad37ffd7d58
doc: import the training support
Import the training support which was stored in a private-repository before.
author | Boris Feld <boris.feld@octobus.net> |
---|---|
date | Mon, 08 Jan 2018 11:46:53 +0100 |
parents | |
children | 8406d9b06130 |
comparison
equal
deleted
inserted
replaced
3375:1cb549cd6236 | 3376:aad37ffd7d58 |
---|---|
1 --- | |
2 title: Changeset Evolution training | |
3 author: | | |
4 <span style="text-transform: none;"><small>Boris Feld<br/><a href="https://octobus.net">octobus.net</a></small></span> | |
5 --- | |
6 | |
7 # Introduction | |
8 | |
9 ## Welcome | |
10 | |
11 Hello everyone, and welcome to this Changeset Evolution training. During this session, you will learn how to safely rewrite history with Mercurial and Evolve, and how to collaborate together with your colleagues while rewriting the history at the same time. | |
12 | |
13 This training is designed to last approximately ¾ hours. | |
14 | |
15 You will use this repository during the training: [https://bitbucket.org/octobus/evolve_training_repo](https://bitbucket.org/octobus/evolve_training_repo). Please clone it somewhere relevant. | |
16 | |
17 ```bash | |
18 $ hg clone https://bitbucket.org/octobus/evolve_training_repo | |
19 $ cd evolve_training_repo | |
20 ``` | |
21 | |
22 Copy the provided hgrc to ensure a smooth training experience: | |
23 | |
24 ```bash | |
25 $ cp hgrc .hg/hgrc | |
26 ``` | |
27 | |
28 This training support will contains commands you are expected to type and launch. These commands will be in the following format: | |
29 | |
30 ``` | |
31 $ COMMAND YOU ARE EXPECTED TO TYPE | |
32 output you are expecting to see | |
33 ``` | |
34 | |
35 ## Preliminary checks | |
36 | |
37 #### Mercurial version | |
38 | |
39 First let's use the following command to verify which version of Mercurial you are using: | |
40 | |
41 ``` | |
42 $ hg --version | |
43 Mercurial Distributed SCM (version 4.4.2) | |
44 (see https://mercurial-scm.org for more information) | |
45 | |
46 Copyright (C) 2005-2017 Matt Mackall and others | |
47 This is free software; see the source for copying conditions. There is NO | |
48 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
49 ``` | |
50 | |
51 You need at least Mercurial version `4.1`. If you don't have a recent enough version, please call your instructor. | |
52 | |
53 In order to activate the Evolve extension, add these lines in your user configuration (using the command `hg config --edit`): | |
54 | |
55 ```ini | |
56 [extensions] | |
57 evolve = | |
58 topic = | |
59 ``` | |
60 | |
61 #### Mercurial extensions | |
62 | |
63 Now let's check the version of your extensions. You will need all of these for the training: | |
64 | |
65 ``` | |
66 $ hg --version --verbose | |
67 [...] | |
68 evolve external 7.1.0 | |
69 topic external 0.6.0 | |
70 rebase internal | |
71 histedit internal | |
72 ``` | |
73 | |
74 # The Basics | |
75 | |
76 <!-- #### What is Changeset Evolution? | |
77 | |
78 With core Mercurial, changesets are permanent and history rewriting has been discouraged for a long time. You can | |
79 commit new changesets to modify your source code, but you cannot | |
80 modify or remove old changesets. | |
81 | |
82 For years, Mercurial has included various commands that allow | |
83 history modification: ``rebase``, ``histedit``, ``commit --amend`` and so forth. | |
84 However, there's a catch: until now, Mercurial's various mechanisms for | |
85 modifying history have been *unsafe* and expensive, in that changesets were | |
86 destroyed (“stripped”) rather than simply hidden and still easy to recover. | |
87 | |
88 Changeset Evolution makes things better by changing the behaviour of most existing | |
89 history modification commands so they use a safer mechanism (*changeset | |
90 obsolescence*, covered below) rather than the older, less safe *strip* | |
91 operation. | |
92 | |
93 ``evolve`` is built on infrastructure in core Mercurial: | |
94 | |
95 * *Phases* (starting in Mercurial 2.1) allow you to distinguish | |
96 mutable and immutable changesets. | |
97 | |
98 * *Changeset obsolescence* (starting in Mercurial 2.3) is how | |
99 Mercurial knows how history has been modified, specifically when | |
100 one changeset replaces another. In the obsolescence model, a | |
101 changeset is neither removed nor modified, but is instead marked | |
102 *obsolete* and typically replaced by a *successor*. Obsolete | |
103 changesets usually become *hidden* as well. Obsolescence is a | |
104 disabled feature in Mercurial until you start using ``evolve``. | |
105 | |
106 XXX More than just than obsolescence in core ? XXX | |
107 | |
108 XXX The part below is a bit overselling XXX | |
109 | |
110 Some of the things you can do with ``evolve`` are: | |
111 | |
112 * Fix a mistake immediately: “Oops! I just committed a changeset | |
113 with a syntax error—I'll fix that and amend the changeset so no | |
114 one sees my mistake.” (While this is possible using default | |
115 features of core Mercurial, Changeset Evolution makes it safer.) | |
116 | |
117 * Fix a mistake a little bit later: “Oops! I broke the tests three | |
118 commits back, but only noticed it now—I'll just update back to the | |
119 bad changeset, fix my mistake, amend the changeset, and evolve | |
120 history to update the affected changesets.” | |
121 | |
122 * Remove unwanted changes: “I hacked in some debug output two | |
123 commits back; everything is working now, so I'll just prune that | |
124 unwanted changeset and evolve history before pushing.” | |
125 | |
126 * Share mutable history with yourself: say you do most of your | |
127 programming work locally, but need to test on a big remote server | |
128 somewhere before you know everything is good. You can use | |
129 ``evolve`` to share mutable history between two computers, pushing | |
130 finely polished changesets to a public repository only after | |
131 testing on the test server. | |
132 | |
133 * Share mutable history for code review: you don't want to publish | |
134 unreviewed changesets, but you can't block every commit waiting | |
135 for code review. The solution is to share mutable history with | |
136 your reviewer, amending each changeset until it passes review. | |
137 | |
138 * Explore and audit the rewrite history of a changeset. Since Mercurial is | |
139 tracking the edits you make to a changeset, you can look at the history of | |
140 these edits. This is similar to Mercurial tracking the history of file | |
141 edits, but at the changeset level. --> | |
142 | |
143 In this section, we are going to learn how to do basic history rewriting like rewriting a changeset or rebasing. | |
144 | |
145 ### Amend | |
146 | |
147 The smallest possible history rewriting is rewriting a changeset description message. We often save and close the editor too early, and/or haven't seen a typo. | |
148 | |
149 It is very easy to fix a changeset description message, so let's do that. First be sure that you are in your clone of the `evolve_training_repo`. then update to the `typo` branch: | |
150 | |
151 ``` | |
152 $ hg update typo | |
153 ``` | |
154 | |
155 Check what the current repository looks like: | |
156 | |
157 ~~~raw-file | |
158 output/fix-a-bug-base.log | |
159 ~~~ | |
160 | |
161 ~~~graphviz-file | |
162 graphs/fix-bug-1.dot | |
163 ~~~ | |
164 | |
165 We have a root commit and another based on it. Double-check that you are on the right changeset with the `hg summary` command: | |
166 | |
167 ~~~raw-file | |
168 output/fix-a-bug-base-summary.log | |
169 ~~~ | |
170 | |
171 The current commit description message seems wrong, `Fx bug`, there is definitely a letter missing. Let's fix this typo with the `hg commit` command. | |
172 | |
173 Usually, the `hg commit` is used to create new commit but we can use the ``--amend`` option to instead modify the current commit (see `hg help commit` for more information): | |
174 | |
175 ~~~ | |
176 $ hg commit --amend --message "Fix bug" | |
177 ~~~ | |
178 | |
179 Let's take a look at the repository now: | |
180 | |
181 ~~~raw-file | |
182 output/amend-after.log | |
183 ~~~ | |
184 | |
185 ~~~graphviz-file | |
186 graphs/fix-bug-2.dot | |
187 ~~~ | |
188 | |
189 The logs before and after amending looks pretty similar, we are going to analyze the differences later. Did you catch the differences? | |
190 | |
191 ### Rebase | |
192 | |
193 <!-- XXX probably needs a sentence about the merge (Why do you want to avoid it) XXX --> | |
194 | |
195 Let's try to rebase something now. Let's say that you have a branch named `build/linuxsupport-v2` which was started on another branch named `build/v2`. Everything was fine until `build/v2` grew a new commit, and now you want to rebase `build/linuxsupport-v2` on top of `build/v2` to be up-to-date with other the changes: | |
196 | |
197 ``` | |
198 $ hg update build/linuxsupport-v2 | |
199 ``` | |
200 | |
201 ~~~raw-file | |
202 output/rebase-before.log | |
203 ~~~ | |
204 | |
205 ~~~graphviz-file | |
206 graphs/rebase-before.dot | |
207 ~~~ | |
208 | |
209 <!-- XXX-REVIEW: Explain rebase CLI interface --> | |
210 | |
211 Let's rebase our branch on top of `build/v2` with the `hg rebase` command. The `hg rebase` command have many ways to select commits: | |
212 | |
213 1. Explicitly select them using "--rev". | |
214 2. Use "--source" to select a root commit and include all of its descendants. | |
215 3. Use "--base" to select a commit; rebase will find ancestors and their descendants which are not also ancestors of the destination. | |
216 4. If you do not specify any of "--rev", "source", or "--base", rebase will use "--base ." as above. | |
217 | |
218 For this first example, we are gonna stays simple and explicitly select the commits we want to rebase with the `--rev` option. | |
219 | |
220 The `hg rebase` command also accepts a destination with the ``--dest`` option. And finally, as we are using named branches, don't forget to use the `--keepbranches` or the rebased commits will be on the wrong branch: | |
221 | |
222 ~~~raw-file | |
223 output/rebase.log | |
224 ~~~ | |
225 | |
226 Now we have a nice, clean and flat history: | |
227 | |
228 ~~~raw-file | |
229 output/rebase-after.log | |
230 ~~~ | |
231 | |
232 ~~~graphviz-file | |
233 graphs/rebase-after.dot | |
234 ~~~ | |
235 | |
236 For more details about how to use the `hg rebase` command, see `hg help rebase`. | |
237 | |
238 ### Under the hood | |
239 | |
240 What did happened when we just ran the `hg amend` and `hg rebase` commands? What was done exactly to make the whole process work seamlessly? | |
241 | |
242 Let's go back to our previous amend example. | |
243 | |
244 ##### Amend | |
245 | |
246 When we did our amend, the status of the repository was: | |
247 | |
248 ~~~raw-file | |
249 output/behind-the-hood-amend-before-hash-hidden.log | |
250 ~~~ | |
251 | |
252 ~~~graphviz-file | |
253 graphs/fix-bug-1.dot | |
254 ~~~ | |
255 | |
256 And after the amend, the repository looked like: | |
257 | |
258 ~~~raw-file | |
259 output/behind-the-hood-amend-after.log | |
260 ~~~ | |
261 | |
262 ~~~graphviz-file | |
263 graphs/fix-bug-2.dot | |
264 ~~~ | |
265 | |
266 Do you see what is the difference? | |
267 | |
268 The big difference, apart from the fixed changeset message, is the revision hash and revision number. The `Fix bug` revision changed from `d2eb2ac6a5bd` to `708369dc1bfe`. It means that the fixed changeset is a new one. But where did the old changeset go? | |
269 | |
270 It didn't actually go very far, as it just became **hidden**. When we rewrite a changeset with the Evolve extension, instead of blindly delete it, we create a new changeset and hide the old one, which is still there, and we can even see it with the `--hidden` option available on most Mercurial commands: | |
271 | |
272 ~~~raw-file | |
273 output/under-the-hood-amend-after-log-hidden.log | |
274 ~~~ | |
275 | |
276 Notice the `x` in the log output which shows that a changeset is hidden. | |
277 | |
278 In addition to hiding the original changeset, we are also storing additional information which is recording the relation between a changeset, the **precursor** and its **successor**. It basically stores the information that the commit **X** was rewritten into the commit **Y** by the user **U** at the date **D**. This piece of information is stored in something called an **obsolescence marker**. It will be displayed like this: | |
279 | |
280 ~~~graphviz-file | |
281 graphs/fix-bug-3.dot | |
282 ~~~ | |
283 | |
284 Here the commit **5d48a444aba7** was rewritten into **708369dc1bfe**. Also please notice the difference of style of the commit **5d48a444aba7**, that's because it have been rewritten. | |
285 | |
286 ##### Rebase | |
287 | |
288 **Successors** don't need to share anything with their **precursor**. They could have a different description message, user, date or even parents. | |
289 | |
290 Let's look at our earlier rebase example. The status before the rebase was: | |
291 | |
292 ~~~raw-file | |
293 output/behind-the-hood-rebase-before-hash-hidden.log | |
294 ~~~ | |
295 | |
296 ~~~graphviz-file | |
297 graphs/rebase-before.dot | |
298 ~~~ | |
299 | |
300 And after it was: | |
301 | |
302 ~~~raw-file | |
303 output/behind-the-hood-rebase-after.log | |
304 ~~~ | |
305 | |
306 ~~~graphviz-file | |
307 graphs/rebase-after.dot | |
308 ~~~ | |
309 | |
310 Did the same thing happen under the hood? | |
311 | |
312 Yes, exactly! The old changesets are still around, and they are just hidden. | |
313 | |
314 ~~~raw-file | |
315 output/rebase-after-hidden.log | |
316 ~~~ | |
317 | |
318 And we created three **obsolescence markers**, between each rebased commit and its **successor**: | |
319 | |
320 ~~~graphviz-file | |
321 graphs/rebase-after-hidden.dot | |
322 ~~~ | |
323 | |
324 ### Evolution History | |
325 | |
326 Mercurial is designed to track the history of files. Evolution goes beyond, and tracks the history of the history of files. It basically tracks the different versions of your commits. | |
327 | |
328 As it is a new dimension of history, the classical Mercurial commands are not always the best to visualize this new history. | |
329 | |
330 We have seen that we can see the **hidden** changesets with the `--hidden` option on `hg log`: | |
331 | |
332 ~~~raw-file | |
333 output/under-the-hood-amend-after-log-hidden.log | |
334 ~~~ | |
335 | |
336 To visualize the **obsolescence history** of a particular changeset, we can use the dedicated command `hg obslog`. The option are quite similar to `hg log` (you can read `hg help obslog` for more information): | |
337 | |
338 ~~~raw-file | |
339 output/under-the-hood-amend-after-obslog.log | |
340 ~~~ | |
341 | |
342 We can even print what changed between the two versions with the `--patch` option: | |
343 | |
344 ~~~raw-file | |
345 output/under-the-hood-amend-after-obslog-patch.log | |
346 ~~~ | |
347 | |
348 Obslog works both ways, as it can display **precursors** and **successors** with the `--all` option: | |
349 | |
350 ```raw-file | |
351 output/under-the-hood-amend-after-obslog-no-all.log | |
352 ``` | |
353 | |
354 ~~~raw-file | |
355 output/under-the-hood-amend-after-obslog-all.log | |
356 ~~~ | |
357 | |
358 ~~~graphviz-file | |
359 graphs/fix-bug-3.dot | |
360 ~~~ | |
361 | |
362 We can also use obslog on the changesets that we rebased earlier: | |
363 | |
364 ~~~raw-file | |
365 output/under-the-hood-rebase-after-obslog.log | |
366 ~~~ | |
367 | |
368 Why the `hg obslog` command is only showing two commits while we rebased three of them? | |
369 | |
370 ```raw-file | |
371 output/under-the-hood-rebase-after-obslog-branch.log | |
372 ``` | |
373 | |
374 And why the `hg obslog` command show disconnected graphs when asking for the obslog of the whole branch? | |
375 | |
376 ~~~graphviz-file | |
377 graphs/rebase-after-hidden.dot | |
378 ~~~ | |
379 | |
380 While these two obsolescence logs look very similar —because they show a similar change—, the two changesets log histories looked quite different. | |
381 | |
382 Using the `hg log` command to understand the Evolution history is hard because it is designed for displaying the files history, not the Evolution history. The `hg obslog` has been specially designed for this use-case and is more suited for this use-case. | |
383 | |
384 #### TortoiseHG | |
385 | |
386 TortoiseHG should be able to display obsolescence history for your repositories. | |
387 | |
388 To display all the **hidden** commits, we need to click on the **search icon**, then on the **Show/Hide hidden changesets** at the right of the **filter** check box. It is also possible to provide a *revset* to filter the repository, for example `:6 + ::20` to display only the revisions we have been working with until now: | |
389 | |
390 ![](img/thg-obs.png) | |
391 | |
392 <!-- #### Deroulement | |
393 | |
394 Travail chacun de son côté pour apprendre à utiliser: | |
395 | |
396 - Réecriture de changeset | |
397 - Affichage de l'obsolescence, log, obslog | |
398 | |
399 | |
400 - Vérifier que chacun sait utiliser les commandes de base | |
401 - Vérifier que chacun sait utiliser les commandes de visu, hg log, hg log -G, thg? | |
402 => Pas trop longtemps // répartir | |
403 | |
404 - Créer un commit | |
405 - Le amend sans evolve == bundle | |
406 - Strip? | |
407 - rebase sans evolve? | |
408 - Why is it bad? exemple | |
409 (Peut-etre pas leur faire pratiquer amend sans evolve, ca prends du temps) | |
410 | |
411 - With evolve, now | |
412 - Activate it, check version | |
413 - Amend with evolve | |
414 - rebase with evolve | |
415 | |
416 - What happened? | |
417 - View obs-history, hg log, obslog --> | |
418 | |
419 | |
420 # Medium level | |
421 | |
422 ## More rewriting commands | |
423 | |
424 The `hg amend` and `hg rebase` commands are the foundations for changeset evolution in Mercurial. You could do everything with these, but, luckily for us, the evolve extension provides human-friendly commands for common needs. We are going to see them now: | |
425 | |
426 ### Amend | |
427 | |
428 The Evolve extension provides its own `hg amend` command, which is similar to the `hg commit --amend` that we used previously, and adds several nice features: | |
429 | |
430 - The `-e`/`--edit` option edits the commit message in an editor, which is not opened by default any more. | |
431 - The user and date can be updated to the current ones with the `-U`/`--current-user` and `-D`/`--current-date` options. | |
432 - More capabilities for rewriting the changeset. | |
433 | |
434 The `hg amend` command accepts either file paths, to add all the modifications on these files in the current changeset, or the `-i`/`--interactive` option to select precisely what to add in it. | |
435 | |
436 We are going to use it to rewrite the author of the changeset: | |
437 | |
438 ``` | |
439 $ hg update amend-extract | |
440 ``` | |
441 | |
442 We have two commits on the **amend-extract** branch: | |
443 | |
444 ```raw-file | |
445 output/amend-extract-before.log | |
446 ``` | |
447 | |
448 The user for the **amend-extract** head seems wrong, so let's fix it with the `hg amend` command: | |
449 | |
450 ```raw-file | |
451 output/amend-user.log | |
452 ``` | |
453 | |
454 Now let's check that the user has been amended correctly: | |
455 | |
456 ```raw-file | |
457 output/amend-user-after-export.log | |
458 ``` | |
459 | |
460 The user is the good one, but the diff looks weird. It seems that both a bad file **and** an incorrect line have slipped in this commit. We need to fix that. | |
461 | |
462 There are several solutions here, and we could manually edit the file and amend it. But, luckily for us, the `hg amend` command also has a very helpful option named `--extract` that will help us. | |
463 | |
464 ### Amend extract | |
465 | |
466 The `hg amend` command is meant to move file modifications from your working directory to the current changeset (which is considered as the parent of working directory). `hg amend` also provides the option `--extract` that can be used to invert the meaning of the command: with this option, `hg amend` will move the file modifications from your current changeset to your working directory. | |
467 | |
468 This is often used to remove a file or a line that is not meant to be in the current commit. | |
469 | |
470 As usual, we can either pass file paths or use the `-i` option to select which lines to extract. | |
471 | |
472 First, let's extract the badfile: | |
473 | |
474 ```raw-file | |
475 output/amend-extract-badfile.log | |
476 ``` | |
477 | |
478 Now let's check the status of the changeset and the working directory: | |
479 | |
480 ```raw-file | |
481 output/amend-extract-badfile-after-export.log | |
482 ``` | |
483 | |
484 The file is not included in the commit anymore! Did it just vanish? What if you wanted to keep it and, for example, put it in another commit? | |
485 | |
486 Don't worry, the extracted files and lines still are in your working directory: | |
487 | |
488 ```raw-file | |
489 output/amend-extract-badfile-after-status.log | |
490 ``` | |
491 | |
492 As we are not going to need this file anymore, let's forget it with the `hg revert` command: | |
493 | |
494 ```raw-file | |
495 output/amend-extract-badfile-after-revert.log | |
496 ``` | |
497 | |
498 Also don't forget to remove the file: | |
499 | |
500 ```bash | |
501 $ rm badfile | |
502 ``` | |
503 | |
504 Ok. Now we still have a line to extract from our commit, so let's use the handy interactive mode of `hg amend --extract` to extract lines: | |
505 | |
506 ```raw-file | |
507 output/amend-extract.log | |
508 ``` | |
509 | |
510 Much better! One last thing, as the line that we extracted is still in our working directory, just like when we extracted a file: | |
511 | |
512 ```raw-file | |
513 output/amend-extract-after-status.log | |
514 ``` | |
515 | |
516 ```raw-file | |
517 output/amend-extract-after-diff.log | |
518 ``` | |
519 | |
520 Don't forget to revert the change, as we are not going to need it any more: | |
521 | |
522 ```raw-file | |
523 output/amend-extract-after-revert.log | |
524 ``` | |
525 | |
526 Now let's take a look at the obsolescence history: | |
527 | |
528 ```raw-file | |
529 output/amend-extract-after-obslog.log | |
530 ``` | |
531 | |
532 The obslog is read from bottom to top: | |
533 | |
534 - First we rewrite the user, | |
535 - Then we extracted a whole file, | |
536 - Then we extracted a line from a file | |
537 | |
538 We have made three changes that generated three **successors**. | |
539 | |
540 ```graphviz-file | |
541 graphs/amend-extract-after-hidden.dot | |
542 ``` | |
543 | |
544 ### Fold | |
545 | |
546 Sometimes we want to group together several consecutive changesets. Evolve has a command for that: `hg fold`. First, let's update to the right branch: | |
547 | |
548 ``` | |
549 $ hg update fold | |
550 ``` | |
551 | |
552 Three changesets change the same file, and they could be folded together. This would make a cleaner and more linear history, and hide those pesky intermediate changesets: | |
553 | |
554 ```raw-file | |
555 output/fold-before.log | |
556 ``` | |
557 | |
558 ```graphviz-file | |
559 graphs/fold-before.dot | |
560 ``` | |
561 | |
562 We all have been in a similar situation. Let's make a nice and clean changeset with fold: | |
563 | |
564 ```raw-file | |
565 output/fold.log | |
566 ``` | |
567 | |
568 That was easy! | |
569 | |
570 ```raw-file | |
571 output/fold-after.log | |
572 ``` | |
573 | |
574 ```raw-file | |
575 output/fold-after-hidden.log | |
576 ``` | |
577 | |
578 Can you imagine what the graphs will looks like? | |
579 | |
580 ```raw-file | |
581 output/fold-after-hidden-obslog.log | |
582 ``` | |
583 | |
584 ```graphviz-file | |
585 graphs/fold-after-hidden.log | |
586 ``` | |
587 | |
588 ### Split | |
589 | |
590 Sometimes you want to `fold` changesets together, and sometimes you want to `split` a changeset into several ones, because it is too big. | |
591 | |
592 ``` | |
593 $ hg update split | |
594 ``` | |
595 | |
596 Evolve also has a command for that, `hg split`: | |
597 | |
598 ```raw-file | |
599 output/split-before.log | |
600 ``` | |
601 | |
602 ```graphviz-file | |
603 graphs/split-before.dot | |
604 ``` | |
605 | |
606 Split accepts a list of revisions and will interactively ask you how you want to split them: | |
607 | |
608 ```raw-file | |
609 output/split.log | |
610 ``` | |
611 | |
612 Now let's check the state of the repository: | |
613 | |
614 ```raw-file | |
615 output/split-before-after.log | |
616 ``` | |
617 | |
618 ```graphviz-file | |
619 graphs/split-before-after-hidden.dot | |
620 ``` | |
621 | |
622 It looks good. What about the obsolescence history? | |
623 | |
624 ```raw-file | |
625 output/split-after-obslog.log | |
626 ``` | |
627 | |
628 ```raw-file | |
629 output/split-after-obslog-all.log | |
630 ``` | |
631 | |
632 ### Prune | |
633 | |
634 After rewriting and rebasing changesets, the next common use case for history rewriting is removing a changeset. | |
635 | |
636 But we can't permanently remove a changeset without leaving a trace. What if other users are working with the changeset that we want to remove? | |
637 | |
638 The common solution is to mark the changeset as removed, and simulate the fact that it has been removed. | |
639 | |
640 This is why the Evolve extension is offering the `prune` command. Let's try to prune a changeset: | |
641 | |
642 ``` | |
643 $ hg update prune | |
644 ``` | |
645 | |
646 ```raw-file | |
647 output/prune-before.log | |
648 ``` | |
649 | |
650 ```graphviz-file | |
651 graphs/prune-before.dot | |
652 ``` | |
653 | |
654 `prune` is easy to use, just give it the revisions you want to prune: | |
655 | |
656 ```raw-file | |
657 output/prune.log | |
658 ``` | |
659 | |
660 Now the changeset is not visible any more: | |
661 | |
662 ```raw-file | |
663 output/prune-after.log | |
664 ``` | |
665 | |
666 But we can still access it with the `--hidden` option: | |
667 | |
668 ```raw-file | |
669 output/prune-after-hidden.log | |
670 ``` | |
671 | |
672 The output of `obslog` changes a bit when displaying pruned changesets: | |
673 | |
674 ```raw-file | |
675 output/prune-after-obslog.log | |
676 ``` | |
677 | |
678 ```graphviz-file | |
679 graphs/prune-after-hidden.dot | |
680 ``` | |
681 | |
682 ### Histedit | |
683 | |
684 The `hg histedit` command is a power-user command. It allows you to edit a linear series of changesets, and applies a combination of operations on them: | |
685 | |
686 - 'pick' to [re]order a changeset | |
687 - 'drop' to omit changeset | |
688 - 'mess' to reword the changeset commit message | |
689 - 'fold' to combine it with the preceding changeset (using the later date) | |
690 - 'roll' like fold, but discarding this commit's description and date | |
691 - 'edit' to edit this changeset (preserving date) | |
692 - 'base' to checkout changeset and apply further changesets from there | |
693 | |
694 It's similar to the `git rebase -i` command. | |
695 | |
696 First, let's update to the right branch: | |
697 | |
698 ``` | |
699 $ hg update histedit | |
700 ``` | |
701 | |
702 ```raw-file | |
703 output/histedit-before-log.log | |
704 ``` | |
705 | |
706 ```graphviz-file | |
707 graphs/histedit-before.dot | |
708 ``` | |
709 | |
710 When launching the `hg histedit` command, an editor will show up with the following contents: | |
711 | |
712 ```raw-file | |
713 output/histedit-no-edit.log | |
714 ``` | |
715 | |
716 Swap the first two lines with your text editor: | |
717 | |
718 ```raw-file | |
719 output/histedit-commands.log | |
720 ``` | |
721 | |
722 Save and exit. Histedit will apply your instructions and finish. | |
723 | |
724 Let's see the state of the repository: | |
725 | |
726 ```raw-file | |
727 output/histedit-after-log.log | |
728 ``` | |
729 | |
730 ```raw-file | |
731 output/histedit-after-log-hidden.log | |
732 ``` | |
733 | |
734 ```graphviz-file | |
735 graphs/histedit-after-hidden.dot | |
736 ``` | |
737 | |
738 <!-- #### Deroulement | |
739 | |
740 - prune with evolve | |
741 | |
742 - advanced commands | |
743 - fold | |
744 - split --> | |
745 | |
746 ## Stack | |
747 | |
748 ### Stack definition | |
749 | |
750 One big problem when working with a DVCS to identify and switch between the different features/bugfixes you are working on. | |
751 | |
752 ### Named branches | |
753 | |
754 One solution is to use **named branches**. Named branches are a battle-tested, long-supported solution in Mercurial. Basically, a branch name is stored inside each changeset. | |
755 | |
756 This solution has several advantages: | |
757 | |
758 - It's supported in all recent-ish Mercurial versions. | |
759 - It's simple to use. | |
760 - Most tools are supporting it. | |
761 | |
762 But it also has several disadvantages: | |
763 | |
764 - Branches do not disappear once they are merged. You need to explicitely close them with `hg commit --close-branch`. | |
765 - Branches are lost when rebasing them without the `--keepbranches` option of the `hg rebase` command. | |
766 - New branches needs to be explicitly pushed with the `--new-branch` option of the `hg push` command. | |
767 | |
768 We will use named branches for this training, but other solutions are possible, like [topics](https://www.mercurial-scm.org/doc/evolution/tutorials/topic-tutorial.html). | |
769 | |
770 <!-- #### Topics | |
771 --> | |
772 | |
773 ### Stack | |
774 | |
775 The `topic` extension provides a command to show your current stack, no matter how you defined it. Let's try it on some changesets that we rewrote earlier: | |
776 | |
777 ``` | |
778 $ hg update typo | |
779 ``` | |
780 | |
781 ```raw-file | |
782 output/stack-typo.log | |
783 ``` | |
784 | |
785 The stack output shows three important data: | |
786 | |
787 - First, which branch you are working on (a.k.a. the **current** branch). | |
788 - Then, all the commits that you are currently working on, with the current one highlighted. | |
789 - Finally, which commit your branch is based on (**b0**). | |
790 | |
791 This branch is not very interesting, so let's move to another one. | |
792 | |
793 ``` | |
794 $ hg update build/linuxsupport-v2 | |
795 ``` | |
796 | |
797 ```raw-file | |
798 output/stack-rebase.log | |
799 ``` | |
800 | |
801 This is more interesting, as now we can see all the three changesets grouped together in the same view. The stack view provides a nice and linear view, even if the changesets are not immediate neighbors. | |
802 | |
803 ### Stack movement | |
804 | |
805 There is an easy way to navigate in your stack, the `hg next` and `hg prev` commands: | |
806 | |
807 ```raw-file | |
808 output/stack-rebase-prev-from-b3.log | |
809 ``` | |
810 | |
811 ```raw-file | |
812 output/stack-rebase-stack-b2.log | |
813 ``` | |
814 | |
815 And now for the `hg next` command: | |
816 | |
817 ```raw-file | |
818 output/stack-rebase-next-from-b2.log | |
819 ``` | |
820 | |
821 ```raw-file | |
822 output/stack-rebase.log | |
823 ``` | |
824 | |
825 The stack view also displays nice and easy relative ids for these changesets. You can use theses ids in all commands, for example with the `hg export` command: | |
826 | |
827 ```raw-file | |
828 output/stack-rebase-export-b1.log | |
829 ``` | |
830 | |
831 Or with the `hg update` command: | |
832 | |
833 ```raw-file | |
834 output/stack-rebase-update-b2.log | |
835 ``` | |
836 | |
837 These ids are handy because you don't need to manipulate changeset ids or revision numbers: contrary to the latters, the formers won't be affected by history edition. They only depend on their order in the branch. | |
838 | |
839 ```raw-file | |
840 output/stack-rebase-stack-b2.log | |
841 ``` | |
842 | |
843 ### Edit mid-stack | |
844 | |
845 Now that we are in the middle of a stack, let's try amending a commit. The current commit message ends with a dot `.`, and we want to remove it: | |
846 | |
847 ```raw-file | |
848 output/stack-rebase-stack-b2.log | |
849 ``` | |
850 | |
851 ```raw-file | |
852 output/edit-mid-stack.log | |
853 ``` | |
854 | |
855 The message `1 new orphan changesets` means that, by amending a changeset having a child, this child is now **unstable**, as we can see with the `hg stack` command: | |
856 | |
857 ```raw-file | |
858 output/edit-mid-stack-after-stack.log | |
859 ``` | |
860 | |
861 `hg stack` tries to simplify the view for you. We have amended **b2**, and **b3**'s parent is the precursor version of **b2**, so it is not stable any more. It is now **orphan**. | |
862 | |
863 For once, let's use log to see in detail in which situation we are: | |
864 | |
865 ```raw-file | |
866 output/edit-mid-stack-after-log.log | |
867 ``` | |
868 | |
869 ```graphviz-file | |
870 graphs/edit-mid-stack-after.dot | |
871 ``` | |
872 | |
873 How can we resolve this situation? It is actually very easy, and we are going to see how in the next section. | |
874 | |
875 <!-- #### Deroulement | |
876 | |
877 Tout seul: | |
878 | |
879 - Topic? stack? | |
880 | |
881 - Comment définir ce sur quoi on travaille? | |
882 | |
883 - Solution possible: named branches | |
884 - Avantages des branches nommées | |
885 - Inconvénients des branches nommées | |
886 | |
887 - Solution possible: topic | |
888 - Avantages des topic | |
889 - Inconvénients des topic | |
890 - Commands: hg stack, hg topics, hg topics --age, hg topics --verbose | |
891 (Pas forcément topic, risque de confusion) | |
892 | |
893 - Visualiser une stack avec hg stack, hg show stack? | |
894 - Se déplacer dans une stack avec hg prev/hg next | |
895 | |
896 - Editer au milieu d'une stac | |
897 | |
898 - Absorb? (Pas sous windows dur à installer) --> | |
899 | |
900 ## Basic instabilities + stabilization | |
901 | |
902 Instabilities are a normal step when using Evolve-powered workflows. Several tools are provided to fix them smoothly. | |
903 | |
904 #### Log | |
905 | |
906 First, let's clarify some vocabulary. An **obsolete** changeset is a changeset that has been rewritten. In the current stack, only one commit is `obsolete`: | |
907 | |
908 ```raw-file | |
909 output/basic-stabilize-before-log-obsolete.log | |
910 ``` | |
911 | |
912 A changeset can also be **unstable**, meaning that it could be subject to one or more **instabilities**: | |
913 | |
914 * **orphan**, a changeset whose an ancestor is **obsolete**. | |
915 * **content-divergent**, a changeset which has been rewritten in two different versions. | |
916 * **phase-divergent**, a changeset which has been both rewritten and published. | |
917 | |
918 For the moment, we will only see the **orphan** instability. We can display the **instabilities** of a commit with the `{instabilities}` template keyword: | |
919 | |
920 ```raw-file | |
921 output/basic-stabilize-before-log-instabilities.log | |
922 ``` | |
923 | |
924 Here we have also one **orphan** commit, which is the child of the **obsolete** commit. | |
925 | |
926 #### Evolve --list | |
927 | |
928 The `hg evolve` command has a `--list` option which can list all the instabilities of your repository. | |
929 | |
930 ```raw-file | |
931 output/basic-stabilize-before-evolve-list.log | |
932 ``` | |
933 | |
934 #### TortoiseHG | |
935 | |
936 Tortoise HG also has a nice support for displaying the instabilities of your repository: | |
937 | |
938 ![](img/thg-mid-stack.png) | |
939 | |
940 If you want to filter to get a better view, you can use the *revset* `branch(build/linuxsupport-v2)`: | |
941 | |
942 ![](img/thg-mid-stack-filter.png) | |
943 | |
944 #### Stabilization using `hg next --evolve` | |
945 | |
946 ```raw-file | |
947 output/edit-mid-stack-after-stack.log | |
948 ``` | |
949 | |
950 In our current situation, a simple solution to solve the instability is to use the `hg next` command with the `--evolve` option. It will update to the next changeset on the stack, and stabilize it if necessary: | |
951 | |
952 ```raw-file | |
953 output/basic-stabilize-next-evolve.log | |
954 ``` | |
955 | |
956 Here, it just rebased our old version of `b3` on top of the new version of `b2`. | |
957 | |
958 And now `hg stack` shows us a clean view again: | |
959 | |
960 ```raw-file | |
961 output/basic-stabilize-after-stack.log | |
962 ``` | |
963 | |
964 That's better! | |
965 | |
966 ```graphviz-file | |
967 graphs/basic-stabilize-after-stack.dot | |
968 ``` | |
969 | |
970 <!-- #### hg evolve | |
971 | |
972 XXX-REVIEW: Later --> | |
973 | |
974 # Advanced | |
975 | |
976 ## Moving change from one commit to another | |
977 | |
978 Create two commits: | |
979 | |
980 - The first one create a new file, add some content in it. | |
981 - The second one create another file and modify the first file. | |
982 | |
983 Now try to move the change on the first file present in the second commit back in the first commit so that the first commit contains all change on the first file and the second change contains all changes on the second file. | |
984 | |
985 ## Exchange | |
986 | |
987 Coming Soon™ | |
988 | |
989 <!-- ## Exchange --> | |
990 | |
991 <!-- #### Obsolescence History Synchronization | |
992 | |
993 XXX Too theoritical (except first sentence maybe) XXX | |
994 | |
995 While obsolescence markers are already useful locally, they unlock their true power when they are exchanged. They are the piece of information that are fundamental to achieve the goal of synchronizing repositories state. | |
996 | |
997 If two people starts with the same repository and they each make some modifications, once exchanging all their obsolescence marker with their partner; they should have the same repository state. | |
998 | |
999 Given a repository state R, if user A creates obs-markers OBSA and user B creates obs-markers OBSB, `R + OBSA + OBSB = R + OBSB + OBSA`. | |
1000 | |
1001 This characteristic is the foundation to make people confident with their modification as they know that they will be able to synchronize with someone and have exactly the same state. XXX-REVIEW BOF | |
1002 | |
1003 #### When are exchanged obsolescence markers | |
1004 | |
1005 Obsolescence markers are exchanges during all usual exchange methods: | |
1006 | |
1007 - Obsolescence markers related to pushed heads are pushed during `hg push`. | |
1008 - Obsolescence markers related to pulled heads are also pulled during `hg pull`. | |
1009 - Obsolescence markers are included in bundles. | |
1010 | |
1011 New obsolescence markers are automatically applied, so after a `pull` some changesets could become obsolete as they have been rewritten by a new changeset you just pulled. | |
1012 | |
1013 XXX-REVIEW: Add example? | |
1014 | |
1015 The obsolescence markers only apply to draft changesets though. | |
1016 | |
1017 ###### Let's exchange obsmarkers | |
1018 | |
1019 Let's try to push and pull some obsolescence-markers, first copy your repository somewhere else, for example: | |
1020 | |
1021 ```raw-file | |
1022 output/basic-exchange-clone.log | |
1023 ``` | |
1024 | |
1025 #### Phases | |
1026 | |
1027 XXX Too theoritical XXX | |
1028 | |
1029 There is a dimension that have been overlooked until now. **Phases**. What are phases? Phases is an information about a changeset status, a changeset could be in one phase at any time: | |
1030 | |
1031 * **draft**, the default phase a changeset is just after committing it. This phase denotes that the changeset is still a work in progress. It could be rewritten, rebased, splitted, folded or even pruned before it's considered finished. This state allow a changeset to evolve into another version. | |
1032 * **public**, the phase a changeset is when it's considered finished. The changeset would likely have been reviewed, tested and even released when they are in this state. This state forbids any rewriting on changeset which are public. | |
1033 * **secret**, this phase is for changesets that should never be shared. It could be local-only modifications for your environment or a way to commit credentials without sharing it outside. This state allow a changeset to be rewritten, like to be rebased on the most up-to-date head for example. | |
1034 | |
1035 Phase are about changesets but they are not part of the commit information, meaning that changing the phase of a changeset does not change it's changeset hash. | |
1036 | |
1037 These phases are ordered (public < draft < secret) and no changeset can be in | |
1038 a lower phase than its ancestors. For instance, if a changeset is public, all | |
1039 its ancestors are also public. Lastly, changeset phases should only be changed | |
1040 towards the public phase. | |
1041 | |
1042 Changeset are created in the **draft** phase by default and move to the **public** phase in several scenarios. | |
1043 | |
1044 #### Phase movement | |
1045 | |
1046 The original scenario for **phases** is to permits local rewriting of changesets that have not been pushed. You create draft changesets, you test them locally, possibly amend them, rebased them or clean it then you push it to a server and they become **public** at this occasion. | |
1047 | |
1048 While this scenario is pretty sensible, not altering shared commit make a lot of problems disappears, move powerful workflows could be unlocked when decoupling the sharing part with the publishing part. | |
1049 | |
1050 By default, hg server are in **publishing** mode, meaning that: | |
1051 | |
1052 - all draft changesets that are pulled or cloned appear in phase public on the client. | |
1053 | |
1054 - all draft changesets that are pushed appear as public on both client and server. | |
1055 | |
1056 - secret changesets are neither pushed, pulled, or cloned. | |
1057 | |
1058 Hg servers could also be configured into **non-publishing** mode with this configuration: | |
1059 | |
1060 ```ini | |
1061 [phases] | |
1062 publish = False | |
1063 ``` | |
1064 | |
1065 When pushing to a **non-publishing** mode, draft changesets are not longer made **public** anymore, allowing people and teams to share unfinished works. This way, it's still possible to edit a changeset after sharing it, meaning that: | |
1066 | |
1067 - a changeset could be updated after it has been reviewed. | |
1068 - a changeset could be updated after a Continuous Integration tool show that some tests on some platforms are broken. | |
1069 - a changeset could be updated after a co-worker tried implementing another feature on top of it. | |
1070 | |
1071 #### Usual phase workflow | |
1072 | |
1073 While sharing unfinished works is powerful, move **draft** changeset to the **public** phase when pushing them to **publishing** server is powerful by its simplicity. Its easy to understand as **non-publishing** servers could be seen as work-in-progress while **publishing** servers is meant for public, finished work that you commit to never alter. XXX-REVIEW Bof | |
1074 | |
1075 The usual way of having both advantages is to have both a **non-publishing** server where developers push for sharing work and asking for review and another **non-publishing** server when ready changesets are pushed, marking them as **public**. | |
1076 | |
1077 This way the **publishing** repository will only contains **public** changesets while the **non-publishing** one will contains all the **public** changesets plus all the **drafts** changesets. | |
1078 | |
1079 #### Phase visualization | |
1080 | |
1081 Phase is not shown by default in `hg log`, but we can ask for it with the `{phase}` template: | |
1082 | |
1083 ```raw-file | |
1084 output/split-after-log-phase.log | |
1085 ``` | |
1086 | |
1087 It's also possible to use `hg phase` to recover the phase of a revision(s): | |
1088 | |
1089 ```raw-file | |
1090 output/split-after-phase.log | |
1091 ``` | |
1092 | |
1093 You might wondered why you saw different forms in the graphs before, that was the phase that were shown. From now on, public changesets will be shown as circles, drafts changesets will be shown as hexagons and secrets changesets will be shown as squares: | |
1094 | |
1095 ```graphviz-file | |
1096 graphs/phases.dot | |
1097 ``` | |
1098 | |
1099 #### Phase selection | |
1100 | |
1101 Phase have a few revsets for selecting changesets by their phases: | |
1102 | |
1103 - `public()`, select all public changesets. | |
1104 - `draft()`, select all draft changesets. | |
1105 - `secrets()`, select all secret changesets. | |
1106 | |
1107 It could be used to: | |
1108 | |
1109 - select all non-public changesets with `hg log -r "not public()"`. | |
1110 - change all secret changesets to draft with `hg phase --draft "secret()"`. --> | |
1111 | |
1112 <!-- #### Deroulement | |
1113 | |
1114 Toujours tout seul: | |
1115 | |
1116 - push / pull | |
1117 - phases --> | |
1118 | |
1119 <!-- ## Advanced --> | |
1120 | |
1121 <!-- #### Deroulement | |
1122 | |
1123 Advances use-cases: | |
1124 | |
1125 - Move part of a changeset to another (split+fold) --> | |
1126 | |
1127 <!-- ## Let's start the fun --> | |
1128 | |
1129 <!-- #### Deroulement | |
1130 | |
1131 À deux: | |
1132 | |
1133 - troubles, divergence, orphan | |
1134 - troubles visualization | |
1135 - troubles resolution | |
1136 - collaboration workflow | |
1137 | |
1138 Parler du happy path d'abord --> | |
1139 | |
1140 <!-- ## Content to integrate (presentation old content) | |
1141 | |
1142 #### Once upon a time | |
1143 | |
1144 #### You fix a bug | |
1145 | |
1146 (With a small typo) | |
1147 | |
1148 ~~~graphviz-file | |
1149 graphs/fix-bug-1.dot | |
1150 ~~~ | |
1151 | |
1152 #### You write more code | |
1153 | |
1154 <img src="https://media0.giphy.com/media/13GIgrGdslD9oQ/giphy.gif"> | |
1155 | |
1156 #### Urgent merge | |
1157 | |
1158 <img src="https://media.giphy.com/media/OBnwDJW77acLK/giphy.gif"> | |
1159 | |
1160 #### Fix the fix | |
1161 | |
1162 But it's easy to fix them: | |
1163 | |
1164 ~~~ {.sh} | |
1165 hg commit --amend -m "Fix bug" | |
1166 ~~~ | |
1167 | |
1168 ~~~graphviz-file | |
1169 graphs/fix-bug-2.dot | |
1170 ~~~ | |
1171 | |
1172 #### Too fast! | |
1173 | |
1174 But wait you had local changes! And they get incorporated into the amend. | |
1175 | |
1176 <img src="https://media1.giphy.com/media/vMiCDfoKdJP0c/giphy.gif"> | |
1177 | |
1178 10 more minutes to unbundle revert the files, relaunch the tests, etc... | |
1179 | |
1180 #### With evolve now | |
1181 | |
1182 ~~~graphviz-file | |
1183 graphs/fix-bug-1.dot | |
1184 ~~~ | |
1185 | |
1186 #### Same CLI | |
1187 | |
1188 With evolve this time: | |
1189 | |
1190 ~~~ {.sh} | |
1191 hg commit --amend -m "Fix bug" | |
1192 ~~~ | |
1193 | |
1194 ~~~graphviz-file | |
1195 graphs/fix-bug-2.dot | |
1196 ~~~ | |
1197 | |
1198 #### Ok what the difference? | |
1199 | |
1200 #### Before / After | |
1201 | |
1202 | |
1203 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
1204 <div class='left' style='order:1; width: 50%'> | |
1205 Before: | |
1206 | |
1207 </div> | |
1208 | |
1209 <div class='right' style='order:2; width: 50%'> | |
1210 After: | |
1211 | |
1212 ~~~raw-file | |
1213 output/fix-a-bug-with-evolve-1.log | |
1214 ~~~ | |
1215 | |
1216 </div> | |
1217 </div> | |
1218 | |
1219 #### Difference is hidden | |
1220 | |
1221 | |
1222 ~~~raw-file | |
1223 output/fix-a-bug-with-evolve-2.log | |
1224 ~~~ | |
1225 | |
1226 The old revision is still there! | |
1227 | |
1228 #### Impact | |
1229 | |
1230 * Easier to access obsolete changesets | |
1231 - No more `.hg/strip-backup/` expedition | |
1232 * Respect the append only model of Mercurial | |
1233 - No large data movement on edition | |
1234 - No cache trauma | |
1235 | |
1236 #### One more thing | |
1237 | |
1238 <img src="https://media.giphy.com/media/F3MoHzSjjJ16w/giphy.gif"> | |
1239 | |
1240 #### Track evolution | |
1241 | |
1242 ~~~graphviz-file | |
1243 graphs/fix-bug-3.dot | |
1244 ~~~ | |
1245 ~~~graphviz | |
1246 digraph G { | |
1247 rankdir="BT"; | |
1248 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; | |
1249 | |
1250 // Revisions | |
1251 node[group=main]; | |
1252 Parent -> "Fix bug"; | |
1253 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
1254 Parent -> "Fx bug"; | |
1255 | |
1256 // Obsolescence links | |
1257 edge[dir=back, style=dotted, arrowtail=dot]; | |
1258 "Fx bug" -> "Fix bug"; | |
1259 } | |
1260 ~~~ | |
1261 | |
1262 #### Obsmarker | |
1263 | |
1264 Stores relation between evolutions | |
1265 | |
1266 | |
1267 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
1268 <div class='left' style='order:1; width: 50%'> | |
1269 ~~~graphviz | |
1270 digraph G { | |
1271 rankdir="BT"; | |
1272 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; | |
1273 | |
1274 node[group=obsolete, style="dotted, filled" fillcolor="#DFDFFF"]; | |
1275 edge[dir=back, style=dotted, arrowtail=dot]; | |
1276 "Predecessor" -> "Successor"; | |
1277 | |
1278 "Successor" [style="filled", fillcolor="#7F7FFF"]; | |
1279 } | |
1280 ~~~ | |
1281 </div> | |
1282 | |
1283 <div class='right' style='order:2; width: 50%'> | |
1284 | |
1285 * And some metas: | |
1286 * User | |
1287 * Date | |
1288 * And others... | |
1289 </div> | |
1290 </div> | |
1291 | |
1292 ## Topic | |
1293 | |
1294 #### Topic | |
1295 | |
1296 <pre> | |
1297 $> hg topic myfeature | |
1298 $> hg topics | |
1299 <span style="color:green;"> * </span><span style="color:green;">myfeature</span> | |
1300 </pre> | |
1301 | |
1302 #### Topic | |
1303 | |
1304 Topic branches are lightweight branches which disappear when changes are | |
1305 finalized (move to the public phase). They can help users to organise and share | |
1306 their unfinished work. | |
1307 | |
1308 #### Topic storage | |
1309 | |
1310 Like named-branches, topics are stored on the changeset. | |
1311 | |
1312 #### Head definition | |
1313 | |
1314 <pre> | |
1315 $> hg log -G | |
1316 @ <span style="color:olive;">changeset: 2:03a68957ddd8</span> | |
1317 | tag: tip | |
1318 | parent: 0:478309adfd3c | |
1319 | user: Boris Feld <boris.feld@octobus.net> | |
1320 | date: Mon Jul 24 22:39:27 2017 +0200 | |
1321 | summary: default | |
1322 | | |
1323 | o <span style="color:olive;">changeset: 1:3d2362d21bb4</span> | |
1324 |/ <span style="background-color:green;">topic: myfeature</span> | |
1325 | user: Boris Feld <boris.feld@octobus.net> | |
1326 | date: Mon Jul 24 22:39:55 2017 +0200 | |
1327 | summary: myfeature | |
1328 | | |
1329 o <span style="color:olive;">changeset: 0:478309adfd3c</span> | |
1330 user: Boris Feld <boris.feld@octobus.net> | |
1331 date: Mon Jul 24 16:01:32 2017 +0200 | |
1332 summary: ROOT | |
1333 </pre> | |
1334 | |
1335 #### Heads | |
1336 | |
1337 <pre> | |
1338 $> hg log -r 'head() and branch(default)' | |
1339 <span style="color:olive;">changeset: 2:03a68957ddd8</span> | |
1340 tag: tip | |
1341 parent: 0:478309adfd3c | |
1342 user: Boris Feld <boris.feld@octobus.net> | |
1343 date: Mon Jul 24 22:39:27 2017 +0200 | |
1344 summary: default | |
1345 </pre> | |
1346 | |
1347 #### Name definition | |
1348 | |
1349 We can update to a topic directly: | |
1350 | |
1351 <pre> | |
1352 $> hg update myfeature | |
1353 switching to topic myfeature | |
1354 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
1355 </pre> | |
1356 | |
1357 #### Pre-rebase | |
1358 | |
1359 <pre> | |
1360 $> hg log -G | |
1361 o <span style="color:olive;">changeset: 2:03a68957ddd8</span> | |
1362 | tag: tip | |
1363 | parent: 0:478309adfd3c | |
1364 | user: Boris Feld <boris.feld@octobus.net> | |
1365 | date: Mon Jul 24 22:39:27 2017 +0200 | |
1366 | summary: default | |
1367 | | |
1368 | @ <span style="color:olive;">changeset: 1:3d2362d21bb4</span> | |
1369 |/ <span style="background-color:green;">topic: myfeature</span> | |
1370 | user: Boris Feld <boris.feld@octobus.net> | |
1371 | date: Mon Jul 24 22:39:55 2017 +0200 | |
1372 | summary: myfeature | |
1373 | | |
1374 o <span style="color:olive;">changeset: 0:478309adfd3c</span> | |
1375 user: Boris Feld <boris.feld@octobus.net> | |
1376 date: Mon Jul 24 16:01:32 2017 +0200 | |
1377 summary: ROOT | |
1378 </pre> | |
1379 | |
1380 #### Topic rebase | |
1381 | |
1382 Topics can be rebased easily on their base branch | |
1383 | |
1384 <pre> | |
1385 $> hg rebase | |
1386 rebasing 1:3d2362d21bb4 "myfeature" | |
1387 switching to topic myfeature | |
1388 </pre> | |
1389 | |
1390 #### Result | |
1391 | |
1392 <pre> | |
1393 $> hg log -G | |
1394 @ <span style="color:olive;">changeset: 3:0a51e0d4d460</span> | |
1395 | tag: tip | |
1396 | <span style="background-color:green;">topic: myfeature</span> | |
1397 | user: Boris Feld <boris.feld@octobus.net> | |
1398 | date: Mon Jul 24 22:39:55 2017 +0200 | |
1399 | summary: myfeature | |
1400 | | |
1401 o <span style="color:olive;">changeset: 2:03a68957ddd8</span> | |
1402 | parent: 0:478309adfd3c | |
1403 | user: Boris Feld <boris.feld@octobus.net> | |
1404 | date: Mon Jul 24 22:39:27 2017 +0200 | |
1405 | summary: default | |
1406 | | |
1407 o <span style="color:olive;">changeset: 0:478309adfd3c</span> | |
1408 user: Boris Feld <boris.feld@octobus.net> | |
1409 date: Mon Jul 24 16:01:32 2017 +0200 | |
1410 summary: ROOT | |
1411 </pre> | |
1412 | |
1413 #### Topic push | |
1414 | |
1415 You can push topic without -f if you push only 1 head: | |
1416 | |
1417 <pre> | |
1418 hg push -r myfeature | |
1419 </pre> | |
1420 | |
1421 Even if the topic is not up-to-date to its branch. | |
1422 | |
1423 ## Stack Workflow | |
1424 | |
1425 #### Stack | |
1426 | |
1427 <pre> | |
1428 $> hg stack | |
1429 ###### topic: <span style="color:green;">myfeature</span> | |
1430 ###### branch: feature | |
1431 <span style="color:teal;">t4</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step4</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1432 <span style="color:olive;">t3</span><span style="color:green;">:</span> Step3 | |
1433 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1434 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step | |
1435 <span style="color:grey;">t0^ Trunk</span> | |
1436 </pre> | |
1437 | |
1438 #### Why Stack? | |
1439 | |
1440 * Feature = multiple steps, | |
1441 | |
1442 * Smaller = Simpler | |
1443 | |
1444 * Simpler = Earlier merge in trunk | |
1445 | |
1446 * Ease experiment with Alternative | |
1447 | |
1448 * etc… | |
1449 | |
1450 #### Prev | |
1451 | |
1452 <pre> | |
1453 $> hg prev | |
1454 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1455 [<span style="color:blue;">7</span>] Step3 | |
1456 $> hg stack | |
1457 ###### topic: <span style="color:green;">myfeature</span> | |
1458 ###### branch: feature | |
1459 <span style="color:olive;">t4</span><span style="color:green;">:</span> Step4 | |
1460 <span style="color:teal;">t3</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step3</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1461 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1462 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step | |
1463 <span style="color:grey;">t0^ Trunk</span> | |
1464 </pre> | |
1465 | |
1466 #### Next | |
1467 | |
1468 <pre> | |
1469 $> hg next | |
1470 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1471 [<span style="color:blue;">8</span>] Step4 | |
1472 $> hg stack | |
1473 ###### topic: <span style="color:green;">myfeature</span> | |
1474 ###### branch: feature | |
1475 <span style="color:teal;">t4</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step4</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1476 <span style="color:olive;">t3</span><span style="color:green;">:</span> Step3 | |
1477 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1478 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step | |
1479 <span style="color:grey;">t0^ Trunk</span> | |
1480 </pre> | |
1481 | |
1482 #### T\# | |
1483 | |
1484 <pre> | |
1485 $> hg update --rev t2 | |
1486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1487 [<span style="color:blue;">8</span>] Step4 | |
1488 $> hg stack | |
1489 ###### topic: <span style="color:green;">myfeature</span> | |
1490 ###### branch: feature | |
1491 <span style="color:olive;">t4</span><span style="color:green;">:</span> Step4 | |
1492 <span style="color:olive;">t3</span><span style="color:green;">:</span> Step3 | |
1493 <span style="color:teal;">t2</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step2</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1494 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step | |
1495 <span style="color:grey;">t0^ Trunk</span> | |
1496 </pre> | |
1497 | |
1498 #### Editing mid-stack | |
1499 | |
1500 <pre> | |
1501 $> hg update --rev t1 | |
1502 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1503 $> hg commit --amend -m "Step1" | |
1504 <span style="color:gold;">3 new unstable changesets</span> | |
1505 </pre> | |
1506 | |
1507 #### What have we done? | |
1508 | |
1509 <pre> | |
1510 $> hg log -G -T compact | |
1511 @ <span style="color:olive;">9</span>[tip] 1aa1be5ada40 Step1 | |
1512 | | |
1513 | o <span style="color:olive;">8</span> cf90b2de7e65 Step4 <span style="color:red;">(unstable)</span> | |
1514 | | | |
1515 | o <span style="color:olive;">7</span> e208d4205c8e Step3 <span style="color:red;">(unstable)</span> | |
1516 | | | |
1517 | o <span style="color:olive;">6</span> 673ff300cf3a Step2 <span style="color:red;">(unstable)</span> | |
1518 | | | |
1519 | <span style="color:grey;">x 5 8bb88a31dd28 Step</span> | |
1520 |/ | |
1521 o <span style="color:olive;">4</span> 3294c1730df7 Trunk | |
1522 ~ | |
1523 </pre> | |
1524 | |
1525 #### Stack to the rescue! | |
1526 | |
1527 <pre> | |
1528 $> hg stack | |
1529 ###### topic: <span style="color:green;">myfeature</span> | |
1530 ###### branch: feature | |
1531 <span style="color:olive;">t4</span><span style="color:red;">$</span> Step4<span style="color:red;"> (unstable)</span> | |
1532 <span style="color:olive;">t3</span><span style="color:red;">$</span> Step3<span style="color:red;"> (unstable)</span> | |
1533 <span style="color:olive;">t2</span><span style="color:red;">$</span> Step2<span style="color:red;"> (unstable)</span> | |
1534 <span style="color:teal;">t1</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step1</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1535 <span style="color:grey;">t0^ Trunk</span> | |
1536 </pre> | |
1537 | |
1538 #### Don't panic | |
1539 | |
1540 <pre> | |
1541 $> hg next --evolve | |
1542 move:[<span style="color:blue;">6</span>] Step2 | |
1543 atop:[<span style="color:blue;">9</span>] Step1 | |
1544 working directory now at <span style="color:olive;">d72473cbf9a6</span> | |
1545 $> hg stack | |
1546 ###### topic: <span style="color:green;">myfeature</span> | |
1547 ###### branch: feature | |
1548 <span style="color:olive;">t4</span><span style="color:red;">$</span> Step4<span style="color:red;"> (unstable)</span> | |
1549 <span style="color:olive;">t3</span><span style="color:red;">$</span> Step3<span style="color:red;"> (unstable)</span> | |
1550 <span style="color:teal;">t2</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step2</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1551 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step1 | |
1552 <span style="color:grey;">t0^ Trunk</span> | |
1553 </pre> | |
1554 | |
1555 #### Go on | |
1556 | |
1557 <img src="https://media.giphy.com/media/KBx7fQoLxuV7G/giphy.gif"> | |
1558 | |
1559 #### Go on | |
1560 | |
1561 <pre> | |
1562 $> hg next --evolve | |
1563 move:[<span style="color:blue;">7</span>] Step3 | |
1564 atop:[<span style="color:blue;">10</span>] Step2 | |
1565 working directory now at <span style="color:olive;">4062d6ecd214</span> | |
1566 $> hg stack | |
1567 ###### topic: <span style="color:green;">myfeature</span> | |
1568 ###### branch: feature | |
1569 <span style="color:olive;">t4</span><span style="color:red;">$</span> Step4<span style="color:red;"> (unstable)</span> | |
1570 <span style="color:teal;">t3</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step3</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1571 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1572 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step1 | |
1573 <span style="color:grey;">t0^ Trunk</span> | |
1574 </pre> | |
1575 | |
1576 #### Go on | |
1577 | |
1578 <pre> | |
1579 $> hg next --evolve | |
1580 move:[<span style="color:blue;">8</span>] Step4 | |
1581 atop:[<span style="color:blue;">11</span>] Step3 | |
1582 working directory now at <span style="color:olive;">4dcd9dfedf1b</span> | |
1583 $> hg stack | |
1584 ###### topic: <span style="color:green;">myfeature</span> | |
1585 ###### branch: feature | |
1586 <span style="color:teal;">t4</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step4</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1587 <span style="color:olive;">t3</span><span style="color:green;">:</span> Step3 | |
1588 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1589 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step1 | |
1590 <span style="color:grey;">t0^ Trunk</span> | |
1591 </pre> | |
1592 | |
1593 #### Go on | |
1594 | |
1595 <pre> | |
1596 $> hg next --evolve | |
1597 no children | |
1598 </pre> | |
1599 | |
1600 #### Better! | |
1601 | |
1602 <pre> | |
1603 $> hg log -G -T compact | |
1604 @ <span style="color:olive;">12</span>[tip] 4dcd9dfedf1b Step4 | |
1605 | | |
1606 o <span style="color:olive;">11</span> 4062d6ecd214 Step3 | |
1607 | | |
1608 o <span style="color:olive;">10</span> d72473cbf9a6 Step2 | |
1609 | | |
1610 o <span style="color:olive;">9</span> 1aa1be5ada40 Step1 | |
1611 | | |
1612 o <span style="color:olive;">4</span> 3294c1730df7 Trunk | |
1613 ~ | |
1614 </pre> | |
1615 | |
1616 #### More Rewrite Tools | |
1617 | |
1618 <table> | |
1619 <tr> | |
1620 <th>Operation</th> | |
1621 <th>command</th> | |
1622 </tr> | |
1623 <tr> | |
1624 <td>Modify</td> | |
1625 <td>`hg amend`<br></td> | |
1626 </tr> | |
1627 <tr> | |
1628 <td>Remove</td> | |
1629 <td>`hg prune`<br></td> | |
1630 </tr> | |
1631 <tr> | |
1632 <td>Move</td> | |
1633 <td>`hg grab`<br></td> | |
1634 </tr> | |
1635 <tr> | |
1636 <td>Split</td> | |
1637 <td>`hg split`<br></td> | |
1638 </tr> | |
1639 <tr> | |
1640 <td>Fold</td> | |
1641 <td>`hg fold`<br></td> | |
1642 </tr> | |
1643 </table> | |
1644 | |
1645 #### Multi headed stack | |
1646 | |
1647 <pre> | |
1648 $> hg log -G -T compact | |
1649 @ <span style="color:olive;">6</span>[tip] 189f54192937 Step4.5 | |
1650 | | |
1651 | o <span style="color:olive;">5</span> c1a91e7c74f5 Step5 | |
1652 |/ | |
1653 o <span style="color:olive;">4</span> 826d2fbb601a Step4 | |
1654 | | |
1655 o <span style="color:olive;">3</span> 08bcdd8d972b Step3 | |
1656 | | |
1657 o <span style="color:olive;">2</span> 06cb53532f1b Step2 | |
1658 | | |
1659 o <span style="color:olive;">1</span> 3eb38d10980d Step1 | |
1660 ~ | |
1661 | |
1662 </pre> | |
1663 | |
1664 #### Multi headed stack | |
1665 | |
1666 <pre> | |
1667 $> hg stack | |
1668 ###### topic: <span style="color:green;">myfeature</span> (<span style="color:olive;">2 heads</span>) | |
1669 ###### branch: feature | |
1670 <span style="color:teal;">t6</span><span style="color:teal;font-weight:bold;">@</span> <span style="color:teal;">Step4.5</span><span style="color:teal;font-weight:bold;"> (current)</span> | |
1671 <span style="color:grey;">t4^ Step4 (base)</span> | |
1672 <span style="color:olive;">t5</span><span style="color:green;">:</span> Step5 | |
1673 <span style="color:olive;">t4</span><span style="color:green;">:</span> Step4 | |
1674 <span style="color:olive;">t3</span><span style="color:green;">:</span> Step3 | |
1675 <span style="color:olive;">t2</span><span style="color:green;">:</span> Step2 | |
1676 <span style="color:olive;">t1</span><span style="color:green;">:</span> Step1 | |
1677 <span style="color:grey;">t0^ Trunk</span> | |
1678 </pre> | |
1679 | |
1680 ## Distributed Workflow | |
1681 | |
1682 #### propagation | |
1683 | |
1684 Obsolescence can be exchanged: | |
1685 | |
1686 * push, pull | |
1687 * bundle / unbundle (hg 4.3+) | |
1688 | |
1689 (affects draft history only) | |
1690 | |
1691 #### Exchanging draft | |
1692 | |
1693 * Works on multiple machines | |
1694 | |
1695 * Collaborate with others | |
1696 | |
1697 * Whole new play field == new traps | |
1698 | |
1699 #### Example | |
1700 | |
1701 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
1702 <div class='left' style='order:1; width: 50%'> | |
1703 ~~~graphviz | |
1704 digraph G { | |
1705 rankdir="BT"; | |
1706 graph[splines=polyline]; | |
1707 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1708 | |
1709 // Revisions | |
1710 node[group=main]; | |
1711 Root -> "A"; | |
1712 Root [shape="circle"]; | |
1713 } | |
1714 ~~~ | |
1715 </div> | |
1716 | |
1717 <div class='right' style='order:2; width: 50%'> | |
1718 ~~~graphviz | |
1719 digraph G { | |
1720 rankdir="BT"; | |
1721 graph[splines=polyline]; | |
1722 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1723 | |
1724 // Revisions | |
1725 node[group=main]; | |
1726 Root -> "A"; | |
1727 Root [shape="circle"]; | |
1728 } | |
1729 ~~~ | |
1730 </div> | |
1731 </div> | |
1732 | |
1733 #### time pass | |
1734 | |
1735 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
1736 <div class='left' style='order:1; width: 50%'> | |
1737 ~~~graphviz | |
1738 digraph G { | |
1739 rankdir="BT"; | |
1740 graph[splines=polyline]; | |
1741 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1742 | |
1743 // Revisions | |
1744 node[group=main]; | |
1745 Root -> "A1"; | |
1746 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
1747 Root -> "A"; | |
1748 | |
1749 // Obsolescence links | |
1750 edge[dir=back, style=dotted, arrowtail=dot]; | |
1751 "A" -> "A1"; | |
1752 | |
1753 Root [shape="circle"]; | |
1754 } | |
1755 ~~~ | |
1756 </div> | |
1757 | |
1758 <div class='right' style='order:2; width: 50%'> | |
1759 ~~~graphviz | |
1760 digraph G { | |
1761 rankdir="BT"; | |
1762 graph[splines=polyline]; | |
1763 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1764 | |
1765 // Revisions | |
1766 node[group=main]; | |
1767 Root -> "A" -> B; | |
1768 | |
1769 Root [shape="circle"]; | |
1770 } | |
1771 ~~~ | |
1772 </div> | |
1773 </div> | |
1774 | |
1775 #### Instability | |
1776 | |
1777 ~~~graphviz | |
1778 digraph G { | |
1779 rankdir="BT"; | |
1780 graph[splines=polyline]; | |
1781 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1782 | |
1783 // Revisions | |
1784 node[group=main]; | |
1785 Root -> "A1"; | |
1786 "B"; | |
1787 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
1788 Root -> "A" -> "B"; | |
1789 | |
1790 // Obsolescence links | |
1791 edge[dir=back, style=dotted, arrowtail=dot]; | |
1792 "A" -> "A1"; | |
1793 | |
1794 Root [shape="circle"]; | |
1795 B [fillcolor="#FF3535"]; | |
1796 } | |
1797 ~~~ | |
1798 | |
1799 #### It's smart | |
1800 | |
1801 <img src="https://media2.giphy.com/media/ZThQqlxY5BXMc/giphy.gif"> | |
1802 | |
1803 #### Stabilization | |
1804 | |
1805 ~~~graphviz | |
1806 digraph G { | |
1807 rankdir="BT"; | |
1808 graph[splines=polyline]; | |
1809 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
1810 | |
1811 // Revisions | |
1812 node[group=main]; | |
1813 Root -> "A1" -> "B1"; | |
1814 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
1815 Root -> "A" -> "B"; | |
1816 | |
1817 // Obsolescence links | |
1818 edge[dir=back, style=dotted, arrowtail=dot]; | |
1819 "A" -> "A1"; | |
1820 "B" -> "B1"; | |
1821 | |
1822 Root [shape="circle"]; | |
1823 } | |
1824 ~~~ | |
1825 | |
1826 #### rewrite anything? | |
1827 | |
1828 Phases enforce a reliable history: | |
1829 | |
1830 * **draft**: can we rewritten | |
1831 * **public**: immutable part of the history | |
1832 | |
1833 Contact your local workflow manager. | |
1834 | |
1835 ## Helpfull Tooling | |
1836 | |
1837 #### Summary | |
1838 | |
1839 <pre> | |
1840 $> hg summary | |
1841 <span style="color:olive;">parent: 10:890ac95deb83 </span>tip (unstable) | |
1842 Head | |
1843 branch: feature | |
1844 commit: (clean) | |
1845 update: (current) | |
1846 phases: 9 draft | |
1847 unstable: <span style="color:red;">1 changesets</span> | |
1848 topic: <span style="color:green;">myfeature</span> | |
1849 </pre> | |
1850 | |
1851 #### Topics | |
1852 | |
1853 <pre> | |
1854 $> hg topics | |
1855 4.3compat | |
1856 doc | |
1857 evolvecolor | |
1858 import-checker | |
1859 more-output | |
1860 obscache | |
1861 obsfatefixes | |
1862 obsmarkerbitfield | |
1863 obsrangecacheiterative | |
1864 packaging | |
1865 prev-next | |
1866 split | |
1867 stack_unstable_bug | |
1868 tutorial | |
1869 * tutorialtypos | |
1870 </pre> | |
1871 | |
1872 #### Topics age | |
1873 | |
1874 <pre> | |
1875 $> hg topics --age | |
1876 tutorial (5 hours ago) | |
1877 <span style="color:green;"> * </span><span style="color:green;">tutorialtypos </span> (5 hours ago) | |
1878 4.3compat (4 days ago) | |
1879 prev-next (12 days ago) | |
1880 obsfatefixes (2 weeks ago) | |
1881 more-output (3 weeks ago) | |
1882 obsmarkerbitfield (2 months ago) | |
1883 obscache (2 months ago) | |
1884 evolvecolor (2 months ago) | |
1885 obsrangecacheiterative (2 months ago) | |
1886 stack_unstable_bug (2 months ago) | |
1887 doc (3 months ago) | |
1888 split (3 months ago) | |
1889 import-checker (4 months ago) | |
1890 packaging (4 months ago) | |
1891 </pre> | |
1892 | |
1893 #### Topics verbose | |
1894 | |
1895 <pre class="shell_output"> | |
1896 $> hg topics --verbose | |
1897 4.3compat (on branch: default, 1 changesets, <span style="color:teal;">43 behind</span>) | |
1898 doc (on branch: stable, 1 changesets, <span style="color:teal;">415 behind</span>) | |
1899 evolvecolor (on branch: default, 1 changesets, <span style="color:teal;">369 behind</span>) | |
1900 import-checker (on branch: default, 1 changesets, <span style="color:teal;">637 behind</span>) | |
1901 more-output (on branch: default, 1 changesets, <span style="color:teal;">104 behind</span>) | |
1902 obscache (on branch: default, 1 changesets, <span style="color:teal;">325 behind</span>) | |
1903 obsfatefixes (on branch: default, 1 changesets, <span style="color:teal;">82 behind</span>) | |
1904 obsmarkerbitfield (on branch: default, 1 changesets, <span style="color:teal;">324 behind</span>) | |
1905 obsrangecacheiterative (on branch: default, 1 changesets, <span style="color:teal;">461 behind</span>) | |
1906 packaging (on branch: default, 1 changesets, <span style="color:teal;">2521 behind</span>) | |
1907 prev-next (on branch: default, 4 changesets, <span style="color:teal;">72 behind</span>) | |
1908 split (on branch: default, 1 changesets, <span style="color:teal;">492 behind</span>) | |
1909 stack_unstable_bug (on branch: default, 1 changesets, <span style="color:teal;">474 behind</span>) | |
1910 tutorial (on branch: default, 2 changesets, <span style="color:teal;">492 behind</span>) | |
1911 <span style="color:green;"> * </span><span style="color:green;">tutorialtypos </span> (on branch: default, 3 changesets, <span style="color:red;">1 troubled</span>, <span style="color:olive;">2 heads</span>, <span style="color:teal;">2 behind</span>) | |
1912 </pre> | |
1913 | |
1914 #### Log | |
1915 | |
1916 <pre> | |
1917 $ hg log -G --hidden -T '{node|short}\n{obsfate}\n' | |
1918 @ c55cb2ee8a91 | |
1919 | | |
1920 o 23abfc79b7ce | |
1921 | | |
1922 | o 4302274177b9 <span style="color:red;">(unstable)</span> | |
1923 | | | |
1924 | <span style="color:grey;">x fba593aaaa10</span> | |
1925 |/ rewritten as c55cb2ee8a91; | |
1926 o 2ff53d8bf7d7 | |
1927 </pre> | |
1928 | |
1929 #### Evolve --list | |
1930 | |
1931 <pre> | |
1932 $> hg evolve --list | |
1933 <span style="color:gold;">9ac0d376e01c</span>: changelog: introduce a 'tiprev' method | |
1934 <span style="color:red;">unstable</span>: <span style="color:grey;">52ec3072fe46</span> (obsolete parent) | |
1935 | |
1936 <span style="color:gold;">3efd3eab9860</span>: changelog: use 'tiprev()' in 'tip()' | |
1937 <span style="color:red;">unstable</span>: <span style="color:red;">9ac0d376e01c</span> (unstable parent) | |
1938 </pre> | |
1939 | |
1940 (see also `hg evolve --list --rev`) | |
1941 | |
1942 #### Obslog | |
1943 | |
1944 <pre> | |
1945 $> hg obslog | |
1946 @ <span style="color:olive;">c55cb2ee8a91</span> <span style="color:blue;">(4)</span> A2 | |
1947 | | |
1948 | o <span style="color:olive;">4302274177b9</span> <span style="color:blue;">(2)</span> A1 | |
1949 |/ | |
1950 x <span style="color:olive;">fba593aaaa10</span> <span style="color:blue;">(1)</span> A | |
1951 rewritten(description, parent) as <span style="color:olive;">c55cb2ee8a91</span> | |
1952 by <span style="color:green;">Boris Feld <boris.feld@octobus.net></span> | |
1953 <span style="color:teal;">(Thu Jun 22 00:00:29 2017 +0200)</span> | |
1954 rewritten(description) as <span style="color:olive;">4302274177b9</span> | |
1955 by <span style="color:green;">Boris Feld <boris.feld@octobus.net></span> | |
1956 <span style="color:teal;">(Thu Jun 22 00:00:28 2017 +0200)</span> | |
1957 | |
1958 </pre> | |
1959 | |
1960 #### Obslog --patch | |
1961 | |
1962 <pre> | |
1963 $> hg obslog -p | |
1964 @ <span style="color:olive;">f6b1dded9e95</span> <span style="color:blue;">(2)</span> A1 | |
1965 | | |
1966 x <span style="color:olive;">364e589e2bac</span> <span style="color:blue;">(1)</span> A | |
1967 rewritten(description, parent) as <span style="color:olive;">a6be771bedcf</span> | |
1968 by <span style="color:green;">Boris Feld <boris.feld@octobus.net></span> | |
1969 <span style="color:teal;">(Thu Jun 22 00:00:29 2017 +0200)</span> | |
1970 (No patch available yet, changesets rebased) | |
1971 rewritten(description) as <span style="color:olive;">f6b1dded9e95</span> | |
1972 by <span style="color:green;">Boris Feld <boris.feld@octobus.net></span> | |
1973 <span style="color:teal;">(Thu Jun 22 00:00:28 2017 +0200)</span> | |
1974 --- a/364e589e2bac-changeset-description | |
1975 +++ b/f6b1dded9e95-changeset-description | |
1976 @@ -1,1 +1,1 @@ | |
1977 -A | |
1978 +A1 | |
1979 </pre> | |
1980 | |
1981 #### Journal | |
1982 | |
1983 <pre> | |
1984 $> hg journal | |
1985 previous locations of '.': | |
1986 2fb6d364d453 commit --amend -m Step1 | |
1987 701fb5d73e07 update --rev t1 | |
1988 ae11635effb7 commit -A -m Step2 | |
1989 701fb5d73e07 commit -A -m Step | |
1990 </pre> | |
1991 | |
1992 ## Semantic | |
1993 | |
1994 #### Use the right commands! | |
1995 | |
1996 <img src="https://media.giphy.com/media/uRb2p09vY8lEs/giphy.gif"> | |
1997 | |
1998 #### smart commands | |
1999 | |
2000 <table> | |
2001 <tr> | |
2002 <th>Operation</th> | |
2003 <th>command</th> | |
2004 </tr> | |
2005 <tr> | |
2006 <td>Modify</td> | |
2007 <td>`hg amend`<br></td> | |
2008 </tr> | |
2009 <tr> | |
2010 <td>Remove</td> | |
2011 <td>`hg prune`<br></td> | |
2012 </tr> | |
2013 <tr> | |
2014 <td>Move</td> | |
2015 <td>`hg grab`<br></td> | |
2016 </tr> | |
2017 <tr> | |
2018 <td>Split</td> | |
2019 <td>`hg split`<br></td> | |
2020 </tr> | |
2021 <tr> | |
2022 <td>Fold</td> | |
2023 <td>`hg fold`<br></td> | |
2024 </tr> | |
2025 </table> | |
2026 | |
2027 | |
2028 ## Troubles | |
2029 | |
2030 #### Evolution | |
2031 | |
2032 * Unlock powerful unique features | |
2033 | |
2034 * Hide **most** of the complexity | |
2035 | |
2036 * Help with unstable situations | |
2037 | |
2038 - Automatic detection | |
2039 | |
2040 - Automated resolution `hg help evolve` | |
2041 | |
2042 #### instability | |
2043 | |
2044 (currently: *troubles*) | |
2045 | |
2046 * **Orphans:** ancestors were rewritten | |
2047 | |
2048 * **Divergence:** branching in evolutions | |
2049 | |
2050 - Content-divergence: independent rewrites | |
2051 | |
2052 - Phase-divergence: older version got published | |
2053 | |
2054 ## Conclusion | |
2055 | |
2056 #### Work in progress | |
2057 | |
2058 * Concepts are solid | |
2059 * Implementation in progress | |
2060 * Common case works fine | |
2061 * Some rough edges | |
2062 * Feedback → priority | |
2063 | |
2064 #### Use Evolution Today | |
2065 | |
2066 install `hg-evolve` | |
2067 | |
2068 <pre> | |
2069 [extensions] | |
2070 evolve= | |
2071 topic= ## provides hg stack | |
2072 </pre> | |
2073 | |
2074 #### Helps | |
2075 | |
2076 * Mailing-list: `evolve-testers@mercurial-scm.org` | |
2077 * IRC channel: `#mercurial` | |
2078 | |
2079 #### Documentation | |
2080 | |
2081 * Documentation: <br/><small><https://www.mercurial-scm.org/doc/evolution/index.html></small> | |
2082 * Wiki: <br/><small><https://www.mercurial-scm.org/wiki/EvolveExtension></small> | |
2083 | |
2084 ## Conclusion | |
2085 | |
2086 #### Rewrite all the things! | |
2087 | |
2088 <img src="https://cdn.meme.am/cache/instances/folder258/500x/54913258.jpg"> | |
2089 | |
2090 #### Safety first! | |
2091 | |
2092 <img src="https://media.giphy.com/media/46vrhWWOJ4wHC/giphy.gif"> | |
2093 | |
2094 ## extra - Troubles | |
2095 | |
2096 #### Obsolete | |
2097 | |
2098 ~~~graphviz | |
2099 digraph G { | |
2100 rankdir="BT"; | |
2101 graph[splines=polyline]; | |
2102 node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; | |
2103 | |
2104 | |
2105 node[group=main]; | |
2106 Root -> New; | |
2107 node[group=obsolete]; | |
2108 Root -> Obsolete; | |
2109 | |
2110 // Obsolescence links | |
2111 edge[dir=back, style=dotted, arrowtail=dot]; | |
2112 Obsolete -> New; | |
2113 | |
2114 Obsolete [fillcolor="#DFDFFF"]; | |
2115 Root[shape="circle"]; | |
2116 } | |
2117 ~~~ | |
2118 | |
2119 #### Unstable | |
2120 | |
2121 Now called `orphan` | |
2122 | |
2123 ~~~graphviz | |
2124 digraph G { | |
2125 rankdir="BT"; | |
2126 graph[splines=polyline]; | |
2127 node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; | |
2128 | |
2129 node[group=main]; | |
2130 Root -> New; | |
2131 node[group=obsolete]; | |
2132 Root -> Obsolete -> Unstable; | |
2133 | |
2134 // Obsolescence links | |
2135 edge[dir=back, style=dotted, arrowtail=dot]; | |
2136 Obsolete -> New; | |
2137 | |
2138 Obsolete [fillcolor="#DFDFFF"]; | |
2139 Unstable [fillcolor="#FF3535"]; | |
2140 Root[shape="circle"]; | |
2141 } | |
2142 ~~~ | |
2143 | |
2144 #### Bumped | |
2145 | |
2146 Now called `Phase-divergent` | |
2147 | |
2148 ~~~graphviz | |
2149 digraph G { | |
2150 rankdir="BT"; | |
2151 graph[splines=polyline]; | |
2152 node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; | |
2153 | |
2154 node[group=main]; | |
2155 Root -> New; | |
2156 node[group=obsolete]; | |
2157 Root -> Obsolete; | |
2158 node[group=bumped]; | |
2159 Root -> Bumped; | |
2160 | |
2161 // Obsolescence links | |
2162 edge[dir=back, style=dotted, arrowtail=dot]; | |
2163 Obsolete -> New; | |
2164 Obsolete -> Bumped; | |
2165 | |
2166 New [shape="circle"]; | |
2167 Obsolete [fillcolor="#DFDFFF"]; | |
2168 Bumped [fillcolor="#FF3535"]; | |
2169 Root[shape="circle"]; | |
2170 } | |
2171 ~~~ | |
2172 | |
2173 #### Divergent | |
2174 | |
2175 Now called `Content-divergent` | |
2176 | |
2177 ~~~graphviz | |
2178 digraph G { | |
2179 rankdir="BT"; | |
2180 graph[splines=polyline]; | |
2181 node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; | |
2182 | |
2183 Root -> Base; | |
2184 Root -> Divergent1; | |
2185 Root -> Divergent2; | |
2186 | |
2187 // Obsolescence links | |
2188 edge[dir=back, style=dotted, arrowtail=dot]; | |
2189 Base -> Divergent1; | |
2190 Base -> Divergent2; | |
2191 | |
2192 Base [shape="pentagon", fillcolor="#DFDFFF"]; | |
2193 Divergent1 [fillcolor="#FF3535"]; | |
2194 Divergent2 [fillcolor="#FF3535"]; | |
2195 Root[shape="circle"]; | |
2196 } | |
2197 ~~~ | |
2198 | |
2199 ## extra-commands | |
2200 | |
2201 #### Amend | |
2202 | |
2203 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
2204 <div class='left' style='order:1; width: 20%'> | |
2205 ~~~graphviz | |
2206 digraph G { | |
2207 rankdir="BT"; | |
2208 graph[splines=polyline]; | |
2209 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2210 | |
2211 // Revisions | |
2212 node[group=main]; | |
2213 Root -> "A"; | |
2214 Root [shape="circle"]; | |
2215 } | |
2216 ~~~ | |
2217 </div> | |
2218 | |
2219 <div class="middle" style='order:2; width: 60%'> | |
2220 To amend A: | |
2221 | |
2222 hg amend -m 'A1' | |
2223 </div> | |
2224 | |
2225 <div class='right' style='order:2; width: 20%'> | |
2226 ~~~graphviz | |
2227 digraph G { | |
2228 rankdir="BT"; | |
2229 graph[splines=polyline]; | |
2230 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2231 | |
2232 // Revisions | |
2233 node[group=main]; | |
2234 Root -> "A1"; | |
2235 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
2236 Root -> "A"; | |
2237 | |
2238 // Obsolescence links | |
2239 edge[dir=back, style=dotted, arrowtail=dot]; | |
2240 "A" -> "A1"; | |
2241 Root [shape="circle"]; | |
2242 } | |
2243 ~~~ | |
2244 </div> | |
2245 </div> | |
2246 | |
2247 #### Prune | |
2248 | |
2249 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
2250 <div class='left' style='order:1; width: 20%'> | |
2251 ~~~graphviz | |
2252 digraph G { | |
2253 rankdir="BT"; | |
2254 graph[splines=polyline]; | |
2255 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2256 | |
2257 // Revisions | |
2258 node[group=main]; | |
2259 Root -> "A"; | |
2260 Root [shape="circle"]; | |
2261 } | |
2262 ~~~ | |
2263 </div> | |
2264 | |
2265 <div class="middle" style='order:2; width: 60%'> | |
2266 | |
2267 To prune A: | |
2268 | |
2269 hg prune -r "desc(A)" | |
2270 </div> | |
2271 | |
2272 <div class='right' style='order:2; width: 20%'> | |
2273 ~~~graphviz | |
2274 digraph G { | |
2275 rankdir="BT"; | |
2276 graph[splines=polyline]; | |
2277 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2278 | |
2279 Root [shape="circle"]; | |
2280 | |
2281 // Revisions | |
2282 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
2283 Root -> "A"; | |
2284 } | |
2285 ~~~ | |
2286 </div> | |
2287 </div> | |
2288 | |
2289 #### Rebase | |
2290 | |
2291 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
2292 <div class='left' style='order:1; width: 20%'> | |
2293 ~~~graphviz | |
2294 digraph G { | |
2295 rankdir="BT"; | |
2296 graph[splines=polyline]; | |
2297 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2298 | |
2299 // Revisions | |
2300 node[group=branch]; | |
2301 Root -> B; | |
2302 node[group=main]; | |
2303 Root -> "A"; | |
2304 | |
2305 Root [shape="circle"]; | |
2306 } | |
2307 ~~~ | |
2308 </div> | |
2309 | |
2310 <div class="middle" style='order:2; width: 60%'> | |
2311 | |
2312 In order to rebase A on top of B; | |
2313 | |
2314 hg rebase -r "desc(A)" -d "desc(B)" | |
2315 | |
2316 </div> | |
2317 | |
2318 <div class='right' style='order:2; width: 20%'> | |
2319 ~~~graphviz | |
2320 digraph G { | |
2321 rankdir="BT"; | |
2322 graph[splines=polyline]; | |
2323 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2324 | |
2325 // Revisions | |
2326 node[group=branch]; | |
2327 Root -> B -> "A'"; | |
2328 | |
2329 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
2330 Root -> "A"; | |
2331 | |
2332 // Obsolescence links | |
2333 edge[dir=back, style=dotted, arrowtail=dot]; | |
2334 "A" -> "A'"; | |
2335 | |
2336 Root [shape="circle"]; | |
2337 } | |
2338 ~~~ | |
2339 </div> | |
2340 </div> | |
2341 | |
2342 #### Fold | |
2343 | |
2344 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
2345 <div class='left' style='order:1; width: 15%'> | |
2346 | |
2347 ~~~graphviz | |
2348 digraph G { | |
2349 rankdir="BT"; | |
2350 graph[splines=polyline]; | |
2351 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2352 | |
2353 // Revisions | |
2354 node[group=branch]; | |
2355 Root -> A -> B; | |
2356 | |
2357 Root [shape="circle"]; | |
2358 } | |
2359 ~~~ | |
2360 </div> | |
2361 | |
2362 <div class="middle" style='order:2; width: 70%'> | |
2363 | |
2364 To fold A and B: | |
2365 | |
2366 hg fold -r "desc(A)" -r "desc(B)" -m "C" | |
2367 | |
2368 </div> | |
2369 | |
2370 <div class='right' style='order:2; width: 15%'> | |
2371 | |
2372 ~~~graphviz | |
2373 digraph G { | |
2374 rankdir="BT"; | |
2375 graph[splines=polyline]; | |
2376 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2377 | |
2378 // Revisions | |
2379 node[group=branch]; | |
2380 Root -> C; | |
2381 | |
2382 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
2383 Root -> A -> B; | |
2384 | |
2385 // Obsolescence links | |
2386 edge[dir=back, style=dotted, arrowtail=dot]; | |
2387 "A" -> "C"; | |
2388 "B" -> "C"; | |
2389 | |
2390 Root [shape="circle"]; | |
2391 } | |
2392 ~~~ | |
2393 | |
2394 </div> | |
2395 </div> | |
2396 | |
2397 #### Split | |
2398 | |
2399 <div class='graph' style='display: flex ;align-items: stretch ;flex-flow: row wrap ; align-items: center;'> | |
2400 <div class='left' style='order:1; width: 20%'> | |
2401 ~~~graphviz | |
2402 digraph G { | |
2403 rankdir="BT"; | |
2404 graph[splines=polyline]; | |
2405 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2406 | |
2407 // Revisions | |
2408 node[group=branch]; | |
2409 Root -> A; | |
2410 | |
2411 Root [shape="circle"]; | |
2412 } | |
2413 ~~~ | |
2414 </div> | |
2415 | |
2416 <div class="middle" style='order:2; width: 60%'> | |
2417 | |
2418 Split in two: | |
2419 | |
2420 hg split -r "desc(A)" | |
2421 </div> | |
2422 | |
2423 <div class='right' style='order:2; width: 20%'> | |
2424 ~~~graphviz | |
2425 digraph G { | |
2426 rankdir="BT"; | |
2427 graph[splines=polyline]; | |
2428 node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; | |
2429 | |
2430 // Revisions | |
2431 node[group=branch]; | |
2432 Root -> B -> C; | |
2433 | |
2434 node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; | |
2435 Root -> A; | |
2436 | |
2437 // Obsolescence links | |
2438 edge[dir=back, style=dotted, arrowtail=dot]; | |
2439 "A" -> "C"; | |
2440 "A" -> "B"; | |
2441 | |
2442 Root [shape="circle"]; | |
2443 } | |
2444 ~~~ | |
2445 </div> | |
2446 </div> | |
2447 --> |