changeset 192:706a3a57b567

docs: Merged obs-concept changes by hand.
author Arne Babenhauserheide <bab@draketo.de>
date Wed, 28 Mar 2012 12:50:42 +0200
parents 0f1b8119a281 (current diff) e7d7201e79ce (diff)
children adf92ff8d4f6
files docs/obs-concept.rst
diffstat 8 files changed, 233 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
--- a/docs/evolve-collaboration.rst
+++ b/docs/evolve-collaboration.rst
@@ -7,7 +7,7 @@
 After having written some code for ticket #42, M W. start a patch (this
 will be kind of like a 'work-in-progress' checkpoint initially)::
 
-    $ ci -m '[entities] remove magic'
+    $ hg ci -m '[entities] remove magic'
 
 Instant patch ! Note how the default phase of this changeset is (still)
 in "draft" state.
@@ -27,7 +27,7 @@
 "publishing" since they do not have the notion of non-public changesets
 (or mutable history).
 
-In the transition ... phase from older mercurial servers, this will
+During the transition from older mercurial servers to new ones, this will
 happen often, so be careful.
 
 Now let's come back to our patch. Next hour sees good progress and W.
@@ -44,10 +44,10 @@
 
     $ hg push # was done with a modern mercurial, draft phase is preserved
 
-The next day, Mr C.W, which arrives very very early, can immediately
+The next day, Mr C.W., who arrives very early, can immediately
 work out some glitches in the patch.
 
-He then starts another one, for ticket #43 and finally commits it.
+He then starts two other, for ticket #43 and #44 and finally commits them.
 Then, as original worker arrives, he pushes his stuff.
 
 M W., now equipped with enough properly sugared coffee to survive the
@@ -57,7 +57,7 @@
 
 Then::
 
-    $ hg up "tip ~ 1"
+    $ hg up "tip ~ 2"
 
 brings him to yesterday's patch. Indeed the patch serial number has
 increased (827 still exists but has been obsoleted).
@@ -78,4 +78,55 @@
 * odiff
 
 
+Amend ... Stabilize
+--------------------
 
+Almost perfect ! W. just needs to fix a half dozen grammar oddities in
+the new docstrings and it will be publishable.
+
+Then, another round of:
+
+    $ hg amend
+
+and a quick look at hgview ... shows something strange (at first).
+
+Ticket #42 yesterday's version is still showing up, with two descendant lineages:
+
+* the next version, containing grammar fixes,
+
+* the two stacked changesets for tickets #43 .. 44 committed by C.W.
+
+Indeed, since this changeset still has non-obsolete descendant
+changesets it cannot be hidden. This branch (old version of #42 and
+the two descendants by C.W.) is said to be _unstable_.
+
+Why would one want such a state ? Why not auto-stabilize each time "hg
+amend" is spelt ?
+
+W. for one, wouldn't want to merge each time he amends something that
+might conflict with the descendant changesets; remember he is
+currently updating the very middle of an history !
+
+Being now done with grammar and typo fixes, W. decides it is time to
+stabilize again the tree. He:
+
+    $ hg stabilize
+
+two times, one for each unstable descendant. The last time, hgview
+shows him a straight line again. Wow ! that feels a bit like a
+well-planned surgical operation. At the end, the patient^Wtree has
+been properly sewed and any conflict properly handled.
+
+Of course nothing fancy really happened: each "stablilize" can be
+understood in terms of a rebase of the next unstable descendant to the
+newest version of its parent (including the possible manual conflict
+resolution intermission ...).
+
+Except that rebase is a destructive (it removes information from the
+repository), unexchangeable operation, and the "evolve + obsolete"
+combo, using changeset copy and obsolescence marker, provide evolution
+semantics by only adding new information to the repository (but more
+on that later).
+
+He pushes again.
+
--- a/docs/evolve-faq.rst
+++ b/docs/evolve-faq.rst
@@ -8,7 +8,7 @@
 Add a changeset: ``commit``
 ------------------------------------------------------------
 
-Just use commit as usual. New changeset will be in the `draft` phase.
+Just use commit as usual. New changesets will be in the `draft` phase.
 
 Rewrite a changeset: ``amend``
 ------------------------------------------------------------
@@ -65,13 +65,13 @@
 
 
 .. [#] add this `-O` to graft instead of a dedicated command is probably
-       abusive. But this was very convenient for experimental purpose.
+       abusive. But this was very convenient for experimental purposes.
        This will likely change in non experimental release.
 
 Delete a changeset: ``kill``
 ------------------------------------------------------------
 
-A new ``kill`` command allows to remove a changeset.
+A new ``kill`` command allows removing a changeset.
 
 Just use ``hg kill <some-rev>``.
 
@@ -88,18 +88,38 @@
 .. note:: those command only exist for the convenience of getting qpush and qpop
           feeling back.
 
-collapse changesets: ``amend``
+Collapse changesets: ``amend``
 ------------------------------------------------------------
 
 you can use amend -c to collapse multiple changeset in a single one.
 
+Split changesets
+-----------------------
+
+There is no official command to split a changeset. However is it easily achieved
+by manual operation::
+
+  ### you want to split changeset A: 42
+  # update to A parent
+  $ hg up 42^
+  # restore content from A
+  $ hg revert -r 42 --all
+  # partially commit the first part
+  $ hg record
+  # commit the second part
+  $ hg commit
+  # informs mercurial of what appened
+  # current changeset (.) and previous one (.) replace A (42)
+  $ hg kill --new . --new .^ 42
+
+
 Move multiple changesets: ``rebase``
 ------------------------------------------------------------
 
-You can still use rebase to move whole part of the changeset graph at once.
+You can still use rebase to move a whole segment of the changeset graph together.
 
-.. warning:: Beware that rebasing obsolete changeset will result in new
-             conflicting version.
+.. warning:: Beware that rebasing obsolete changesets will result in
+             conflicting versions of the changesets.
 
 Stabilize history: ``stabilize``
 ------------------------------------------------------------
@@ -108,7 +128,7 @@
 those children you create *unstable* changesets and *suspended
 obsolete* changesets.
 
-When you are finished amending a given changeset you will want to
+When you are finished amending a given changeset, you will want to
 declare it stable, in other words rebase its former descendants on its
 newest version. This is not done automatically to avoid the
 proliferation of useless hidden changesets.
@@ -118,8 +138,8 @@
 
 .. warning:: stabilization does not handle deletion yet.
 
-.. warning:: obsolete currently rely on secret changeset to not exchange
-             obsolete and unstable changeset.
+.. warning:: obsolete currently relies on changesets in secret phase
+              to avoid exchanging obsolete and unstable changesets.
 
              XXX details issue here
 
@@ -128,7 +148,7 @@
 ------------------------------------------------------------
 
 Sometimes you need to create an obsolete marker by hand. This may happen when
-upstream has applied some of you patches for example.
+upstream has applied some of your patches for example.
 
 you can use ``hg kill --new <new-changeset> <old-changeset>`` to add obsolete
 marker.
--- a/docs/from-mq.rst
+++ b/docs/from-mq.rst
@@ -28,11 +28,11 @@
 hg qseries
 ```````````
 
-All your work in progress are now real changeset all the time.
+All your work in progress is now in 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.
+You can use the standard log to display them. You can use the phase revset to
+display unfinished business only and templates to have the same kind of compact
+output qseries has.
 
 This will result in something like that::
 
@@ -42,9 +42,9 @@
 hg qnew
 ````````
 
-With evolve you handle standard changeset without additional overlay.
+With evolve you handle standard changesets without an additional overlay.
 
-Standard changeset are created using hg commit as usual.
+Standard changeset are created using hg commit as usual.::
 
   $ hg commit
 
@@ -52,7 +52,7 @@
 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.
+commits will inherit their parents phase.
 
 If you always want your new commit to be in the secret phase, your should
 consider updating your configuration:
@@ -69,11 +69,11 @@
   $ hg amend
 
 
-This command takes the same option than commit  plus useful switch '-e' (--edit)
-to edit the commit message.
+This command takes the same options as commit, plus the switch '-e' (--edit)
+to edit the commit message in an editor.
 
-Amend have also a -c switch which allow you to make and explicit amending
-commit before rewriting a changeset.
+Amend have also a -c switch which allow you to make an explicit amending
+commit before rewriting a changeset.::
 
   $ hg record -m 'feature A'
   # oups, I forget some stuff
@@ -99,19 +99,19 @@
 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
+When you rewrite changesets, descendants of rewritten changesets are marked as
+"out of sync". You need to rewrite them on top of the new version of their
 ancestor.
 
-The evolution extension add a command to rewrite the next changeset:
+The evolution extension adds a command to rewrite the "out of sync" changesets:::
 
   $ hg stabilize
 
-You can also decide to do it manually using
+You can also decide to do it manually using::
 
   $ hg graft -O <old-version>
 
-or 
+or::
 
   $ hg rebase -r <revset for old version> -d .
 
@@ -122,7 +122,7 @@
 hg qrm
 ```````
 
-evolution introduce a new command to mark a changeset as "not wanted anymore".
+evolution introduce a new command to mark a changeset as "not wanted anymore".::
 
   $ hg kill <revset>
 
@@ -139,27 +139,26 @@
 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.
+``odiff`` is an alias for `hg diff -r .^` it works as qdiff, but 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
+Is not necessary anymore. If you want to control exchange and mutability of
+changesets, see the phase feature
 
 
 
 hg qcommit
 ```````````````
 
-If you really need to send patches through a versionned mq patches you should
+If you really need to send patches through versioned mq patches, you should
 look at the qsync extension.
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -7,7 +7,7 @@
 :obsolete marker:
     express a relation from 0..n new changesets to 1 old changeset
 :obsolete changesets:
-    non public changeset target of a obsolete marker
+    non public changeset which are target of a obsolete marker
 
 :unstable changeset:
     changeset not obsolete but with obsolete ancestor
@@ -34,8 +34,8 @@
     diff between a changeset and it's obsolete parent
 
 :obsolete-tip:
-    obsolete-descendants not obsolete themself.
+    obsolete-descendants which are not obsolete themselves.
 
 :conflicting changeset:
     multiple obsolete-tip for an obsolete changeset through diverging obsolete
-    marker (no changeset split marker)
+    markers (no changeset split marker)
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -62,7 +62,8 @@
     $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/mutable-history/
     $ mutable-history/enable.sh >> ~/.hgrc
 
-You will probably want to use the associated version of hgview (QT viewer only)::
+You will probably want to use the associated version of hgview (QT viewer
+only). ::
 
     $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/hgview/
     $ cd hgview
@@ -80,6 +81,7 @@
    evolve-faq
    from-mq
    evolve-collaboration
+   qsync
 
 Smart changeset deletion: Obsolete Marker
 ==========================================
@@ -144,8 +146,10 @@
 
 
 
-Anexe
+Annexe
 =================================
 
 .. toctree::
+   :maxdepth: 1
+
    glossary
--- a/docs/obs-concept.rst
+++ b/docs/obs-concept.rst
@@ -1,33 +1,34 @@
-==============================
- Why Do We Need a New Concept
-==============================
+-----------------------------------------------------------
+Why Do We Need a New Concept
+-----------------------------------------------------------
 
-Current DVCS are great tool to forge a series of flawless changeset on your own.
-But they perform poorly when is comes to **share** work in progress and
-**collaborate** on such work in progress.
+Current DVCS are great tools to forge a series of flawless changeset on your own.
+But they perform poorly when it comes to **sharing** some work in progress and
+**collaborating** on such work in progress.
 
-When people forge new version of a changeset they create a new changeset and get
-ride of the original changeset. Difficulties to collaborate mostly came from the
-way old content are *removed* from repository.
+When people forge a new version of a changeset they actually create a
+new changeset and get rid of the original changeset. Difficulties to
+collaborate mostly came from the way old content is *removed* from
+a repository.
 
 Mercurial Approach: Strip
-=========================
+-----------------------------------------------------
 
-With current version of mercurial, every changesets that exist in your
-repository are *visible* and *meaningful*. To get ride of old changeset you
-rewrote mercurial remove them from the repository storage. with an operation
-called *strip*. After the *strip* the repository looks like if the changeset
-never existed.
+With the current version of mercurial, every changeset that exists in
+your repository is *visible* and *meaningful*. To delete old
+(rewritten) changesets, mercurial removes them from the repository
+storage with an operation called *strip*. After the *stripping*, the
+repository looks like if the changeset never existed.
 
-This approach is simple and effective but have a very big drawback: You can
-remove changesets from **your repository only**. If strip exists in other
-repositories it will show of again and again. This only cure for this is to
-strip the offending changeset from all repository. And operation at best
-impractical and in most case impossible!
-
+This approach is simple and effective except for one big
+drawback: you can remove changesets from **your repository only**. If
+a stripped changeset exists in another repository it touches, it will
+show up again. This is because a shared changeset becomes
+part of a shared global history. Stripping a changeset from all
+repositories is at best impractical and in most case impossible!
 
 As consequence, **you can not rewrite something once you exchange it with
-others**. The old version will still exists along side the new one [#]_.
+others**. The old version will still exist along side the new one [#]_.
 
 Moreover stripping changesets creates backup bundles. This allows
 restoration of the deleted changesets, but the process is painful.
@@ -35,17 +36,19 @@
 Finally, as the repository format is not optimized for deletion. stripping a
 changeset may be slow in some situations.
 
-To sum up, the strip approach is very simple but does not handle interaction
-with the outer world. Which is unfortunate for a *Distributed* VCS.
+To sum up, the strip approach is very simple but does not handle
+interaction with the outer world, which is very unfortunate for a
+*Distributed* VCS.
 
 .. [#] various work around exists but they require their own workflows which are distinct from the very elegant basic workflow of Mercurial.
 
 Git Approach: Overwrite Reference
-=================================
+-----------------------------------------------------
 
-Git approach for repository is a bit more complex: Any number of
-changesets can exist in a repository. but **only changesets referenced by a git
-branch** are *visible* and *meaningful*.
+The Git approach to repository structure is a bit more complex: there
+can be any amount of unrelated changesets in a repository, and **only
+changesets referenced by a git branch** are *visible* and
+*meaningful*.
 
 
 .. warning:: add a schema::
@@ -60,47 +63,41 @@
 
 This simplifies the process of getting rid of old changesets. You can
 just leave them in place and move the reference on the new one. You
-can then propagate that change by moving the git-branch on remote host
+can then propagate this change by moving the git-branch on remote host
 with the newer version of the marker overwriting the older one.
 
 This approach goes a bit further but still has a major drawback:
 
-
 Because you **overwrite** the git-branch, you have no conflict resolution. The last
 to act wins. This makes collaboration on multiple changesets difficult because
 you can't merge concurrent updates on a changeset.
 
-Every overwrite is a forced operation where the operator say "Yes I want this to
+Every overwrite is a forced operation where the operator says "Yes I want this to
 replace that. In highly distributed environments, a user may end up with conflicting
 references and no proper way to choose.
 
 Because of this way to visualize a repository, git-branches are a core
 part of git, which makes the user interface more complicated and
-constrains the ways to move through history.
+constrains moving through history.
 
-Finally, even if all older changeset still exist in the repository, access to them
+Finally, even if all older changesets still exist in the repository, accesing them
 is still painful.
 
 
-=============================
- The Obsolete Marker Concept
-=============================
-
-
-
+-----------------------------------------------------
+The Obsolete Marker Concept
+-----------------------------------------------------
 
 
-As None of the concepts was powerful enough to fulfill the need of safely rewriting
-history, including easy sharing and collaborating on mutable history, we needed another one.
-
-
+As None of the concepts was powerful enough to fulfill the need of safely rewriting                              
+history, including easy sharing and collaborating on mutable history, we needed another one. 
 
 Basic concept
-=============
+-----------------------------------------------------
 
 
-Every history rewriting operation stores the information that the old rewritten
-changeset is replaced by newer version in a given set of changeset.
+Every history rewriting operation stores the information that old rewritten
+changeset is replaced by newer version in a given set of changesets.
 
 All basic history rewriting operation can create an appropriate obsolete marker.
 
@@ -146,45 +143,47 @@
 changesets to **1** old changeset.
 
 Basic Usage
-===========
+-----------------------------------------------------
 
 Obsolete markers create a perpendicular history: **a versioned changeset graph**. This means that offers the same features we have for
 versioned files but applied to changeset:
 
 First: we can display a **coherent view** of the history graph in which only a
-single version of your changesets are displayed by the UI.
+single version of your changesets is displayed by the UI.
 
 Second, because obsolete changeset content is still **available**. You can 
+you can
 
-    * **browse** the content of your obsolete commit,
+    * **browse** the content of your obsolete commits,
 
-    * **compare** newer and older version of a changeset,
+    * **compare** newer and older versions of a changeset,
 
-    * **restore** content of previously obsolete changeset.
+    * **restore** content of previously obsolete changesets.
 
-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**.
+Finally, the obsolete marker can be **exchanged between
+repositories**. You are able to share the result on your history
+rewriting operations with other prople and **collaborate on the
+mutable part of the history**.
 
-Conflicting history rewriting operation can be detected and **resolved** as easily
-as conflicting changes on file.
+Conflicting history rewriting operation can be detected and
+**resolved** as easily as conflicting changes on a file.
 
 
 Detecting and solving tricky situations
-======================================
+-----------------------------------------------------
 
-History rewriting can lead to complex situations. Obsolete marker introduce a
-simple representation of this complex reality. But people using complex workflows
-will one day or another have to face the intrinsic complexity of some
-situations.
+History rewriting can lead to complex situations. The obsolete marker
+introduces a simple representation for this complex reality. But
+people using complex workflows will one day or another have to face
+the intrinsic complexity of some real-world situation.
 
-This section describes possible situations, defines precise sets of changesets
-involved in such situations and explains how error cases can automatically be
-resolved using available information.
+This section describes possible situations, defines precise sets of
+changesets involved in such situations and explains how the error
+cases can be resolved automatically using the available information.
 
 
-obsolete changesets
--------------------
+Obsolete changesets
+````````````````````
 
 Old changesets left behind by obsolete operation are called **obsolete**.
 
@@ -199,21 +198,21 @@
     changesets. These two old changesets are now part of the *obsolete* part of the
     history.
 
-In most cases, the obsolete set will be fully hidden to both UI and discovery so
-the user does not have to care about them unless he wants to audit the history rewriting
-operation.
+In most cases, the obsolete set will be fully hidden to both the UI and
+discovery, hence users do not have to care about them unless they want to
+audit history rewriting operations.
 
 Unstable changesets
--------------------
+```````````````````
 
-While exploring the possibilities of the obsolete a bit further, you may end up with
-*obsolete* changeset which have *non-obsolete* children. There is two common ways to
+While exploring the possibilities of the obsolete marker a bit further, you may end up with
+*obsolete* changesets which have *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
-  children .
+  children.
 
 *Non-obsolete* changeset based on *obsolete* one are called **unstable**
 
@@ -228,9 +227,10 @@
     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.
+Proper warnings should be issued when part of the history becomes
+unstable. The UI will be able to use the obsolete marker to
+automatically suggest a resolution to the user of even carry them out
+for him.
 
 
 XXX details on automatic resolution for
@@ -245,11 +245,11 @@
 .. [#] For this to happen one needs to explicitly enable exchange of draft
        changesets. See phase help for details.
 
-The two part of the obsolete set
---------------------------------
+The two parts of the obsolete set
+``````````````````````````````````````
 
-The previous section show that there can be two kinds of an *obsolete* changeset:
-
+The previous section shows that there could be two kinds of *obsolete*
+changesets:
 
 * an *obsolete* changeset with no or *obsolete* only descendants is called **extinct**.
 
@@ -272,7 +272,7 @@
 
 
 Conflicting rewrites
----------------------
+````````````````````
 
 If people start to concurrently edit the same part of the history they will
 likely meet conflicting situations when a changeset has been rewritten in two
@@ -283,20 +283,21 @@
 
     Conflicting rewrite of `A` into `A'` and `A''`
 
-This kind of conflict is easy to detect with obsolete markers, because an obsolete
-changeset can have more than one new version. It may be seen as the multiple heads
-case which Mercurial warns 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
+This kind of conflict is easy to detect with an obsolete marker
+because an obsolete changeset can have more than one new version. It
+may be seen as the multiple heads case. Mercurial warns you about this
+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 allows to differenciate
-split changesets from history rewriting conflicts.
+Allowing multiple new changesets to obsolete a single one allows to
+distinguish a split changeset from a history rewriting conflict.
 
 Reliable history
-----------------
+``````````````````````
 
 Obsolete marker help to smooth rewriting operation process. However they
 do not change the fact that **you should only rewrite the mutable part of the
@@ -305,25 +306,24 @@
 public changesets, but there are still some corner cases where previously rewritten changesets
 are made public.
 
-Special rules apply for obsolete markers pointing to public changesets
+Special rules apply for obsolete markers pointing to public changesets:
 
-* Public changesets are excluded from the obsolete set (public changeset are
-  never hidden or candidate to garbage collection)
+* Public changesets are excluded from the obsolete set (public
+  changesets are never hidden or candidate to garbage collection)
 
-* *newer* version of public changeset are said **latecomer** and highlighted as
-  error case.
-
+* *newer* version of a public changeset are called **latecomer** and highlighted as
+  an 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*.
-
+Solving such an error is easy. Because we know what changeset a
+*latecomer* tries 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
 
 
 Conclusion
-==========
+----------------
 
 The obsolete marker is a powerful concept that allows mercurial to safely handle
 history rewriting operations. It is a new type of relation between Mercurial
new file mode 100644
--- /dev/null
+++ b/docs/qsync.rst
@@ -0,0 +1,16 @@
+---------------------------------------------------------------------
+Qsync: Mercurial to MQ exporter
+---------------------------------------------------------------------
+
+
+People may have tools or wo-worker that export to receive mutable history using
+versionned mq repository.
+
+For this purpose you can use the ``qsync`` extension:
+
+
+To enable the evolve extension use::
+
+    $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/mutable-history/
+    $ mutable-history/iqsync-enable.sh >> ~/.hgrc
+    $ hg help qsync
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -21,7 +21,7 @@
 from mercurial import commands
 from mercurial import util
 from mercurial.i18n import _
-from mercurial.commands import walkopts, commitopts, commitopts2, logopt
+from mercurial.commands import walkopts, commitopts, commitopts2, logopts
 from mercurial import hg
 
 ### util function