# HG changeset patch # User Boris Feld # Date 1515408413 -3600 # Node ID aad37ffd7d5829dc355a5766d2e4d5338b373244 # Parent 1cb549cd62369a8d6dadf01e40882dd7c72228ce doc: import the training support Import the training support which was stored in a private-repository before. diff -r 1cb549cd6236 -r aad37ffd7d58 .hgignore --- a/.hgignore Fri Jan 05 23:20:30 2018 +0100 +++ b/.hgignore Mon Jan 08 11:46:53 2018 +0100 @@ -14,3 +14,11 @@ ^docs/tutorials/.*\.rst$ \.ico$ tests/\.testtimes + +^docs/training/graphs/ +^docs/training/html/ +^docs/training/index.html +^docs/training/graphviz-images/ +^docs/training/img/ +^docs/training/output/ +^docs/training/pandocfilters/ diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/.netlify --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/.netlify Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,1 @@ +{"site_id":"cf023865-0eb1-49e9-951b-29555949abf0","path":"html/"} \ No newline at end of file diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/README.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/README.rst Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,63 @@ +============================= +Training supports +============================= + +Contributing +============ + +The main source for the supports is the `slides.md` but it doesn't contains +all the source. + +The `slides.md` file contains several snippets that are replaced by other +files at compilation time. + +For example: + +.. code:: markdown + + ~~~raw-file + output/fix-a-bug-base.log + ~~~ + +Will replace this three lines by the content of the file `output/fix-a-bug- +base.log` which is generated when running the .t test file (see below for +instruction how to do that). + +.. code:: markdown + + ~~~graphviz-file + graphs/fix-bug-1.dot + ~~~ + +Will replace this three lines by the svg rendering of the graphviz definition +in the file `graphs/fix-bug-1.dot`. This file is generated when running the .t +test file (see below for instruction how to do that). + + +Environment preparation +======================= + +This training supports needs pandoc to compile. + +You'll need a copy of the Mercurial source in order to generate the training +supports. + +You will also needs a functioning Python environment with the possibility to +use `pip install` with your current user. In doubt, you can use a `virtualenv +`. + +You can then run the `prepare.sh` script that will configure the environment +for you. + +Generating the supports +======================= + +First, you need to run a .t test file to generate a bunch of files. You can +run the test file with this command: + +`python /PATH/TO/MERCURIAL/tests/run-tests.py -l test-training.t` + +It should have generated files in at least two directories: `graphs` and +`output`. + +Finally, launch the `compile.sh` to generate the `index.html` output file. diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/compile.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/compile.sh Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,16 @@ +#!/bin/bash +set -eox pipefail + + +function compile { + pandoc \ + -s $1 \ + -o $2 \ + --toc --toc-depth=4 \ + -F pandocfilters/examples/graphviz.py -F mypandocfilters/graphviz-file.py -F mypandocfilters/raw-file.py \ + -t html5 \ + --template standalone.html --variable=template_css:uikit.css + +} + +compile slides.md index.html diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/deploy.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/deploy.sh Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,9 @@ +mkdir -p html + +cp index.html html/ +cp *.css html/ +cp *.js html/ +cp -R img html/ +cp -R graphviz-images/ html/ + +netlify deploy diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/draft.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/draft.md Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,1288 @@ +--- +author: Boris Feld +title: Changeset evolution +date: June 23, 2017 +--- + +# Why Evolve is the future? (TO CHANGE) + +Use hexagon or drop all of themes +Use old names +Replace hg amend by commit --amend + +Flow + +Basic - Feature - Tool / instability - command semantic + +Basic (local amend + local rebase) + +Stabilization -> Evolution + +Feature + +# Local amend + +## Amending commits + +We all makes mistake: + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fx bug[case"; + } +~~~ + +## Some times pass + +## Urgent Amend needed + +But it's easy to fix the fix: + +~~~ {.sh} +hg commit --amend -m "Fix bug" +~~~ + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + } +~~~ + +## So easy to do something wrong + +But wait you had local changes! And they get incorporated into the amend. + +## Too bad + +It's too late, they are gone! + + + +## HARD + +UNbundle, get the rev, strip + +## Never without Evolve! + + + + +## Let's try again! + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fx bug"; + } +~~~ + +## Evolve powa + +With evolve this time: + +~~~ {.sh} +hg commit --amend -m "Fix bug" +~~~ + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + } +~~~ + +## Ok what the difference? + +
+$> hg log -G
+@  changeset:   3:467de638a224
+|  tag:         tip
+|  parent:      0:852811e0e2a8
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:15:55 2017 +0200
+|  summary:     Fix bug
+|
+o  changeset:   0:852811e0e2a8
+   user:        Boris Feld <boris.feld@octobus.net>
+   date:        Wed Jun 21 14:15:55 2017 +0200
+   summary:     Root
+
+
+ +## The difference + +
+$> hg log -G --hidden
+@  changeset:   3:467de638a224
+|  tag:         tip
+|  parent:      0:852811e0e2a8
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:15:55 2017 +0200
+|  summary:     Fix bug
+|
+| x  changeset:   2:614cb09cc83d
+| |  user:        Boris Feld <boris.feld@octobus.net>
+| |  date:        Wed Jun 21 14:15:55 2017 +0200
+| |  summary:     temporary amend commit for e46245132d3d
+| |
+| x  changeset:   1:e46245132d3d
+|/   user:        Boris Feld <boris.feld@octobus.net>
+|    date:        Wed Jun 21 14:15:55 2017 +0200
+|    summary:     Fx bug
+|
+o  changeset:   0:852811e0e2a8
+   user:        Boris Feld <boris.feld@octobus.net>
+   date:        Wed Jun 21 14:15:55 2017 +0200
+   summary:     Root
+
+
+ +## Perf impact + +No strip == no cache bust, == faster + +# Local rebase + +## You are working on your branch + +~~~graphviz + digraph G { + rankdir="LR"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=feature]; + Parent -> "Feature"; + } +~~~ + +## More work + +~~~graphviz + digraph G { + rankdir="LR"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=feature]; + Parent -> "Feature" -> "Feature 2"; + } +~~~ + +## Pull + +~~~graphviz + digraph G { + rankdir="LR"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Trunk" -> "Trunk 2"; + + node[group=feature]; + Parent -> "Feature" -> "Feature 2"; + } +~~~ + +## Time to rebase + +~~~graphviz + digraph G { + rankdir="LR"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Trunk" -> "Trunk 2"; + + node[group=feature]; + "Trunk 2" -> "Feature" -> "Feature 2"; + } +~~~ + +## Without evolve + +
+@  changeset:   6:105f743d81c8
+|  tag:         tip
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:47:48 2017 +0200
+|  summary:     Feature2
+|
+o  changeset:   5:3966a515e569
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:47:48 2017 +0200
+|  summary:     Feature
+|
+o  changeset:   4:bd3d94325819
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:47:49 2017 +0200
+|  summary:     Trunk2
+|
+o  changeset:   3:120d3e4ce8b7
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:47:49 2017 +0200
+|  summary:     Trunk
+|
+o  changeset:   2:36db121866a2
+|  user:        Boris Feld <boris.feld@octobus.net>
+~  date:        Wed Jun 21 14:47:48 2017 +0200
+   summary:     Parent
+
+
+ +## With evolve + +
+@  changeset:   10:2c1a992b87c3
+|  tag:         tip
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature2
+|
+o  changeset:   9:751113c206d0
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature
+|
+o  changeset:   8:9f9f3db01630
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk2
+|
+o  changeset:   7:a5e9a3060e20
+|  parent:      4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk
+|
+| x  changeset:   6:a57f1852d740
+| |  branch:      feature
+| |  user:        Boris Feld <boris.feld@octobus.net>
+| |  date:        Wed Jun 21 14:50:39 2017 +0200
+| |  summary:     Feature2
+| |
+| x  changeset:   5:896dc0771e5e
+|/   branch:      feature
+|    user:        Boris Feld <boris.feld@octobus.net>
+|    date:        Wed Jun 21 14:50:39 2017 +0200
+|    summary:     Feature
+|
+o  changeset:   4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+~  date:        Wed Jun 21 14:50:39 2017 +0200
+   summary:     Parent
+
+
+ +# How does it works? + +## It's smart + + + +## Does Evolve only stores more changesets? (CHANGE) + +## Not only + +Remember our amend? + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fx bug"; + } +~~~ +
+ +
+ +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + } +~~~ +
+
+ +## More revisions + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fx bug"; + } +~~~ +
+ +
+ +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + node[group=obsolete]; + Parent -> "Fx bug"; + } +~~~ +
+
+ +## But hidden + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fx bug"; + } +~~~ +
+ +
+ +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Parent -> "Fx bug"; + } +~~~ +
+
+ +## Here is the smartness (change word)! + +~~~graphviz + digraph G { + rankdir="BT"; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Parent -> "Fix bug"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Parent -> "Fx bug"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "Fx bug" -> "Fix bug"; + } +~~~ + +## Obs markers + +Obs markers stores the relation between a changeset and its evolutions. + +XXX: Speak about META + +~~~graphviz + digraph G { + rankdir="BT"; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + node[group=obsolete, style="dotted, filled" fillcolor="#DFDFFF"]; + edge[dir=back, style=dotted, arrowtail=dot]; + "Predecessor" -> "Successor"; + + "Successor" [style="filled", fillcolor="#7F7FFF"]; + } +~~~ + + +# Phases + +## 3 phases + +Changesets can be in one of three phases: + +* Public +* Draft +* Secrets + +## Public + +The public phase holds changesets that have been exchanged publicly. + +Changesets in the public phase are expected to remain in your repository history and are said to be immutable. + +## Drafts + +The draft phase holds changesets that are not yet considered a part of the repository's permanent history. + +You can safely rewrite them. + +New commits are in the draft phase by default. + +## Secrets (hide) + +The secret phase holds changesets that you do not want to exchange with other repositories. + +Secret changesets are hidden from remote peers and will not be included in push operations. + +Manual operations or extensions may move a changeset into the secret phase. + +## Representation + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF"]; + + // Revisions + node[group=main]; + Public -> Draft -> Secret; + + Draft [shape="pentagon"]; + Secret [shape="square"]; + } +~~~ + +# Instability (add sub-titles, obsolete -> orphan, etc...) + +## Obsolete + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + + node[group=main]; + Root -> New; + node[group=obsolete]; + Root -> Obsolete; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + Obsolete -> New; + + Obsolete [fillcolor="#DFDFFF"]; + Root[shape="circle"]; + } +~~~ + +## Unstable + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + node[group=main]; + Root -> New; + node[group=obsolete]; + Root -> Obsolete -> Unstable; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + Obsolete -> New; + + Obsolete [fillcolor="#DFDFFF"]; + Unstable [fillcolor="#FF3535"]; + Root[shape="circle"]; + } +~~~ + +## Bumped + +## Divergent + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + Root -> Base; + Root -> Divergent1; + Root -> Divergent2; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + Base -> Divergent1; + Base -> Divergent2; + + Base [shape="pentagon", fillcolor="#DFDFFF"]; + Divergent1 [fillcolor="#FF3535"]; + Divergent2 [fillcolor="#FF3535"]; + Root[shape="circle"]; + } +~~~ + +# Topic + +# CHANGE TITLE (LATER IN THE FLOW) + +## Log on obsolete + +
+$> hg log -G
+o  changeset:   10:2c1a992b87c3
+|  tag:         tip
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature2
+|
+o  changeset:   9:751113c206d0
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature
+|
+o  changeset:   8:9f9f3db01630
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk2
+|
+o  changeset:   7:a5e9a3060e20
+|  parent:      4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk
+|
+| @  changeset:   6:a57f1852d740
+| |  branch:      feature
+| |  user:        Boris Feld <boris.feld@octobus.net>
+| |  date:        Wed Jun 21 14:50:39 2017 +0200
+| |  summary:     Feature2
+| |
+| x  changeset:   5:896dc0771e5e
+|/   branch:      feature
+|    user:        Boris Feld <boris.feld@octobus.net>
+|    date:        Wed Jun 21 14:50:39 2017 +0200
+|    summary:     Feature
+|
+o  changeset:   4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+~  date:        Wed Jun 21 14:50:39 2017 +0200
+   summary:     Parent
+
+
+ +## Log with hidden + +
+$ hg log -G --hidden
+@  changeset:   10:2c1a992b87c3
+|  tag:         tip
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature2
+|
+o  changeset:   9:751113c206d0
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Feature
+|
+o  changeset:   8:9f9f3db01630
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk2
+|
+o  changeset:   7:a5e9a3060e20
+|  parent:      4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+|  date:        Wed Jun 21 14:50:39 2017 +0200
+|  summary:     Trunk
+|
+| x  changeset:   6:a57f1852d740
+| |  branch:      feature
+| |  user:        Boris Feld <boris.feld@octobus.net>
+| |  date:        Wed Jun 21 14:50:39 2017 +0200
+| |  summary:     Feature2
+| |
+| x  changeset:   5:896dc0771e5e
+|/   branch:      feature
+|    user:        Boris Feld <boris.feld@octobus.net>
+|    date:        Wed Jun 21 14:50:39 2017 +0200
+|    summary:     Feature
+|
+o  changeset:   4:32253567b531
+|  user:        Boris Feld <boris.feld@octobus.net>
+~  date:        Wed Jun 21 14:50:39 2017 +0200
+   summary:     Parent
+
+
+ +## Obslog + +Behold our savior Obslog! + +## Obslog + +
+$> hg obslog -r 3
+o  c4414d4a5955 (3) Fix bug
+|
+x  9b5b4aa63d51 (1) Fx bug
+     rewritten by Boris Feld <boris.feld@octobus.net> (Wed Jun 21 14:50:38 2017 +0200) as c4414d4a5955
+
+
+ +
+$> hg obslog -r 6 --all --hidden
+@  2c1a992b87c3 (10) Feature2
+|
+x  a57f1852d740 (6) Feature2
+     rewritten by Boris Feld <boris.feld@octobus.net> (Wed Jun 21 14:50:39 2017 +0200) as 2c1a992b87c3
+
+
+ +Obslog is your next best friend! + +## Obslog + + + +# Evolve Basics behind the hood + +## Amend + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=main]; + Root -> "A"; + Root [shape="circle"]; + } +~~~ +
+ +
+To amend A: + + hg amend -m 'A1' +
+ +
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=main]; + Root -> "A1"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "A1"; + Root [shape="circle"]; + } +~~~ +
+
+ +## Amend bis + +It also works with: + + hg commit --amend -m 'A1' + + +## Prune + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=main]; + Root -> "A"; + Root [shape="circle"]; + } +~~~ +
+ +
+ +To prune A: + + hg prune -r "desc(A)" +
+ +
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + Root [shape="circle"]; + + // Revisions + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + } +~~~ +
+
+ + + +## Rebase + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> B; + node[group=main]; + Root -> "A"; + + Root [shape="circle"]; + } +~~~ +
+ +
+ +In order to rebase A on top of B; + + hg rebase -r "desc(A)" -d "desc(B)" + +
+ +
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> B -> "A'"; + + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "A'"; + + Root [shape="circle"]; + } +~~~ +
+
+ + +# More advanced + +## Fold + +
+
+ +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> A -> B; + + Root [shape="circle"]; + } +~~~ +
+ +
+ +To fold A and B: + + hg fold -r "desc(A)" -r "desc(B)" -m "C" + +
+ +
+ +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> C; + + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> A -> B; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "C"; + "B" -> "C"; + + Root [shape="circle"]; + } +~~~ + +
+
+ + +## Split + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> A; + + Root [shape="circle"]; + } +~~~ +
+ +
+ +Split in two: + + hg split -r "desc(A)" +
+ +
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> B -> C; + + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> A; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "C"; + "A" -> "B"; + + Root [shape="circle"]; + } +~~~ +
+
+ + +# Warning zone + +## Divergence + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> "A"; + + Root [shape="circle"]; + } +~~~ + +## Divergence + +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + // Revisions + node[group=branch]; + Root -> "B"; + + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "B"; + + Root [shape="circle"]; + } +~~~ +
+ +
+ +First amend: + + hg amend -m B; + +
+
+ + +## Divergence 2 + +
+ +
+ +Second amend: + + hg amend -m C + +
+ +
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, width=1, height=1, style="filled", fillcolor="#7F7FFF", shape="pentagon"]; + + Root; + + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + + // Revisions + node[group=branch, fillcolor="#7F7FFF", style="filled"]; + Root -> "C"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "C"; + + Root [shape="circle"]; + } +~~~ +
+
+ +## Result + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + node[group=main]; + Root -> "B"; + node[group=divergence]; + Root -> "C"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A"; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + A -> B; + A -> C; + + Root [shape="pentagon"]; + B [fillcolor="#FF3535"]; + C [fillcolor="#FF3535"]; + Root[shape="circle"]; + } +~~~ + +## That's gonna hurt! + +# Stabilization + +## Stabilization with amend + +~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + node[group=main]; + Root -> "A'"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A" -> B; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "A'"; + + B[fillcolor="#FF3535"]; + Root[shape="circle"]; + } +~~~ + +## Evolve! + +
+
+ +Stabilize repo: + + hg evolve --all +
+
+~~~graphviz + digraph G { + rankdir="BT"; + graph[splines=polyline]; + node[fixedsize=true, style="filled", width=1, height=1, fillcolor="#7F7FFF", shape="pentagon"]; + + node[group=main]; + Root -> "A'" -> "B'"; + node[group=obsolete, style="dotted, filled", fillcolor="#DFDFFF"]; + Root -> "A" -> B; + + // Obsolescence links + edge[dir=back, style=dotted, arrowtail=dot]; + "A" -> "A'"; + "B" -> "B'"; + + Root[shape="circle"]; + } +~~~ + +
+
+ +# Future is near! + +## Effect-flag + +Remember our obs-markers? + +They are great for evolution, but how do you know what changed between two evolutions? + +## Effect-flag + +Effect-flag are storing what changed between evolutions. You can view them with `obslog`, who else? + +## Effect-flag + +Does the meta only changed? + +
+o  5732d5ea6aa2 (2) Fix bug
+|
+@  aa3cd7ee52fc (1) Fx bug
+     rewritten(description) by Boris Feld <boris.feld@octobus.net> (Wed Jun 21 15:49:54 2017 +0200) as 5732d5ea6aa2
+
+
+ +## Or did the code changed? + +
+@  8f824718f3f7 (12) Fix the build
+|
+x  f9310b4b05e1 (10) Fix the build
+     rewritten(content) by Boris Feld <boris.feld@octobus.net> (Wed Jun 21 15:53:07 2017 +0200) as 8f824718f3f7
+
+
+ +## Or was rebased? + +
+o  ab709059df38 (9) Feature2
+|
+@  3d61cb9ab34f (5) Feature2
+     rewritten(branch, parent) by Boris Feld <boris.feld@octobus.net> (Wed Jun 21 15:53:06 2017 +0200) as ab709059df38
+
+
+ +## Obslog + + + +## Obsfate + +
+o  8f824718f3f7
+|
+| x  f39472eb8519
+| |    Obsfate: pruned by Boris Feld <boris.feld@octobus.net> (at 2017-06-21 15:53 +0200)
+| |
+| x  f9310b4b05e1
+|/     Obsfate: rewritten by Boris Feld <boris.feld@octobus.net> as 8f824718f3f7 (at 2017-06-21 15:53 +0200)
+|
+o  ab709059df38
+|
+o  b0d7c614e47d
+|
+o  d61083b45bba
+|
+o  50ebd46e2452
+|
+| @  3d61cb9ab34f
+| |    Obsfate: rewritten by Boris Feld <boris.feld@octobus.net> as ab709059df38 (at 2017-06-21 15:53 +0200)
+| |
+| x  1c6a75c00a45
+|/     Obsfate: rewritten by Boris Feld <boris.feld@octobus.net> as b0d7c614e47d (at 2017-06-21 15:53 +0200)
+|
+o  c1bdb750ab80
+|
+o  39752c0e48a4
+|
+| x  36744bfd9d65
+|/     Obsfate: rewritten by Boris Feld <boris.feld@octobus.net> as 39752c0e48a4 (at 2017-06-21 15:53 +0200)
+|
+o  7d12a4681f84
+
+ +## Obslog --patch + +
+$> hg obslog --patch
+x  19fb99aaa0d5 (3594) obslog: add a patch option
+|    rewritten(content) by Pierre-Yves David <pierre-yves.david@octobus.net> (Mon Jun 19 19:25:18 2017 +0200) as 81b01fe6db3b
+|      diff -r 19fb99aaa0d5 -r 81b01fe6db3b hgext3rd/evolve/obshistory.py
+|      --- a/hgext3rd/evolve/obshistory.py  Mon Jun 19 19:00:36 2017 +0200
+|      +++ b/hgext3rd/evolve/obshistory.py  Mon Jun 19 19:00:36 2017 +0200
+|      @@ -105,6 +105,10 @@
+|                   markerfm.plain('\n')
+|
+|                   # Patch
+|      +
+|      +# XXX-review: I find it a bit hacky always call showpatch and expect it to not
+|      +# XXX-review: show anything without --patch. I would prefer and explicite condition for
+|      +# XXX-review: calling showpatch.
+|                   self.showpatch(ctx, matchfn)
+|
+|                   self.hunk[ctx.node()] = self.ui.popbuffer()
+|      ...
+|
+| o  a788967aa800 (3593) obslog: clarify some sorting code
+| |
+x |  4c2be5027b23
+|/     rewritten(user) by Pierre-Yves David <pierre-yves.david@octobus.net> (Mon Jun 19 19:00:54 2017 +0200) as 19fb99aaa0d5
+|        (No patch available yet, context is not local)
+|
+x  5d04c9bfac7e
+|    rewritten(description, user, date, parent, content) by Pierre-Yves David <pierre-yves.david@octobus.net> (Mon Jun 19 19:00:36 2017 +0200) as 4c2be5027b23, a788967aa800
+|      (No patch available yet, context is not local)
+|
+x  8ddfd687cf57 (3559) obslog: add a patch option
+|    rewritten(parent) by Pierre-Yves David <pierre-yves.david@octobus.net> (Mon Jun 19 18:59:02 2017 +0200) as 5d04c9bfac7e
+|      (No patch available yet, succ is unknown locally)
+|
+x  27d388000e90 (3541) obslog: add a patch option
+     rewritten(content) by Boris Feld <boris.feld@octobus.net> (Mon Jun 19 18:40:16 2017 +0200) as 8ddfd687cf57
+
+ + +# Conclusion + +
+
+~~~graphviz + digraph G{} +~~~ +
+ +
+To stuff: + + hg +
+ +
+~~~graphviz + digraph G{} +~~~ +
+
diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/jquery.sticky-kit.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/jquery.sticky-kit.js Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,251 @@ +// Generated by CoffeeScript 1.9.2 + +/** +@license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net + */ + +(function() { + var $, win; + + $ = this.jQuery || window.jQuery; + + win = $(window); + + $.fn.stick_in_parent = function(opts) { + var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, parent_selector, recalc_every, sticky_class; + if (opts == null) { + opts = {}; + } + sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming; + if (offset_top == null) { + offset_top = 0; + } + if (parent_selector == null) { + parent_selector = void 0; + } + if (inner_scrolling == null) { + inner_scrolling = true; + } + if (sticky_class == null) { + sticky_class = "is_stuck"; + } + doc = $(document); + if (enable_bottoming == null) { + enable_bottoming = true; + } + fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) { + var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick; + if (elm.data("sticky_kit")) { + return; + } + elm.data("sticky_kit", true); + last_scroll_height = doc.height(); + parent = elm.parent(); + if (parent_selector != null) { + parent = parent.closest(parent_selector); + } + if (!parent.length) { + throw "failed to find stick parent"; + } + fixed = false; + bottomed = false; + spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("
"); + if (spacer) { + spacer.css('position', elm.css('position')); + } + recalc = function() { + var border_top, padding_top, restore; + if (detached) { + return; + } + last_scroll_height = doc.height(); + border_top = parseInt(parent.css("border-top-width"), 10); + padding_top = parseInt(parent.css("padding-top"), 10); + padding_bottom = parseInt(parent.css("padding-bottom"), 10); + parent_top = parent.offset().top + border_top + padding_top; + parent_height = parent.height(); + if (fixed) { + fixed = false; + bottomed = false; + if (manual_spacer == null) { + elm.insertAfter(spacer); + spacer.detach(); + } + elm.css({ + position: "", + top: "", + width: "", + bottom: "" + }).removeClass(sticky_class); + restore = true; + } + top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top; + height = elm.outerHeight(true); + el_float = elm.css("float"); + if (spacer) { + spacer.css({ + width: elm.outerWidth(true), + height: height, + display: elm.css("display"), + "vertical-align": elm.css("vertical-align"), + "float": el_float + }); + } + if (restore) { + return tick(); + } + }; + recalc(); + if (height === parent_height) { + return; + } + last_pos = void 0; + offset = offset_top; + recalc_counter = recalc_every; + tick = function() { + var css, delta, recalced, scroll, will_bottom, win_height; + if (detached) { + return; + } + recalced = false; + if (recalc_counter != null) { + recalc_counter -= 1; + if (recalc_counter <= 0) { + recalc_counter = recalc_every; + recalc(); + recalced = true; + } + } + if (!recalced && doc.height() !== last_scroll_height) { + recalc(); + recalced = true; + } + scroll = win.scrollTop(); + if (last_pos != null) { + delta = scroll - last_pos; + } + last_pos = scroll; + if (fixed) { + if (enable_bottoming) { + will_bottom = scroll + height + offset > parent_height + parent_top; + if (bottomed && !will_bottom) { + bottomed = false; + elm.css({ + position: "fixed", + bottom: "", + top: offset + }).trigger("sticky_kit:unbottom"); + } + } + if (scroll < top) { + fixed = false; + offset = offset_top; + if (manual_spacer == null) { + if (el_float === "left" || el_float === "right") { + elm.insertAfter(spacer); + } + spacer.detach(); + } + css = { + position: "", + width: "", + top: "" + }; + elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick"); + } + if (inner_scrolling) { + win_height = win.height(); + if (height + offset_top > win_height) { + if (!bottomed) { + offset -= delta; + offset = Math.max(win_height - height, offset); + offset = Math.min(offset_top, offset); + if (fixed) { + elm.css({ + top: offset + "px" + }); + } + } + } + } + } else { + if (scroll > top) { + fixed = true; + css = { + position: "fixed", + top: offset + }; + css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px"; + elm.css(css).addClass(sticky_class); + if (manual_spacer == null) { + elm.after(spacer); + if (el_float === "left" || el_float === "right") { + spacer.append(elm); + } + } + elm.trigger("sticky_kit:stick"); + } + } + if (fixed && enable_bottoming) { + if (will_bottom == null) { + will_bottom = scroll + height + offset > parent_height + parent_top; + } + if (!bottomed && will_bottom) { + bottomed = true; + if (parent.css("position") === "static") { + parent.css({ + position: "relative" + }); + } + return elm.css({ + position: "absolute", + bottom: padding_bottom, + top: "auto" + }).trigger("sticky_kit:bottom"); + } + } + }; + recalc_and_tick = function() { + recalc(); + return tick(); + }; + detach = function() { + detached = true; + win.off("touchmove", tick); + win.off("scroll", tick); + win.off("resize", recalc_and_tick); + $(document.body).off("sticky_kit:recalc", recalc_and_tick); + elm.off("sticky_kit:detach", detach); + elm.removeData("sticky_kit"); + elm.css({ + position: "", + bottom: "", + top: "", + width: "" + }); + parent.position("position", ""); + if (fixed) { + if (manual_spacer == null) { + if (el_float === "left" || el_float === "right") { + elm.insertAfter(spacer); + } + spacer.remove(); + } + return elm.removeClass(sticky_class); + } + }; + win.on("touchmove", tick); + win.on("scroll", tick); + win.on("resize", recalc_and_tick); + $(document.body).on("sticky_kit:recalc", recalc_and_tick); + elm.on("sticky_kit:detach", detach); + return setTimeout(tick, 0); + }; + for (i = 0, len = this.length; i < len; i++) { + elm = this[i]; + fn($(elm)); + } + return this; + }; + +}).call(this); diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/mypandocfilters/graphviz-file.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/mypandocfilters/graphviz-file.py Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +""" +Pandoc filter to process code blocks with class "graphviz" into +graphviz-generated images. + +Needs pygraphviz +""" + +import os +import sys + +import pygraphviz + +from pandocfilters import toJSONFilter, Para, Image, get_filename4code, get_caption, get_extension, get_value + +def graphviz(key, value, format, _): + if key == 'CodeBlock': + [[ident, classes, keyvals], file] = value + if "graphviz-file" in classes: + caption, typef, keyvals = get_caption(keyvals) + prog, keyvals = get_value(keyvals, u"prog", u"dot") + filetype = get_extension(format, "svg", html="svg", latex="pdf") + with open(file) as f: + code = f.read() + dest = get_filename4code("graphviz", code, filetype) + + if not os.path.isfile(dest): + g = pygraphviz.AGraph(string=code) + g.layout() + g.draw(dest, prog=prog) + sys.stderr.write('Created image ' + dest + '\n') + + return Para([Image([ident, ['graphviz'], keyvals], caption, [dest, typef])]) + +if __name__ == "__main__": + toJSONFilter(graphviz) diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/mypandocfilters/raw-file.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/mypandocfilters/raw-file.py Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,24 @@ +#!/usr/bin/env python +""" +Insert a raw-file as HTML code block +""" + +import panflute as pf + + +def action(elem, doc): + if isinstance(elem, pf.CodeBlock) and 'raw-file' in elem.classes: + filepath = elem.text + + with open(filepath, 'r') as fd: + content = fd.read() + + return pf.RawBlock('
%s
' % content, "html") + # elem.text = content + +def main(doc=None): + return pf.run_filter(action, doc=doc) + + +if __name__ == '__main__': + main() diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/prepare.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/prepare.sh Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,41 @@ +#!/bin/bash +set -euo pipefail + +# Prepare pandoc filters +if [ -d pandocfilters/.git ]; then + (cd pandocfilters && git remote update && git merge --ff-only) +else + git clone https://github.com/Lothiraldan/pandocfilters.git +fi + +pip2 install pandocfilters +pip2 install pygraphviz +pip2 install panflute +pip2 install hg+https://bitbucket.org/octobus/mercurial_docgraph +pip2 install hg-evolve + +mkdir -p graphs output + +CMD_NOT_FOUND=0 +check_command() { + cmd=$1 + if ! which "$cmd" >/dev/null 2>&1; then + echo "Error: command '$cmd' not found in \$PATH" + echo "Please install '$cmd'" + CMD_NOT_FOUND=1 + else + echo "$cmd command was found" + fi +} + +check_command pandoc +check_command aha + +if [ "$CMD_NOT_FOUND" -ne "0" ]; then + exit 1 +fi + +# Prepare directory for repositories generated by the training.t file +mkdir -p base-repos + +rm -Rf base-repos/* diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/scripts.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/scripts.js Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,157 @@ + +$(document).ready(function () { + /* uk-nav-parent-icon */ + $(".menu-begin ul:first-child").addClass('uk-nav uk-nav-side'); + $(".menu-begin ul:first-child").data('uk-nav', '{multiple:false}'); + $(".menu-begin ul:first-child").attr('data-uk-nav', '{multiple:false}'); + + // Parent click + $(".uk-parent > a").on('click', function (event) { + + event.preventDefault(); + $(".uk-parent > a").parent().removeClass('uk-active'); + $(this).parent().toggleClass('uk-active'); + + var hash = $(this).attr('href').split('#')[1]; + + // scroll.To(hash); + scrollTo(hash); + // $('body').scrollTo(hash); + // $('body').scrollTo(hash,{duration:'slow', offsetTop : '50'}); + $('a[href="' + hash + '"]').addClass('uk-active'); + }); + +}); + +function scrollTo(hash) { + + location.hash = "#" + hash; + +} + +function setStickyMenu () { + + var options = { + bottoming: false, + inner_scrolling: false + }; + + var sticky = ".uk-overflow-container"; + + + + + + + var width = $(window).width(); + + if (width >= 768) { + + $(".uk-nav > li").addClass('uk-parent'); + $(".menu-begin ul > li > ul").addClass('uk-nav-sub'); + + $('.uk-parent').removeClass('uk-open'); + $('.uk-parent div').addClass('uk-hidden'); + + $(sticky).stick_in_parent(options); + + } else { + + + $('.uk-parent').addClass('uk-open'); + + $('.uk-parent div').removeClass('uk-hidden'); + $('.uk-parent div').removeAttr('style'); + $('.uk-nav li').removeClass('uk-parent'); + + + $(sticky).trigger("sticky_kit:detach"); + } +}; + +$(document).ready(function(){ + + $(".pager").wrapInner( '
    ' ); + $(".pager a").wrap( '
  • ' ); + $(".pager b").wrap( '
  • ' ); + $(".pager b").wrapInner( '' ); + $(".pager b span").unwrap( ); + + // Normalize tables without style + $( "table" ).addClass( "uk-table" ); + + // Normalize tables without style + $( "form" ).addClass( "uk-form" ); + + + +}); + +$(document).ready(function () { + setStickyMenu(); + $(window).on('resize', function () { + setStickyMenu(); + }); +}); + + +$(document).ready(function () { + $( 'table' ).addClass( "table" ); +}); + +/* +var scroll = (function() { + + var elementPosition = function(a) { + return function() { + return a.getBoundingClientRect().top; + }; + }; + + var scrolling = function( elementID ) { + + var el = document.getElementById( elementID ), + elPos = elementPosition( el ), + duration = 400, + increment = Math.round( Math.abs( elPos() )/40 ), + time = Math.round( duration/increment ), + prev = 0, + E; + + function scroller() { + E = elPos(); + + if (E === prev) { + return; + } else { + prev = E; + } + + increment = (E > -20 && E < 20) ? ((E > - 5 && E < 5) ? 1 : 5) : increment; + + if (E > 1 || E < -1) { + + if (E < 0) { + window.scrollBy( 0,-increment ); + } else { + window.scrollBy( 0,increment ); + } + + setTimeout(scroller, time); + + } else { + + el.scrollTo( 0,0 ); + + } + } + + scroller(); + }; + + return { + To: scrolling + } + +})(); +*/ \ No newline at end of file diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/slides.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/slides.md Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,2447 @@ +--- +title: Changeset Evolution training +author: | + Boris Feld
    octobus.net
    +--- + +# Introduction + +## Welcome + +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. + +This training is designed to last approximately ¾ hours. + +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. + +```bash +$ hg clone https://bitbucket.org/octobus/evolve_training_repo +$ cd evolve_training_repo +``` + +Copy the provided hgrc to ensure a smooth training experience: + +```bash +$ cp hgrc .hg/hgrc +``` + +This training support will contains commands you are expected to type and launch. These commands will be in the following format: + +``` +$ COMMAND YOU ARE EXPECTED TO TYPE +output you are expecting to see +``` + +## Preliminary checks + +#### Mercurial version + +First let's use the following command to verify which version of Mercurial you are using: + +``` +$ hg --version +Mercurial Distributed SCM (version 4.4.2) +(see https://mercurial-scm.org for more information) + +Copyright (C) 2005-2017 Matt Mackall and others +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +``` + +You need at least Mercurial version `4.1`. If you don't have a recent enough version, please call your instructor. + +In order to activate the Evolve extension, add these lines in your user configuration (using the command `hg config --edit`): + +```ini +[extensions] +evolve = +topic = +``` + +#### Mercurial extensions + +Now let's check the version of your extensions. You will need all of these for the training: + +``` +$ hg --version --verbose +[...] + evolve external 7.1.0 + topic external 0.6.0 + rebase internal + histedit internal +``` + +# The Basics + + + +In this section, we are going to learn how to do basic history rewriting like rewriting a changeset or rebasing. + +### Amend + +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. + +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: + +``` +$ hg update typo +``` + +Check what the current repository looks like: + +~~~raw-file +output/fix-a-bug-base.log +~~~ + +~~~graphviz-file +graphs/fix-bug-1.dot +~~~ + +We have a root commit and another based on it. Double-check that you are on the right changeset with the `hg summary` command: + +~~~raw-file +output/fix-a-bug-base-summary.log +~~~ + +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. + +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): + +~~~ +$ hg commit --amend --message "Fix bug" +~~~ + +Let's take a look at the repository now: + +~~~raw-file +output/amend-after.log +~~~ + +~~~graphviz-file +graphs/fix-bug-2.dot +~~~ + +The logs before and after amending looks pretty similar, we are going to analyze the differences later. Did you catch the differences? + +### Rebase + + + +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: + +``` +$ hg update build/linuxsupport-v2 +``` + +~~~raw-file +output/rebase-before.log +~~~ + +~~~graphviz-file +graphs/rebase-before.dot +~~~ + + + +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: + +1. Explicitly select them using "--rev". +2. Use "--source" to select a root commit and include all of its descendants. +3. Use "--base" to select a commit; rebase will find ancestors and their descendants which are not also ancestors of the destination. +4. If you do not specify any of "--rev", "source", or "--base", rebase will use "--base ." as above. + +For this first example, we are gonna stays simple and explicitly select the commits we want to rebase with the `--rev` option. + +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: + +~~~raw-file +output/rebase.log +~~~ + +Now we have a nice, clean and flat history: + +~~~raw-file +output/rebase-after.log +~~~ + +~~~graphviz-file +graphs/rebase-after.dot +~~~ + +For more details about how to use the `hg rebase` command, see `hg help rebase`. + +### Under the hood + +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? + +Let's go back to our previous amend example. + +##### Amend + +When we did our amend, the status of the repository was: + +~~~raw-file +output/behind-the-hood-amend-before-hash-hidden.log +~~~ + +~~~graphviz-file +graphs/fix-bug-1.dot +~~~ + +And after the amend, the repository looked like: + +~~~raw-file +output/behind-the-hood-amend-after.log +~~~ + +~~~graphviz-file +graphs/fix-bug-2.dot +~~~ + +Do you see what is the difference? + +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? + +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: + +~~~raw-file +output/under-the-hood-amend-after-log-hidden.log +~~~ + +Notice the `x` in the log output which shows that a changeset is hidden. + +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: + +~~~graphviz-file +graphs/fix-bug-3.dot +~~~ + +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. + +##### Rebase + +**Successors** don't need to share anything with their **precursor**. They could have a different description message, user, date or even parents. + +Let's look at our earlier rebase example. The status before the rebase was: + +~~~raw-file +output/behind-the-hood-rebase-before-hash-hidden.log +~~~ + +~~~graphviz-file +graphs/rebase-before.dot +~~~ + +And after it was: + +~~~raw-file +output/behind-the-hood-rebase-after.log +~~~ + +~~~graphviz-file +graphs/rebase-after.dot +~~~ + +Did the same thing happen under the hood? + +Yes, exactly! The old changesets are still around, and they are just hidden. + +~~~raw-file +output/rebase-after-hidden.log +~~~ + +And we created three **obsolescence markers**, between each rebased commit and its **successor**: + +~~~graphviz-file +graphs/rebase-after-hidden.dot +~~~ + +### Evolution History + +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. + +As it is a new dimension of history, the classical Mercurial commands are not always the best to visualize this new history. + +We have seen that we can see the **hidden** changesets with the `--hidden` option on `hg log`: + +~~~raw-file +output/under-the-hood-amend-after-log-hidden.log +~~~ + +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): + +~~~raw-file +output/under-the-hood-amend-after-obslog.log +~~~ + +We can even print what changed between the two versions with the `--patch` option: + +~~~raw-file +output/under-the-hood-amend-after-obslog-patch.log +~~~ + +Obslog works both ways, as it can display **precursors** and **successors** with the `--all` option: + +```raw-file +output/under-the-hood-amend-after-obslog-no-all.log +``` + +~~~raw-file +output/under-the-hood-amend-after-obslog-all.log +~~~ + +~~~graphviz-file +graphs/fix-bug-3.dot +~~~ + +We can also use obslog on the changesets that we rebased earlier: + +~~~raw-file +output/under-the-hood-rebase-after-obslog.log +~~~ + +Why the `hg obslog` command is only showing two commits while we rebased three of them? + +```raw-file +output/under-the-hood-rebase-after-obslog-branch.log +``` + +And why the `hg obslog` command show disconnected graphs when asking for the obslog of the whole branch? + +~~~graphviz-file +graphs/rebase-after-hidden.dot +~~~ + +While these two obsolescence logs look very similar —because they show a similar change—, the two changesets log histories looked quite different. + +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. + +#### TortoiseHG + +TortoiseHG should be able to display obsolescence history for your repositories. + +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: + +![](img/thg-obs.png) + + + + +# Medium level + +## More rewriting commands + +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: + +### Amend + +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: + +- The `-e`/`--edit` option edits the commit message in an editor, which is not opened by default any more. +- The user and date can be updated to the current ones with the `-U`/`--current-user` and `-D`/`--current-date` options. +- More capabilities for rewriting the changeset. + +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. + +We are going to use it to rewrite the author of the changeset: + +``` +$ hg update amend-extract +``` + +We have two commits on the **amend-extract** branch: + +```raw-file +output/amend-extract-before.log +``` + +The user for the **amend-extract** head seems wrong, so let's fix it with the `hg amend` command: + +```raw-file +output/amend-user.log +``` + +Now let's check that the user has been amended correctly: + +```raw-file +output/amend-user-after-export.log +``` + +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. + +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. + +### Amend extract + +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. + +This is often used to remove a file or a line that is not meant to be in the current commit. + +As usual, we can either pass file paths or use the `-i` option to select which lines to extract. + +First, let's extract the badfile: + +```raw-file +output/amend-extract-badfile.log +``` + +Now let's check the status of the changeset and the working directory: + +```raw-file +output/amend-extract-badfile-after-export.log +``` + +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? + +Don't worry, the extracted files and lines still are in your working directory: + +```raw-file +output/amend-extract-badfile-after-status.log +``` + +As we are not going to need this file anymore, let's forget it with the `hg revert` command: + +```raw-file +output/amend-extract-badfile-after-revert.log +``` + +Also don't forget to remove the file: + +```bash +$ rm badfile +``` + +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: + +```raw-file +output/amend-extract.log +``` + +Much better! One last thing, as the line that we extracted is still in our working directory, just like when we extracted a file: + +```raw-file +output/amend-extract-after-status.log +``` + +```raw-file +output/amend-extract-after-diff.log +``` + +Don't forget to revert the change, as we are not going to need it any more: + +```raw-file +output/amend-extract-after-revert.log +``` + +Now let's take a look at the obsolescence history: + +```raw-file +output/amend-extract-after-obslog.log +``` + +The obslog is read from bottom to top: + +- First we rewrite the user, +- Then we extracted a whole file, +- Then we extracted a line from a file + +We have made three changes that generated three **successors**. + +```graphviz-file +graphs/amend-extract-after-hidden.dot +``` + +### Fold + +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: + +``` +$ hg update fold +``` + +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: + +```raw-file +output/fold-before.log +``` + +```graphviz-file +graphs/fold-before.dot +``` + +We all have been in a similar situation. Let's make a nice and clean changeset with fold: + +```raw-file +output/fold.log +``` + +That was easy! + +```raw-file +output/fold-after.log +``` + +```raw-file +output/fold-after-hidden.log +``` + +Can you imagine what the graphs will looks like? + +```raw-file +output/fold-after-hidden-obslog.log +``` + +```graphviz-file +graphs/fold-after-hidden.log +``` + +### Split + +Sometimes you want to `fold` changesets together, and sometimes you want to `split` a changeset into several ones, because it is too big. + +``` +$ hg update split +``` + +Evolve also has a command for that, `hg split`: + +```raw-file +output/split-before.log +``` + +```graphviz-file +graphs/split-before.dot +``` + +Split accepts a list of revisions and will interactively ask you how you want to split them: + +```raw-file +output/split.log +``` + +Now let's check the state of the repository: + +```raw-file +output/split-before-after.log +``` + +```graphviz-file +graphs/split-before-after-hidden.dot +``` + +It looks good. What about the obsolescence history? + +```raw-file +output/split-after-obslog.log +``` + +```raw-file +output/split-after-obslog-all.log +``` + +### Prune + +After rewriting and rebasing changesets, the next common use case for history rewriting is removing a changeset. + +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? + +The common solution is to mark the changeset as removed, and simulate the fact that it has been removed. + +This is why the Evolve extension is offering the `prune` command. Let's try to prune a changeset: + +``` +$ hg update prune +``` + +```raw-file +output/prune-before.log +``` + +```graphviz-file +graphs/prune-before.dot +``` + +`prune` is easy to use, just give it the revisions you want to prune: + +```raw-file +output/prune.log +``` + +Now the changeset is not visible any more: + +```raw-file +output/prune-after.log +``` + +But we can still access it with the `--hidden` option: + +```raw-file +output/prune-after-hidden.log +``` + +The output of `obslog` changes a bit when displaying pruned changesets: + +```raw-file +output/prune-after-obslog.log +``` + +```graphviz-file +graphs/prune-after-hidden.dot +``` + +### Histedit + +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: + +- 'pick' to [re]order a changeset +- 'drop' to omit changeset +- 'mess' to reword the changeset commit message +- 'fold' to combine it with the preceding changeset (using the later date) +- 'roll' like fold, but discarding this commit's description and date +- 'edit' to edit this changeset (preserving date) +- 'base' to checkout changeset and apply further changesets from there + +It's similar to the `git rebase -i` command. + +First, let's update to the right branch: + +``` +$ hg update histedit +``` + +```raw-file +output/histedit-before-log.log +``` + +```graphviz-file +graphs/histedit-before.dot +``` + +When launching the `hg histedit` command, an editor will show up with the following contents: + +```raw-file +output/histedit-no-edit.log +``` + +Swap the first two lines with your text editor: + +```raw-file +output/histedit-commands.log +``` + +Save and exit. Histedit will apply your instructions and finish. + +Let's see the state of the repository: + +```raw-file +output/histedit-after-log.log +``` + +```raw-file +output/histedit-after-log-hidden.log +``` + +```graphviz-file +graphs/histedit-after-hidden.dot +``` + + + +## Stack + +### Stack definition + +One big problem when working with a DVCS to identify and switch between the different features/bugfixes you are working on. + +### Named branches + +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. + +This solution has several advantages: + +- It's supported in all recent-ish Mercurial versions. +- It's simple to use. +- Most tools are supporting it. + +But it also has several disadvantages: + +- Branches do not disappear once they are merged. You need to explicitely close them with `hg commit --close-branch`. +- Branches are lost when rebasing them without the `--keepbranches` option of the `hg rebase` command. +- New branches needs to be explicitly pushed with the `--new-branch` option of the `hg push` command. + +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). + + + +### Stack + +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: + +``` +$ hg update typo +``` + +```raw-file +output/stack-typo.log +``` + +The stack output shows three important data: + +- First, which branch you are working on (a.k.a. the **current** branch). +- Then, all the commits that you are currently working on, with the current one highlighted. +- Finally, which commit your branch is based on (**b0**). + +This branch is not very interesting, so let's move to another one. + +``` +$ hg update build/linuxsupport-v2 +``` + +```raw-file +output/stack-rebase.log +``` + +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. + +### Stack movement + +There is an easy way to navigate in your stack, the `hg next` and `hg prev` commands: + +```raw-file +output/stack-rebase-prev-from-b3.log +``` + +```raw-file +output/stack-rebase-stack-b2.log +``` + +And now for the `hg next` command: + +```raw-file +output/stack-rebase-next-from-b2.log +``` + +```raw-file +output/stack-rebase.log +``` + +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: + +```raw-file +output/stack-rebase-export-b1.log +``` + +Or with the `hg update` command: + +```raw-file +output/stack-rebase-update-b2.log +``` + +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. + +```raw-file +output/stack-rebase-stack-b2.log +``` + +### Edit mid-stack + +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: + +```raw-file +output/stack-rebase-stack-b2.log +``` + +```raw-file +output/edit-mid-stack.log +``` + +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: + +```raw-file +output/edit-mid-stack-after-stack.log +``` + +`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**. + +For once, let's use log to see in detail in which situation we are: + +```raw-file +output/edit-mid-stack-after-log.log +``` + +```graphviz-file +graphs/edit-mid-stack-after.dot +``` + +How can we resolve this situation? It is actually very easy, and we are going to see how in the next section. + + + +## Basic instabilities + stabilization + +Instabilities are a normal step when using Evolve-powered workflows. Several tools are provided to fix them smoothly. + +#### Log + +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`: + +```raw-file +output/basic-stabilize-before-log-obsolete.log +``` + +A changeset can also be **unstable**, meaning that it could be subject to one or more **instabilities**: + +* **orphan**, a changeset whose an ancestor is **obsolete**. +* **content-divergent**, a changeset which has been rewritten in two different versions. +* **phase-divergent**, a changeset which has been both rewritten and published. + +For the moment, we will only see the **orphan** instability. We can display the **instabilities** of a commit with the `{instabilities}` template keyword: + +```raw-file +output/basic-stabilize-before-log-instabilities.log +``` + +Here we have also one **orphan** commit, which is the child of the **obsolete** commit. + +#### Evolve --list + +The `hg evolve` command has a `--list` option which can list all the instabilities of your repository. + +```raw-file +output/basic-stabilize-before-evolve-list.log +``` + +#### TortoiseHG + +Tortoise HG also has a nice support for displaying the instabilities of your repository: + +![](img/thg-mid-stack.png) + +If you want to filter to get a better view, you can use the *revset* `branch(build/linuxsupport-v2)`: + +![](img/thg-mid-stack-filter.png) + +#### Stabilization using `hg next --evolve` + +```raw-file +output/edit-mid-stack-after-stack.log +``` + +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: + +```raw-file +output/basic-stabilize-next-evolve.log +``` + +Here, it just rebased our old version of `b3` on top of the new version of `b2`. + +And now `hg stack` shows us a clean view again: + +```raw-file +output/basic-stabilize-after-stack.log +``` + +That's better! + +```graphviz-file +graphs/basic-stabilize-after-stack.dot +``` + + + +# Advanced + +## Moving change from one commit to another + +Create two commits: + +- The first one create a new file, add some content in it. +- The second one create another file and modify the first file. + +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. + +## Exchange + +Coming Soon™ + + + + + + + + + + + + + + + + diff -r 1cb549cd6236 -r aad37ffd7d58 docs/tutorial/standalone.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/tutorial/standalone.html Mon Jan 08 11:46:53 2018 +0100 @@ -0,0 +1,98 @@ + + + + + + + $if(title)$$title$$endif$ + +$if(template_css)$ + +$else$ + +$endif$ + + + + + + + + + $for(author-meta)$ + + $endfor$ + $if(date-meta)$ + + $endif$ + $if(title-prefix)$$title-prefix$ - $endif$$pagetitle$ + + $if(quotes)$ + + $endif$ + $if(highlighting-css)$ + + $endif$ + $for(css)$ + + $endfor$ + $if(math)$ + $math$ + $endif$ + $for(header-includes)$ + $header-includes$ + $endfor$ + + + + + +
    + + $if(title)$ +
    +
    +

    $title$

    + $if(date)$ +

    $date$

    + $endif$ + $for(author)$ +

    $author$

    + $endfor$ +
    +
    + $endif$ + +
    +
    +
    + +
    +
    + +
    +$body$ +
    +
    +$if(analytics)$ +