[PATCH evolve-ext] evolve: add a command to split commits
Pierre-Yves David
pierre-yves.david at ens-lyon.org
Fri Aug 7 18:09:22 UTC 2015
On 08/07/2015 10:53 AM, Laurent Charignon wrote:
> # HG changeset patch
> # User Laurent Charignon <lcharignon at fb.com>
> # Date 1434671333 25200
> # Thu Jun 18 16:48:53 2015 -0700
> # Node ID ec33aec0415556a456660e09ad61094c34aacb04
> # Parent 8e6de39b724d854cb92d2de3a0472ffb03627034
> evolve: add a command to split commits
>
> Before this patch, to split commit one had to use prune. This patch adds a
> new command called split that prompts the user interactively to split a given
> changeset with record/crecord.
>
> diff --git a/hgext/evolve.py b/hgext/evolve.py
> --- a/hgext/evolve.py
> +++ b/hgext/evolve.py
> @@ -2554,6 +2554,75 @@ def commitwrapper(orig, ui, repo, *arg,
> finally:
> lockmod.release(lock, wlock)
>
> + at command('^split',
> + [('r', 'rev', [], _("revision to fold")),
> + ] + commitopts + commitopts2,
> + _('hg split [OPTION]... [-r] REV'))
> +def split(ui, repo, *revs, **opts):
> + """Split the current commit using interactive selection
> +
> + By default, split the current revision by prompting for all its hunk to be
> + redistributed into new changesets.
> +
> + Use --rev for splitting a given changeset instead.
> + """
> + tr = wlock = lock = None
> + cmdutil.bailifchanged(repo)
> + newcommits = []
> +
> + revopt = opts.get('rev')
> + if revopt:
> + revs = scmutil.revrange(repo, revopt)
> + if len(revs) != 1:
> + raise util.Abort(_("you can only specify one revision to split"))
> + else:
> + rev = list(revs)[0]
> + commands.update(ui, repo, rev)
> + else:
> + rev = '.'
> +
> + try:
> + wlock = repo.wlock()
> + lock = repo.lock()
> + tr = repo.transaction('split')
> + ctx = repo[rev]
> + r = ctx.rev()
> + disallowunstable = not obsolete.isenabled(repo,
> + obsolete.allowunstableopt)
> + if disallowunstable:
> + # XXX We should check head revs
> + if repo.revs("(%d::) - %d", rev, rev):
> + raise util.Abort(_("cannot split commit: %s not a head" % ctx))
> +
> + if len(ctx.parents()) > 1:
> + raise util.Abort(_("cannot split merge commits"))
> + prev = ctx.p1()
> + hg.update(repo, prev)
I would be happier if we could do all the diffing, recording and
patching directly in memory. But I'm fine with this as a first step.
However, if you do an update here, you have to check if the working copy
has any change or this can result in some butchery.
cf mercurial.cmdutil.bailifchanged
> +
> + commands.revert(ui, repo, rev=r, all=True)
> + def haschanges():
> + return len(list(patch.diff(repo))) != 0
We usually use status for such check.
cf mercurial.cmdutil.bailifchanged
> + while haschanges():
> + pats = ()
> + cmdutil.dorecord(ui, repo, commands.commit, 'commit', False,
> + cmdutil.recordfilter, *pats, **opts)
> + # TODO: Does no seem like the best way to do this
> + # We should make dorecord return the newly created commit
> + newcommits.append(repo['.'])
> + if haschanges():
> + if ui.prompt('Done splitting? [yN]', default='n') == 'y':
> + commands.commit(ui, repo, **opts)
> + newcommits.append(repo['.'])
> + break
> + else:
> + ui.status("no more change to split\n")
> +
> + obsolete.createmarkers(repo, [(repo[r], newcommits)])
> + tr.close()
> + finally:
> + lockmod.release(tr, lock, wlock)
> +
> +
> @eh.wrapcommand('strip', extension='strip', opts=[
> ('', 'bundle', None, _("delete the commit entirely and move it to a "
> "backup bundle")),
> diff --git a/tests/test-split.t b/tests/test-split.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-split.t
> @@ -0,0 +1,184 @@
> +test of the split command
> +-----------------------
> +
> + $ cat >> $HGRCPATH <<EOF
> + > [defaults]
> + > amend=-d "0 0"
> + > fold=-d "0 0"
> + > split=-d "0 0"
> + > amend=-d "0 0"
> + > [web]
> + > push_ssl = false
> + > allow_push = *
> + > [phases]
> + > publish = False
> + > [diff]
> + > git = 1
> + > unified = 0
> + > [ui]
> + > interactive = true
> + > [extensions]
> + > hgext.graphlog=
> + > EOF
> + $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
> + $ mkcommit() {
> + > echo "$1" > "$1"
> + > hg add "$1"
> + > hg ci -m "add $1"
> + > }
> +
> +
> +Basic case, split a head
> + $ hg init testsplit
> + $ cd testsplit
> + $ mkcommit _a
> + $ mkcommit _b
> + $ mkcommit _c
> + $ mkcommit _d
> + $ echo "change to a" >> _a
> + $ hg amend
> + $ hg debugobsolete
> + 9e84a109b8eb081ad754681ee4b1380d17a3741f aa8f656bb307022172d2648be6fb65322f801225 0 (*) {'user': 'test'} (glob)
> + f002b57772d7f09b180c407213ae16d92996a988 0 {9e84a109b8eb081ad754681ee4b1380d17a3741f} (*) {'user': 'test'} (glob)
> +
> +To create commits with the number of split
> + $ export NUM=0
> + $ export HGEDITOR="NUM=$((NUM+1)); echo split$NUM > $1"
You probably want to document (or some pointeur) to the NUM logic.
--
Pierre-Yves David
More information about the Mercurial-devel
mailing list