Mercurial > evolve
changeset 161:4e3f25ba5401
More doc and index with sphynx
author | Pierre-Yves David <pierre-yves.david@logilab.fr> |
---|---|
date | Tue, 20 Mar 2012 19:26:55 +0100 |
parents | 24346b78cd99 |
children | 1a6ae8d8f104 06c942f9bac6 |
files | .hgignore doc/evolve-faq.rst doc/from-mq.rst doc/obs-concept.rst doc/obs-implementation.rst doc/simple-tuto.t doc/vocabulary.rst docs/README docs/conf.py docs/evolve-faq.rst docs/evolve-intro.rst docs/from-mq.rst docs/glossary.rst docs/index.rst docs/obs-concept.rst docs/obs-implementation.rst tests/tutorial.t |
diffstat | 17 files changed, 1609 insertions(+), 1450 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Wed Mar 21 11:57:03 2012 +0100 +++ b/.hgignore Tue Mar 20 19:26:55 2012 +0100 @@ -1,2 +1,3 @@ syntax: re /figures/[^/]+\.png$ +^docs/build/
--- a/doc/evolve-faq.rst Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -======================================== -Introduction to the evolution extension -======================================== - -An history rewriting extension - -* Using the obsolete marker concept - -* Inspired from mq - -it is simple to enable:: - - $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/mutable-history/ - $ mutable-history/enable.sh > ~/.hgrc - - - -Quick Guide -===================================================================== - - - -Add a changeset: ``commit`` ------------------------------------------------------------- - -Just use commit as usual. - -Rewrite a changeset: ``amend`` ------------------------------------------------------------- - -A new command ``hg amend`` is added by the extension. it write a new changeset -combining working-directory parent changes and working directory parent changes. - -To understand what the result of amend will be I do use the two following -aliases [#]_:: - - # diff what amend will look likes - pdiff=diff --rev .^ - - # status what amend will look likes - pstatus=status --rev .^ - -It take various options to choose the user, the date and the branch of the -result. see ``hg help amend for detail`` - -This command can be invoqued on any mutable changeset even changeset with -children ! - - -.. note:: the amend command is very similar to mq's ``qrefresh``, a ``refresh`` - alias for amend is also available. But note that contrary to - ``qrefresh``, ``amend`` does not exclude changes on file not specified - on the command line. - - XXX add idank example - - -.. [#] (added by enable.sh) - - - -Move a changeset: ``graft`` ------------------------------------------------------------- - -the graft command introduced in 2.0 allows to "copy changes from other branches -onto the current branch" - -The graft command have been altered to be able to create an obsolete marker from -the copy result to the copy source, acting like changeset movement operation. -This is achieved using a new flag `-O` (or `old-obsolete`) [#]_. - - -XXX example - -.. warning:: when using graft --continue after conflict resolution you **MUST** - pass `-O` or `-o` flag again because they are not saved for now - - -.. [#] add this `-O` to graft instead of a dedicated command is probably - abusive. But this was very convenient for experimental purpose. - This will likely change in non experimental release. - -Delete a changeset: ``kill`` ------------------------------------------------------------- - -A new ``kill`` command allow to remove a changeset. - -Just use ``hg kill <some-rev>``. - -Moving within the history: ``up`` ``gdown`` and ``gup`` ------------------------------------------------------------- - -While working on mutable part of the history you often need to move between -mutable commit. - -You just need to use standard update to work with evolve. For convenience, you -can use ``hg gup`` to move to children commit or ``hg gdown`` to move to working -directory parent commit. - -.. note:: those command only exist for the convenience of getting qpush and qpop - feeling back. - - They are - -collapse changesets: ``amend`` ------------------------------------------------------------- - -you can use amend -c to collapse multiple changeset in a single one. - -Move multiple changesets: ``rebase`` ------------------------------------------------------------- - -You can still use rebase to move whole part of the changeset graph at once. - -.. warning:: Beware that rebasing obsolete changeset will result in new - conflicting version. - -Stabilize history: ``stabilize`` ------------------------------------------------------------- - -When you rewrite changeset with children without rewriting those children you -create *unstable* changeset and *suspended obsolete* changeset - -.. warning:: ``hg stabilize`` have no --continue to use after conflict - resolution. is conflict occurs use:: - - $ hg up -C . # cancel the failed merge - $ hg stabilize -n # go get a command to execute - -.. warning:: stabilization does not handle deletion yet. - -.. warning:: obsolete currently rely on secret changeset to not exchange - obsolete and unstable changeset. - - XXX details issue here - - -Fix my history afterward: ``kill -n`` ------------------------------------------------------------- - -sometime you need to create obsolete marker by hand. This may happen when -upstream applied some of you patches for example. - -you can use ``hg kill --new <new-changeset> <old-changeset>`` to add obsolete -marker. - -export to mq: ``synchronize`` ------------------------------------------------------------- - -Another extension allows to export - -view change to your file ------------------------------------------------------------- - -Another extension allows to export - -view diff from the last amend ------------------------------------------------------------- - -an odiff alias have been added by enable.sh - -:: - [alias] - odiff = diff --rev 'limit(obsparents(.),1)' --rev . - -view obsolete marker ------------------------------------------------------------- - -hgview is the only viewer that support this feature. you need an experimental -version available here: - - $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/hgview/ - -Prevent my unfinished changeset to get published ------------------------------------------------------------- - -The easiest way is to set them in the private phase - -Important Note -===================================================================== - -view change to your file ------------------------------------------------------------- - -extinct changeset are hidden using the *hidden* feature of mercurial. - -only hg log and hgview support it. hg glog or other visual viewer don't. - - - - - - - - - -
--- a/doc/from-mq.rst Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -Moving from mq to hg-evolution -=============================== - -Cheat sheet -------------- - -============================== ============================================ -mq command new equivalent -============================== ============================================ - -qseries ``log`` -qnew ``commit`` -qrefresh ``amend`` -qpop ``update`` or ``qdown`` -qpush ``update`` or ``gup`` sometimes ``stabilize`` -qrm ``kill`` -qfold ``amend -c`` (for now, ``collapse`` soon) -qdiff ``odiff`` - -qfinish -- -qimport -- - - -Replacement details ---------------------- - -hg qseries -``````````` - -All your work in progress are now real changeset all the time. - -You can then use standard log to display them. You can use phase revset to -display unfinished business only and template to have the same kind of compact -output qseries have. - -This will result in something like that:: - - [alias] - wip = log -r 'not public()' --template='{rev}:{node|short} {description|firstline}\n' - -hg qnew -```````` - -With evolve you handle standard changeset without additional overlay. - -Standard changeset are created using hg commit as usual. - - $ hg commit - -If you want to keep the "wip are not pushed" behavior, you are looking for -setting your changeset in the secret phase using the phase command. - -Note that you only need it for the first commit you want to be secret. Later -commit will inherit their parents phase. - -If you always want your new commit to be in the secret phase, your should -consider updating your configuration: - - [phases] - new-commit=secret - -hg qref -```````` - -A new command from evolution will allow you to rewrite the changeset you are -currently on. just call: - - $ hg amend - - -This command takes the same option than commit plus useful switch '-e' (--edit) -to edit the commit message. - -Amend have also a -c switch which allow you to make and explicit amending -commit before rewriting a changeset. - - $ hg record -m 'feature A' - # oups, I forget some stuff - $ hg record babar.py - $ hg amend -c .^ # .^ refer to "working directoy parent, here 'feature A' - -note: refresh is an alias for amend - -hg qpop -````````` - -the following command emule the behavior of hg qpop: - - $ hg gdown - -If you need to go back to an arbitrary commit you can just us: - - $ hg update - -.. note:: gdown and update allow movement with working directory changes applied - and gracefully merge them. - -hg qpush -```````` - -When you rewrite changeset, descendant of rewritten changeset are marked as -"out of sync". You new to rewrite them on top of the new version of their -ancestor. - -The evolution extension add a command to rewrite the next changeset: - - $ hg stabilize - -You can also decide to do it manually using - - $ hg graft -O <old-version> - -or - - $ hg rebase -r <revset for old version> -d . - -note: using graft allow you to pick the changeset you want next as the --move -option of qpush do. - - -hg qrm -``````` - -evolution introduce a new command to mark a changeset as "not wanted anymore". - - $ hg kill <revset> - -hg qfold -````````` - - -:: - - $ hg up <top changeset> - $ amend --edit -c <bottom changeset> - - -or later:: - - $ hg collapse # XXX not implemented - - $ hg rebase --collapse # XXX not tested - - -hg qdiff -````````` - -``odiff`` is an alias for `hg diff -r .^` it works as qdiff event outside mq. - - - -hg qfinish and hg qimport -```````````````````````````` - -Is not useful anymore if you want to controll exchange and mutability of -changeset see the phase feature
--- a/doc/obs-concept.rst Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -========================= -Obsolete concept -========================= - - -Obsolete marker is a powerful concept that allow mercurial to safely handle -history rewriting operations. It is a new type of relation between Mercurial -changesets that track the result of history rewriting operations. - -This concept is simple to define and provides a very solid base to: - - -- Very fast history rewriting operations, - -- auditable and reversible history rewritting process, - -- clean final history, - -- share and collaborate on mutable part of the history, - -- gracefully handle history rewriting conflict, - -- allows various history rewriting UI to collaborate with a underlying common API. - - ------------------------------------------------------ -Basic concept ------------------------------------------------------ - - -Every history rewriting operation stores the information that old rewritten -changesets has newer version available in a set of changeset. - -This simple rules allows to express any possible history rewriting operation: - - - - -.. figure:: ./figures/example-1-update.png - - *Updating* a changeset - - Create one obsolete marker: ``([A'] obsolete A)`` - - - -.. figure:: ./figures/example-2-split.png - - *Splitting* a changeset in multiple one - - Create one obsolete marker ``([B1, B2] obsolete B)]`` - - -.. figure:: ./figures/example-3-merge.png - - *Merging* multiple changeset in a single one - - Create two obsolete markers ``([C] obsolete A), ([C] obsolete B)`` - -.. figure:: ./figures/example-4-reorder.png - - *Moving* changeset around - - Reordering those two changesets need two obsolete markers: - ``([A'] obsolete A), ([B'] obsolete B)`` - - - -.. figure:: ./figures/example-5-delete.png - - *Removing* a changeset: - - One obselete marker ``([] obsolete B)`` - - -To conclude, a single obsolete marker express a relation from **0..n** new -changesets to **1** old changeset. - ------------------------------------------------------ -Basic Usage ------------------------------------------------------ - -Obsolete markers create a perpendicular history: **a versionned version of the -changeset graph**. This means that we can have the same feature we have for -versioned files but applied to changeset: - -First: we can display a **coherent view** of the history graph with only a -single version of your changeset are displayed by the UI. - -Second, because obsolete changeset content are still **available**. You can - - * **browse** the content of your obsolete commit, - - * **compare** newer and older version of a changeset, - - * **restore** content of previously obsolete changeset. - -Finally, obsolete marker can be **exchanged between repositories**. You are able to -share the result on your history rewriting operation with other and **collaborate -on mutable part of the history**. - -Conflicting history rewriting operation can be detected and **resolved** as easily -as conflicting changes on file. - - ------------------------------------------------------ -Detecting and solving tricky situation ------------------------------------------------------ - -History rewriting can lead to complex situation. Obsolete marker introduce a -simple representation this complex reality. But people using complex workflow -will one day or another you have to face the intrinsics complexity of some -situation. - -This section describe possible situations, define precise set of changesets -involved in such situation and explains how error case can we automatically -resolved using available information. - - -obsolete changesets -```````````````````` - -Old changesets left behind by obsolete operation are said **obsolete**. - -With current version of mercurial, this *obsolete* part is stripped from the -repository before the end of every rewritting operation. - -.. figure:: ./figures/error-obsolete.png - - Rebasing `B` and `C` on `A` (as `B'`, `C'`) - - This rebase operation added two obsolete markers from new changesets to old - changesets. These Two old changesets are now part of the *obsolete* part of the - history. - -In most case the obsolete set will be fully hidden to both UI and discovery so -user do not have to care about them unless he wants to audit history rewriting -operation. - -Unstable changesets -``````````````````` - -While exploring obsolete marker possibility a bit further you way end up with -*obsolete* changeset with *non-obsolete* children. There is two common ways to -achieve this: - -* Pull a changeset based of an old version of a changeset [#]_. - -* Use a partial rewriting operation. For example amend on a changeset with - childrens. - -*Non-obsolete* changeset based on *obsolete* one are said **unstable** - -.. figure:: ./figures/error-unstable.png - - Amend `A` into `A'` leaving `B` behind. - - In this situation we can not consider `B` as *obsolete*. But we have all - necessary data to detect `B` as an *unstable* branch of the history because - its parent `A` is *obsolete*. In addition, we have enough data to - automatically resolve this instability: we know that the new version of `B` - parent (`A`) is `A'`, We can deduce that we should rebase `B` on `A'` to get - a stable history again. - -Proper warning should be issued when part of the history become unstable. UI -will be able to use the obsolete marker to automatically suggest resolution to -the user of even carry them out for him. - - -XXX details automatic resolution for - -* movement - -* handling deletion - -* handling split on multiple head - - -.. [#] For this to happen one needs to explicitly enable exchange of draft - changeset. See phase help for details. - -The two part of the obsolete set -`````````````````````````````````````` - -The previous section show that it could be two kinds of *obsolete* changeset: - - -* *obsolete* changeset with no or *obsolete* only descendants, said **extinct**. - -* *obsolete* changeset with *unstable* descendants, said **suspended**. - - -.. figure:: ./figures/error-extinct.png - - Amend `A` and `C` leaving `B` behind. - - In this example we have two *obsolete* changesets: `C` with no *unstable* - children is *extinct*. `A` with *unstable* descendant (`B`) is *suspended*. - `B` is *unstable* as before. - - -Because nothing outside the obsolete set default on *extinct* changesets, they -can be safely hidden in the UI and even garbage collected. *Suspended* changeset -have to stay visible and available until they unstable descendant are rewritten -in stable version. - - -Conflicting rewriting -`````````````````````` - -If people start to concurrently edit the same part of the history they will -likely meet conflicting situation when a changeset have been rewritten in two -different versions. - - -.. figure:: ./figures/error-conflicting.png - - Conflicting rewriting of `A` into `A'` and `A''` - -This kind of conflict is easy to detect with obsolete marker because an obsolete -changeset have more than one new version. It may be seen as the multiple heads -case Mercurial warn you about on pull. It is resolved the same way by a merge of -A' and A'' that will keep the same parent than `A'` and `A''` with two obsolete -markers pointing to both `A` and `A'` - -.. warning:: TODO: Add a schema of the resolution. (merge A' and A'' with A as - ancestor and graft the result of A^) - -Allowing multiple new changesets to obsolete a single one allow to distinct a -splitted changeset from history rewriting conflict. - -Reliable history -`````````````````````` - -Obsolete marker really help to smooth rewriting operation process. However they -do not change the fact that **you should only rewrite the mutable part of the -history**. The phase concept enforce this rules by explicitly defining a -public immutable set of changeset. Rewriting operation refuse to work on -public changeset, but they is still some corner case where changesets -rewritten in the past are made public. - -Special rules apply for obsolete marker pointing to public changeset - -* Public changesets are excluded from the obsolete set (public changeset are - never hidden or candidate to garbage collection) - -* *newer* version of public changeset are said **latecomer** and highlighted as - error case. - - -Solving such error is easy. Because we know what changeset a *latecomer* try to -rewrite, we can easily compute a smaller changeset containing only the change -from the old *public* to the new *latecomer*. - - -.. warning:: add a schema -
--- a/doc/obs-implementation.rst Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ - -.. warning:: This document is still in heavy work in progress - ------------------------------------------------------ -Various technical details ------------------------------------------------------ - -Some stuff that worse to note. some may deserve their own section later. - -storing old changeset -`````````````````````` - -The new general delta format allow a very efficient storage of two very similar -changesets. Storing obsolete childrens using general delta takes no more place -than storing the obsolete diff. Reverted file will even we reused. The whole -operation will take much less space the strip backup. - - -Abstraction from history rewriting UI -``````````````````````````````````````````` - -How Mercurial handle obsolete marker is independent from who decide to create -them and what actual operation solve error case. Any of the existing history -rewriting UI (rebase, mq, histedit) can lay obsolete marker and resolve -situation created by other. To go further a hook system of obsolete marker -creation would allow each mechanism to collaborate with other though a standard -and central mechanism. - - -Obsolete marker storage -``````````````````````````` - -Obsolete marker will most likely be stored outside standard history. They are -multiple reasons for that: - - -First, obsolete markers are really perpendicular to standard history there is not -strong reason to include it here other than convenience. - -Second, storing obsolete marker inside standard history means: - - -* A changeset must be created every time an obsolete relation is added. Very - inconvenient for delete operation. - -* Obsolete marker must be forged at the creation of the new changeset. This - is very inconvenient for split operation. And in general it become - complicated to fix history afterward in particular when working with older - client. - -Storing obsolete marker outside history have several pro: - -* It ease Exchange of obsolete marker without unnecessary obsolete changeset content - -* It allow tuning the actual storage and protocol exchange while maintaining - compatibility with older client through the wire (as we do the repository - format) - -* ease the exchange of obsolete related information during discovery to exchange - obsolete changeset relevant to conflict resolution. Exchanging such - information deserve a dedicated protocol. - -Persistent -``````````````````````` - -*Extinct* changeset and obsolete marker will most likely be garbage collected as -some point. However, archive server may decide to keep them forever in order to -keep a fully auditable history in it's finest conception. - - ------------------------------------------------------ -Current status ------------------------------------------------------ - -An experimental implementatione exists. What have been done so far. - - -* 1-1 obsolete marker stored outside history, - -* compute obsolete-tip - -* obsolete marker exchange through pushkey, - -* compute obsolete, unstable, extinct and suspended set. - -* hidden extinct changesets for UI. - -* Use secret phase to remove from discovery obsolete and unstable changeset (to - be improved soon) - -* alter rebase to use obsolete marker instead of stripping. (XXX break --keep for now) - -* Have an experimental mq-like extension to rewrite history (more on that later) - -* Have an extension to update and mq repository according evolution of standard (more on that later) -
--- a/doc/simple-tuto.t Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,702 +0,0 @@ -Mutable History and collaboration -===================================================================== - - -History mutation -===================== - -.. Albert Beugras - -.. René de Robert - - -Here is small introduction of - -Single Developer Usage -====================== - -This tutorial shows how to use evolution to replace the basics of *mq*. - - -Amending a changeset ---------------------- - - -First there is some setup phase you will understand later. - -there is a local repository and a remote one. - -Please close your eyes. - - $ hg init local - $ cat >> local/.hg/hgrc << EOF - > [paths] - > remote = ../remote - > [ui] - > user = Albert Beugras - > [diff] - > git = 1 - > [alias] - > amend = amend -d '0 0' - > tlog = log --template "{node|short}: '{desc}'\n" - > ttlog = log --template "{node|short}: '{desc}' ({state})\n" - > tglog = log -G --template "{node|short}: '{desc}' {branches}\n" - > [extensions] - > hgext.graphlog= - > hgext.rebase= - > EOF - $ echo "states=$(echo $(dirname $TESTDIR))/hgext/states.py" >> local/.hg/hgrc - $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> local/.hg/hgrc - $ echo "evolution=$(echo $(dirname $TESTDIR))/hgext/evolution.py" >> local/.hg/hgrc - $ hg init remote - $ cat >> remote/.hg/hgrc << EOF - > [paths] - > local = ../local - > [ui] - > user = René de Robert - > [diff] - > git = 1 - > [alias] - > amend = amend -d '0 0' - > tlog = log --template "{node|short}: '{desc}' {branches}\n" - > ttlog = log --template "{node|short}: '{desc}' {state}\n" - > tglog = log -G --template "{node|short}: '{desc}' {branches}\n" - > [extensions] - > hgext.graphlog= - > hgext.rebase= - > EOF - $ echo "states=$(echo $(dirname $TESTDIR))/hgext/states.py" >> remote/.hg/hgrc - $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> remote/.hg/hgrc - $ echo "evolution=$(echo $(dirname $TESTDIR))/hgext/evolution.py" >> remote/.hg/hgrc - $ cd local - -You can reopen you eyes. - -Now we make a first version of our shopping list. - - $ cat >> shopping << EOF - > Spam - > Whizzo butter - > Albatross - > Rat (rather a lot) - > Jugged fish - > Blancmange - > Salmon mousse - > EOF - $ hg commit -A -m "Monthy Python Shopping list" - adding shopping - -We share this first version with the outside. - - $ hg push remote - pushing to $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 1 changesets with 1 changes to 1 files - -Later I add additional item to my list - - $ cat >> shopping << EOF - > Egg - > Suggar - > Vinegar - > Oil - > EOF - $ hg commit -m "adding condiment" - $ cat >> shopping << EOF - > Bananos - > Pear - > Apple - > EOF - $ hg commit -m "adding fruit" - -I now have the following history: - - $ hg tlog - d85de4546133: 'adding fruit' - 4d5dc8187023: 'adding condiment' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - -But, I just notice, I made a typo in Banana. - - $ hg export tip - # HG changeset patch - # User test - # Date 0 0 - # Node ID d85de4546133030c82d257bbcdd9b1b416d0c31c - # Parent 4d5dc81870237d492284826e21840b2ca00e26d1 - adding fruit - - diff --git a/shopping b/shopping - --- a/shopping - +++ b/shopping - @@ -9,3 +9,6 @@ - Suggar - Vinegar - Oil - +Bananos - +Pear - +Apple - -hopefully. I can use hg amend to rewrite my faulty changeset! - - $ sed -i'' -e s/Bananos/Banana/ shopping - $ hg diff - diff --git a/shopping b/shopping - --- a/shopping - +++ b/shopping - @@ -9,6 +9,6 @@ - Suggar - Vinegar - Oil - -Bananos - +Banana - Pear - Apple - $ hg amend - abort: can not rewrite immutable changeset d85de4546133 - [255] - -By default all changeset are considered "published" and can't be rewrittent. - - $ hg ttlog - -You need to enable a mutable state in your repo the "ready" one - - $ hg states ready --clever - $ hg ttlog - d85de4546133: 'adding fruit' (ready) - 4d5dc8187023: 'adding condiment' (ready) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - -Notice that changeset you already shared with the outside have been keep -published. - -The changeset we want to rewrite is now in a mutable state. - - $ hg amend - -A new changeset with the right diff replace the wrong one. - - $ hg tlog - 0cacb48f4482: 'adding fruit' - 4d5dc8187023: 'adding condiment' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - $ hg export tip - # HG changeset patch - # User test - # Date 0 0 - # Node ID 0cacb48f44828d2fd31c4e45e18fde32a5b2f07b - # Parent 4d5dc81870237d492284826e21840b2ca00e26d1 - adding fruit - - diff --git a/shopping b/shopping - --- a/shopping - +++ b/shopping - @@ -9,3 +9,6 @@ - Suggar - Vinegar - Oil - +Banana - +Pear - +Apple - -Getting Ride of branchy history ----------------------------------- - -While I was working on my list. someone help made a change remotly. - -close your eyes - - $ cd ../remote - $ hg up -q - $ sed -i'' -e 's/Spam/Spam Spam Spam/' shopping - $ hg ci -m 'SPAM' - $ cd ../local - -open your eyes - - $ hg pull remote - pulling from $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 1 changesets with 1 changes to 1 files (+1 heads) - (run 'hg heads .' to see heads, 'hg merge' to merge) - -I now have a new heads. Note that the remote head is immutable - - $ hg ttlog - 9ca060c80d74: 'SPAM' (published) - 0cacb48f4482: 'adding fruit' (ready) - 4d5dc8187023: 'adding condiment' (ready) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - $ hg tglog -r "::(9ca060c80d74 + 0cacb48f4482)" - o 9ca060c80d74: 'SPAM' - | - | @ 0cacb48f4482: 'adding fruit' - | | - | o 4d5dc8187023: 'adding condiment' - |/ - o 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -instead of merging my head with the new one. I'm going to rebase my work - - $ hg diff - $ hg rebase -d 9ca060c80d74 -s 4d5dc8187023 - merging shopping - merging shopping - merging shopping - merging shopping - - -My local work is now rebase on the remote one. - - $ hg kill e7a71e229632 ad97bbd3e37d # XXX fix me instead - $ hg ttlog - 387187ad9bd9: 'adding fruit' (ready) - dfd3a2d7691e: 'adding condiment' (ready) - 9ca060c80d74: 'SPAM' (published) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - $ hg tglog -r '::.' - @ 387187ad9bd9: 'adding fruit' - | - o dfd3a2d7691e: 'adding condiment' - | - o 9ca060c80d74: 'SPAM' - | - o 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -Removing changeset ------------------------- - -I add new item to my list - - $ cat >> shopping << EOF - > car - > bus - > plane - > boat - > EOF - $ hg ci -m 'transport' - $ hg ttlog - d58c77aa15d7: 'transport' (ready) - 387187ad9bd9: 'adding fruit' (ready) - dfd3a2d7691e: 'adding condiment' (ready) - 9ca060c80d74: 'SPAM' (published) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - -I have a new commit but I realize that don't want it. (transport shop list does -not fit well in my standard shopping list) - - $ hg kill . # . is for working directory parent. - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - working directory now at 387187ad9bd9 - -The silly changeset is gone. - - $ hg ttlog - 387187ad9bd9: 'adding fruit' (ready) - dfd3a2d7691e: 'adding condiment' (ready) - 9ca060c80d74: 'SPAM' (published) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - -Reordering changeset ------------------------- - - -We create two changeset. - - - $ cat >> shopping << EOF - > Shampoo - > Toothbrush - > ... More bathroom stuff to come - > Towel - > Soap - > EOF - $ hg ci -m 'bathroom stuff' -q # XXX remove the -q - - $ sed -i'' -e 's/Spam/Spam Spam Spam/g' shopping - $ hg ci -m 'SPAM SPAM' - $ hg ttlog - c48f32fb1787: 'SPAM SPAM' (ready) - 8d39a843582d: 'bathroom stuff' (ready) - 387187ad9bd9: 'adding fruit' (ready) - dfd3a2d7691e: 'adding condiment' (ready) - 9ca060c80d74: 'SPAM' (published) - 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) - -.. note: don't amend changeset 7e82d3f3c2cb or 9ca060c80d74 as they are -immutable. - -I now want to push to remote all my change but the bathroom one that i'm not totally happy with yet. - -To be able to push "SPAM SPAM" I need a version of "SPAM SPAM" not children of "bathroom stuff" - -You can use rebase or relocate for that: - - $ hg relocate 'p1(8d39a843582d)' --traceback - merging shopping - $ hg tglog -r '::(. + 8d39a843582d)' - @ 02e33960e937: 'SPAM SPAM' - | - | o 8d39a843582d: 'bathroom stuff' - |/ - o 387187ad9bd9: 'adding fruit' - | - o dfd3a2d7691e: 'adding condiment' - | - o 9ca060c80d74: 'SPAM' - | - o 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -We have a new SPAM SPAM version without the bathroom stuff - - $ grep Spam shopping # enouth spamm - Spam Spam Spam Spam Spam Spam Spam Spam Spam - $ grep Toothbrush shopping # no Toothbrush - [1] - $ hg export . - # HG changeset patch - # User test - # Date 0 0 - # Node ID 02e33960e937ad1bd59241ebdafd7a2494240ddf - # Parent 387187ad9bd9d8f9a00a9fa804a26231db547429 - SPAM SPAM - - diff --git a/shopping b/shopping - --- a/shopping - +++ b/shopping - @@ -1,4 +1,4 @@ - -Spam Spam Spam - +Spam Spam Spam Spam Spam Spam Spam Spam Spam - Whizzo butter - Albatross - Rat (rather a lot) - -we can now push our change: - - $ hg push -r . remote - pushing to $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 3 changesets with 3 changes to 1 files - -for simplicity shake we relocate the bathroom changeset - - $ hg relocate -r 8d39a843582d 02e33960e937 - merging shopping - - -Splitting change ------------------- - -To be done (currently achieve with "two commit + debugobsolete") - -Collapsing change ------------------- - -To be done (currently achieve with "revert + debugobsolete" or "rebase --collapse") - -collaboration -==================== - - -sharing mutable changeset ----------------------------- - -To share mutable changeset with other just check that both have the "ready" -state activated. Otherwise you will get the previously observe behavior where -exchanged changeset are automatically published. - - $ cd ../remote - $ hg states - published - -The remote repository have only the immutable "published" state activated. Any -changeset echanged from "local" to "remote" will be set in the publised state: - - $ hg -R ../local push -f remote # XXX we should pull but the support is awful - pushing to $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 1 changesets with 1 changes to 1 files - $ hg ttlog - a3515e5d0332: 'bathroom stuff' published - 02e33960e937: 'SPAM SPAM' published - 387187ad9bd9: 'adding fruit' published - dfd3a2d7691e: 'adding condiment' published - 9ca060c80d74: 'SPAM' published - 7e82d3f3c2cb: 'Monthy Python Shopping list' published - - - -We do not want to publish the "bathroom changeset". Let's rollback the last transaction - - $ hg rollback - repository tip rolled back to revision 4 (undo push) - working directory now based on revision 1 - $ hg ttlog - 02e33960e937: 'SPAM SPAM' published - 387187ad9bd9: 'adding fruit' published - dfd3a2d7691e: 'adding condiment' published - 9ca060c80d74: 'SPAM' published - 7e82d3f3c2cb: 'Monthy Python Shopping list' published - $ rm ../local/.hg/states/published-heads # XXX USE --exact - $ hg -R ../local publish 02e33960e937 # XXX FIX THE BUG - -To enable the mutable "ready" state in a repository, use the states command. - - $ hg states ready - $ hg states - published - ready - -I can nom exchange mutable changeset between "remote" and "local" repository. - - $ hg pull local # XXX We pull too much stuff - pulling from $TESTTMP/local - searching for changes - adding changesets - adding manifests - adding file changes - added 10 changesets with 10 changes to 1 files (+5 heads) - (run 'hg heads' to see heads, 'hg merge' to merge) - $ hg ttlog - a3515e5d0332: 'bathroom stuff' ready - 02e33960e937: 'SPAM SPAM' published - 387187ad9bd9: 'adding fruit' published - dfd3a2d7691e: 'adding condiment' published - 9ca060c80d74: 'SPAM' published - 7e82d3f3c2cb: 'Monthy Python Shopping list' published - -Rebasing out-of-sync change after update ----------------------------------------------- - -Remotely someone add a new changeset on top of our mutable "bathroom" on. - - $ hg up a3515e5d0332 -q - $ cat >> shopping << EOF - > Giraffe - > Rhino - > Lion - > Bear - > EOF - $ hg ci -m 'animals' -q # XXX remove the -q - -While this time locally, we rebase the updated the "bathroom changeset" - - $ cd ../local - $ hg up a3515e5d0332 -q - $ sed -i'' -e 's/... More bathroom stuff to come/Bath Robe/' shopping - $ hg amend - $ hg tlog - 962d3a7d27ad: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -When we pull from remote again we get an unstable state! - - $ hg pull remote - pulling from $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 1 changesets with 1 changes to 1 files (+1 heads) - (run 'hg heads .' to see heads, 'hg merge' to merge) - $ hg tlog - 0b061760b677: 'animals' - 962d3a7d27ad: 'bathroom stuff' - a3515e5d0332: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - -The new changeset "animal" is based one an old changeset of "bathroom". You can -see both version showing up the log. - - $ hg tglog -r '::(962d3a7d27ad + 0b061760b677)' - o 0b061760b677: 'animals' - | - | @ 962d3a7d27ad: 'bathroom stuff' - | | - o | a3515e5d0332: 'bathroom stuff' - |/ - o 02e33960e937: 'SPAM SPAM' - | - o 387187ad9bd9: 'adding fruit' - | - o dfd3a2d7691e: 'adding condiment' - | - o 9ca060c80d74: 'SPAM' - | - o 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -In hgviewn there is a nice doted relation highlighting 962d3a7d27ad is a new -version of a3515e5d0332. this is not yet ported to graphlog. - -To resolve this unstable state, you need to relocate 0b061760b677 onto -962d3a7d27ad the "hg evolve" will make the thinking for you and suggest it to -you. - - $ hg evolve - hg relocate --rev 0b061760b677 962d3a7d27ad - -Let's do it - - $ hg relocate --rev 0b061760b677 962d3a7d27ad - merging shopping - -The old vesion of bathroom is hidden again now. - - $ hg tlog - 39a85a192689: 'animals' - 962d3a7d27ad: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - -We can push this evolution to remote - - $ hg push -f remote # XXX should not require -f - pushing to $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 2 changesets with 2 changes to 1 files (+1 heads) - -remote get a warning that current working directory is based on an obsolete changeset - - $ cd ../remote - $ hg up . # XXX "loulz" - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - Working directory parent is obsolete - - $ hg up 39a85a192689 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - -Relocating out-of-sync change after kill ----------------------------------------------- - -The remote guy keep working - - $ sed -i'' -e 's/Spam/Spam Spam Spam Spam/g' shopping - $ hg commit -m "SPAM SPAM SPAM" - -Work I can keep getting localy - - $ cd ../local - $ hg pull remote - pulling from $TESTTMP/remote - searching for changes - adding changesets - adding manifests - adding file changes - added 1 changesets with 1 changes to 1 files - (run 'hg update' to get a working copy) - $ hg tlog - e768beeb835c: 'SPAM SPAM SPAM' - 39a85a192689: 'animals' - 962d3a7d27ad: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - -In the mean time I noticed you can't buy animals in a super market and I kill the animal changeset: - - $ hg kill 39a85a192689 # issue warning here - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - working directory now at 962d3a7d27ad - -The animals changeset is still displayed because the "SPAM SPAM SPAM" changeset -is neither dead or obsolete. My repository is in an unstable state again. - - $ hg tlog - e768beeb835c: 'SPAM SPAM SPAM' - 39a85a192689: 'animals' - 962d3a7d27ad: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - $ hg tglog -r '::e768beeb835c' - o e768beeb835c: 'SPAM SPAM SPAM' - | - o 39a85a192689: 'animals' - | - @ 962d3a7d27ad: 'bathroom stuff' - | - o 02e33960e937: 'SPAM SPAM' - | - o 387187ad9bd9: 'adding fruit' - | - o dfd3a2d7691e: 'adding condiment' - | - o 9ca060c80d74: 'SPAM' - | - o 7e82d3f3c2cb: 'Monthy Python Shopping list' - - -# $ hg evolve # XXX not ready yet -# hg relocate --rev e768beeb835c 962d3a7d27ad - - $ hg relocate -r e768beeb835c 'p1(39a85a192689)' - merging shopping - - $ hg tlog - 19098f8178f3: 'SPAM SPAM SPAM' - 962d3a7d27ad: 'bathroom stuff' - 02e33960e937: 'SPAM SPAM' - 387187ad9bd9: 'adding fruit' - dfd3a2d7691e: 'adding condiment' - 9ca060c80d74: 'SPAM' - 7e82d3f3c2cb: 'Monthy Python Shopping list' - -Handling Conflicting amend ----------------------------------------------- - -We can detect that multiple diverging//conflicting amend have been made. There -will be a "evol-merge" command to merge conflicting amend - -collaboration -==================== - -Turning changeset immutable ----------------------------------------------- - -* push on published//only repo - -* tag - -* explicite published command - -Handling Invalid amend on published changeset ----------------------------------------------- - -you can't amend published changeset. changeset that do this will have an "invalid amend" obsolete-status -
--- a/doc/vocabulary.rst Wed Mar 21 11:57:03 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ - ------------------------------------------------------ -Vocabulary ------------------------------------------------------ - -.. note:: all terminology is subject to change - -:obsolete marker: - express a relation from 0..n new changesets to 1 old changeset -:obsolete changesets: - non public changeset target of a obsolete marker - -:unstable changeset: - changeset not obsolete but with obsolete ancestor - -:extinct changeset: - obsolete changeset without unstable descendant - -:suspended changeset: - obsolete changeset with unstable descendant - -:obsolete-parents: - previous versions of a changeset, through a direct obsolete marker. - -:obsolete-children: - new versions of a changeset, through a direct obsolete marker. - -:obsolete-ancestors: - previous versions of a changeset, through any number of obsolete marker - -:obsolete-descendant: - new versions of a changeset, through any number of obsolete marker - -:obsolete-diff: - diff between a changeset and it's obsolete parent - -:obsolete-tip: - obsolete-descendants not obsolete themself. - -:conflicting changeset: - multiple obsolete-tip for an obsolete changeset through diverging obsolete - marker (no changeset split marker)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/README Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,3 @@ +doc generated with sphinx. tutorial exported using sphinxedhg + +http://hg.piranha.org.ua/sphinxedhg/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/conf.py Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,124 @@ +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] +#autoclass_content = 'both' +# Add any paths that contain templates here, relative to this directory. +#templates_path = [] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General substitutions. +project = 'Obsolete experimentation' +copyright = '2010-2011, pierre-yves.david@logilab.fr' + +# The default replacements for |version| and |release|, also used in various +# other places throughout the built documents. +# +# The short X.Y version. +version = '0.0' +# The full version, including alpha/beta/rc tags. +release = '0.0' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +unused_docs = [] + +# List of directories, relative to source directories, that shouldn't be searched +# for source files. +#exclude_dirs = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# Options for HTML output +# ----------------------- + +# The style sheet to use for HTML and HTML Help pages. A file of that name +# must exist either in Sphinx' static/ path, or in one of the custom paths +# given in html_static_path. +#html_style = 'sphinx-default.css' + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = project +#html_theme = +html_theme_path = ['.'] + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (within the static path) to place at the top of +# the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['.static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/<name>. +#html_copy_source = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '.html' + +# Output file base name for HTML help builder. +#htmlhelp_basename = ''
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/evolve-faq.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,175 @@ + +--------------------------------------------------------------------- +Evolve How To +--------------------------------------------------------------------- + + +Add a changeset: ``commit`` +------------------------------------------------------------ + +Just use commit as usual. + +Rewrite a changeset: ``amend`` +------------------------------------------------------------ + +A new command ``hg amend`` is added by the extension. it write a new changeset +combining working-directory parent changes and working directory parent changes. + +To understand what the result of amend will be I do use the two following +aliases [#]_:: + + # diff what amend will look likes + pdiff=diff --rev .^ + + # status what amend will look likes + pstatus=status --rev .^ + +It take various options to choose the user, the date and the branch of the +result. see ``hg help amend for detail`` + +This command can be invoqued on any mutable changeset even changeset with +children ! + + +.. note:: the amend command is very similar to mq's ``qrefresh``, a ``refresh`` + alias for amend is also available. But note that contrary to + ``qrefresh``, ``amend`` does not exclude changes on file not specified + on the command line. + + XXX add idank example + + +.. [#] (added by enable.sh) + + +Move a changeset: ``graft`` +------------------------------------------------------------ + +the graft command introduced in 2.0 allows to "copy changes from other branches +onto the current branch" + +The graft command have been altered to be able to create an obsolete marker from +the copy result to the copy source, acting like changeset movement operation. +This is achieved using a new flag `-O` (or `old-obsolete`) [#]_. + + +XXX example + +.. warning:: when using graft --continue after conflict resolution you **MUST** + pass `-O` or `-o` flag again because they are not saved for now + + +.. [#] add this `-O` to graft instead of a dedicated command is probably + abusive. But this was very convenient for experimental purpose. + This will likely change in non experimental release. + +Delete a changeset: ``kill`` +------------------------------------------------------------ + +A new ``kill`` command allow to remove a changeset. + +Just use ``hg kill <some-rev>``. + +Moving within the history: ``up`` ``gdown`` and ``gup`` +------------------------------------------------------------ + +While working on mutable part of the history you often need to move between +mutable commit. + +You just need to use standard update to work with evolve. For convenience, you +can use ``hg gup`` to move to children commit or ``hg gdown`` to move to working +directory parent commit. + +.. note:: those command only exist for the convenience of getting qpush and qpop + feeling back. + + They are + +collapse changesets: ``amend`` +------------------------------------------------------------ + +you can use amend -c to collapse multiple changeset in a single one. + +Move multiple changesets: ``rebase`` +------------------------------------------------------------ + +You can still use rebase to move whole part of the changeset graph at once. + +.. warning:: Beware that rebasing obsolete changeset will result in new + conflicting version. + +Stabilize history: ``stabilize`` +------------------------------------------------------------ + +When you rewrite changeset with children without rewriting those children you +create *unstable* changeset and *suspended obsolete* changeset + +.. warning:: ``hg stabilize`` have no --continue to use after conflict + resolution. is conflict occurs use:: + + $ hg up -C . # cancel the failed merge + $ hg stabilize -n # go get a command to execute + +.. warning:: stabilization does not handle deletion yet. + +.. warning:: obsolete currently rely on secret changeset to not exchange + obsolete and unstable changeset. + + XXX details issue here + + +Fix my history afterward: ``kill -n`` +------------------------------------------------------------ + +sometime you need to create obsolete marker by hand. This may happen when +upstream applied some of you patches for example. + +you can use ``hg kill --new <new-changeset> <old-changeset>`` to add obsolete +marker. + +view change to your file +------------------------------------------------------------ + +Another extension allows to export + +view diff from the last amend +------------------------------------------------------------ + +an odiff alias have been added by enable.sh + +:: + [alias] + odiff = diff --rev 'limit(obsparents(.),1)' --rev . + +view obsolete marker +------------------------------------------------------------ + +hgview is the only viewer that support this feature. you need an experimental +version available here: + + $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/hgview/ + +Prevent my unfinished changeset to get published +------------------------------------------------------------ + +The easiest way is to set them in the private phase + +Important Note +===================================================================== + +view change to your file +------------------------------------------------------------ + +extinct changeset are hidden using the *hidden* feature of mercurial. + +only hg log and hgview support it. hg glog or other visual viewer don't. + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/evolve-intro.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,14 @@ +---------------------------------------- +Introduction to the evolve extension +---------------------------------------- + +An history rewriting extension + +* Using the obsolete marker concept + +* Inspired from mq + +it is simple to enable:: + + $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/mutable-history/ + $ mutable-history/enable.sh > ~/.hgrc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/from-mq.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,165 @@ +------------------------------------------- +From MQ To Evolve, The Refugee Book +------------------------------------------- + +Cheat sheet +------------- + +============================== ============================================ +mq command new equivalent +============================== ============================================ + +qseries ``log`` +qnew ``commit`` +qrefresh ``amend`` +qpop ``update`` or ``qdown`` +qpush ``update`` or ``gup`` sometimes ``stabilize`` +qrm ``kill`` +qfold ``amend -c`` (for now, ``collapse`` soon) +qdiff ``odiff`` + +qfinish -- +qimport -- + + +Replacement details +--------------------- + +hg qseries +``````````` + +All your work in progress are now real changeset all the time. + +You can then use standard log to display them. You can use phase revset to +display unfinished business only and template to have the same kind of compact +output qseries have. + +This will result in something like that:: + + [alias] + wip = log -r 'not public()' --template='{rev}:{node|short} {description|firstline}\n' + +hg qnew +```````` + +With evolve you handle standard changeset without additional overlay. + +Standard changeset are created using hg commit as usual. + + $ hg commit + +If you want to keep the "wip are not pushed" behavior, you are looking for +setting your changeset in the secret phase using the phase command. + +Note that you only need it for the first commit you want to be secret. Later +commit will inherit their parents phase. + +If you always want your new commit to be in the secret phase, your should +consider updating your configuration: + + [phases] + new-commit=secret + +hg qref +```````` + +A new command from evolution will allow you to rewrite the changeset you are +currently on. just call: + + $ hg amend + + +This command takes the same option than commit plus useful switch '-e' (--edit) +to edit the commit message. + +Amend have also a -c switch which allow you to make and explicit amending +commit before rewriting a changeset. + + $ hg record -m 'feature A' + # oups, I forget some stuff + $ hg record babar.py + $ hg amend -c .^ # .^ refer to "working directoy parent, here 'feature A' + +note: refresh is an alias for amend + +hg qpop +````````` + +the following command emule the behavior of hg qpop: + + $ hg gdown + +If you need to go back to an arbitrary commit you can just us: + + $ hg update + +.. note:: gdown and update allow movement with working directory changes applied + and gracefully merge them. + +hg qpush +```````` + +When you rewrite changeset, descendant of rewritten changeset are marked as +"out of sync". You new to rewrite them on top of the new version of their +ancestor. + +The evolution extension add a command to rewrite the next changeset: + + $ hg stabilize + +You can also decide to do it manually using + + $ hg graft -O <old-version> + +or + + $ hg rebase -r <revset for old version> -d . + +note: using graft allow you to pick the changeset you want next as the --move +option of qpush do. + + +hg qrm +``````` + +evolution introduce a new command to mark a changeset as "not wanted anymore". + + $ hg kill <revset> + +hg qfold +````````` + + +:: + + $ hg up <top changeset> + $ amend --edit -c <bottom changeset> + + +or later:: + + $ hg collapse # XXX not implemented + + $ hg rebase --collapse # XXX not tested + + +hg qdiff +````````` + +``odiff`` is an alias for `hg diff -r .^` it works as qdiff event outside mq. + + + +hg qfinish and hg qimport +```````````````````````````` + +Is not useful anymore if you want to controll exchange and mutability of +changeset see the phase feature + + + +hg qcommit +``````````````` + +If you really need to send patches through a versionned mq patches you should +look at the qsync extension.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/glossary.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,41 @@ +----------------------------------------------------- +Vocabulary +----------------------------------------------------- + +.. note:: all terminology is subject to change + +:obsolete marker: + express a relation from 0..n new changesets to 1 old changeset +:obsolete changesets: + non public changeset target of a obsolete marker + +:unstable changeset: + changeset not obsolete but with obsolete ancestor + +:extinct changeset: + obsolete changeset without unstable descendant + +:suspended changeset: + obsolete changeset with unstable descendant + +:obsolete-parents: + previous versions of a changeset, through a direct obsolete marker. + +:obsolete-children: + new versions of a changeset, through a direct obsolete marker. + +:obsolete-ancestors: + previous versions of a changeset, through any number of obsolete marker + +:obsolete-descendant: + new versions of a changeset, through any number of obsolete marker + +:obsolete-diff: + diff between a changeset and it's obsolete parent + +:obsolete-tip: + obsolete-descendants not obsolete themself. + +:conflicting changeset: + multiple obsolete-tip for an obsolete changeset through diverging obsolete + marker (no changeset split marker)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/index.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,58 @@ +======================================== +Safe Mutable History +======================================== + + +Here are various Materials on planned improvement to mercurial regarding +rewriting mutable history. + +The effort is splitted in two part: + + * The **obsolete marker** concept that + + + + add an alternative to strip to remove changeset from a repository. + + * The changeset evolution UI + + to replace mq. + + + adding in mercurial core an new concept of **obsolete marker** in mercurial + core, + + * + + + + + +Evolve: A new UI to replace MQ +================================= + +For user + +.. toctree:: + :maxdepth: 1 + + evolve-intro + tutorial + evolve-faq + from-mq + +A new UI to replace MQ +================================= + +for dev and advanced user + + +.. toctree:: + :maxdepth: 1 + + obs-concept + glossary + obs-implementation + + +Big flasshy warning on current remaining issue
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/obs-concept.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,254 @@ +------------------------- +Obsolete Marker Concept +------------------------- + + +Obsolete marker is a powerful concept that allow mercurial to safely handle +history rewriting operations. It is a new type of relation between Mercurial +changesets that track the result of history rewriting operations. + +This concept is simple to define and provides a very solid base to: + + +- Very fast history rewriting operations, + +- auditable and reversible history rewritting process, + +- clean final history, + +- share and collaborate on mutable part of the history, + +- gracefully handle history rewriting conflict, + +- allows various history rewriting UI to collaborate with a underlying common API. + + +Basic concept +----------------------------------------------------- + + +Every history rewriting operation stores the information that old rewritten +changesets has newer version available in a set of changeset. + +This simple rules allows to express any possible history rewriting operation: + + + + +.. figure:: ./figures/example-1-update.png + + *Updating* a changeset + + Create one obsolete marker: ``([A'] obsolete A)`` + + + +.. figure:: ./figures/example-2-split.png + + *Splitting* a changeset in multiple one + + Create one obsolete marker ``([B1, B2] obsolete B)]`` + + +.. figure:: ./figures/example-3-merge.png + + *Merging* multiple changeset in a single one + + Create two obsolete markers ``([C] obsolete A), ([C] obsolete B)`` + +.. figure:: ./figures/example-4-reorder.png + + *Moving* changeset around + + Reordering those two changesets need two obsolete markers: + ``([A'] obsolete A), ([B'] obsolete B)`` + + + +.. figure:: ./figures/example-5-delete.png + + *Removing* a changeset: + + One obselete marker ``([] obsolete B)`` + + +To conclude, a single obsolete marker express a relation from **0..n** new +changesets to **1** old changeset. + +Basic Usage +----------------------------------------------------- + +Obsolete markers create a perpendicular history: **a versionned version of the +changeset graph**. This means that we can have the same feature we have for +versioned files but applied to changeset: + +First: we can display a **coherent view** of the history graph with only a +single version of your changeset are displayed by the UI. + +Second, because obsolete changeset content are still **available**. You can + + * **browse** the content of your obsolete commit, + + * **compare** newer and older version of a changeset, + + * **restore** content of previously obsolete changeset. + +Finally, obsolete marker can be **exchanged between repositories**. You are able to +share the result on your history rewriting operation with other and **collaborate +on mutable part of the history**. + +Conflicting history rewriting operation can be detected and **resolved** as easily +as conflicting changes on file. + + +Detecting and solving tricky situation +----------------------------------------------------- + +History rewriting can lead to complex situation. Obsolete marker introduce a +simple representation this complex reality. But people using complex workflow +will one day or another you have to face the intrinsics complexity of some +situation. + +This section describe possible situations, define precise set of changesets +involved in such situation and explains how error case can we automatically +resolved using available information. + + +obsolete changesets +```````````````````` + +Old changesets left behind by obsolete operation are said **obsolete**. + +With current version of mercurial, this *obsolete* part is stripped from the +repository before the end of every rewritting operation. + +.. figure:: ./figures/error-obsolete.png + + Rebasing `B` and `C` on `A` (as `B'`, `C'`) + + This rebase operation added two obsolete markers from new changesets to old + changesets. These Two old changesets are now part of the *obsolete* part of the + history. + +In most case the obsolete set will be fully hidden to both UI and discovery so +user do not have to care about them unless he wants to audit history rewriting +operation. + +Unstable changesets +``````````````````` + +While exploring obsolete marker possibility a bit further you way end up with +*obsolete* changeset with *non-obsolete* children. There is two common ways to +achieve this: + +* Pull a changeset based of an old version of a changeset [#]_. + +* Use a partial rewriting operation. For example amend on a changeset with + childrens. + +*Non-obsolete* changeset based on *obsolete* one are said **unstable** + +.. figure:: ./figures/error-unstable.png + + Amend `A` into `A'` leaving `B` behind. + + In this situation we can not consider `B` as *obsolete*. But we have all + necessary data to detect `B` as an *unstable* branch of the history because + its parent `A` is *obsolete*. In addition, we have enough data to + automatically resolve this instability: we know that the new version of `B` + parent (`A`) is `A'`, We can deduce that we should rebase `B` on `A'` to get + a stable history again. + +Proper warning should be issued when part of the history become unstable. UI +will be able to use the obsolete marker to automatically suggest resolution to +the user of even carry them out for him. + + +XXX details automatic resolution for + +* movement + +* handling deletion + +* handling split on multiple head + + +.. [#] For this to happen one needs to explicitly enable exchange of draft + changeset. See phase help for details. + +The two part of the obsolete set +`````````````````````````````````````` + +The previous section show that it could be two kinds of *obsolete* changeset: + + +* *obsolete* changeset with no or *obsolete* only descendants, said **extinct**. + +* *obsolete* changeset with *unstable* descendants, said **suspended**. + + +.. figure:: ./figures/error-extinct.png + + Amend `A` and `C` leaving `B` behind. + + In this example we have two *obsolete* changesets: `C` with no *unstable* + children is *extinct*. `A` with *unstable* descendant (`B`) is *suspended*. + `B` is *unstable* as before. + + +Because nothing outside the obsolete set default on *extinct* changesets, they +can be safely hidden in the UI and even garbage collected. *Suspended* changeset +have to stay visible and available until they unstable descendant are rewritten +in stable version. + + +Conflicting rewriting +`````````````````````` + +If people start to concurrently edit the same part of the history they will +likely meet conflicting situation when a changeset have been rewritten in two +different versions. + + +.. figure:: ./figures/error-conflicting.png + + Conflicting rewriting of `A` into `A'` and `A''` + +This kind of conflict is easy to detect with obsolete marker because an obsolete +changeset have more than one new version. It may be seen as the multiple heads +case Mercurial warn you about on pull. It is resolved the same way by a merge of +A' and A'' that will keep the same parent than `A'` and `A''` with two obsolete +markers pointing to both `A` and `A'` + +.. warning:: TODO: Add a schema of the resolution. (merge A' and A'' with A as + ancestor and graft the result of A^) + +Allowing multiple new changesets to obsolete a single one allow to distinct a +splitted changeset from history rewriting conflict. + +Reliable history +`````````````````````` + +Obsolete marker really help to smooth rewriting operation process. However they +do not change the fact that **you should only rewrite the mutable part of the +history**. The phase concept enforce this rules by explicitly defining a +public immutable set of changeset. Rewriting operation refuse to work on +public changeset, but they is still some corner case where changesets +rewritten in the past are made public. + +Special rules apply for obsolete marker pointing to public changeset + +* Public changesets are excluded from the obsolete set (public changeset are + never hidden or candidate to garbage collection) + +* *newer* version of public changeset are said **latecomer** and highlighted as + error case. + + +Solving such error is easy. Because we know what changeset a *latecomer* try to +rewrite, we can easily compute a smaller changeset containing only the change +from the old *public* to the new *latecomer*. + + +.. warning:: add a schema +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/obs-implementation.rst Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,97 @@ + +----------------------------------------------------- +Implementation of Obsolete Marker +----------------------------------------------------- +.. warning:: This document is still in heavy work in progress + +Various technical details +----------------------------------------------------- + +Some stuff that worse to note. some may deserve their own section later. + +storing old changeset +`````````````````````` + +The new general delta format allow a very efficient storage of two very similar +changesets. Storing obsolete childrens using general delta takes no more place +than storing the obsolete diff. Reverted file will even we reused. The whole +operation will take much less space the strip backup. + + +Abstraction from history rewriting UI +``````````````````````````````````````````` + +How Mercurial handle obsolete marker is independent from who decide to create +them and what actual operation solve error case. Any of the existing history +rewriting UI (rebase, mq, histedit) can lay obsolete marker and resolve +situation created by other. To go further a hook system of obsolete marker +creation would allow each mechanism to collaborate with other though a standard +and central mechanism. + + +Obsolete marker storage +``````````````````````````` + +Obsolete marker will most likely be stored outside standard history. They are +multiple reasons for that: + + +First, obsolete markers are really perpendicular to standard history there is not +strong reason to include it here other than convenience. + +Second, storing obsolete marker inside standard history means: + + +* A changeset must be created every time an obsolete relation is added. Very + inconvenient for delete operation. + +* Obsolete marker must be forged at the creation of the new changeset. This + is very inconvenient for split operation. And in general it become + complicated to fix history afterward in particular when working with older + client. + +Storing obsolete marker outside history have several pro: + +* It ease Exchange of obsolete marker without unnecessary obsolete changeset content + +* It allow tuning the actual storage and protocol exchange while maintaining + compatibility with older client through the wire (as we do the repository + format) + +* ease the exchange of obsolete related information during discovery to exchange + obsolete changeset relevant to conflict resolution. Exchanging such + information deserve a dedicated protocol. + +Persistent +``````````````````````` + +*Extinct* changeset and obsolete marker will most likely be garbage collected as +some point. However, archive server may decide to keep them forever in order to +keep a fully auditable history in it's finest conception. + + +Current status +----------------------------------------------------- + +An experimental implementatione exists. What have been done so far. + + +* 1-1 obsolete marker stored outside history, + +* compute obsolete-tip + +* obsolete marker exchange through pushkey, + +* compute obsolete, unstable, extinct and suspended set. + +* hidden extinct changesets for UI. + +* Use secret phase to remove from discovery obsolete and unstable changeset (to + be improved soon) + +* alter rebase to use obsolete marker instead of stripping. (XXX break --keep for now) + +* Have an experimental mq-like extension to rewrite history (more on that later) + +* Have an extension to update and mq repository according evolution of standard (more on that later) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tutorial.t Tue Mar 20 19:26:55 2012 +0100 @@ -0,0 +1,677 @@ +Mutable History and collaboration +===================================================================== + + +.. warning:: need heavy update + + +Single Developer Usage +====================== + +This tutorial shows how to use evolution to replace the basics of *mq*. + + +Amending a changeset +--------------------- + + +First there is some setup phase you will understand later. + +there is a local repository and a remote one. + +Please close your eyes. + + $ hg init local + $ cat >> local/.hg/hgrc << EOF + > [paths] + > remote = ../remote + > [ui] + > user = Albert Beugras + > [diff] + > git = 1 + > [alias] + > amend = amend -d '0 0' + > tlog = log --template "{node|short}: '{desc}'\n" + > ttlog = log --template "{node|short}: '{desc}' ({state})\n" + > tglog = log -G --template "{node|short}: '{desc}' {branches}\n" + > [extensions] + > hgext.graphlog= + > hgext.rebase= + > EOF + $ echo "states=$(echo $(dirname $TESTDIR))/hgext/states.py" >> local/.hg/hgrc + $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> local/.hg/hgrc + $ echo "evolution=$(echo $(dirname $TESTDIR))/hgext/evolution.py" >> local/.hg/hgrc + $ hg init remote + $ cat >> remote/.hg/hgrc << EOF + > [paths] + > local = ../local + > [ui] + > user = René de Robert + > [diff] + > git = 1 + > [alias] + > amend = amend -d '0 0' + > tlog = log --template "{node|short}: '{desc}' {branches}\n" + > ttlog = log --template "{node|short}: '{desc}' {state}\n" + > tglog = log -G --template "{node|short}: '{desc}' {branches}\n" + > [extensions] + > hgext.graphlog= + > hgext.rebase= + > EOF + $ echo "states=$(echo $(dirname $TESTDIR))/hgext/states.py" >> remote/.hg/hgrc + $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> remote/.hg/hgrc + $ echo "evolution=$(echo $(dirname $TESTDIR))/hgext/evolution.py" >> remote/.hg/hgrc + $ cd local + +You can reopen you eyes. + +Now we make a first version of our shopping list. + + $ cat >> shopping << EOF + > Spam + > Whizzo butter + > Albatross + > Rat (rather a lot) + > Jugged fish + > Blancmange + > Salmon mousse + > EOF + $ hg commit -A -m "Monthy Python Shopping list" + adding shopping + +We share this first version with the outside. + + $ hg push remote + pushing to $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + +Later I add additional item to my list + + $ cat >> shopping << EOF + > Egg + > Suggar + > Vinegar + > Oil + > EOF + $ hg commit -m "adding condiment" + $ cat >> shopping << EOF + > Bananos + > Pear + > Apple + > EOF + $ hg commit -m "adding fruit" + +I now have the following history: + + $ hg tlog + d85de4546133: 'adding fruit' + 4d5dc8187023: 'adding condiment' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + +But, I just notice, I made a typo in Banana. + + $ hg export tip + # HG changeset patch + # User test + # Date 0 0 + # Node ID d85de4546133030c82d257bbcdd9b1b416d0c31c + # Parent 4d5dc81870237d492284826e21840b2ca00e26d1 + adding fruit + + diff --git a/shopping b/shopping + --- a/shopping + +++ b/shopping + @@ -9,3 +9,6 @@ + Suggar + Vinegar + Oil + +Bananos + +Pear + +Apple + +hopefully. I can use hg amend to rewrite my faulty changeset! + + $ sed -i'' -e s/Bananos/Banana/ shopping + $ hg diff + diff --git a/shopping b/shopping + --- a/shopping + +++ b/shopping + @@ -9,6 +9,6 @@ + Suggar + Vinegar + Oil + -Bananos + +Banana + Pear + Apple + $ hg amend + abort: can not rewrite immutable changeset d85de4546133 + [255] + +By default all changeset are considered "published" and can't be rewrittent. + + $ hg ttlog + +You need to enable a mutable state in your repo the "ready" one + + $ hg states ready --clever + $ hg ttlog + d85de4546133: 'adding fruit' (ready) + 4d5dc8187023: 'adding condiment' (ready) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + +Notice that changeset you already shared with the outside have been keep +published. + +The changeset we want to rewrite is now in a mutable state. + + $ hg amend + +A new changeset with the right diff replace the wrong one. + + $ hg tlog + 0cacb48f4482: 'adding fruit' + 4d5dc8187023: 'adding condiment' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + $ hg export tip + # HG changeset patch + # User test + # Date 0 0 + # Node ID 0cacb48f44828d2fd31c4e45e18fde32a5b2f07b + # Parent 4d5dc81870237d492284826e21840b2ca00e26d1 + adding fruit + + diff --git a/shopping b/shopping + --- a/shopping + +++ b/shopping + @@ -9,3 +9,6 @@ + Suggar + Vinegar + Oil + +Banana + +Pear + +Apple + +Getting Ride of branchy history +---------------------------------- + +While I was working on my list. someone help made a change remotly. + +close your eyes + + $ cd ../remote + $ hg up -q + $ sed -i'' -e 's/Spam/Spam Spam Spam/' shopping + $ hg ci -m 'SPAM' + $ cd ../local + +open your eyes + + $ hg pull remote + pulling from $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + (run 'hg heads .' to see heads, 'hg merge' to merge) + +I now have a new heads. Note that the remote head is immutable + + $ hg ttlog + 9ca060c80d74: 'SPAM' (published) + 0cacb48f4482: 'adding fruit' (ready) + 4d5dc8187023: 'adding condiment' (ready) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + $ hg tglog -r "::(9ca060c80d74 + 0cacb48f4482)" + o 9ca060c80d74: 'SPAM' + | + | @ 0cacb48f4482: 'adding fruit' + | | + | o 4d5dc8187023: 'adding condiment' + |/ + o 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +instead of merging my head with the new one. I'm going to rebase my work + + $ hg diff + $ hg rebase -d 9ca060c80d74 -s 4d5dc8187023 + merging shopping + merging shopping + merging shopping + merging shopping + + +My local work is now rebase on the remote one. + + $ hg kill e7a71e229632 ad97bbd3e37d # XXX fix me instead + $ hg ttlog + 387187ad9bd9: 'adding fruit' (ready) + dfd3a2d7691e: 'adding condiment' (ready) + 9ca060c80d74: 'SPAM' (published) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + $ hg tglog -r '::.' + @ 387187ad9bd9: 'adding fruit' + | + o dfd3a2d7691e: 'adding condiment' + | + o 9ca060c80d74: 'SPAM' + | + o 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +Removing changeset +------------------------ + +I add new item to my list + + $ cat >> shopping << EOF + > car + > bus + > plane + > boat + > EOF + $ hg ci -m 'transport' + $ hg ttlog + d58c77aa15d7: 'transport' (ready) + 387187ad9bd9: 'adding fruit' (ready) + dfd3a2d7691e: 'adding condiment' (ready) + 9ca060c80d74: 'SPAM' (published) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + +I have a new commit but I realize that don't want it. (transport shop list does +not fit well in my standard shopping list) + + $ hg kill . # . is for working directory parent. + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory now at 387187ad9bd9 + +The silly changeset is gone. + + $ hg ttlog + 387187ad9bd9: 'adding fruit' (ready) + dfd3a2d7691e: 'adding condiment' (ready) + 9ca060c80d74: 'SPAM' (published) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + +Reordering changeset +------------------------ + + +We create two changeset. + + + $ cat >> shopping << EOF + > Shampoo + > Toothbrush + > ... More bathroom stuff to come + > Towel + > Soap + > EOF + $ hg ci -m 'bathroom stuff' -q # XXX remove the -q + + $ sed -i'' -e 's/Spam/Spam Spam Spam/g' shopping + $ hg ci -m 'SPAM SPAM' + $ hg ttlog + c48f32fb1787: 'SPAM SPAM' (ready) + 8d39a843582d: 'bathroom stuff' (ready) + 387187ad9bd9: 'adding fruit' (ready) + dfd3a2d7691e: 'adding condiment' (ready) + 9ca060c80d74: 'SPAM' (published) + 7e82d3f3c2cb: 'Monthy Python Shopping list' (published) + +.. note: don't amend changeset 7e82d3f3c2cb or 9ca060c80d74 as they are +immutable. + +I now want to push to remote all my change but the bathroom one that i'm not totally happy with yet. + +To be able to push "SPAM SPAM" I need a version of "SPAM SPAM" not children of "bathroom stuff" + +You can use rebase or relocate for that: + + $ hg relocate 'p1(8d39a843582d)' --traceback + merging shopping + $ hg tglog -r '::(. + 8d39a843582d)' + @ 02e33960e937: 'SPAM SPAM' + | + | o 8d39a843582d: 'bathroom stuff' + |/ + o 387187ad9bd9: 'adding fruit' + | + o dfd3a2d7691e: 'adding condiment' + | + o 9ca060c80d74: 'SPAM' + | + o 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +We have a new SPAM SPAM version without the bathroom stuff + + $ grep Spam shopping # enouth spamm + Spam Spam Spam Spam Spam Spam Spam Spam Spam + $ grep Toothbrush shopping # no Toothbrush + [1] + $ hg export . + # HG changeset patch + # User test + # Date 0 0 + # Node ID 02e33960e937ad1bd59241ebdafd7a2494240ddf + # Parent 387187ad9bd9d8f9a00a9fa804a26231db547429 + SPAM SPAM + + diff --git a/shopping b/shopping + --- a/shopping + +++ b/shopping + @@ -1,4 +1,4 @@ + -Spam Spam Spam + +Spam Spam Spam Spam Spam Spam Spam Spam Spam + Whizzo butter + Albatross + Rat (rather a lot) + +we can now push our change: + + $ hg push -r . remote + pushing to $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 3 changes to 1 files + +for simplicity shake we relocate the bathroom changeset + + $ hg relocate -r 8d39a843582d 02e33960e937 + merging shopping + + +Splitting change +------------------ + +To be done (currently achieve with "two commit + debugobsolete") + +Collapsing change +------------------ + +To be done (currently achieve with "revert + debugobsolete" or "rebase --collapse") + +collaboration +==================== + + +sharing mutable changeset +---------------------------- + +To share mutable changeset with other just check that both have the "ready" +state activated. Otherwise you will get the previously observe behavior where +exchanged changeset are automatically published. + + $ cd ../remote + $ hg states + published + +The remote repository have only the immutable "published" state activated. Any +changeset echanged from "local" to "remote" will be set in the publised state: + + $ hg -R ../local push -f remote # XXX we should pull but the support is awful + pushing to $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + $ hg ttlog + a3515e5d0332: 'bathroom stuff' published + 02e33960e937: 'SPAM SPAM' published + 387187ad9bd9: 'adding fruit' published + dfd3a2d7691e: 'adding condiment' published + 9ca060c80d74: 'SPAM' published + 7e82d3f3c2cb: 'Monthy Python Shopping list' published + + + +We do not want to publish the "bathroom changeset". Let's rollback the last transaction + + $ hg rollback + repository tip rolled back to revision 4 (undo push) + working directory now based on revision 1 + $ hg ttlog + 02e33960e937: 'SPAM SPAM' published + 387187ad9bd9: 'adding fruit' published + dfd3a2d7691e: 'adding condiment' published + 9ca060c80d74: 'SPAM' published + 7e82d3f3c2cb: 'Monthy Python Shopping list' published + $ rm ../local/.hg/states/published-heads # XXX USE --exact + $ hg -R ../local publish 02e33960e937 # XXX FIX THE BUG + +To enable the mutable "ready" state in a repository, use the states command. + + $ hg states ready + $ hg states + published + ready + +I can nom exchange mutable changeset between "remote" and "local" repository. + + $ hg pull local # XXX We pull too much stuff + pulling from $TESTTMP/local + searching for changes + adding changesets + adding manifests + adding file changes + added 10 changesets with 10 changes to 1 files (+5 heads) + (run 'hg heads' to see heads, 'hg merge' to merge) + $ hg ttlog + a3515e5d0332: 'bathroom stuff' ready + 02e33960e937: 'SPAM SPAM' published + 387187ad9bd9: 'adding fruit' published + dfd3a2d7691e: 'adding condiment' published + 9ca060c80d74: 'SPAM' published + 7e82d3f3c2cb: 'Monthy Python Shopping list' published + +Rebasing out-of-sync change after update +---------------------------------------------- + +Remotely someone add a new changeset on top of our mutable "bathroom" on. + + $ hg up a3515e5d0332 -q + $ cat >> shopping << EOF + > Giraffe + > Rhino + > Lion + > Bear + > EOF + $ hg ci -m 'animals' -q # XXX remove the -q + +While this time locally, we rebase the updated the "bathroom changeset" + + $ cd ../local + $ hg up a3515e5d0332 -q + $ sed -i'' -e 's/... More bathroom stuff to come/Bath Robe/' shopping + $ hg amend + $ hg tlog + 962d3a7d27ad: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +When we pull from remote again we get an unstable state! + + $ hg pull remote + pulling from $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + (run 'hg heads .' to see heads, 'hg merge' to merge) + $ hg tlog + 0b061760b677: 'animals' + 962d3a7d27ad: 'bathroom stuff' + a3515e5d0332: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + +The new changeset "animal" is based one an old changeset of "bathroom". You can +see both version showing up the log. + + $ hg tglog -r '::(962d3a7d27ad + 0b061760b677)' + o 0b061760b677: 'animals' + | + | @ 962d3a7d27ad: 'bathroom stuff' + | | + o | a3515e5d0332: 'bathroom stuff' + |/ + o 02e33960e937: 'SPAM SPAM' + | + o 387187ad9bd9: 'adding fruit' + | + o dfd3a2d7691e: 'adding condiment' + | + o 9ca060c80d74: 'SPAM' + | + o 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +In hgviewn there is a nice doted relation highlighting 962d3a7d27ad is a new +version of a3515e5d0332. this is not yet ported to graphlog. + +To resolve this unstable state, you need to relocate 0b061760b677 onto +962d3a7d27ad the "hg evolve" will make the thinking for you and suggest it to +you. + + $ hg evolve + hg relocate --rev 0b061760b677 962d3a7d27ad + +Let's do it + + $ hg relocate --rev 0b061760b677 962d3a7d27ad + merging shopping + +The old vesion of bathroom is hidden again now. + + $ hg tlog + 39a85a192689: 'animals' + 962d3a7d27ad: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + +We can push this evolution to remote + + $ hg push -f remote # XXX should not require -f + pushing to $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 1 files (+1 heads) + +remote get a warning that current working directory is based on an obsolete changeset + + $ cd ../remote + $ hg up . # XXX "loulz" + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + Working directory parent is obsolete + + $ hg up 39a85a192689 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Relocating out-of-sync change after kill +---------------------------------------------- + +The remote guy keep working + + $ sed -i'' -e 's/Spam/Spam Spam Spam Spam/g' shopping + $ hg commit -m "SPAM SPAM SPAM" + +Work I can keep getting localy + + $ cd ../local + $ hg pull remote + pulling from $TESTTMP/remote + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + (run 'hg update' to get a working copy) + $ hg tlog + e768beeb835c: 'SPAM SPAM SPAM' + 39a85a192689: 'animals' + 962d3a7d27ad: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + +In the mean time I noticed you can't buy animals in a super market and I kill the animal changeset: + + $ hg kill 39a85a192689 # issue warning here + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + working directory now at 962d3a7d27ad + +The animals changeset is still displayed because the "SPAM SPAM SPAM" changeset +is neither dead or obsolete. My repository is in an unstable state again. + + $ hg tlog + e768beeb835c: 'SPAM SPAM SPAM' + 39a85a192689: 'animals' + 962d3a7d27ad: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + $ hg tglog -r '::e768beeb835c' + o e768beeb835c: 'SPAM SPAM SPAM' + | + o 39a85a192689: 'animals' + | + @ 962d3a7d27ad: 'bathroom stuff' + | + o 02e33960e937: 'SPAM SPAM' + | + o 387187ad9bd9: 'adding fruit' + | + o dfd3a2d7691e: 'adding condiment' + | + o 9ca060c80d74: 'SPAM' + | + o 7e82d3f3c2cb: 'Monthy Python Shopping list' + + +# $ hg evolve # XXX not ready yet +# hg relocate --rev e768beeb835c 962d3a7d27ad + + $ hg relocate -r e768beeb835c 'p1(39a85a192689)' + merging shopping + + $ hg tlog + 19098f8178f3: 'SPAM SPAM SPAM' + 962d3a7d27ad: 'bathroom stuff' + 02e33960e937: 'SPAM SPAM' + 387187ad9bd9: 'adding fruit' + dfd3a2d7691e: 'adding condiment' + 9ca060c80d74: 'SPAM' + 7e82d3f3c2cb: 'Monthy Python Shopping list' + +Handling Conflicting amend +---------------------------------------------- + +We can detect that multiple diverging//conflicting amend have been made. There +will be a "evol-merge" command to merge conflicting amend