# HG changeset patch # User Pierre-Yves David # Date 1332237731 -3600 # Node ID 03f314e32058bafedcf6ab9f53fc5aa2c418ac82 # Parent 8e93e1f67205cef9d86cfcb0ef56dca396f5f61b import some doc diff -r 8e93e1f67205 -r 03f314e32058 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Mar 20 11:02:11 2012 +0100 @@ -0,0 +1,2 @@ +syntax: re +/figures/[^/]+\.png$ diff -r 8e93e1f67205 -r 03f314e32058 doc/obs-concept.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/obs-concept.rst Tue Mar 20 11:02:11 2012 +0100 @@ -0,0 +1,257 @@ +========================= +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 + diff -r 8e93e1f67205 -r 03f314e32058 doc/obs-implementation.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/obs-implementation.rst Tue Mar 20 11:02:11 2012 +0100 @@ -0,0 +1,96 @@ + +.. 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) + diff -r 8e93e1f67205 -r 03f314e32058 doc/vocabulary.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/vocabulary.rst Tue Mar 20 11:02:11 2012 +0100 @@ -0,0 +1,42 @@ + +----------------------------------------------------- +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)