diff -r bcf095c8239c -r f589d054329a docs/unstability.rst --- a/docs/unstability.rst Wed May 09 16:41:38 2012 +0200 +++ b/docs/unstability.rst Wed May 09 18:52:57 2012 +0200 @@ -1,5 +1,6 @@ + ----------------------------------- -The Unstability Principle +The instability Principle ----------------------------------- @@ -7,14 +8,15 @@ An intrinsic contradiction ----------------------------------- +XXX starts by talking about getting ride of changeset. DVCS bring two new major concepts to the Version Control Scene: - * Organisation of the history with robust DAG, - * Mutation of history. + * History is organized as a robust DAG, + * History can be rewritten. -However, the two concepts opposes them self: +However, the two concepts are in contradiction: To achieve a robust history, three key elements are gathered in *changeset*: @@ -22,33 +24,34 @@ * Reference to the previous full snapshot used to build the new one, * A description of the change who lead from the old content to the new old. -All three elements are used generate a *unique* hash that identify the changeset +All three elements are to compute a *unique* hash that identify the changeset (with various other metadata). This identification is a key part of DVCS design. +This is a very useful property because Changing B parent means changing B +content too. This require the creation of **another** changeset which is a good +semantic. + :: Schema base, A, B and B' -The old changeset is usually discarded -t in DVCS history. +To avoid duplication, the older changeset is usually discarded from accessible +history. I'm calling them *obsolete* changesets. + +But rewriting a changeset with children does not changes children parent! And +because children of the rewritten changeset still **depends** on the older +"dead" version of the changeset with can not get ride of this dead version. :: Schema base, A and A' and B. -Rewriting a changeset with children does not changes children parent! And -because children of the rewritten changeset still **depends** on the older -"dead" version of the changeset with can not get ride of this dead version. - -This is a very useful property because Changing B parent means changing B -content too. This require the creation of **another** changeset. - -I'll qualify those children as **unstable** because they are based one a dead +I'm calling those children **unstable** because they are based one a dead changeset and prevent people to get ride of it. This instability is an **unavoidable consequence** of the strict dependency of -changese. History Rewriting history alway need to take it in account and +changeset. History Rewriting history alway need to take it in account and provide a way to rewrite the descendant on the new changeset to avoid coexistence of the old and new version of a rewritten changeset.. @@ -56,73 +59,158 @@ Everybody is working around the issue ------------------------------------------------ -I'm not claiming that rewriting history is impossible. People are - +I'm not claiming that rewriting history is impossible. People are successfully +doing for years. However they all need to work around *instability*. Several +work around strategy exists. Rewriting all at once `````````````````````````` +The simplest way to avoid instability is to ensure rewriting operation always +ends in a stable situation. This is achieve by rewriting all impacted changeset +at the same time. + +Rewriting all descendants at the same time than the rewritted of a changeset. + +:: + + Schema! + +Several Mercurial commands apply it: rebase, collapse, histedit. Mercurial also +refuse to amend changeset with descendant. The git branch design enforce such +approach in git too. -stable situation to stable situation +However, DVCS are **Distributed**. This means that you do not control what +happen outside your repository. Once a changeset have been exchanged *outside*, +there is no way to be sure it does not have descendants somewhere else. +Therefore **if you rewrite changeset that exists elsewhere, you can't eradicate +the risk of instability.** -Distributed means that you do not control what happen outside your repository: - +Do not rewrite exchanged changeset +``````````````````````````````````` -* phase. -* overwrite. +To work around the issue above, mercurial introduced phases that prevent you to +rewrite shared changeset and ensure other can't pull certain changeset from you. +But this is a very frustrating limitation that prevent you to efficiently share, +review and collaborate on mutable changeset. - -Boiler Plate +Git world use another approach to prevent instability. By convention only a +single developper works on a changeset contained in a named branch. But once +again this is a huge blocker for collaborating. Moreover clueless people +**will** mess up social convention soon or later. Loose the DAG robustness ```````````````````````````` -The other approach is +The other approach use in Mercurial is to keep the mutable part of the history +outside the DVCS constraint. This is the MQ approach of sticking a quilt queue +over Mercurial. -mq -- quilt +This allow much more flexible workflow but two major feature are lost in the +process: -Conflict too much conflict +:Graceful merge: MQ use plain-patch to store changeset content and patch have + trouble to apply in changing context. Applying your queue + becomes very painful when context changes. -Linear - +:easy branching: A quilt queue is by definition a linear queue. Increasing risk + of conflict -Deny a lot of option -```````````````````````````` - - +It is possible to collaborate over versioned mq! But you are going ahead a lot +of troubles. -[] rewrite - -[] exchange - -[] collaborate - +.. Ignore conflicts +.. ``````````````````````````````````` +.. +.. Another ignored issue is conflicting rewritting of the same changeset. If a +.. changeset is rewritten two times we have two newer version, duplicated history +.. complicate to merge. +.. +.. Mercurial work around by +.. +.. The "One set of mutable changset == One developper" mantra is also a way to work +.. around conflicting rewritting of changeset. If two different people are able to +.. +.. The git branch model allow to overwrite changeset version by another one. But it +.. does not care about divergent version. It is the equilent of "common ftp" source +.. management for changeset. Facing The Danger Once And For All ------------------------------------------------ -The more effort you put to avoid instability, the more option you deny. And even -most restrictive work flow can't garantee that instability will never show up! + +Above we saw that, the more effort you put to avoid instability, the more option +you deny. And even most restrictive work flow can't guarantee that instability +will never show up! + +Obsolete marker can handle the job +``````````````````````````````````` It is time to provide a full featured solution to deal with instability and to stop working around the issue! This is why I developing a new feature for -mercurial called "Obsolete marker". +mercurial called "Obsolete markers". Obsolete markers have two key properties: -* Any changeset is we want to get ride of is **explicitly** marked as "obsolete" - by history rewritting operation.. +* Any "old" changeset we want to get ride of is **explicitly** marked as "obsolete" + by history rewriting operation. -* Relations between old and new version of changesets are tracked by Obsolete + By explicitly marking the obsolete part of the history, we will be able to + easily detect instability situation. + +* Relations between old and new version of changesets are tracked by obsolete markers. -By explicitly marking the obsolete part of the history, we will be able to -easily detect appearance of unstability. By Storing a meta-history of changeset -evolution we are able to easily resolve instability and edition conflict. + By Storing a meta-history of changeset evolution we are able to easily resolve + instability and edition conflict [#]_ . + +.. [#] edition conflict is another major obstable to collaboration. See the + section dedicated to obsolete marker for details. + +Improves robustness == improves simplicity +```````````````````````````````````````````````` + +This proposal should **first** be seen as a safety measure. + +It allow to detect instability as soon as possible + +:: + $ hg pull + added 3 changeset + +2 unstable changeset + (do you want "hg stabilize" ?) + working directory parent is obsolete! + $ hg push + outgoing unstable changesets + (use "hg stabilize" or force the push) + +And should not not encourage people to create unstability + +:: + $ hg up 42 + $ hg commit --amend + changeset have descendant. + $ hg commit --amend -f + +5 unstable changeset + + $ hg rebase -D --rev 40::44 + rebasing already obsolete changeset 42:AAA will conflict with newer version 48:BBB + +While allowing powerful feature +```````````````````````````````````````````````` +* Help to automatically solve instability. + +* "kill" changeset remotely. + +* track resulting changeset when submitting patch//pull request. + +* Focus on what you do: + + I do not like the "all at once" model of history rewriting. I'm comfortable + with unstability and obsolete marker offer all the tool to safely create and + handle unstability locally. -No instability is still a bad situation. -No instability is still a bad situation that should be avoided.