##// END OF EJS Templates
py3: fix kwargs handling in hgext/split.py...
Pulkit Goyal -
r38080:5ba0cf22 default
parent child Browse files
Show More
@@ -1,178 +1,179 b''
1 1 # split.py - split a changeset into smaller ones
2 2 #
3 3 # Copyright 2015 Laurent Charignon <lcharignon@fb.com>
4 4 # Copyright 2017 Facebook, Inc.
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8 """command to split a changeset into smaller ones (EXPERIMENTAL)"""
9 9
10 10 from __future__ import absolute_import
11 11
12 12 from mercurial.i18n import _
13 13
14 14 from mercurial.node import (
15 15 nullid,
16 16 short,
17 17 )
18 18
19 19 from mercurial import (
20 20 bookmarks,
21 21 cmdutil,
22 22 commands,
23 23 error,
24 24 hg,
25 25 obsolete,
26 26 phases,
27 27 pycompat,
28 28 registrar,
29 29 revsetlang,
30 30 scmutil,
31 31 )
32 32
33 33 # allow people to use split without explicitly enabling rebase extension
34 34 from . import (
35 35 rebase,
36 36 )
37 37
38 38 cmdtable = {}
39 39 command = registrar.command(cmdtable)
40 40
41 41 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
42 42 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
43 43 # be specifying the version(s) of Mercurial they are tested with, or
44 44 # leave the attribute unspecified.
45 45 testedwith = 'ships-with-hg-core'
46 46
47 47 @command('^split',
48 48 [('r', 'rev', '', _("revision to split"), _('REV')),
49 49 ('', 'rebase', True, _('rebase descendants after split')),
50 50 ] + cmdutil.commitopts2,
51 51 _('hg split [--no-rebase] [[-r] REV]'))
52 52 def split(ui, repo, *revs, **opts):
53 53 """split a changeset into smaller ones
54 54
55 55 Repeatedly prompt changes and commit message for new changesets until there
56 56 is nothing left in the original changeset.
57 57
58 58 If --rev was not given, split the working directory parent.
59 59
60 60 By default, rebase connected non-obsoleted descendants onto the new
61 61 changeset. Use --no-rebase to avoid the rebase.
62 62 """
63 opts = pycompat.byteskwargs(opts)
63 64 revlist = []
64 65 if opts.get('rev'):
65 66 revlist.append(opts.get('rev'))
66 67 revlist.extend(revs)
67 68 with repo.wlock(), repo.lock(), repo.transaction('split') as tr:
68 69 revs = scmutil.revrange(repo, revlist or ['.'])
69 70 if len(revs) > 1:
70 71 raise error.Abort(_('cannot split multiple revisions'))
71 72
72 73 rev = revs.first()
73 74 ctx = repo[rev]
74 75 if rev is None or ctx.node() == nullid:
75 76 ui.status(_('nothing to split\n'))
76 77 return 1
77 78 if ctx.node() is None:
78 79 raise error.Abort(_('cannot split working directory'))
79 80
80 81 # rewriteutil.precheck is not very useful here because:
81 82 # 1. null check is done above and it's more friendly to return 1
82 83 # instead of abort
83 84 # 2. mergestate check is done below by cmdutil.bailifchanged
84 85 # 3. unstable check is more complex here because of --rebase
85 86 #
86 87 # So only "public" check is useful and it's checked directly here.
87 88 if ctx.phase() == phases.public:
88 89 raise error.Abort(_('cannot split public changeset'),
89 90 hint=_("see 'hg help phases' for details"))
90 91
91 92 descendants = list(repo.revs('(%d::) - (%d)', rev, rev))
92 93 alloworphaned = obsolete.isenabled(repo, obsolete.allowunstableopt)
93 94 if opts.get('rebase'):
94 95 # Skip obsoleted descendants and their descendants so the rebase
95 96 # won't cause conflicts for sure.
96 97 torebase = list(repo.revs('%ld - (%ld & obsolete())::',
97 98 descendants, descendants))
98 99 if not alloworphaned and len(torebase) != len(descendants):
99 100 raise error.Abort(_('split would leave orphaned changesets '
100 101 'behind'))
101 102 else:
102 103 if not alloworphaned and descendants:
103 104 raise error.Abort(
104 105 _('cannot split changeset with children without rebase'))
105 106 torebase = ()
106 107
107 108 if len(ctx.parents()) > 1:
108 109 raise error.Abort(_('cannot split a merge changeset'))
109 110
110 111 cmdutil.bailifchanged(repo)
111 112
112 113 # Deactivate bookmark temporarily so it won't get moved unintentionally
113 114 bname = repo._activebookmark
114 115 if bname and repo._bookmarks[bname] != ctx.node():
115 116 bookmarks.deactivate(repo)
116 117
117 118 wnode = repo['.'].node()
118 119 top = None
119 120 try:
120 121 top = dosplit(ui, repo, tr, ctx, opts)
121 122 finally:
122 123 # top is None: split failed, need update --clean recovery.
123 124 # wnode == ctx.node(): wnode split, no need to update.
124 125 if top is None or wnode != ctx.node():
125 126 hg.clean(repo, wnode, show_stats=False)
126 127 if bname:
127 128 bookmarks.activate(repo, bname)
128 129 if torebase and top:
129 130 dorebase(ui, repo, torebase, top)
130 131
131 132 def dosplit(ui, repo, tr, ctx, opts):
132 133 committed = [] # [ctx]
133 134
134 135 # Set working parent to ctx.p1(), and keep working copy as ctx's content
135 136 # NOTE: if we can have "update without touching working copy" API, the
136 137 # revert step could be cheaper.
137 138 hg.clean(repo, ctx.p1().node(), show_stats=False)
138 139 parents = repo.changelog.parents(ctx.node())
139 140 ui.pushbuffer()
140 141 cmdutil.revert(ui, repo, ctx, parents)
141 142 ui.popbuffer() # discard "reverting ..." messages
142 143
143 144 # Any modified, added, removed, deleted result means split is incomplete
144 145 incomplete = lambda repo: any(repo.status()[:4])
145 146
146 147 # Main split loop
147 148 while incomplete(repo):
148 149 if committed:
149 150 header = (_('HG: Splitting %s. So far it has been split into:\n')
150 151 % short(ctx.node()))
151 152 for c in committed:
152 153 firstline = c.description().split('\n', 1)[0]
153 154 header += _('HG: - %s: %s\n') % (short(c.node()), firstline)
154 155 header += _('HG: Write commit message for the next split '
155 156 'changeset.\n')
156 157 else:
157 158 header = _('HG: Splitting %s. Write commit message for the '
158 159 'first split changeset.\n') % short(ctx.node())
159 160 opts.update({
160 161 'edit': True,
161 162 'interactive': True,
162 163 'message': header + ctx.description(),
163 164 })
164 165 commands.commit(ui, repo, **pycompat.strkwargs(opts))
165 166 newctx = repo['.']
166 167 committed.append(newctx)
167 168
168 169 if not committed:
169 170 raise error.Abort(_('cannot split an empty revision'))
170 171
171 172 scmutil.cleanupnodes(repo, {ctx.node(): [c.node() for c in committed]},
172 173 operation='split')
173 174
174 175 return committed[-1]
175 176
176 177 def dorebase(ui, repo, src, destctx):
177 178 rebase.rebase(ui, repo, rev=[revsetlang.formatspec('%ld', src)],
178 179 dest=revsetlang.formatspec('%d', destctx.rev()))
General Comments 0
You need to be logged in to leave comments. Login now