# HG changeset patch # User Laurent Charignon # Date 1434671333 25200 # Node ID 9603aa1ecdfd54b0d86e262318a72e0a2ffeb6cc # Parent 6ab5c0f40699c637c3419abc34c0bfdb70295833 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 -r 6ab5c0f40699 -r 9603aa1ecdfd README --- a/README Mon Aug 03 11:29:27 2015 -0700 +++ b/README Thu Jun 18 16:48:53 2015 -0700 @@ -51,6 +51,10 @@ Changelog ========= +5.2.0 -- + +- split: add a new command to split changesets + 5.2.0 -- 2015-06-25 - evolve: gain a --rev option to control what revisions to evolve (issue4391) diff -r 6ab5c0f40699 -r 9603aa1ecdfd hgext/evolve.py --- a/hgext/evolve.py Mon Aug 03 11:29:27 2015 -0700 +++ b/hgext/evolve.py Thu Jun 18 16:48:53 2015 -0700 @@ -2554,6 +2554,76 @@ finally: lockmod.release(lock, wlock) +@command('^split', + [('r', 'rev', [], _("revision to fold")), + ] + commitopts + commitopts2, + _('hg split [OPTION]... [-r] REV')) +def cmdsplit(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 + 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() + cmdutil.bailifchanged(repo) + 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) + + commands.revert(ui, repo, rev=r, all=True) + def haschanges(): + modified, added, removed, deleted = repo.status()[:4] + return modified or added or removed or deleted + 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 -r 6ab5c0f40699 -r 9603aa1ecdfd tests/test-split.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-split.t Thu Jun 18 16:48:53 2015 -0700 @@ -0,0 +1,193 @@ +test of the split command +----------------------- + + $ cat >> $HGRCPATH < [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" + $ hg split << EOF + > y + > y + > y + > n + > N + > y + > y + > EOF + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + reverting _a + adding _d + diff --git a/_a b/_a + 1 hunks, 1 lines changed + examine changes to '_a'? [Ynesfdaq?] y + + @@ -1,0 +2,1 @@ + +change to a + record change 1/2 to '_a'? [Ynesfdaq?] y + + diff --git a/_d b/_d + new file mode 100644 + examine changes to '_d'? [Ynesfdaq?] y + + @@ -0,0 +1,1 @@ + +_d + record change 2/2 to '_d'? [Ynesfdaq?] n + + created new head + Done splitting? [yN] N + diff --git a/_d b/_d + new file mode 100644 + examine changes to '_d'? [Ynesfdaq?] y + + @@ -0,0 +1,1 @@ + +_d + record this change to '_d'? [Ynesfdaq?] y + + no more change to split + + $ hg debugobsolete + 9e84a109b8eb081ad754681ee4b1380d17a3741f aa8f656bb307022172d2648be6fb65322f801225 0 (*) {'user': 'test'} (glob) + f002b57772d7f09b180c407213ae16d92996a988 0 {9e84a109b8eb081ad754681ee4b1380d17a3741f} (*) {'user': 'test'} (glob) + aa8f656bb307022172d2648be6fb65322f801225 8a76f55839e6badd47ed8338803d8bc16f578d68 1e105584671a463974ee2122f95979ce5e507f1a 0 (*) {'user': 'test'} (glob) + +Cannot split a commit with uncommited changes + $ hg up "desc(_c)" + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo "_cd" > _c + $ hg split + abort: uncommitted changes + [255] + +Split a revision specified with -r + $ hg up "desc(_c)" -C + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "change to b" >> _b + $ hg amend -m "_cprim" + 2 new unstable changesets + $ hg evolve --all + move:[6] split0 + atop:[9] _cprim + move:[7] split0 + atop:[10] split0 + working directory is now at * (glob) + $ hg log -r "desc(_cprim)" -v -p + changeset: 9:719157b217ac + parent: 1:37445b16603b + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + files: _b _c + description: + _cprim + + + diff --git a/_b b/_b + --- a/_b + +++ b/_b + @@ -1,0 +2,1 @@ + +change to b + diff --git a/_c b/_c + new file mode 100644 + --- /dev/null + +++ b/_c + @@ -0,0 +1,1 @@ + +_c + + $ hg split -r "desc(_cprim)" < y + > y + > y + > n + > y + > EOF + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + reverting _b + adding _c + diff --git a/_b b/_b + 1 hunks, 1 lines changed + examine changes to '_b'? [Ynesfdaq?] y + + @@ -1,0 +2,1 @@ + +change to b + record change 1/2 to '_b'? [Ynesfdaq?] y + + diff --git a/_c b/_c + new file mode 100644 + examine changes to '_c'? [Ynesfdaq?] y + + @@ -0,0 +1,1 @@ + +_c + record change 2/2 to '_c'? [Ynesfdaq?] n + + created new head + Done splitting? [yN] y + +Stop before splitting the commit completely creates a commit with all the +remaining changes + + $ hg debugobsolete + 9e84a109b8eb081ad754681ee4b1380d17a3741f aa8f656bb307022172d2648be6fb65322f801225 0 (*) {'user': 'test'} (glob) + f002b57772d7f09b180c407213ae16d92996a988 0 {9e84a109b8eb081ad754681ee4b1380d17a3741f} (*) {'user': 'test'} (glob) + aa8f656bb307022172d2648be6fb65322f801225 8a76f55839e6badd47ed8338803d8bc16f578d68 1e105584671a463974ee2122f95979ce5e507f1a 0 (*) {'user': 'test'} (glob) + 10200229058723ce8d67f6612c1f6b4f73b1fe73 719157b217acc43d397369a448824ed4c7a302f2 0 (*) {'user': 'test'} (glob) + 5d0c8b0f2d3e5e1ff95f93d7da2ba06650605ab5 0 {10200229058723ce8d67f6612c1f6b4f73b1fe73} (*) {'user': 'test'} (glob) + 8a76f55839e6badd47ed8338803d8bc16f578d68 0ea1d0d23e674ea8a6affe760741c82bb8e380f7 0 (*) {'user': 'test'} (glob) + 1e105584671a463974ee2122f95979ce5e507f1a b6099ccb49cae181af7c59ed5603a1dfca632445 0 (*) {'user': 'test'} (glob) + 719157b217acc43d397369a448824ed4c7a302f2 8eb71353cb2c70fc1154be3af79c0ce98898ae88 ead904640c8543606f72490c6ae10955fb11fff0 0 (*) {'user': 'test'} (glob) + +Cannot specify multiple revisions with -r + $ hg split -r "desc(_a)::" + abort: you can only specify one revision to split + [255] + +Cannot split a commit that is not a head if instability is not allowed + $ cat >> $HGRCPATH < [experimental] + > evolution=createmarkers + > evolutioncommands=split + > EOF + $ hg split -r "desc(_c)" + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + abort: cannot split commit: 719157b217ac not a head + [255] + +