[PATCH 2 of 2] server: introduce a 'server.single-head' option
Gregory Szorc
gregory.szorc at gmail.com
Thu Nov 16 12:32:55 EST 2017
On Thu, Nov 16, 2017 at 8:16 AM, Boris Feld <boris.feld at octobus.net> wrote:
> # HG changeset patch
> # User Boris Feld <boris.feld at octobus.net>
> # Date 1510800762 -3600
> # Thu Nov 16 03:52:42 2017 +0100
> # Node ID 921ee05859ea9fc17f5a123baa16c2bbe2c49001
> # Parent c46c0f855a64868b90260da603769c8bc1ebdcf7
> # EXP-Topic single-heads
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r
> 921ee05859ea
> server: introduce a 'server.single-head' option
>
I like this feature and feel it should be supported by Mercurial out of the
box. (Mozilla has a hook checking for single heads and we would love to
delete custom code and use a core feature.)
I don't want to scope bloat you and say no to a good patch. However, this
feature is the historical territory of hooks. I value having this feature
in the core distribution. But I feel that a "built-in hooks" mechanism is
the better vehicle for this feature. Only a few weeks ago Augie and I were
discussing the idea of shipping some common, easy-to-enable hooks with
Mercurial. There seems to be some level of agreement that the feature
should exist. What we don't have is a mechanism to easily define them.
I would feel better if the config option naming for this were related to
hooks somehow. If we do that, we can refactor the code to leverage hooks
(or some hooks-like mechanism) later while preserving the user-facing API.
Does that sound reasonable?
>
> When the option is set, the repository will reject any transaction adding
> multiple heads to the same named branch.
>
> For now we reject all scenario with multiple heads. One could imagine
> handling
> closed branches differently. We prefer to keep things simple for now. The
> feature might get extended later. Branch closing is not the best experience
> Mercurial has to offer anyway.
>
> diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> --- a/mercurial/configitems.py
> +++ b/mercurial/configitems.py
> @@ -787,6 +787,9 @@ coreconfigitem('server', 'validate',
> coreconfigitem('server', 'zliblevel',
> default=-1,
> )
> +coreconfigitem('server', 'single-head',
> + default=False,
> +)
> coreconfigitem('share', 'pool',
> default=None,
> )
> diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
> --- a/mercurial/help/config.txt
> +++ b/mercurial/help/config.txt
> @@ -1723,6 +1723,10 @@ Alias definitions for revsets. See :hg:`
>
> Controls generic server settings.
>
> +``single-head``
> + Force the repository to always contains a single head for each named
> + branches. Any push/pull commit adding a new heads will be rejected.
> +
> ``compressionengines``
> List of compression engines and their relative priority to advertise
> to clients.
> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> --- a/mercurial/localrepo.py
> +++ b/mercurial/localrepo.py
> @@ -1244,6 +1244,8 @@ class localrepository(object):
> # gating.
> tracktags(tr2)
> repo = reporef()
> + if repo.ui.configbool('server', 'single-head'):
> + scmutil.enforcesinglehead(repo, tr2)
>
Using "server" in the context of localrepo doesn't feel correct. This code
is running as part of the generic transaction closing code, which means it
applies to *all* repo contexts. I think the config option section should
reflect that.
> if hook.hashook(repo.ui, 'pretxnclose-bookmark'):
> for name, (old, new) in sorted(tr.changes['bookmarks']
> .items()):
> args = tr.hookargs.copy()
> diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
> --- a/mercurial/scmutil.py
> +++ b/mercurial/scmutil.py
> @@ -1277,3 +1277,15 @@ def nodesummaries(repo, nodes, maxnumnod
> return ' '.join(short(h) for h in nodes)
> first = ' '.join(short(h) for h in nodes[:maxnumnodes])
> return _("%s and %s others") % (first, len(nodes) - maxnumnodes)
> +
> +def enforcesinglehead(repo, tr):
> + """check that no named branch has multiple heads"""
> + visible = repo.filtered('visible')
> + # possible improvement: we could restrict the check to affected branch
> + for name, heads in visible.branchmap().iteritems():
> + if len(heads) > 1:
> + msg = _('rejecting multiple heads on branch "%s"')
> + msg %= name
> + hint = _('%d heads: %s')
> + hint %= (len(heads), nodesummaries(repo, heads))
> + raise error.Abort(msg, hint=hint)
>
What happens when you `hg strip` a repo that already has multiple heads on
a named branch? I /think/ that when the stripped changesets are re-applied
to the repo, this code prevents them from being applied and the resulting
repo is truncated and somewhere there is a backup or temp bundle containing
the changesets that would have been re-applied. That's obviously bad. For
this reason, many of Mozilla's "prevent changes" hooks no-op if the
transaction "source" is "strip."
> diff --git a/tests/test-single-head.t b/tests/test-single-head.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-single-head.t
> @@ -0,0 +1,115 @@
> +=====================
> +Test workflow options
> +=====================
> +
> + $ . "$TESTDIR/testlib/obsmarker-common.sh"
> +
> +Test single head enforcing - Setup
> +=============================================
> +
> + $ cat << EOF >> $HGRCPATH
> + > [experimental]
> + > evolution = all
> + > EOF
> + $ hg init single-head-server
> + $ cd single-head-server
> + $ cat <<EOF >> .hg/hgrc
> + > [phases]
> + > publish = no
> + > [server]
> + > single-head = yes
> + > EOF
> + $ mkcommit ROOT
> + $ mkcommit c_dA0
> + $ cd ..
> +
> + $ hg clone single-head-server client
> + updating to branch default
> + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +Test single head enforcing - with branch only
> +---------------------------------------------
> +
> + $ cd client
> +
> +continuing the current defaultbranch
> +
> + $ mkcommit c_dB0
> + $ hg push
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files
> +
> +creating a new branch
> +
> + $ hg up 'desc("ROOT")'
> + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
> + $ hg branch branch_A
> + marked working directory as branch branch_A
> + (branches are permanent and global, did you want a bookmark?)
> + $ mkcommit c_aC0
> + $ hg push --new-branch
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files (+1 heads)
> +
> +Create a new head on the default branch
> +
> + $ hg up 'desc("c_dA0")'
> + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> + $ mkcommit c_dD0
> + created new head
> + $ hg push -f
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files (+1 heads)
> + transaction abort!
> + rollback completed
> + abort: rejecting multiple heads on branch "default"
> + (2 heads: 286d02a6e2a2 9bf953aa81f6)
> + [255]
> +
> +remerge them
> +
> + $ hg merge
> + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> + (branch merge, don't forget to commit)
> + $ mkcommit c_dE0
> + $ hg push
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 2 changesets with 2 changes to 2 files
> +
> +Test single head enforcing - after rewrite
> +------------------------------------------
> +
> + $ mkcommit c_dF0
> + $ hg push
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files
> + $ hg commit --amend -m c_dF1
> + $ hg push
> + pushing to $TESTTMP/single-head-server (glob)
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 0 changes to 1 files (+1 heads)
> + 1 new obsolescence markers
> + obsoleted 1 changesets
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20171116/4bd38eb3/attachment.html>
More information about the Mercurial-devel
mailing list