##// END OF EJS Templates
py3: make hgext/rebase.py use absolute_import
Pulkit Goyal -
r29128:e521cb13 default
parent child Browse files
Show More
@@ -1,1374 +1,1401 b''
1 # rebase.py - rebasing feature for mercurial
1 # rebase.py - rebasing feature for mercurial
2 #
2 #
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to move sets of revisions to a different ancestor
8 '''command to move sets of revisions to a different ancestor
9
9
10 This extension lets you rebase changesets in an existing Mercurial
10 This extension lets you rebase changesets in an existing Mercurial
11 repository.
11 repository.
12
12
13 For more information:
13 For more information:
14 https://mercurial-scm.org/wiki/RebaseExtension
14 https://mercurial-scm.org/wiki/RebaseExtension
15 '''
15 '''
16
16
17 from mercurial import hg, util, repair, merge, cmdutil, commands, bookmarks
17 from __future__ import absolute_import
18 from mercurial import extensions, patch, scmutil, phases, obsolete, error
18
19 from mercurial import copies, destutil, repoview, registrar, revset
19 import errno
20 from mercurial.commands import templateopts
20 import os
21 from mercurial.node import nullrev, nullid, hex, short
21 from mercurial import (
22 from mercurial.lock import release
22 bookmarks,
23 cmdutil,
24 commands,
25 copies,
26 destutil,
27 error,
28 extensions,
29 hg,
30 lock,
31 merge,
32 obsolete,
33 patch,
34 phases,
35 registrar,
36 repair,
37 repoview,
38 revset,
39 scmutil,
40 util,
41 )
42 from mercurial.node import (
43 hex,
44 nullid,
45 nullrev,
46 short,
47 )
23 from mercurial.i18n import _
48 from mercurial.i18n import _
24 import os, errno
49
50 release = lock.release
51 templateopts = commands.templateopts
25
52
26 # The following constants are used throughout the rebase module. The ordering of
53 # The following constants are used throughout the rebase module. The ordering of
27 # their values must be maintained.
54 # their values must be maintained.
28
55
29 # Indicates that a revision needs to be rebased
56 # Indicates that a revision needs to be rebased
30 revtodo = -1
57 revtodo = -1
31 nullmerge = -2
58 nullmerge = -2
32 revignored = -3
59 revignored = -3
33 # successor in rebase destination
60 # successor in rebase destination
34 revprecursor = -4
61 revprecursor = -4
35 # plain prune (no successor)
62 # plain prune (no successor)
36 revpruned = -5
63 revpruned = -5
37 revskipped = (revignored, revprecursor, revpruned)
64 revskipped = (revignored, revprecursor, revpruned)
38
65
39 cmdtable = {}
66 cmdtable = {}
40 command = cmdutil.command(cmdtable)
67 command = cmdutil.command(cmdtable)
41 # Note for extension authors: ONLY specify testedwith = 'internal' for
68 # Note for extension authors: ONLY specify testedwith = 'internal' for
42 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
69 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
43 # be specifying the version(s) of Mercurial they are tested with, or
70 # be specifying the version(s) of Mercurial they are tested with, or
44 # leave the attribute unspecified.
71 # leave the attribute unspecified.
45 testedwith = 'internal'
72 testedwith = 'internal'
46
73
47 def _nothingtorebase():
74 def _nothingtorebase():
48 return 1
75 return 1
49
76
50 def _savegraft(ctx, extra):
77 def _savegraft(ctx, extra):
51 s = ctx.extra().get('source', None)
78 s = ctx.extra().get('source', None)
52 if s is not None:
79 if s is not None:
53 extra['source'] = s
80 extra['source'] = s
54 s = ctx.extra().get('intermediate-source', None)
81 s = ctx.extra().get('intermediate-source', None)
55 if s is not None:
82 if s is not None:
56 extra['intermediate-source'] = s
83 extra['intermediate-source'] = s
57
84
58 def _savebranch(ctx, extra):
85 def _savebranch(ctx, extra):
59 extra['branch'] = ctx.branch()
86 extra['branch'] = ctx.branch()
60
87
61 def _makeextrafn(copiers):
88 def _makeextrafn(copiers):
62 """make an extrafn out of the given copy-functions.
89 """make an extrafn out of the given copy-functions.
63
90
64 A copy function takes a context and an extra dict, and mutates the
91 A copy function takes a context and an extra dict, and mutates the
65 extra dict as needed based on the given context.
92 extra dict as needed based on the given context.
66 """
93 """
67 def extrafn(ctx, extra):
94 def extrafn(ctx, extra):
68 for c in copiers:
95 for c in copiers:
69 c(ctx, extra)
96 c(ctx, extra)
70 return extrafn
97 return extrafn
71
98
72 def _destrebase(repo, sourceset, destspace=None):
99 def _destrebase(repo, sourceset, destspace=None):
73 """small wrapper around destmerge to pass the right extra args
100 """small wrapper around destmerge to pass the right extra args
74
101
75 Please wrap destutil.destmerge instead."""
102 Please wrap destutil.destmerge instead."""
76 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
103 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
77 onheadcheck=False, destspace=destspace)
104 onheadcheck=False, destspace=destspace)
78
105
79 revsetpredicate = registrar.revsetpredicate()
106 revsetpredicate = registrar.revsetpredicate()
80
107
81 @revsetpredicate('_destrebase')
108 @revsetpredicate('_destrebase')
82 def _revsetdestrebase(repo, subset, x):
109 def _revsetdestrebase(repo, subset, x):
83 # ``_rebasedefaultdest()``
110 # ``_rebasedefaultdest()``
84
111
85 # default destination for rebase.
112 # default destination for rebase.
86 # # XXX: Currently private because I expect the signature to change.
113 # # XXX: Currently private because I expect the signature to change.
87 # # XXX: - bailing out in case of ambiguity vs returning all data.
114 # # XXX: - bailing out in case of ambiguity vs returning all data.
88 # i18n: "_rebasedefaultdest" is a keyword
115 # i18n: "_rebasedefaultdest" is a keyword
89 sourceset = None
116 sourceset = None
90 if x is not None:
117 if x is not None:
91 sourceset = revset.getset(repo, revset.fullreposet(repo), x)
118 sourceset = revset.getset(repo, revset.fullreposet(repo), x)
92 return subset & revset.baseset([_destrebase(repo, sourceset)])
119 return subset & revset.baseset([_destrebase(repo, sourceset)])
93
120
94 @command('rebase',
121 @command('rebase',
95 [('s', 'source', '',
122 [('s', 'source', '',
96 _('rebase the specified changeset and descendants'), _('REV')),
123 _('rebase the specified changeset and descendants'), _('REV')),
97 ('b', 'base', '',
124 ('b', 'base', '',
98 _('rebase everything from branching point of specified changeset'),
125 _('rebase everything from branching point of specified changeset'),
99 _('REV')),
126 _('REV')),
100 ('r', 'rev', [],
127 ('r', 'rev', [],
101 _('rebase these revisions'),
128 _('rebase these revisions'),
102 _('REV')),
129 _('REV')),
103 ('d', 'dest', '',
130 ('d', 'dest', '',
104 _('rebase onto the specified changeset'), _('REV')),
131 _('rebase onto the specified changeset'), _('REV')),
105 ('', 'collapse', False, _('collapse the rebased changesets')),
132 ('', 'collapse', False, _('collapse the rebased changesets')),
106 ('m', 'message', '',
133 ('m', 'message', '',
107 _('use text as collapse commit message'), _('TEXT')),
134 _('use text as collapse commit message'), _('TEXT')),
108 ('e', 'edit', False, _('invoke editor on commit messages')),
135 ('e', 'edit', False, _('invoke editor on commit messages')),
109 ('l', 'logfile', '',
136 ('l', 'logfile', '',
110 _('read collapse commit message from file'), _('FILE')),
137 _('read collapse commit message from file'), _('FILE')),
111 ('k', 'keep', False, _('keep original changesets')),
138 ('k', 'keep', False, _('keep original changesets')),
112 ('', 'keepbranches', False, _('keep original branch names')),
139 ('', 'keepbranches', False, _('keep original branch names')),
113 ('D', 'detach', False, _('(DEPRECATED)')),
140 ('D', 'detach', False, _('(DEPRECATED)')),
114 ('i', 'interactive', False, _('(DEPRECATED)')),
141 ('i', 'interactive', False, _('(DEPRECATED)')),
115 ('t', 'tool', '', _('specify merge tool')),
142 ('t', 'tool', '', _('specify merge tool')),
116 ('c', 'continue', False, _('continue an interrupted rebase')),
143 ('c', 'continue', False, _('continue an interrupted rebase')),
117 ('a', 'abort', False, _('abort an interrupted rebase'))] +
144 ('a', 'abort', False, _('abort an interrupted rebase'))] +
118 templateopts,
145 templateopts,
119 _('[-s REV | -b REV] [-d REV] [OPTION]'))
146 _('[-s REV | -b REV] [-d REV] [OPTION]'))
120 def rebase(ui, repo, **opts):
147 def rebase(ui, repo, **opts):
121 """move changeset (and descendants) to a different branch
148 """move changeset (and descendants) to a different branch
122
149
123 Rebase uses repeated merging to graft changesets from one part of
150 Rebase uses repeated merging to graft changesets from one part of
124 history (the source) onto another (the destination). This can be
151 history (the source) onto another (the destination). This can be
125 useful for linearizing *local* changes relative to a master
152 useful for linearizing *local* changes relative to a master
126 development tree.
153 development tree.
127
154
128 Published commits cannot be rebased (see :hg:`help phases`).
155 Published commits cannot be rebased (see :hg:`help phases`).
129 To copy commits, see :hg:`help graft`.
156 To copy commits, see :hg:`help graft`.
130
157
131 If you don't specify a destination changeset (``-d/--dest``), rebase
158 If you don't specify a destination changeset (``-d/--dest``), rebase
132 will use the same logic as :hg:`merge` to pick a destination. if
159 will use the same logic as :hg:`merge` to pick a destination. if
133 the current branch contains exactly one other head, the other head
160 the current branch contains exactly one other head, the other head
134 is merged with by default. Otherwise, an explicit revision with
161 is merged with by default. Otherwise, an explicit revision with
135 which to merge with must be provided. (destination changeset is not
162 which to merge with must be provided. (destination changeset is not
136 modified by rebasing, but new changesets are added as its
163 modified by rebasing, but new changesets are added as its
137 descendants.)
164 descendants.)
138
165
139 Here are the ways to select changesets:
166 Here are the ways to select changesets:
140
167
141 1. Explicitly select them using ``--rev``.
168 1. Explicitly select them using ``--rev``.
142
169
143 2. Use ``--source`` to select a root changeset and include all of its
170 2. Use ``--source`` to select a root changeset and include all of its
144 descendants.
171 descendants.
145
172
146 3. Use ``--base`` to select a changeset; rebase will find ancestors
173 3. Use ``--base`` to select a changeset; rebase will find ancestors
147 and their descendants which are not also ancestors of the destination.
174 and their descendants which are not also ancestors of the destination.
148
175
149 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
176 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
150 rebase will use ``--base .`` as above.
177 rebase will use ``--base .`` as above.
151
178
152 Rebase will destroy original changesets unless you use ``--keep``.
179 Rebase will destroy original changesets unless you use ``--keep``.
153 It will also move your bookmarks (even if you do).
180 It will also move your bookmarks (even if you do).
154
181
155 Some changesets may be dropped if they do not contribute changes
182 Some changesets may be dropped if they do not contribute changes
156 (e.g. merges from the destination branch).
183 (e.g. merges from the destination branch).
157
184
158 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
185 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
159 a named branch with two heads. You will need to explicitly specify source
186 a named branch with two heads. You will need to explicitly specify source
160 and/or destination.
187 and/or destination.
161
188
162 If you need to use a tool to automate merge/conflict decisions, you
189 If you need to use a tool to automate merge/conflict decisions, you
163 can specify one with ``--tool``, see :hg:`help merge-tools`.
190 can specify one with ``--tool``, see :hg:`help merge-tools`.
164 As a caveat: the tool will not be used to mediate when a file was
191 As a caveat: the tool will not be used to mediate when a file was
165 deleted, there is no hook presently available for this.
192 deleted, there is no hook presently available for this.
166
193
167 If a rebase is interrupted to manually resolve a conflict, it can be
194 If a rebase is interrupted to manually resolve a conflict, it can be
168 continued with --continue/-c or aborted with --abort/-a.
195 continued with --continue/-c or aborted with --abort/-a.
169
196
170 .. container:: verbose
197 .. container:: verbose
171
198
172 Examples:
199 Examples:
173
200
174 - move "local changes" (current commit back to branching point)
201 - move "local changes" (current commit back to branching point)
175 to the current branch tip after a pull::
202 to the current branch tip after a pull::
176
203
177 hg rebase
204 hg rebase
178
205
179 - move a single changeset to the stable branch::
206 - move a single changeset to the stable branch::
180
207
181 hg rebase -r 5f493448 -d stable
208 hg rebase -r 5f493448 -d stable
182
209
183 - splice a commit and all its descendants onto another part of history::
210 - splice a commit and all its descendants onto another part of history::
184
211
185 hg rebase --source c0c3 --dest 4cf9
212 hg rebase --source c0c3 --dest 4cf9
186
213
187 - rebase everything on a branch marked by a bookmark onto the
214 - rebase everything on a branch marked by a bookmark onto the
188 default branch::
215 default branch::
189
216
190 hg rebase --base myfeature --dest default
217 hg rebase --base myfeature --dest default
191
218
192 - collapse a sequence of changes into a single commit::
219 - collapse a sequence of changes into a single commit::
193
220
194 hg rebase --collapse -r 1520:1525 -d .
221 hg rebase --collapse -r 1520:1525 -d .
195
222
196 - move a named branch while preserving its name::
223 - move a named branch while preserving its name::
197
224
198 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
225 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
199
226
200 Returns 0 on success, 1 if nothing to rebase or there are
227 Returns 0 on success, 1 if nothing to rebase or there are
201 unresolved conflicts.
228 unresolved conflicts.
202
229
203 """
230 """
204 originalwd = target = None
231 originalwd = target = None
205 activebookmark = None
232 activebookmark = None
206 external = nullrev
233 external = nullrev
207 # Mapping between the old revision id and either what is the new rebased
234 # Mapping between the old revision id and either what is the new rebased
208 # revision or what needs to be done with the old revision. The state dict
235 # revision or what needs to be done with the old revision. The state dict
209 # will be what contains most of the rebase progress state.
236 # will be what contains most of the rebase progress state.
210 state = {}
237 state = {}
211 skipped = set()
238 skipped = set()
212 targetancestors = set()
239 targetancestors = set()
213
240
214
241
215 lock = wlock = None
242 lock = wlock = None
216 try:
243 try:
217 wlock = repo.wlock()
244 wlock = repo.wlock()
218 lock = repo.lock()
245 lock = repo.lock()
219
246
220 # Validate input and define rebasing points
247 # Validate input and define rebasing points
221 destf = opts.get('dest', None)
248 destf = opts.get('dest', None)
222 srcf = opts.get('source', None)
249 srcf = opts.get('source', None)
223 basef = opts.get('base', None)
250 basef = opts.get('base', None)
224 revf = opts.get('rev', [])
251 revf = opts.get('rev', [])
225 # search default destination in this space
252 # search default destination in this space
226 # used in the 'hg pull --rebase' case, see issue 5214.
253 # used in the 'hg pull --rebase' case, see issue 5214.
227 destspace = opts.get('_destspace')
254 destspace = opts.get('_destspace')
228 contf = opts.get('continue')
255 contf = opts.get('continue')
229 abortf = opts.get('abort')
256 abortf = opts.get('abort')
230 collapsef = opts.get('collapse', False)
257 collapsef = opts.get('collapse', False)
231 collapsemsg = cmdutil.logmessage(ui, opts)
258 collapsemsg = cmdutil.logmessage(ui, opts)
232 date = opts.get('date', None)
259 date = opts.get('date', None)
233 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
260 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
234 extrafns = [_savegraft]
261 extrafns = [_savegraft]
235 if e:
262 if e:
236 extrafns = [e]
263 extrafns = [e]
237 keepf = opts.get('keep', False)
264 keepf = opts.get('keep', False)
238 keepbranchesf = opts.get('keepbranches', False)
265 keepbranchesf = opts.get('keepbranches', False)
239 # keepopen is not meant for use on the command line, but by
266 # keepopen is not meant for use on the command line, but by
240 # other extensions
267 # other extensions
241 keepopen = opts.get('keepopen', False)
268 keepopen = opts.get('keepopen', False)
242
269
243 if opts.get('interactive'):
270 if opts.get('interactive'):
244 try:
271 try:
245 if extensions.find('histedit'):
272 if extensions.find('histedit'):
246 enablehistedit = ''
273 enablehistedit = ''
247 except KeyError:
274 except KeyError:
248 enablehistedit = " --config extensions.histedit="
275 enablehistedit = " --config extensions.histedit="
249 help = "hg%s help -e histedit" % enablehistedit
276 help = "hg%s help -e histedit" % enablehistedit
250 msg = _("interactive history editing is supported by the "
277 msg = _("interactive history editing is supported by the "
251 "'histedit' extension (see \"%s\")") % help
278 "'histedit' extension (see \"%s\")") % help
252 raise error.Abort(msg)
279 raise error.Abort(msg)
253
280
254 if collapsemsg and not collapsef:
281 if collapsemsg and not collapsef:
255 raise error.Abort(
282 raise error.Abort(
256 _('message can only be specified with collapse'))
283 _('message can only be specified with collapse'))
257
284
258 if contf or abortf:
285 if contf or abortf:
259 if contf and abortf:
286 if contf and abortf:
260 raise error.Abort(_('cannot use both abort and continue'))
287 raise error.Abort(_('cannot use both abort and continue'))
261 if collapsef:
288 if collapsef:
262 raise error.Abort(
289 raise error.Abort(
263 _('cannot use collapse with continue or abort'))
290 _('cannot use collapse with continue or abort'))
264 if srcf or basef or destf:
291 if srcf or basef or destf:
265 raise error.Abort(
292 raise error.Abort(
266 _('abort and continue do not allow specifying revisions'))
293 _('abort and continue do not allow specifying revisions'))
267 if abortf and opts.get('tool', False):
294 if abortf and opts.get('tool', False):
268 ui.warn(_('tool option will be ignored\n'))
295 ui.warn(_('tool option will be ignored\n'))
269
296
270 try:
297 try:
271 (originalwd, target, state, skipped, collapsef, keepf,
298 (originalwd, target, state, skipped, collapsef, keepf,
272 keepbranchesf, external, activebookmark) = restorestatus(repo)
299 keepbranchesf, external, activebookmark) = restorestatus(repo)
273 collapsemsg = restorecollapsemsg(repo)
300 collapsemsg = restorecollapsemsg(repo)
274 except error.RepoLookupError:
301 except error.RepoLookupError:
275 if abortf:
302 if abortf:
276 clearstatus(repo)
303 clearstatus(repo)
277 clearcollapsemsg(repo)
304 clearcollapsemsg(repo)
278 repo.ui.warn(_('rebase aborted (no revision is removed,'
305 repo.ui.warn(_('rebase aborted (no revision is removed,'
279 ' only broken state is cleared)\n'))
306 ' only broken state is cleared)\n'))
280 return 0
307 return 0
281 else:
308 else:
282 msg = _('cannot continue inconsistent rebase')
309 msg = _('cannot continue inconsistent rebase')
283 hint = _('use "hg rebase --abort" to clear broken state')
310 hint = _('use "hg rebase --abort" to clear broken state')
284 raise error.Abort(msg, hint=hint)
311 raise error.Abort(msg, hint=hint)
285 if abortf:
312 if abortf:
286 return abort(repo, originalwd, target, state,
313 return abort(repo, originalwd, target, state,
287 activebookmark=activebookmark)
314 activebookmark=activebookmark)
288
315
289 obsoletenotrebased = {}
316 obsoletenotrebased = {}
290 if ui.configbool('experimental', 'rebaseskipobsolete',
317 if ui.configbool('experimental', 'rebaseskipobsolete',
291 default=True):
318 default=True):
292 rebaseobsrevs = set([r for r, status in state.items()
319 rebaseobsrevs = set([r for r, status in state.items()
293 if status == revprecursor])
320 if status == revprecursor])
294 rebasesetrevs = set(state.keys())
321 rebasesetrevs = set(state.keys())
295 obsoletenotrebased = _computeobsoletenotrebased(repo,
322 obsoletenotrebased = _computeobsoletenotrebased(repo,
296 rebaseobsrevs,
323 rebaseobsrevs,
297 target)
324 target)
298 rebaseobsskipped = set(obsoletenotrebased)
325 rebaseobsskipped = set(obsoletenotrebased)
299 _checkobsrebase(repo, ui, rebaseobsrevs, rebasesetrevs,
326 _checkobsrebase(repo, ui, rebaseobsrevs, rebasesetrevs,
300 rebaseobsskipped)
327 rebaseobsskipped)
301 else:
328 else:
302 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
329 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
303 destspace=destspace)
330 destspace=destspace)
304 if dest is None:
331 if dest is None:
305 return _nothingtorebase()
332 return _nothingtorebase()
306
333
307 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
334 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
308 if (not (keepf or allowunstable)
335 if (not (keepf or allowunstable)
309 and repo.revs('first(children(%ld) - %ld)',
336 and repo.revs('first(children(%ld) - %ld)',
310 rebaseset, rebaseset)):
337 rebaseset, rebaseset)):
311 raise error.Abort(
338 raise error.Abort(
312 _("can't remove original changesets with"
339 _("can't remove original changesets with"
313 " unrebased descendants"),
340 " unrebased descendants"),
314 hint=_('use --keep to keep original changesets'))
341 hint=_('use --keep to keep original changesets'))
315
342
316 obsoletenotrebased = {}
343 obsoletenotrebased = {}
317 if ui.configbool('experimental', 'rebaseskipobsolete',
344 if ui.configbool('experimental', 'rebaseskipobsolete',
318 default=True):
345 default=True):
319 rebasesetrevs = set(rebaseset)
346 rebasesetrevs = set(rebaseset)
320 rebaseobsrevs = _filterobsoleterevs(repo, rebasesetrevs)
347 rebaseobsrevs = _filterobsoleterevs(repo, rebasesetrevs)
321 obsoletenotrebased = _computeobsoletenotrebased(repo,
348 obsoletenotrebased = _computeobsoletenotrebased(repo,
322 rebaseobsrevs,
349 rebaseobsrevs,
323 dest)
350 dest)
324 rebaseobsskipped = set(obsoletenotrebased)
351 rebaseobsskipped = set(obsoletenotrebased)
325 _checkobsrebase(repo, ui, rebaseobsrevs,
352 _checkobsrebase(repo, ui, rebaseobsrevs,
326 rebasesetrevs,
353 rebasesetrevs,
327 rebaseobsskipped)
354 rebaseobsskipped)
328
355
329 result = buildstate(repo, dest, rebaseset, collapsef,
356 result = buildstate(repo, dest, rebaseset, collapsef,
330 obsoletenotrebased)
357 obsoletenotrebased)
331
358
332 if not result:
359 if not result:
333 # Empty state built, nothing to rebase
360 # Empty state built, nothing to rebase
334 ui.status(_('nothing to rebase\n'))
361 ui.status(_('nothing to rebase\n'))
335 return _nothingtorebase()
362 return _nothingtorebase()
336
363
337 root = min(rebaseset)
364 root = min(rebaseset)
338 if not keepf and not repo[root].mutable():
365 if not keepf and not repo[root].mutable():
339 raise error.Abort(_("can't rebase public changeset %s")
366 raise error.Abort(_("can't rebase public changeset %s")
340 % repo[root],
367 % repo[root],
341 hint=_('see "hg help phases" for details'))
368 hint=_('see "hg help phases" for details'))
342
369
343 originalwd, target, state = result
370 originalwd, target, state = result
344 if collapsef:
371 if collapsef:
345 targetancestors = repo.changelog.ancestors([target],
372 targetancestors = repo.changelog.ancestors([target],
346 inclusive=True)
373 inclusive=True)
347 external = externalparent(repo, state, targetancestors)
374 external = externalparent(repo, state, targetancestors)
348
375
349 if dest.closesbranch() and not keepbranchesf:
376 if dest.closesbranch() and not keepbranchesf:
350 ui.status(_('reopening closed branch head %s\n') % dest)
377 ui.status(_('reopening closed branch head %s\n') % dest)
351
378
352 if keepbranchesf:
379 if keepbranchesf:
353 # insert _savebranch at the start of extrafns so if
380 # insert _savebranch at the start of extrafns so if
354 # there's a user-provided extrafn it can clobber branch if
381 # there's a user-provided extrafn it can clobber branch if
355 # desired
382 # desired
356 extrafns.insert(0, _savebranch)
383 extrafns.insert(0, _savebranch)
357 if collapsef:
384 if collapsef:
358 branches = set()
385 branches = set()
359 for rev in state:
386 for rev in state:
360 branches.add(repo[rev].branch())
387 branches.add(repo[rev].branch())
361 if len(branches) > 1:
388 if len(branches) > 1:
362 raise error.Abort(_('cannot collapse multiple named '
389 raise error.Abort(_('cannot collapse multiple named '
363 'branches'))
390 'branches'))
364
391
365 # Rebase
392 # Rebase
366 if not targetancestors:
393 if not targetancestors:
367 targetancestors = repo.changelog.ancestors([target], inclusive=True)
394 targetancestors = repo.changelog.ancestors([target], inclusive=True)
368
395
369 # Keep track of the current bookmarks in order to reset them later
396 # Keep track of the current bookmarks in order to reset them later
370 currentbookmarks = repo._bookmarks.copy()
397 currentbookmarks = repo._bookmarks.copy()
371 activebookmark = activebookmark or repo._activebookmark
398 activebookmark = activebookmark or repo._activebookmark
372 if activebookmark:
399 if activebookmark:
373 bookmarks.deactivate(repo)
400 bookmarks.deactivate(repo)
374
401
375 extrafn = _makeextrafn(extrafns)
402 extrafn = _makeextrafn(extrafns)
376
403
377 sortedstate = sorted(state)
404 sortedstate = sorted(state)
378 total = len(sortedstate)
405 total = len(sortedstate)
379 pos = 0
406 pos = 0
380 for rev in sortedstate:
407 for rev in sortedstate:
381 ctx = repo[rev]
408 ctx = repo[rev]
382 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
409 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
383 ctx.description().split('\n', 1)[0])
410 ctx.description().split('\n', 1)[0])
384 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
411 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
385 if names:
412 if names:
386 desc += ' (%s)' % ' '.join(names)
413 desc += ' (%s)' % ' '.join(names)
387 pos += 1
414 pos += 1
388 if state[rev] == revtodo:
415 if state[rev] == revtodo:
389 ui.status(_('rebasing %s\n') % desc)
416 ui.status(_('rebasing %s\n') % desc)
390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
417 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
391 _('changesets'), total)
418 _('changesets'), total)
392 p1, p2, base = defineparents(repo, rev, target, state,
419 p1, p2, base = defineparents(repo, rev, target, state,
393 targetancestors,
420 targetancestors,
394 obsoletenotrebased)
421 obsoletenotrebased)
395 storestatus(repo, originalwd, target, state, collapsef, keepf,
422 storestatus(repo, originalwd, target, state, collapsef, keepf,
396 keepbranchesf, external, activebookmark)
423 keepbranchesf, external, activebookmark)
397 storecollapsemsg(repo, collapsemsg)
424 storecollapsemsg(repo, collapsemsg)
398 if len(repo[None].parents()) == 2:
425 if len(repo[None].parents()) == 2:
399 repo.ui.debug('resuming interrupted rebase\n')
426 repo.ui.debug('resuming interrupted rebase\n')
400 else:
427 else:
401 try:
428 try:
402 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
429 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
403 'rebase')
430 'rebase')
404 stats = rebasenode(repo, rev, p1, base, state,
431 stats = rebasenode(repo, rev, p1, base, state,
405 collapsef, target)
432 collapsef, target)
406 if stats and stats[3] > 0:
433 if stats and stats[3] > 0:
407 raise error.InterventionRequired(
434 raise error.InterventionRequired(
408 _('unresolved conflicts (see hg '
435 _('unresolved conflicts (see hg '
409 'resolve, then hg rebase --continue)'))
436 'resolve, then hg rebase --continue)'))
410 finally:
437 finally:
411 ui.setconfig('ui', 'forcemerge', '', 'rebase')
438 ui.setconfig('ui', 'forcemerge', '', 'rebase')
412 if not collapsef:
439 if not collapsef:
413 merging = p2 != nullrev
440 merging = p2 != nullrev
414 editform = cmdutil.mergeeditform(merging, 'rebase')
441 editform = cmdutil.mergeeditform(merging, 'rebase')
415 editor = cmdutil.getcommiteditor(editform=editform, **opts)
442 editor = cmdutil.getcommiteditor(editform=editform, **opts)
416 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
443 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
417 editor=editor,
444 editor=editor,
418 keepbranches=keepbranchesf,
445 keepbranches=keepbranchesf,
419 date=date)
446 date=date)
420 else:
447 else:
421 # Skip commit if we are collapsing
448 # Skip commit if we are collapsing
422 repo.dirstate.beginparentchange()
449 repo.dirstate.beginparentchange()
423 repo.setparents(repo[p1].node())
450 repo.setparents(repo[p1].node())
424 repo.dirstate.endparentchange()
451 repo.dirstate.endparentchange()
425 newnode = None
452 newnode = None
426 # Update the state
453 # Update the state
427 if newnode is not None:
454 if newnode is not None:
428 state[rev] = repo[newnode].rev()
455 state[rev] = repo[newnode].rev()
429 ui.debug('rebased as %s\n' % short(newnode))
456 ui.debug('rebased as %s\n' % short(newnode))
430 else:
457 else:
431 if not collapsef:
458 if not collapsef:
432 ui.warn(_('note: rebase of %d:%s created no changes '
459 ui.warn(_('note: rebase of %d:%s created no changes '
433 'to commit\n') % (rev, ctx))
460 'to commit\n') % (rev, ctx))
434 skipped.add(rev)
461 skipped.add(rev)
435 state[rev] = p1
462 state[rev] = p1
436 ui.debug('next revision set to %s\n' % p1)
463 ui.debug('next revision set to %s\n' % p1)
437 elif state[rev] == nullmerge:
464 elif state[rev] == nullmerge:
438 ui.debug('ignoring null merge rebase of %s\n' % rev)
465 ui.debug('ignoring null merge rebase of %s\n' % rev)
439 elif state[rev] == revignored:
466 elif state[rev] == revignored:
440 ui.status(_('not rebasing ignored %s\n') % desc)
467 ui.status(_('not rebasing ignored %s\n') % desc)
441 elif state[rev] == revprecursor:
468 elif state[rev] == revprecursor:
442 targetctx = repo[obsoletenotrebased[rev]]
469 targetctx = repo[obsoletenotrebased[rev]]
443 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
470 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
444 targetctx.description().split('\n', 1)[0])
471 targetctx.description().split('\n', 1)[0])
445 msg = _('note: not rebasing %s, already in destination as %s\n')
472 msg = _('note: not rebasing %s, already in destination as %s\n')
446 ui.status(msg % (desc, desctarget))
473 ui.status(msg % (desc, desctarget))
447 elif state[rev] == revpruned:
474 elif state[rev] == revpruned:
448 msg = _('note: not rebasing %s, it has no successor\n')
475 msg = _('note: not rebasing %s, it has no successor\n')
449 ui.status(msg % desc)
476 ui.status(msg % desc)
450 else:
477 else:
451 ui.status(_('already rebased %s as %s\n') %
478 ui.status(_('already rebased %s as %s\n') %
452 (desc, repo[state[rev]]))
479 (desc, repo[state[rev]]))
453
480
454 ui.progress(_('rebasing'), None)
481 ui.progress(_('rebasing'), None)
455 ui.note(_('rebase merging completed\n'))
482 ui.note(_('rebase merging completed\n'))
456
483
457 if collapsef and not keepopen:
484 if collapsef and not keepopen:
458 p1, p2, _base = defineparents(repo, min(state), target,
485 p1, p2, _base = defineparents(repo, min(state), target,
459 state, targetancestors,
486 state, targetancestors,
460 obsoletenotrebased)
487 obsoletenotrebased)
461 editopt = opts.get('edit')
488 editopt = opts.get('edit')
462 editform = 'rebase.collapse'
489 editform = 'rebase.collapse'
463 if collapsemsg:
490 if collapsemsg:
464 commitmsg = collapsemsg
491 commitmsg = collapsemsg
465 else:
492 else:
466 commitmsg = 'Collapsed revision'
493 commitmsg = 'Collapsed revision'
467 for rebased in state:
494 for rebased in state:
468 if rebased not in skipped and state[rebased] > nullmerge:
495 if rebased not in skipped and state[rebased] > nullmerge:
469 commitmsg += '\n* %s' % repo[rebased].description()
496 commitmsg += '\n* %s' % repo[rebased].description()
470 editopt = True
497 editopt = True
471 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
498 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
472 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
499 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
473 extrafn=extrafn, editor=editor,
500 extrafn=extrafn, editor=editor,
474 keepbranches=keepbranchesf,
501 keepbranches=keepbranchesf,
475 date=date)
502 date=date)
476 if newnode is None:
503 if newnode is None:
477 newrev = target
504 newrev = target
478 else:
505 else:
479 newrev = repo[newnode].rev()
506 newrev = repo[newnode].rev()
480 for oldrev in state.iterkeys():
507 for oldrev in state.iterkeys():
481 if state[oldrev] > nullmerge:
508 if state[oldrev] > nullmerge:
482 state[oldrev] = newrev
509 state[oldrev] = newrev
483
510
484 if 'qtip' in repo.tags():
511 if 'qtip' in repo.tags():
485 updatemq(repo, state, skipped, **opts)
512 updatemq(repo, state, skipped, **opts)
486
513
487 if currentbookmarks:
514 if currentbookmarks:
488 # Nodeids are needed to reset bookmarks
515 # Nodeids are needed to reset bookmarks
489 nstate = {}
516 nstate = {}
490 for k, v in state.iteritems():
517 for k, v in state.iteritems():
491 if v > nullmerge:
518 if v > nullmerge:
492 nstate[repo[k].node()] = repo[v].node()
519 nstate[repo[k].node()] = repo[v].node()
493 # XXX this is the same as dest.node() for the non-continue path --
520 # XXX this is the same as dest.node() for the non-continue path --
494 # this should probably be cleaned up
521 # this should probably be cleaned up
495 targetnode = repo[target].node()
522 targetnode = repo[target].node()
496
523
497 # restore original working directory
524 # restore original working directory
498 # (we do this before stripping)
525 # (we do this before stripping)
499 newwd = state.get(originalwd, originalwd)
526 newwd = state.get(originalwd, originalwd)
500 if newwd < 0:
527 if newwd < 0:
501 # original directory is a parent of rebase set root or ignored
528 # original directory is a parent of rebase set root or ignored
502 newwd = originalwd
529 newwd = originalwd
503 if newwd not in [c.rev() for c in repo[None].parents()]:
530 if newwd not in [c.rev() for c in repo[None].parents()]:
504 ui.note(_("update back to initial working directory parent\n"))
531 ui.note(_("update back to initial working directory parent\n"))
505 hg.updaterepo(repo, newwd, False)
532 hg.updaterepo(repo, newwd, False)
506
533
507 if not keepf:
534 if not keepf:
508 collapsedas = None
535 collapsedas = None
509 if collapsef:
536 if collapsef:
510 collapsedas = newnode
537 collapsedas = newnode
511 clearrebased(ui, repo, state, skipped, collapsedas)
538 clearrebased(ui, repo, state, skipped, collapsedas)
512
539
513 with repo.transaction('bookmark') as tr:
540 with repo.transaction('bookmark') as tr:
514 if currentbookmarks:
541 if currentbookmarks:
515 updatebookmarks(repo, targetnode, nstate, currentbookmarks, tr)
542 updatebookmarks(repo, targetnode, nstate, currentbookmarks, tr)
516 if activebookmark not in repo._bookmarks:
543 if activebookmark not in repo._bookmarks:
517 # active bookmark was divergent one and has been deleted
544 # active bookmark was divergent one and has been deleted
518 activebookmark = None
545 activebookmark = None
519 clearstatus(repo)
546 clearstatus(repo)
520 clearcollapsemsg(repo)
547 clearcollapsemsg(repo)
521
548
522 ui.note(_("rebase completed\n"))
549 ui.note(_("rebase completed\n"))
523 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
550 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
524 if skipped:
551 if skipped:
525 ui.note(_("%d revisions have been skipped\n") % len(skipped))
552 ui.note(_("%d revisions have been skipped\n") % len(skipped))
526
553
527 if (activebookmark and
554 if (activebookmark and
528 repo['.'].node() == repo._bookmarks[activebookmark]):
555 repo['.'].node() == repo._bookmarks[activebookmark]):
529 bookmarks.activate(repo, activebookmark)
556 bookmarks.activate(repo, activebookmark)
530
557
531 finally:
558 finally:
532 release(lock, wlock)
559 release(lock, wlock)
533
560
534 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=[],
561 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=[],
535 destspace=None):
562 destspace=None):
536 """use revisions argument to define destination and rebase set
563 """use revisions argument to define destination and rebase set
537 """
564 """
538 # destspace is here to work around issues with `hg pull --rebase` see
565 # destspace is here to work around issues with `hg pull --rebase` see
539 # issue5214 for details
566 # issue5214 for details
540 if srcf and basef:
567 if srcf and basef:
541 raise error.Abort(_('cannot specify both a source and a base'))
568 raise error.Abort(_('cannot specify both a source and a base'))
542 if revf and basef:
569 if revf and basef:
543 raise error.Abort(_('cannot specify both a revision and a base'))
570 raise error.Abort(_('cannot specify both a revision and a base'))
544 if revf and srcf:
571 if revf and srcf:
545 raise error.Abort(_('cannot specify both a revision and a source'))
572 raise error.Abort(_('cannot specify both a revision and a source'))
546
573
547 cmdutil.checkunfinished(repo)
574 cmdutil.checkunfinished(repo)
548 cmdutil.bailifchanged(repo)
575 cmdutil.bailifchanged(repo)
549
576
550 if destf:
577 if destf:
551 dest = scmutil.revsingle(repo, destf)
578 dest = scmutil.revsingle(repo, destf)
552
579
553 if revf:
580 if revf:
554 rebaseset = scmutil.revrange(repo, revf)
581 rebaseset = scmutil.revrange(repo, revf)
555 if not rebaseset:
582 if not rebaseset:
556 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
583 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
557 return None, None
584 return None, None
558 elif srcf:
585 elif srcf:
559 src = scmutil.revrange(repo, [srcf])
586 src = scmutil.revrange(repo, [srcf])
560 if not src:
587 if not src:
561 ui.status(_('empty "source" revision set - nothing to rebase\n'))
588 ui.status(_('empty "source" revision set - nothing to rebase\n'))
562 return None, None
589 return None, None
563 rebaseset = repo.revs('(%ld)::', src)
590 rebaseset = repo.revs('(%ld)::', src)
564 assert rebaseset
591 assert rebaseset
565 else:
592 else:
566 base = scmutil.revrange(repo, [basef or '.'])
593 base = scmutil.revrange(repo, [basef or '.'])
567 if not base:
594 if not base:
568 ui.status(_('empty "base" revision set - '
595 ui.status(_('empty "base" revision set - '
569 "can't compute rebase set\n"))
596 "can't compute rebase set\n"))
570 return None, None
597 return None, None
571 if not destf:
598 if not destf:
572 dest = repo[_destrebase(repo, base, destspace=destspace)]
599 dest = repo[_destrebase(repo, base, destspace=destspace)]
573 destf = str(dest)
600 destf = str(dest)
574
601
575 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
602 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
576 if commonanc is not None:
603 if commonanc is not None:
577 rebaseset = repo.revs('(%d::(%ld) - %d)::',
604 rebaseset = repo.revs('(%d::(%ld) - %d)::',
578 commonanc, base, commonanc)
605 commonanc, base, commonanc)
579 else:
606 else:
580 rebaseset = []
607 rebaseset = []
581
608
582 if not rebaseset:
609 if not rebaseset:
583 # transform to list because smartsets are not comparable to
610 # transform to list because smartsets are not comparable to
584 # lists. This should be improved to honor laziness of
611 # lists. This should be improved to honor laziness of
585 # smartset.
612 # smartset.
586 if list(base) == [dest.rev()]:
613 if list(base) == [dest.rev()]:
587 if basef:
614 if basef:
588 ui.status(_('nothing to rebase - %s is both "base"'
615 ui.status(_('nothing to rebase - %s is both "base"'
589 ' and destination\n') % dest)
616 ' and destination\n') % dest)
590 else:
617 else:
591 ui.status(_('nothing to rebase - working directory '
618 ui.status(_('nothing to rebase - working directory '
592 'parent is also destination\n'))
619 'parent is also destination\n'))
593 elif not repo.revs('%ld - ::%d', base, dest):
620 elif not repo.revs('%ld - ::%d', base, dest):
594 if basef:
621 if basef:
595 ui.status(_('nothing to rebase - "base" %s is '
622 ui.status(_('nothing to rebase - "base" %s is '
596 'already an ancestor of destination '
623 'already an ancestor of destination '
597 '%s\n') %
624 '%s\n') %
598 ('+'.join(str(repo[r]) for r in base),
625 ('+'.join(str(repo[r]) for r in base),
599 dest))
626 dest))
600 else:
627 else:
601 ui.status(_('nothing to rebase - working '
628 ui.status(_('nothing to rebase - working '
602 'directory parent is already an '
629 'directory parent is already an '
603 'ancestor of destination %s\n') % dest)
630 'ancestor of destination %s\n') % dest)
604 else: # can it happen?
631 else: # can it happen?
605 ui.status(_('nothing to rebase from %s to %s\n') %
632 ui.status(_('nothing to rebase from %s to %s\n') %
606 ('+'.join(str(repo[r]) for r in base), dest))
633 ('+'.join(str(repo[r]) for r in base), dest))
607 return None, None
634 return None, None
608
635
609 if not destf:
636 if not destf:
610 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
637 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
611 destf = str(dest)
638 destf = str(dest)
612
639
613 return dest, rebaseset
640 return dest, rebaseset
614
641
615 def externalparent(repo, state, targetancestors):
642 def externalparent(repo, state, targetancestors):
616 """Return the revision that should be used as the second parent
643 """Return the revision that should be used as the second parent
617 when the revisions in state is collapsed on top of targetancestors.
644 when the revisions in state is collapsed on top of targetancestors.
618 Abort if there is more than one parent.
645 Abort if there is more than one parent.
619 """
646 """
620 parents = set()
647 parents = set()
621 source = min(state)
648 source = min(state)
622 for rev in state:
649 for rev in state:
623 if rev == source:
650 if rev == source:
624 continue
651 continue
625 for p in repo[rev].parents():
652 for p in repo[rev].parents():
626 if (p.rev() not in state
653 if (p.rev() not in state
627 and p.rev() not in targetancestors):
654 and p.rev() not in targetancestors):
628 parents.add(p.rev())
655 parents.add(p.rev())
629 if not parents:
656 if not parents:
630 return nullrev
657 return nullrev
631 if len(parents) == 1:
658 if len(parents) == 1:
632 return parents.pop()
659 return parents.pop()
633 raise error.Abort(_('unable to collapse on top of %s, there is more '
660 raise error.Abort(_('unable to collapse on top of %s, there is more '
634 'than one external parent: %s') %
661 'than one external parent: %s') %
635 (max(targetancestors),
662 (max(targetancestors),
636 ', '.join(str(p) for p in sorted(parents))))
663 ', '.join(str(p) for p in sorted(parents))))
637
664
638 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
665 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
639 keepbranches=False, date=None):
666 keepbranches=False, date=None):
640 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
667 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
641 but also store useful information in extra.
668 but also store useful information in extra.
642 Return node of committed revision.'''
669 Return node of committed revision.'''
643 dsguard = cmdutil.dirstateguard(repo, 'rebase')
670 dsguard = cmdutil.dirstateguard(repo, 'rebase')
644 try:
671 try:
645 repo.setparents(repo[p1].node(), repo[p2].node())
672 repo.setparents(repo[p1].node(), repo[p2].node())
646 ctx = repo[rev]
673 ctx = repo[rev]
647 if commitmsg is None:
674 if commitmsg is None:
648 commitmsg = ctx.description()
675 commitmsg = ctx.description()
649 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
676 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
650 extra = {'rebase_source': ctx.hex()}
677 extra = {'rebase_source': ctx.hex()}
651 if extrafn:
678 if extrafn:
652 extrafn(ctx, extra)
679 extrafn(ctx, extra)
653
680
654 backup = repo.ui.backupconfig('phases', 'new-commit')
681 backup = repo.ui.backupconfig('phases', 'new-commit')
655 try:
682 try:
656 targetphase = max(ctx.phase(), phases.draft)
683 targetphase = max(ctx.phase(), phases.draft)
657 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
684 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
658 if keepbranch:
685 if keepbranch:
659 repo.ui.setconfig('ui', 'allowemptycommit', True)
686 repo.ui.setconfig('ui', 'allowemptycommit', True)
660 # Commit might fail if unresolved files exist
687 # Commit might fail if unresolved files exist
661 if date is None:
688 if date is None:
662 date = ctx.date()
689 date = ctx.date()
663 newnode = repo.commit(text=commitmsg, user=ctx.user(),
690 newnode = repo.commit(text=commitmsg, user=ctx.user(),
664 date=date, extra=extra, editor=editor)
691 date=date, extra=extra, editor=editor)
665 finally:
692 finally:
666 repo.ui.restoreconfig(backup)
693 repo.ui.restoreconfig(backup)
667
694
668 repo.dirstate.setbranch(repo[newnode].branch())
695 repo.dirstate.setbranch(repo[newnode].branch())
669 dsguard.close()
696 dsguard.close()
670 return newnode
697 return newnode
671 finally:
698 finally:
672 release(dsguard)
699 release(dsguard)
673
700
674 def rebasenode(repo, rev, p1, base, state, collapse, target):
701 def rebasenode(repo, rev, p1, base, state, collapse, target):
675 'Rebase a single revision rev on top of p1 using base as merge ancestor'
702 'Rebase a single revision rev on top of p1 using base as merge ancestor'
676 # Merge phase
703 # Merge phase
677 # Update to target and merge it with local
704 # Update to target and merge it with local
678 if repo['.'].rev() != p1:
705 if repo['.'].rev() != p1:
679 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
706 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
680 merge.update(repo, p1, False, True)
707 merge.update(repo, p1, False, True)
681 else:
708 else:
682 repo.ui.debug(" already in target\n")
709 repo.ui.debug(" already in target\n")
683 repo.dirstate.write(repo.currenttransaction())
710 repo.dirstate.write(repo.currenttransaction())
684 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
711 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
685 if base is not None:
712 if base is not None:
686 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
713 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
687 # When collapsing in-place, the parent is the common ancestor, we
714 # When collapsing in-place, the parent is the common ancestor, we
688 # have to allow merging with it.
715 # have to allow merging with it.
689 stats = merge.update(repo, rev, True, True, base, collapse,
716 stats = merge.update(repo, rev, True, True, base, collapse,
690 labels=['dest', 'source'])
717 labels=['dest', 'source'])
691 if collapse:
718 if collapse:
692 copies.duplicatecopies(repo, rev, target)
719 copies.duplicatecopies(repo, rev, target)
693 else:
720 else:
694 # If we're not using --collapse, we need to
721 # If we're not using --collapse, we need to
695 # duplicate copies between the revision we're
722 # duplicate copies between the revision we're
696 # rebasing and its first parent, but *not*
723 # rebasing and its first parent, but *not*
697 # duplicate any copies that have already been
724 # duplicate any copies that have already been
698 # performed in the destination.
725 # performed in the destination.
699 p1rev = repo[rev].p1().rev()
726 p1rev = repo[rev].p1().rev()
700 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
727 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
701 return stats
728 return stats
702
729
703 def nearestrebased(repo, rev, state):
730 def nearestrebased(repo, rev, state):
704 """return the nearest ancestors of rev in the rebase result"""
731 """return the nearest ancestors of rev in the rebase result"""
705 rebased = [r for r in state if state[r] > nullmerge]
732 rebased = [r for r in state if state[r] > nullmerge]
706 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
733 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
707 if candidates:
734 if candidates:
708 return state[candidates.first()]
735 return state[candidates.first()]
709 else:
736 else:
710 return None
737 return None
711
738
712 def _checkobsrebase(repo, ui,
739 def _checkobsrebase(repo, ui,
713 rebaseobsrevs,
740 rebaseobsrevs,
714 rebasesetrevs,
741 rebasesetrevs,
715 rebaseobsskipped):
742 rebaseobsskipped):
716 """
743 """
717 Abort if rebase will create divergence or rebase is noop because of markers
744 Abort if rebase will create divergence or rebase is noop because of markers
718
745
719 `rebaseobsrevs`: set of obsolete revision in source
746 `rebaseobsrevs`: set of obsolete revision in source
720 `rebasesetrevs`: set of revisions to be rebased from source
747 `rebasesetrevs`: set of revisions to be rebased from source
721 `rebaseobsskipped`: set of revisions from source skipped because they have
748 `rebaseobsskipped`: set of revisions from source skipped because they have
722 successors in destination
749 successors in destination
723 """
750 """
724 # Obsolete node with successors not in dest leads to divergence
751 # Obsolete node with successors not in dest leads to divergence
725 divergenceok = ui.configbool('experimental',
752 divergenceok = ui.configbool('experimental',
726 'allowdivergence')
753 'allowdivergence')
727 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
754 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
728
755
729 if divergencebasecandidates and not divergenceok:
756 if divergencebasecandidates and not divergenceok:
730 divhashes = (str(repo[r])
757 divhashes = (str(repo[r])
731 for r in divergencebasecandidates)
758 for r in divergencebasecandidates)
732 msg = _("this rebase will cause "
759 msg = _("this rebase will cause "
733 "divergences from: %s")
760 "divergences from: %s")
734 h = _("to force the rebase please set "
761 h = _("to force the rebase please set "
735 "experimental.allowdivergence=True")
762 "experimental.allowdivergence=True")
736 raise error.Abort(msg % (",".join(divhashes),), hint=h)
763 raise error.Abort(msg % (",".join(divhashes),), hint=h)
737
764
738 # - plain prune (no successor) changesets are rebased
765 # - plain prune (no successor) changesets are rebased
739 # - split changesets are not rebased if at least one of the
766 # - split changesets are not rebased if at least one of the
740 # changeset resulting from the split is an ancestor of dest
767 # changeset resulting from the split is an ancestor of dest
741 rebaseset = rebasesetrevs - rebaseobsskipped
768 rebaseset = rebasesetrevs - rebaseobsskipped
742 if rebasesetrevs and not rebaseset:
769 if rebasesetrevs and not rebaseset:
743 msg = _('all requested changesets have equivalents '
770 msg = _('all requested changesets have equivalents '
744 'or were marked as obsolete')
771 'or were marked as obsolete')
745 hint = _('to force the rebase, set the config '
772 hint = _('to force the rebase, set the config '
746 'experimental.rebaseskipobsolete to False')
773 'experimental.rebaseskipobsolete to False')
747 raise error.Abort(msg, hint=hint)
774 raise error.Abort(msg, hint=hint)
748
775
749 def defineparents(repo, rev, target, state, targetancestors,
776 def defineparents(repo, rev, target, state, targetancestors,
750 obsoletenotrebased):
777 obsoletenotrebased):
751 'Return the new parent relationship of the revision that will be rebased'
778 'Return the new parent relationship of the revision that will be rebased'
752 parents = repo[rev].parents()
779 parents = repo[rev].parents()
753 p1 = p2 = nullrev
780 p1 = p2 = nullrev
754 rp1 = None
781 rp1 = None
755
782
756 p1n = parents[0].rev()
783 p1n = parents[0].rev()
757 if p1n in targetancestors:
784 if p1n in targetancestors:
758 p1 = target
785 p1 = target
759 elif p1n in state:
786 elif p1n in state:
760 if state[p1n] == nullmerge:
787 if state[p1n] == nullmerge:
761 p1 = target
788 p1 = target
762 elif state[p1n] in revskipped:
789 elif state[p1n] in revskipped:
763 p1 = nearestrebased(repo, p1n, state)
790 p1 = nearestrebased(repo, p1n, state)
764 if p1 is None:
791 if p1 is None:
765 p1 = target
792 p1 = target
766 else:
793 else:
767 p1 = state[p1n]
794 p1 = state[p1n]
768 else: # p1n external
795 else: # p1n external
769 p1 = target
796 p1 = target
770 p2 = p1n
797 p2 = p1n
771
798
772 if len(parents) == 2 and parents[1].rev() not in targetancestors:
799 if len(parents) == 2 and parents[1].rev() not in targetancestors:
773 p2n = parents[1].rev()
800 p2n = parents[1].rev()
774 # interesting second parent
801 # interesting second parent
775 if p2n in state:
802 if p2n in state:
776 if p1 == target: # p1n in targetancestors or external
803 if p1 == target: # p1n in targetancestors or external
777 p1 = state[p2n]
804 p1 = state[p2n]
778 if p1 == revprecursor:
805 if p1 == revprecursor:
779 rp1 = obsoletenotrebased[p2n]
806 rp1 = obsoletenotrebased[p2n]
780 elif state[p2n] in revskipped:
807 elif state[p2n] in revskipped:
781 p2 = nearestrebased(repo, p2n, state)
808 p2 = nearestrebased(repo, p2n, state)
782 if p2 is None:
809 if p2 is None:
783 # no ancestors rebased yet, detach
810 # no ancestors rebased yet, detach
784 p2 = target
811 p2 = target
785 else:
812 else:
786 p2 = state[p2n]
813 p2 = state[p2n]
787 else: # p2n external
814 else: # p2n external
788 if p2 != nullrev: # p1n external too => rev is a merged revision
815 if p2 != nullrev: # p1n external too => rev is a merged revision
789 raise error.Abort(_('cannot use revision %d as base, result '
816 raise error.Abort(_('cannot use revision %d as base, result '
790 'would have 3 parents') % rev)
817 'would have 3 parents') % rev)
791 p2 = p2n
818 p2 = p2n
792 repo.ui.debug(" future parents are %d and %d\n" %
819 repo.ui.debug(" future parents are %d and %d\n" %
793 (repo[rp1 or p1].rev(), repo[p2].rev()))
820 (repo[rp1 or p1].rev(), repo[p2].rev()))
794
821
795 if not any(p.rev() in state for p in parents):
822 if not any(p.rev() in state for p in parents):
796 # Case (1) root changeset of a non-detaching rebase set.
823 # Case (1) root changeset of a non-detaching rebase set.
797 # Let the merge mechanism find the base itself.
824 # Let the merge mechanism find the base itself.
798 base = None
825 base = None
799 elif not repo[rev].p2():
826 elif not repo[rev].p2():
800 # Case (2) detaching the node with a single parent, use this parent
827 # Case (2) detaching the node with a single parent, use this parent
801 base = repo[rev].p1().rev()
828 base = repo[rev].p1().rev()
802 else:
829 else:
803 # Assuming there is a p1, this is the case where there also is a p2.
830 # Assuming there is a p1, this is the case where there also is a p2.
804 # We are thus rebasing a merge and need to pick the right merge base.
831 # We are thus rebasing a merge and need to pick the right merge base.
805 #
832 #
806 # Imagine we have:
833 # Imagine we have:
807 # - M: current rebase revision in this step
834 # - M: current rebase revision in this step
808 # - A: one parent of M
835 # - A: one parent of M
809 # - B: other parent of M
836 # - B: other parent of M
810 # - D: destination of this merge step (p1 var)
837 # - D: destination of this merge step (p1 var)
811 #
838 #
812 # Consider the case where D is a descendant of A or B and the other is
839 # Consider the case where D is a descendant of A or B and the other is
813 # 'outside'. In this case, the right merge base is the D ancestor.
840 # 'outside'. In this case, the right merge base is the D ancestor.
814 #
841 #
815 # An informal proof, assuming A is 'outside' and B is the D ancestor:
842 # An informal proof, assuming A is 'outside' and B is the D ancestor:
816 #
843 #
817 # If we pick B as the base, the merge involves:
844 # If we pick B as the base, the merge involves:
818 # - changes from B to M (actual changeset payload)
845 # - changes from B to M (actual changeset payload)
819 # - changes from B to D (induced by rebase) as D is a rebased
846 # - changes from B to D (induced by rebase) as D is a rebased
820 # version of B)
847 # version of B)
821 # Which exactly represent the rebase operation.
848 # Which exactly represent the rebase operation.
822 #
849 #
823 # If we pick A as the base, the merge involves:
850 # If we pick A as the base, the merge involves:
824 # - changes from A to M (actual changeset payload)
851 # - changes from A to M (actual changeset payload)
825 # - changes from A to D (with include changes between unrelated A and B
852 # - changes from A to D (with include changes between unrelated A and B
826 # plus changes induced by rebase)
853 # plus changes induced by rebase)
827 # Which does not represent anything sensible and creates a lot of
854 # Which does not represent anything sensible and creates a lot of
828 # conflicts. A is thus not the right choice - B is.
855 # conflicts. A is thus not the right choice - B is.
829 #
856 #
830 # Note: The base found in this 'proof' is only correct in the specified
857 # Note: The base found in this 'proof' is only correct in the specified
831 # case. This base does not make sense if is not D a descendant of A or B
858 # case. This base does not make sense if is not D a descendant of A or B
832 # or if the other is not parent 'outside' (especially not if the other
859 # or if the other is not parent 'outside' (especially not if the other
833 # parent has been rebased). The current implementation does not
860 # parent has been rebased). The current implementation does not
834 # make it feasible to consider different cases separately. In these
861 # make it feasible to consider different cases separately. In these
835 # other cases we currently just leave it to the user to correctly
862 # other cases we currently just leave it to the user to correctly
836 # resolve an impossible merge using a wrong ancestor.
863 # resolve an impossible merge using a wrong ancestor.
837 #
864 #
838 # xx, p1 could be -4, and both parents could probably be -4...
865 # xx, p1 could be -4, and both parents could probably be -4...
839 for p in repo[rev].parents():
866 for p in repo[rev].parents():
840 if state.get(p.rev()) == p1:
867 if state.get(p.rev()) == p1:
841 base = p.rev()
868 base = p.rev()
842 break
869 break
843 else: # fallback when base not found
870 else: # fallback when base not found
844 base = None
871 base = None
845
872
846 # Raise because this function is called wrong (see issue 4106)
873 # Raise because this function is called wrong (see issue 4106)
847 raise AssertionError('no base found to rebase on '
874 raise AssertionError('no base found to rebase on '
848 '(defineparents called wrong)')
875 '(defineparents called wrong)')
849 return rp1 or p1, p2, base
876 return rp1 or p1, p2, base
850
877
851 def isagitpatch(repo, patchname):
878 def isagitpatch(repo, patchname):
852 'Return true if the given patch is in git format'
879 'Return true if the given patch is in git format'
853 mqpatch = os.path.join(repo.mq.path, patchname)
880 mqpatch = os.path.join(repo.mq.path, patchname)
854 for line in patch.linereader(file(mqpatch, 'rb')):
881 for line in patch.linereader(file(mqpatch, 'rb')):
855 if line.startswith('diff --git'):
882 if line.startswith('diff --git'):
856 return True
883 return True
857 return False
884 return False
858
885
859 def updatemq(repo, state, skipped, **opts):
886 def updatemq(repo, state, skipped, **opts):
860 'Update rebased mq patches - finalize and then import them'
887 'Update rebased mq patches - finalize and then import them'
861 mqrebase = {}
888 mqrebase = {}
862 mq = repo.mq
889 mq = repo.mq
863 original_series = mq.fullseries[:]
890 original_series = mq.fullseries[:]
864 skippedpatches = set()
891 skippedpatches = set()
865
892
866 for p in mq.applied:
893 for p in mq.applied:
867 rev = repo[p.node].rev()
894 rev = repo[p.node].rev()
868 if rev in state:
895 if rev in state:
869 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
896 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
870 (rev, p.name))
897 (rev, p.name))
871 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
898 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
872 else:
899 else:
873 # Applied but not rebased, not sure this should happen
900 # Applied but not rebased, not sure this should happen
874 skippedpatches.add(p.name)
901 skippedpatches.add(p.name)
875
902
876 if mqrebase:
903 if mqrebase:
877 mq.finish(repo, mqrebase.keys())
904 mq.finish(repo, mqrebase.keys())
878
905
879 # We must start import from the newest revision
906 # We must start import from the newest revision
880 for rev in sorted(mqrebase, reverse=True):
907 for rev in sorted(mqrebase, reverse=True):
881 if rev not in skipped:
908 if rev not in skipped:
882 name, isgit = mqrebase[rev]
909 name, isgit = mqrebase[rev]
883 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
910 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
884 (name, state[rev], repo[state[rev]]))
911 (name, state[rev], repo[state[rev]]))
885 mq.qimport(repo, (), patchname=name, git=isgit,
912 mq.qimport(repo, (), patchname=name, git=isgit,
886 rev=[str(state[rev])])
913 rev=[str(state[rev])])
887 else:
914 else:
888 # Rebased and skipped
915 # Rebased and skipped
889 skippedpatches.add(mqrebase[rev][0])
916 skippedpatches.add(mqrebase[rev][0])
890
917
891 # Patches were either applied and rebased and imported in
918 # Patches were either applied and rebased and imported in
892 # order, applied and removed or unapplied. Discard the removed
919 # order, applied and removed or unapplied. Discard the removed
893 # ones while preserving the original series order and guards.
920 # ones while preserving the original series order and guards.
894 newseries = [s for s in original_series
921 newseries = [s for s in original_series
895 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
922 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
896 mq.fullseries[:] = newseries
923 mq.fullseries[:] = newseries
897 mq.seriesdirty = True
924 mq.seriesdirty = True
898 mq.savedirty()
925 mq.savedirty()
899
926
900 def updatebookmarks(repo, targetnode, nstate, originalbookmarks, tr):
927 def updatebookmarks(repo, targetnode, nstate, originalbookmarks, tr):
901 'Move bookmarks to their correct changesets, and delete divergent ones'
928 'Move bookmarks to their correct changesets, and delete divergent ones'
902 marks = repo._bookmarks
929 marks = repo._bookmarks
903 for k, v in originalbookmarks.iteritems():
930 for k, v in originalbookmarks.iteritems():
904 if v in nstate:
931 if v in nstate:
905 # update the bookmarks for revs that have moved
932 # update the bookmarks for revs that have moved
906 marks[k] = nstate[v]
933 marks[k] = nstate[v]
907 bookmarks.deletedivergent(repo, [targetnode], k)
934 bookmarks.deletedivergent(repo, [targetnode], k)
908 marks.recordchange(tr)
935 marks.recordchange(tr)
909
936
910 def storecollapsemsg(repo, collapsemsg):
937 def storecollapsemsg(repo, collapsemsg):
911 'Store the collapse message to allow recovery'
938 'Store the collapse message to allow recovery'
912 collapsemsg = collapsemsg or ''
939 collapsemsg = collapsemsg or ''
913 f = repo.vfs("last-message.txt", "w")
940 f = repo.vfs("last-message.txt", "w")
914 f.write("%s\n" % collapsemsg)
941 f.write("%s\n" % collapsemsg)
915 f.close()
942 f.close()
916
943
917 def clearcollapsemsg(repo):
944 def clearcollapsemsg(repo):
918 'Remove collapse message file'
945 'Remove collapse message file'
919 util.unlinkpath(repo.join("last-message.txt"), ignoremissing=True)
946 util.unlinkpath(repo.join("last-message.txt"), ignoremissing=True)
920
947
921 def restorecollapsemsg(repo):
948 def restorecollapsemsg(repo):
922 'Restore previously stored collapse message'
949 'Restore previously stored collapse message'
923 try:
950 try:
924 f = repo.vfs("last-message.txt")
951 f = repo.vfs("last-message.txt")
925 collapsemsg = f.readline().strip()
952 collapsemsg = f.readline().strip()
926 f.close()
953 f.close()
927 except IOError as err:
954 except IOError as err:
928 if err.errno != errno.ENOENT:
955 if err.errno != errno.ENOENT:
929 raise
956 raise
930 raise error.Abort(_('no rebase in progress'))
957 raise error.Abort(_('no rebase in progress'))
931 return collapsemsg
958 return collapsemsg
932
959
933 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
960 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
934 external, activebookmark):
961 external, activebookmark):
935 'Store the current status to allow recovery'
962 'Store the current status to allow recovery'
936 f = repo.vfs("rebasestate", "w")
963 f = repo.vfs("rebasestate", "w")
937 f.write(repo[originalwd].hex() + '\n')
964 f.write(repo[originalwd].hex() + '\n')
938 f.write(repo[target].hex() + '\n')
965 f.write(repo[target].hex() + '\n')
939 f.write(repo[external].hex() + '\n')
966 f.write(repo[external].hex() + '\n')
940 f.write('%d\n' % int(collapse))
967 f.write('%d\n' % int(collapse))
941 f.write('%d\n' % int(keep))
968 f.write('%d\n' % int(keep))
942 f.write('%d\n' % int(keepbranches))
969 f.write('%d\n' % int(keepbranches))
943 f.write('%s\n' % (activebookmark or ''))
970 f.write('%s\n' % (activebookmark or ''))
944 for d, v in state.iteritems():
971 for d, v in state.iteritems():
945 oldrev = repo[d].hex()
972 oldrev = repo[d].hex()
946 if v >= 0:
973 if v >= 0:
947 newrev = repo[v].hex()
974 newrev = repo[v].hex()
948 elif v == revtodo:
975 elif v == revtodo:
949 # To maintain format compatibility, we have to use nullid.
976 # To maintain format compatibility, we have to use nullid.
950 # Please do remove this special case when upgrading the format.
977 # Please do remove this special case when upgrading the format.
951 newrev = hex(nullid)
978 newrev = hex(nullid)
952 else:
979 else:
953 newrev = v
980 newrev = v
954 f.write("%s:%s\n" % (oldrev, newrev))
981 f.write("%s:%s\n" % (oldrev, newrev))
955 f.close()
982 f.close()
956 repo.ui.debug('rebase status stored\n')
983 repo.ui.debug('rebase status stored\n')
957
984
958 def clearstatus(repo):
985 def clearstatus(repo):
959 'Remove the status files'
986 'Remove the status files'
960 _clearrebasesetvisibiliy(repo)
987 _clearrebasesetvisibiliy(repo)
961 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
988 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
962
989
963 def restorestatus(repo):
990 def restorestatus(repo):
964 'Restore a previously stored status'
991 'Restore a previously stored status'
965 keepbranches = None
992 keepbranches = None
966 target = None
993 target = None
967 collapse = False
994 collapse = False
968 external = nullrev
995 external = nullrev
969 activebookmark = None
996 activebookmark = None
970 state = {}
997 state = {}
971
998
972 try:
999 try:
973 f = repo.vfs("rebasestate")
1000 f = repo.vfs("rebasestate")
974 for i, l in enumerate(f.read().splitlines()):
1001 for i, l in enumerate(f.read().splitlines()):
975 if i == 0:
1002 if i == 0:
976 originalwd = repo[l].rev()
1003 originalwd = repo[l].rev()
977 elif i == 1:
1004 elif i == 1:
978 target = repo[l].rev()
1005 target = repo[l].rev()
979 elif i == 2:
1006 elif i == 2:
980 external = repo[l].rev()
1007 external = repo[l].rev()
981 elif i == 3:
1008 elif i == 3:
982 collapse = bool(int(l))
1009 collapse = bool(int(l))
983 elif i == 4:
1010 elif i == 4:
984 keep = bool(int(l))
1011 keep = bool(int(l))
985 elif i == 5:
1012 elif i == 5:
986 keepbranches = bool(int(l))
1013 keepbranches = bool(int(l))
987 elif i == 6 and not (len(l) == 81 and ':' in l):
1014 elif i == 6 and not (len(l) == 81 and ':' in l):
988 # line 6 is a recent addition, so for backwards compatibility
1015 # line 6 is a recent addition, so for backwards compatibility
989 # check that the line doesn't look like the oldrev:newrev lines
1016 # check that the line doesn't look like the oldrev:newrev lines
990 activebookmark = l
1017 activebookmark = l
991 else:
1018 else:
992 oldrev, newrev = l.split(':')
1019 oldrev, newrev = l.split(':')
993 if newrev in (str(nullmerge), str(revignored),
1020 if newrev in (str(nullmerge), str(revignored),
994 str(revprecursor), str(revpruned)):
1021 str(revprecursor), str(revpruned)):
995 state[repo[oldrev].rev()] = int(newrev)
1022 state[repo[oldrev].rev()] = int(newrev)
996 elif newrev == nullid:
1023 elif newrev == nullid:
997 state[repo[oldrev].rev()] = revtodo
1024 state[repo[oldrev].rev()] = revtodo
998 # Legacy compat special case
1025 # Legacy compat special case
999 else:
1026 else:
1000 state[repo[oldrev].rev()] = repo[newrev].rev()
1027 state[repo[oldrev].rev()] = repo[newrev].rev()
1001
1028
1002 except IOError as err:
1029 except IOError as err:
1003 if err.errno != errno.ENOENT:
1030 if err.errno != errno.ENOENT:
1004 raise
1031 raise
1005 cmdutil.wrongtooltocontinue(repo, _('rebase'))
1032 cmdutil.wrongtooltocontinue(repo, _('rebase'))
1006
1033
1007 if keepbranches is None:
1034 if keepbranches is None:
1008 raise error.Abort(_('.hg/rebasestate is incomplete'))
1035 raise error.Abort(_('.hg/rebasestate is incomplete'))
1009
1036
1010 skipped = set()
1037 skipped = set()
1011 # recompute the set of skipped revs
1038 # recompute the set of skipped revs
1012 if not collapse:
1039 if not collapse:
1013 seen = set([target])
1040 seen = set([target])
1014 for old, new in sorted(state.items()):
1041 for old, new in sorted(state.items()):
1015 if new != revtodo and new in seen:
1042 if new != revtodo and new in seen:
1016 skipped.add(old)
1043 skipped.add(old)
1017 seen.add(new)
1044 seen.add(new)
1018 repo.ui.debug('computed skipped revs: %s\n' %
1045 repo.ui.debug('computed skipped revs: %s\n' %
1019 (' '.join(str(r) for r in sorted(skipped)) or None))
1046 (' '.join(str(r) for r in sorted(skipped)) or None))
1020 repo.ui.debug('rebase status resumed\n')
1047 repo.ui.debug('rebase status resumed\n')
1021 _setrebasesetvisibility(repo, state.keys())
1048 _setrebasesetvisibility(repo, state.keys())
1022 return (originalwd, target, state, skipped,
1049 return (originalwd, target, state, skipped,
1023 collapse, keep, keepbranches, external, activebookmark)
1050 collapse, keep, keepbranches, external, activebookmark)
1024
1051
1025 def needupdate(repo, state):
1052 def needupdate(repo, state):
1026 '''check whether we should `update --clean` away from a merge, or if
1053 '''check whether we should `update --clean` away from a merge, or if
1027 somehow the working dir got forcibly updated, e.g. by older hg'''
1054 somehow the working dir got forcibly updated, e.g. by older hg'''
1028 parents = [p.rev() for p in repo[None].parents()]
1055 parents = [p.rev() for p in repo[None].parents()]
1029
1056
1030 # Are we in a merge state at all?
1057 # Are we in a merge state at all?
1031 if len(parents) < 2:
1058 if len(parents) < 2:
1032 return False
1059 return False
1033
1060
1034 # We should be standing on the first as-of-yet unrebased commit.
1061 # We should be standing on the first as-of-yet unrebased commit.
1035 firstunrebased = min([old for old, new in state.iteritems()
1062 firstunrebased = min([old for old, new in state.iteritems()
1036 if new == nullrev])
1063 if new == nullrev])
1037 if firstunrebased in parents:
1064 if firstunrebased in parents:
1038 return True
1065 return True
1039
1066
1040 return False
1067 return False
1041
1068
1042 def abort(repo, originalwd, target, state, activebookmark=None):
1069 def abort(repo, originalwd, target, state, activebookmark=None):
1043 '''Restore the repository to its original state. Additional args:
1070 '''Restore the repository to its original state. Additional args:
1044
1071
1045 activebookmark: the name of the bookmark that should be active after the
1072 activebookmark: the name of the bookmark that should be active after the
1046 restore'''
1073 restore'''
1047
1074
1048 try:
1075 try:
1049 # If the first commits in the rebased set get skipped during the rebase,
1076 # If the first commits in the rebased set get skipped during the rebase,
1050 # their values within the state mapping will be the target rev id. The
1077 # their values within the state mapping will be the target rev id. The
1051 # dstates list must must not contain the target rev (issue4896)
1078 # dstates list must must not contain the target rev (issue4896)
1052 dstates = [s for s in state.values() if s >= 0 and s != target]
1079 dstates = [s for s in state.values() if s >= 0 and s != target]
1053 immutable = [d for d in dstates if not repo[d].mutable()]
1080 immutable = [d for d in dstates if not repo[d].mutable()]
1054 cleanup = True
1081 cleanup = True
1055 if immutable:
1082 if immutable:
1056 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1083 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1057 % ', '.join(str(repo[r]) for r in immutable),
1084 % ', '.join(str(repo[r]) for r in immutable),
1058 hint=_('see "hg help phases" for details'))
1085 hint=_('see "hg help phases" for details'))
1059 cleanup = False
1086 cleanup = False
1060
1087
1061 descendants = set()
1088 descendants = set()
1062 if dstates:
1089 if dstates:
1063 descendants = set(repo.changelog.descendants(dstates))
1090 descendants = set(repo.changelog.descendants(dstates))
1064 if descendants - set(dstates):
1091 if descendants - set(dstates):
1065 repo.ui.warn(_("warning: new changesets detected on target branch, "
1092 repo.ui.warn(_("warning: new changesets detected on target branch, "
1066 "can't strip\n"))
1093 "can't strip\n"))
1067 cleanup = False
1094 cleanup = False
1068
1095
1069 if cleanup:
1096 if cleanup:
1070 shouldupdate = False
1097 shouldupdate = False
1071 rebased = filter(lambda x: x >= 0 and x != target, state.values())
1098 rebased = filter(lambda x: x >= 0 and x != target, state.values())
1072 if rebased:
1099 if rebased:
1073 strippoints = [
1100 strippoints = [
1074 c.node() for c in repo.set('roots(%ld)', rebased)]
1101 c.node() for c in repo.set('roots(%ld)', rebased)]
1075 shouldupdate = len([
1102 shouldupdate = len([
1076 c.node() for c in repo.set('. & (%ld)', rebased)]) > 0
1103 c.node() for c in repo.set('. & (%ld)', rebased)]) > 0
1077
1104
1078 # Update away from the rebase if necessary
1105 # Update away from the rebase if necessary
1079 if shouldupdate or needupdate(repo, state):
1106 if shouldupdate or needupdate(repo, state):
1080 merge.update(repo, originalwd, False, True)
1107 merge.update(repo, originalwd, False, True)
1081
1108
1082 # Strip from the first rebased revision
1109 # Strip from the first rebased revision
1083 if rebased:
1110 if rebased:
1084 # no backup of rebased cset versions needed
1111 # no backup of rebased cset versions needed
1085 repair.strip(repo.ui, repo, strippoints)
1112 repair.strip(repo.ui, repo, strippoints)
1086
1113
1087 if activebookmark and activebookmark in repo._bookmarks:
1114 if activebookmark and activebookmark in repo._bookmarks:
1088 bookmarks.activate(repo, activebookmark)
1115 bookmarks.activate(repo, activebookmark)
1089
1116
1090 finally:
1117 finally:
1091 clearstatus(repo)
1118 clearstatus(repo)
1092 clearcollapsemsg(repo)
1119 clearcollapsemsg(repo)
1093 repo.ui.warn(_('rebase aborted\n'))
1120 repo.ui.warn(_('rebase aborted\n'))
1094 return 0
1121 return 0
1095
1122
1096 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1123 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1097 '''Define which revisions are going to be rebased and where
1124 '''Define which revisions are going to be rebased and where
1098
1125
1099 repo: repo
1126 repo: repo
1100 dest: context
1127 dest: context
1101 rebaseset: set of rev
1128 rebaseset: set of rev
1102 '''
1129 '''
1103 _setrebasesetvisibility(repo, rebaseset)
1130 _setrebasesetvisibility(repo, rebaseset)
1104
1131
1105 # This check isn't strictly necessary, since mq detects commits over an
1132 # This check isn't strictly necessary, since mq detects commits over an
1106 # applied patch. But it prevents messing up the working directory when
1133 # applied patch. But it prevents messing up the working directory when
1107 # a partially completed rebase is blocked by mq.
1134 # a partially completed rebase is blocked by mq.
1108 if 'qtip' in repo.tags() and (dest.node() in
1135 if 'qtip' in repo.tags() and (dest.node() in
1109 [s.node for s in repo.mq.applied]):
1136 [s.node for s in repo.mq.applied]):
1110 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1137 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1111
1138
1112 roots = list(repo.set('roots(%ld)', rebaseset))
1139 roots = list(repo.set('roots(%ld)', rebaseset))
1113 if not roots:
1140 if not roots:
1114 raise error.Abort(_('no matching revisions'))
1141 raise error.Abort(_('no matching revisions'))
1115 roots.sort()
1142 roots.sort()
1116 state = {}
1143 state = {}
1117 detachset = set()
1144 detachset = set()
1118 for root in roots:
1145 for root in roots:
1119 commonbase = root.ancestor(dest)
1146 commonbase = root.ancestor(dest)
1120 if commonbase == root:
1147 if commonbase == root:
1121 raise error.Abort(_('source is ancestor of destination'))
1148 raise error.Abort(_('source is ancestor of destination'))
1122 if commonbase == dest:
1149 if commonbase == dest:
1123 samebranch = root.branch() == dest.branch()
1150 samebranch = root.branch() == dest.branch()
1124 if not collapse and samebranch and root in dest.children():
1151 if not collapse and samebranch and root in dest.children():
1125 repo.ui.debug('source is a child of destination\n')
1152 repo.ui.debug('source is a child of destination\n')
1126 return None
1153 return None
1127
1154
1128 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
1155 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
1129 state.update(dict.fromkeys(rebaseset, revtodo))
1156 state.update(dict.fromkeys(rebaseset, revtodo))
1130 # Rebase tries to turn <dest> into a parent of <root> while
1157 # Rebase tries to turn <dest> into a parent of <root> while
1131 # preserving the number of parents of rebased changesets:
1158 # preserving the number of parents of rebased changesets:
1132 #
1159 #
1133 # - A changeset with a single parent will always be rebased as a
1160 # - A changeset with a single parent will always be rebased as a
1134 # changeset with a single parent.
1161 # changeset with a single parent.
1135 #
1162 #
1136 # - A merge will be rebased as merge unless its parents are both
1163 # - A merge will be rebased as merge unless its parents are both
1137 # ancestors of <dest> or are themselves in the rebased set and
1164 # ancestors of <dest> or are themselves in the rebased set and
1138 # pruned while rebased.
1165 # pruned while rebased.
1139 #
1166 #
1140 # If one parent of <root> is an ancestor of <dest>, the rebased
1167 # If one parent of <root> is an ancestor of <dest>, the rebased
1141 # version of this parent will be <dest>. This is always true with
1168 # version of this parent will be <dest>. This is always true with
1142 # --base option.
1169 # --base option.
1143 #
1170 #
1144 # Otherwise, we need to *replace* the original parents with
1171 # Otherwise, we need to *replace* the original parents with
1145 # <dest>. This "detaches" the rebased set from its former location
1172 # <dest>. This "detaches" the rebased set from its former location
1146 # and rebases it onto <dest>. Changes introduced by ancestors of
1173 # and rebases it onto <dest>. Changes introduced by ancestors of
1147 # <root> not common with <dest> (the detachset, marked as
1174 # <root> not common with <dest> (the detachset, marked as
1148 # nullmerge) are "removed" from the rebased changesets.
1175 # nullmerge) are "removed" from the rebased changesets.
1149 #
1176 #
1150 # - If <root> has a single parent, set it to <dest>.
1177 # - If <root> has a single parent, set it to <dest>.
1151 #
1178 #
1152 # - If <root> is a merge, we cannot decide which parent to
1179 # - If <root> is a merge, we cannot decide which parent to
1153 # replace, the rebase operation is not clearly defined.
1180 # replace, the rebase operation is not clearly defined.
1154 #
1181 #
1155 # The table below sums up this behavior:
1182 # The table below sums up this behavior:
1156 #
1183 #
1157 # +------------------+----------------------+-------------------------+
1184 # +------------------+----------------------+-------------------------+
1158 # | | one parent | merge |
1185 # | | one parent | merge |
1159 # +------------------+----------------------+-------------------------+
1186 # +------------------+----------------------+-------------------------+
1160 # | parent in | new parent is <dest> | parents in ::<dest> are |
1187 # | parent in | new parent is <dest> | parents in ::<dest> are |
1161 # | ::<dest> | | remapped to <dest> |
1188 # | ::<dest> | | remapped to <dest> |
1162 # +------------------+----------------------+-------------------------+
1189 # +------------------+----------------------+-------------------------+
1163 # | unrelated source | new parent is <dest> | ambiguous, abort |
1190 # | unrelated source | new parent is <dest> | ambiguous, abort |
1164 # +------------------+----------------------+-------------------------+
1191 # +------------------+----------------------+-------------------------+
1165 #
1192 #
1166 # The actual abort is handled by `defineparents`
1193 # The actual abort is handled by `defineparents`
1167 if len(root.parents()) <= 1:
1194 if len(root.parents()) <= 1:
1168 # ancestors of <root> not ancestors of <dest>
1195 # ancestors of <root> not ancestors of <dest>
1169 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1196 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1170 [root.rev()]))
1197 [root.rev()]))
1171 for r in detachset:
1198 for r in detachset:
1172 if r not in state:
1199 if r not in state:
1173 state[r] = nullmerge
1200 state[r] = nullmerge
1174 if len(roots) > 1:
1201 if len(roots) > 1:
1175 # If we have multiple roots, we may have "hole" in the rebase set.
1202 # If we have multiple roots, we may have "hole" in the rebase set.
1176 # Rebase roots that descend from those "hole" should not be detached as
1203 # Rebase roots that descend from those "hole" should not be detached as
1177 # other root are. We use the special `revignored` to inform rebase that
1204 # other root are. We use the special `revignored` to inform rebase that
1178 # the revision should be ignored but that `defineparents` should search
1205 # the revision should be ignored but that `defineparents` should search
1179 # a rebase destination that make sense regarding rebased topology.
1206 # a rebase destination that make sense regarding rebased topology.
1180 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1207 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1181 for ignored in set(rebasedomain) - set(rebaseset):
1208 for ignored in set(rebasedomain) - set(rebaseset):
1182 state[ignored] = revignored
1209 state[ignored] = revignored
1183 for r in obsoletenotrebased:
1210 for r in obsoletenotrebased:
1184 if obsoletenotrebased[r] is None:
1211 if obsoletenotrebased[r] is None:
1185 state[r] = revpruned
1212 state[r] = revpruned
1186 else:
1213 else:
1187 state[r] = revprecursor
1214 state[r] = revprecursor
1188 return repo['.'].rev(), dest.rev(), state
1215 return repo['.'].rev(), dest.rev(), state
1189
1216
1190 def clearrebased(ui, repo, state, skipped, collapsedas=None):
1217 def clearrebased(ui, repo, state, skipped, collapsedas=None):
1191 """dispose of rebased revision at the end of the rebase
1218 """dispose of rebased revision at the end of the rebase
1192
1219
1193 If `collapsedas` is not None, the rebase was a collapse whose result if the
1220 If `collapsedas` is not None, the rebase was a collapse whose result if the
1194 `collapsedas` node."""
1221 `collapsedas` node."""
1195 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1222 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1196 markers = []
1223 markers = []
1197 for rev, newrev in sorted(state.items()):
1224 for rev, newrev in sorted(state.items()):
1198 if newrev >= 0:
1225 if newrev >= 0:
1199 if rev in skipped:
1226 if rev in skipped:
1200 succs = ()
1227 succs = ()
1201 elif collapsedas is not None:
1228 elif collapsedas is not None:
1202 succs = (repo[collapsedas],)
1229 succs = (repo[collapsedas],)
1203 else:
1230 else:
1204 succs = (repo[newrev],)
1231 succs = (repo[newrev],)
1205 markers.append((repo[rev], succs))
1232 markers.append((repo[rev], succs))
1206 if markers:
1233 if markers:
1207 obsolete.createmarkers(repo, markers)
1234 obsolete.createmarkers(repo, markers)
1208 else:
1235 else:
1209 rebased = [rev for rev in state if state[rev] > nullmerge]
1236 rebased = [rev for rev in state if state[rev] > nullmerge]
1210 if rebased:
1237 if rebased:
1211 stripped = []
1238 stripped = []
1212 for root in repo.set('roots(%ld)', rebased):
1239 for root in repo.set('roots(%ld)', rebased):
1213 if set(repo.changelog.descendants([root.rev()])) - set(state):
1240 if set(repo.changelog.descendants([root.rev()])) - set(state):
1214 ui.warn(_("warning: new changesets detected "
1241 ui.warn(_("warning: new changesets detected "
1215 "on source branch, not stripping\n"))
1242 "on source branch, not stripping\n"))
1216 else:
1243 else:
1217 stripped.append(root.node())
1244 stripped.append(root.node())
1218 if stripped:
1245 if stripped:
1219 # backup the old csets by default
1246 # backup the old csets by default
1220 repair.strip(ui, repo, stripped, "all")
1247 repair.strip(ui, repo, stripped, "all")
1221
1248
1222
1249
1223 def pullrebase(orig, ui, repo, *args, **opts):
1250 def pullrebase(orig, ui, repo, *args, **opts):
1224 'Call rebase after pull if the latter has been invoked with --rebase'
1251 'Call rebase after pull if the latter has been invoked with --rebase'
1225 ret = None
1252 ret = None
1226 if opts.get('rebase'):
1253 if opts.get('rebase'):
1227 wlock = lock = None
1254 wlock = lock = None
1228 try:
1255 try:
1229 wlock = repo.wlock()
1256 wlock = repo.wlock()
1230 lock = repo.lock()
1257 lock = repo.lock()
1231 if opts.get('update'):
1258 if opts.get('update'):
1232 del opts['update']
1259 del opts['update']
1233 ui.debug('--update and --rebase are not compatible, ignoring '
1260 ui.debug('--update and --rebase are not compatible, ignoring '
1234 'the update flag\n')
1261 'the update flag\n')
1235
1262
1236 revsprepull = len(repo)
1263 revsprepull = len(repo)
1237 origpostincoming = commands.postincoming
1264 origpostincoming = commands.postincoming
1238 def _dummy(*args, **kwargs):
1265 def _dummy(*args, **kwargs):
1239 pass
1266 pass
1240 commands.postincoming = _dummy
1267 commands.postincoming = _dummy
1241 try:
1268 try:
1242 ret = orig(ui, repo, *args, **opts)
1269 ret = orig(ui, repo, *args, **opts)
1243 finally:
1270 finally:
1244 commands.postincoming = origpostincoming
1271 commands.postincoming = origpostincoming
1245 revspostpull = len(repo)
1272 revspostpull = len(repo)
1246 if revspostpull > revsprepull:
1273 if revspostpull > revsprepull:
1247 # --rev option from pull conflict with rebase own --rev
1274 # --rev option from pull conflict with rebase own --rev
1248 # dropping it
1275 # dropping it
1249 if 'rev' in opts:
1276 if 'rev' in opts:
1250 del opts['rev']
1277 del opts['rev']
1251 # positional argument from pull conflicts with rebase's own
1278 # positional argument from pull conflicts with rebase's own
1252 # --source.
1279 # --source.
1253 if 'source' in opts:
1280 if 'source' in opts:
1254 del opts['source']
1281 del opts['source']
1255 # revsprepull is the len of the repo, not revnum of tip.
1282 # revsprepull is the len of the repo, not revnum of tip.
1256 destspace = list(repo.changelog.revs(start=revsprepull))
1283 destspace = list(repo.changelog.revs(start=revsprepull))
1257 opts['_destspace'] = destspace
1284 opts['_destspace'] = destspace
1258 try:
1285 try:
1259 rebase(ui, repo, **opts)
1286 rebase(ui, repo, **opts)
1260 except error.NoMergeDestAbort:
1287 except error.NoMergeDestAbort:
1261 # we can maybe update instead
1288 # we can maybe update instead
1262 rev, _a, _b = destutil.destupdate(repo)
1289 rev, _a, _b = destutil.destupdate(repo)
1263 if rev == repo['.'].rev():
1290 if rev == repo['.'].rev():
1264 ui.status(_('nothing to rebase\n'))
1291 ui.status(_('nothing to rebase\n'))
1265 else:
1292 else:
1266 ui.status(_('nothing to rebase - updating instead\n'))
1293 ui.status(_('nothing to rebase - updating instead\n'))
1267 # not passing argument to get the bare update behavior
1294 # not passing argument to get the bare update behavior
1268 # with warning and trumpets
1295 # with warning and trumpets
1269 commands.update(ui, repo)
1296 commands.update(ui, repo)
1270 finally:
1297 finally:
1271 release(lock, wlock)
1298 release(lock, wlock)
1272 else:
1299 else:
1273 if opts.get('tool'):
1300 if opts.get('tool'):
1274 raise error.Abort(_('--tool can only be used with --rebase'))
1301 raise error.Abort(_('--tool can only be used with --rebase'))
1275 ret = orig(ui, repo, *args, **opts)
1302 ret = orig(ui, repo, *args, **opts)
1276
1303
1277 return ret
1304 return ret
1278
1305
1279 def _setrebasesetvisibility(repo, revs):
1306 def _setrebasesetvisibility(repo, revs):
1280 """store the currently rebased set on the repo object
1307 """store the currently rebased set on the repo object
1281
1308
1282 This is used by another function to prevent rebased revision to because
1309 This is used by another function to prevent rebased revision to because
1283 hidden (see issue4505)"""
1310 hidden (see issue4505)"""
1284 repo = repo.unfiltered()
1311 repo = repo.unfiltered()
1285 revs = set(revs)
1312 revs = set(revs)
1286 repo._rebaseset = revs
1313 repo._rebaseset = revs
1287 # invalidate cache if visibility changes
1314 # invalidate cache if visibility changes
1288 hiddens = repo.filteredrevcache.get('visible', set())
1315 hiddens = repo.filteredrevcache.get('visible', set())
1289 if revs & hiddens:
1316 if revs & hiddens:
1290 repo.invalidatevolatilesets()
1317 repo.invalidatevolatilesets()
1291
1318
1292 def _clearrebasesetvisibiliy(repo):
1319 def _clearrebasesetvisibiliy(repo):
1293 """remove rebaseset data from the repo"""
1320 """remove rebaseset data from the repo"""
1294 repo = repo.unfiltered()
1321 repo = repo.unfiltered()
1295 if '_rebaseset' in vars(repo):
1322 if '_rebaseset' in vars(repo):
1296 del repo._rebaseset
1323 del repo._rebaseset
1297
1324
1298 def _rebasedvisible(orig, repo):
1325 def _rebasedvisible(orig, repo):
1299 """ensure rebased revs stay visible (see issue4505)"""
1326 """ensure rebased revs stay visible (see issue4505)"""
1300 blockers = orig(repo)
1327 blockers = orig(repo)
1301 blockers.update(getattr(repo, '_rebaseset', ()))
1328 blockers.update(getattr(repo, '_rebaseset', ()))
1302 return blockers
1329 return blockers
1303
1330
1304 def _filterobsoleterevs(repo, revs):
1331 def _filterobsoleterevs(repo, revs):
1305 """returns a set of the obsolete revisions in revs"""
1332 """returns a set of the obsolete revisions in revs"""
1306 return set(r for r in revs if repo[r].obsolete())
1333 return set(r for r in revs if repo[r].obsolete())
1307
1334
1308 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1335 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1309 """return a mapping obsolete => successor for all obsolete nodes to be
1336 """return a mapping obsolete => successor for all obsolete nodes to be
1310 rebased that have a successors in the destination
1337 rebased that have a successors in the destination
1311
1338
1312 obsolete => None entries in the mapping indicate nodes with no succesor"""
1339 obsolete => None entries in the mapping indicate nodes with no succesor"""
1313 obsoletenotrebased = {}
1340 obsoletenotrebased = {}
1314
1341
1315 # Build a mapping successor => obsolete nodes for the obsolete
1342 # Build a mapping successor => obsolete nodes for the obsolete
1316 # nodes to be rebased
1343 # nodes to be rebased
1317 allsuccessors = {}
1344 allsuccessors = {}
1318 cl = repo.changelog
1345 cl = repo.changelog
1319 for r in rebaseobsrevs:
1346 for r in rebaseobsrevs:
1320 node = cl.node(r)
1347 node = cl.node(r)
1321 for s in obsolete.allsuccessors(repo.obsstore, [node]):
1348 for s in obsolete.allsuccessors(repo.obsstore, [node]):
1322 try:
1349 try:
1323 allsuccessors[cl.rev(s)] = cl.rev(node)
1350 allsuccessors[cl.rev(s)] = cl.rev(node)
1324 except LookupError:
1351 except LookupError:
1325 pass
1352 pass
1326
1353
1327 if allsuccessors:
1354 if allsuccessors:
1328 # Look for successors of obsolete nodes to be rebased among
1355 # Look for successors of obsolete nodes to be rebased among
1329 # the ancestors of dest
1356 # the ancestors of dest
1330 ancs = cl.ancestors([repo[dest].rev()],
1357 ancs = cl.ancestors([repo[dest].rev()],
1331 stoprev=min(allsuccessors),
1358 stoprev=min(allsuccessors),
1332 inclusive=True)
1359 inclusive=True)
1333 for s in allsuccessors:
1360 for s in allsuccessors:
1334 if s in ancs:
1361 if s in ancs:
1335 obsoletenotrebased[allsuccessors[s]] = s
1362 obsoletenotrebased[allsuccessors[s]] = s
1336 elif (s == allsuccessors[s] and
1363 elif (s == allsuccessors[s] and
1337 allsuccessors.values().count(s) == 1):
1364 allsuccessors.values().count(s) == 1):
1338 # plain prune
1365 # plain prune
1339 obsoletenotrebased[s] = None
1366 obsoletenotrebased[s] = None
1340
1367
1341 return obsoletenotrebased
1368 return obsoletenotrebased
1342
1369
1343 def summaryhook(ui, repo):
1370 def summaryhook(ui, repo):
1344 if not os.path.exists(repo.join('rebasestate')):
1371 if not os.path.exists(repo.join('rebasestate')):
1345 return
1372 return
1346 try:
1373 try:
1347 state = restorestatus(repo)[2]
1374 state = restorestatus(repo)[2]
1348 except error.RepoLookupError:
1375 except error.RepoLookupError:
1349 # i18n: column positioning for "hg summary"
1376 # i18n: column positioning for "hg summary"
1350 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1377 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1351 ui.write(msg)
1378 ui.write(msg)
1352 return
1379 return
1353 numrebased = len([i for i in state.itervalues() if i >= 0])
1380 numrebased = len([i for i in state.itervalues() if i >= 0])
1354 # i18n: column positioning for "hg summary"
1381 # i18n: column positioning for "hg summary"
1355 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1382 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1356 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1383 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1357 ui.label(_('%d remaining'), 'rebase.remaining') %
1384 ui.label(_('%d remaining'), 'rebase.remaining') %
1358 (len(state) - numrebased)))
1385 (len(state) - numrebased)))
1359
1386
1360 def uisetup(ui):
1387 def uisetup(ui):
1361 #Replace pull with a decorator to provide --rebase option
1388 #Replace pull with a decorator to provide --rebase option
1362 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1389 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1363 entry[1].append(('', 'rebase', None,
1390 entry[1].append(('', 'rebase', None,
1364 _("rebase working directory to branch head")))
1391 _("rebase working directory to branch head")))
1365 entry[1].append(('t', 'tool', '',
1392 entry[1].append(('t', 'tool', '',
1366 _("specify merge tool for rebase")))
1393 _("specify merge tool for rebase")))
1367 cmdutil.summaryhooks.add('rebase', summaryhook)
1394 cmdutil.summaryhooks.add('rebase', summaryhook)
1368 cmdutil.unfinishedstates.append(
1395 cmdutil.unfinishedstates.append(
1369 ['rebasestate', False, False, _('rebase in progress'),
1396 ['rebasestate', False, False, _('rebase in progress'),
1370 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1397 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1371 cmdutil.afterresolvedstates.append(
1398 cmdutil.afterresolvedstates.append(
1372 ['rebasestate', _('hg rebase --continue')])
1399 ['rebasestate', _('hg rebase --continue')])
1373 # ensure rebased rev are not hidden
1400 # ensure rebased rev are not hidden
1374 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
1401 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
@@ -1,170 +1,169 b''
1 #require test-repo
1 #require test-repo
2
2
3 $ cd "$TESTDIR"/..
3 $ cd "$TESTDIR"/..
4
4
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
6 hgext/fsmonitor/pywatchman/__init__.py not using absolute_import
6 hgext/fsmonitor/pywatchman/__init__.py not using absolute_import
7 hgext/fsmonitor/pywatchman/__init__.py requires print_function
7 hgext/fsmonitor/pywatchman/__init__.py requires print_function
8 hgext/fsmonitor/pywatchman/capabilities.py not using absolute_import
8 hgext/fsmonitor/pywatchman/capabilities.py not using absolute_import
9 hgext/fsmonitor/pywatchman/pybser.py not using absolute_import
9 hgext/fsmonitor/pywatchman/pybser.py not using absolute_import
10 hgext/hgcia.py not using absolute_import
10 hgext/hgcia.py not using absolute_import
11 hgext/highlight/__init__.py not using absolute_import
11 hgext/highlight/__init__.py not using absolute_import
12 hgext/highlight/highlight.py not using absolute_import
12 hgext/highlight/highlight.py not using absolute_import
13 hgext/largefiles/__init__.py not using absolute_import
13 hgext/largefiles/__init__.py not using absolute_import
14 hgext/largefiles/basestore.py not using absolute_import
14 hgext/largefiles/basestore.py not using absolute_import
15 hgext/largefiles/lfcommands.py not using absolute_import
15 hgext/largefiles/lfcommands.py not using absolute_import
16 hgext/largefiles/lfutil.py not using absolute_import
16 hgext/largefiles/lfutil.py not using absolute_import
17 hgext/largefiles/localstore.py not using absolute_import
17 hgext/largefiles/localstore.py not using absolute_import
18 hgext/largefiles/overrides.py not using absolute_import
18 hgext/largefiles/overrides.py not using absolute_import
19 hgext/largefiles/proto.py not using absolute_import
19 hgext/largefiles/proto.py not using absolute_import
20 hgext/largefiles/remotestore.py not using absolute_import
20 hgext/largefiles/remotestore.py not using absolute_import
21 hgext/largefiles/reposetup.py not using absolute_import
21 hgext/largefiles/reposetup.py not using absolute_import
22 hgext/largefiles/uisetup.py not using absolute_import
22 hgext/largefiles/uisetup.py not using absolute_import
23 hgext/largefiles/wirestore.py not using absolute_import
23 hgext/largefiles/wirestore.py not using absolute_import
24 hgext/rebase.py not using absolute_import
25 hgext/share.py not using absolute_import
24 hgext/share.py not using absolute_import
26 hgext/win32text.py not using absolute_import
25 hgext/win32text.py not using absolute_import
27 i18n/check-translation.py not using absolute_import
26 i18n/check-translation.py not using absolute_import
28 i18n/polib.py not using absolute_import
27 i18n/polib.py not using absolute_import
29 setup.py not using absolute_import
28 setup.py not using absolute_import
30 tests/heredoctest.py requires print_function
29 tests/heredoctest.py requires print_function
31 tests/md5sum.py not using absolute_import
30 tests/md5sum.py not using absolute_import
32 tests/readlink.py not using absolute_import
31 tests/readlink.py not using absolute_import
33 tests/readlink.py requires print_function
32 tests/readlink.py requires print_function
34 tests/run-tests.py not using absolute_import
33 tests/run-tests.py not using absolute_import
35 tests/svn-safe-append.py not using absolute_import
34 tests/svn-safe-append.py not using absolute_import
36 tests/test-atomictempfile.py not using absolute_import
35 tests/test-atomictempfile.py not using absolute_import
37 tests/test-demandimport.py not using absolute_import
36 tests/test-demandimport.py not using absolute_import
38
37
39 #if py3exe
38 #if py3exe
40 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py
39 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs $PYTHON3 contrib/check-py3-compat.py
41 contrib/check-code.py: invalid syntax: (unicode error) 'unicodeescape' codec can't decode bytes in position *-*: malformed \N character escape (<unknown>, line *) (glob)
40 contrib/check-code.py: invalid syntax: (unicode error) 'unicodeescape' codec can't decode bytes in position *-*: malformed \N character escape (<unknown>, line *) (glob)
42 doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
41 doc/hgmanpage.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
43 hgext/automv.py: error importing module: <SyntaxError> invalid syntax (commands.py, line *) (line *) (glob)
42 hgext/automv.py: error importing module: <SyntaxError> invalid syntax (commands.py, line *) (line *) (glob)
44 hgext/blackbox.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
43 hgext/blackbox.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
45 hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line *) (glob)
44 hgext/bugzilla.py: error importing module: <ImportError> No module named 'urlparse' (line *) (glob)
46 hgext/censor.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
45 hgext/censor.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
47 hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
46 hgext/chgserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
48 hgext/children.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
47 hgext/children.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
49 hgext/churn.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
48 hgext/churn.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
50 hgext/clonebundles.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
49 hgext/clonebundles.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
51 hgext/color.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
50 hgext/color.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
52 hgext/convert/bzr.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
51 hgext/convert/bzr.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
53 hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
52 hgext/convert/common.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
54 hgext/convert/convcmd.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
53 hgext/convert/convcmd.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
55 hgext/convert/cvs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
54 hgext/convert/cvs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
56 hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
55 hgext/convert/cvsps.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
57 hgext/convert/darcs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
56 hgext/convert/darcs.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
58 hgext/convert/filemap.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
57 hgext/convert/filemap.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
59 hgext/convert/git.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
58 hgext/convert/git.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
60 hgext/convert/gnuarch.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
59 hgext/convert/gnuarch.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
61 hgext/convert/hg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
60 hgext/convert/hg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
62 hgext/convert/monotone.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
61 hgext/convert/monotone.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
63 hgext/convert/p*.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
62 hgext/convert/p*.py: error importing module: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (line *) (glob)
64 hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
63 hgext/convert/subversion.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
65 hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line *) (glob)
64 hgext/convert/transport.py: error importing module: <ImportError> No module named 'svn.client' (line *) (glob)
66 hgext/eol.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
65 hgext/eol.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
67 hgext/extdiff.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
66 hgext/extdiff.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
68 hgext/factotum.py: error importing: <ImportError> No module named 'cStringIO' (error at __init__.py:*) (glob)
67 hgext/factotum.py: error importing: <ImportError> No module named 'cStringIO' (error at __init__.py:*) (glob)
69 hgext/fetch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
68 hgext/fetch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
70 hgext/fsmonitor/watchmanclient.py: error importing module: <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (line *) (glob)
69 hgext/fsmonitor/watchmanclient.py: error importing module: <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (line *) (glob)
71 hgext/gpg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
70 hgext/gpg.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
72 hgext/graphlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
71 hgext/graphlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
73 hgext/hgcia.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
72 hgext/hgcia.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
74 hgext/hgk.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
73 hgext/hgk.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
75 hgext/histedit.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
74 hgext/histedit.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
76 hgext/keyword.py: error importing: <ImportError> No module named 'BaseHTTPServer' (error at common.py:*) (glob)
75 hgext/keyword.py: error importing: <ImportError> No module named 'BaseHTTPServer' (error at common.py:*) (glob)
77 hgext/largefiles/basestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
76 hgext/largefiles/basestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
78 hgext/largefiles/lfcommands.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
77 hgext/largefiles/lfcommands.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
79 hgext/largefiles/lfutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
78 hgext/largefiles/lfutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
80 hgext/largefiles/localstore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
79 hgext/largefiles/localstore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
81 hgext/largefiles/overrides.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
80 hgext/largefiles/overrides.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
82 hgext/largefiles/proto.py: error importing: <ImportError> No module named 'httplib' (error at httppeer.py:*) (glob)
81 hgext/largefiles/proto.py: error importing: <ImportError> No module named 'httplib' (error at httppeer.py:*) (glob)
83 hgext/largefiles/remotestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
82 hgext/largefiles/remotestore.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
84 hgext/largefiles/reposetup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
83 hgext/largefiles/reposetup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
85 hgext/largefiles/uisetup.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
84 hgext/largefiles/uisetup.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
86 hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
85 hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
87 hgext/mq.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
86 hgext/mq.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
88 hgext/notify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
87 hgext/notify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
89 hgext/pager.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
88 hgext/pager.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
90 hgext/patchbomb.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
89 hgext/patchbomb.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
91 hgext/purge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
90 hgext/purge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
92 hgext/rebase.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
91 hgext/rebase.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
93 hgext/record.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
92 hgext/record.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
94 hgext/relink.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
93 hgext/relink.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
95 hgext/schemes.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
94 hgext/schemes.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
96 hgext/share.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
95 hgext/share.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
97 hgext/shelve.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
96 hgext/shelve.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
98 hgext/strip.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
97 hgext/strip.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
99 hgext/transplant.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
98 hgext/transplant.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
100 mercurial/archival.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
99 mercurial/archival.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
101 mercurial/branchmap.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
100 mercurial/branchmap.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
102 mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
101 mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
103 mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
102 mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
104 mercurial/changegroup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
103 mercurial/changegroup.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
105 mercurial/changelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
104 mercurial/changelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
106 mercurial/cmdutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
105 mercurial/cmdutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
107 mercurial/commands.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
106 mercurial/commands.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
108 mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
107 mercurial/commandserver.py: error importing module: <ImportError> No module named 'SocketServer' (line *) (glob)
109 mercurial/context.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
108 mercurial/context.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
110 mercurial/copies.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
109 mercurial/copies.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
111 mercurial/crecord.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
110 mercurial/crecord.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
112 mercurial/dirstate.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
111 mercurial/dirstate.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
113 mercurial/discovery.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
112 mercurial/discovery.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
114 mercurial/dispatch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
113 mercurial/dispatch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
115 mercurial/exchange.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
114 mercurial/exchange.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
116 mercurial/extensions.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
115 mercurial/extensions.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
117 mercurial/filelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
116 mercurial/filelog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
118 mercurial/filemerge.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
117 mercurial/filemerge.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
119 mercurial/fileset.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
118 mercurial/fileset.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
120 mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
119 mercurial/formatter.py: error importing module: <ImportError> No module named 'cPickle' (line *) (glob)
121 mercurial/graphmod.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
120 mercurial/graphmod.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
122 mercurial/help.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
121 mercurial/help.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
123 mercurial/hg.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
122 mercurial/hg.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at bundlerepo.py:*) (glob)
124 mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
123 mercurial/hgweb/common.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
125 mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
124 mercurial/hgweb/hgweb_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
126 mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
125 mercurial/hgweb/hgwebdir_mod.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
127 mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
126 mercurial/hgweb/protocol.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
128 mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
127 mercurial/hgweb/request.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
129 mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
128 mercurial/hgweb/server.py: error importing module: <ImportError> No module named 'BaseHTTPServer' (line *) (glob)
130 mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
129 mercurial/hgweb/webcommands.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
131 mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
130 mercurial/hgweb/webutil.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
132 mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
131 mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
133 mercurial/hook.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
132 mercurial/hook.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
134 mercurial/httpclient/_readers.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
133 mercurial/httpclient/_readers.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
135 mercurial/httpconnection.py: error importing: <ImportError> No module named 'cStringIO' (error at __init__.py:*) (glob)
134 mercurial/httpconnection.py: error importing: <ImportError> No module named 'cStringIO' (error at __init__.py:*) (glob)
136 mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
135 mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
137 mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
136 mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
138 mercurial/localrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
137 mercurial/localrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
139 mercurial/mail.py: error importing module: <AttributeError> module 'email' has no attribute 'Header' (line *) (glob)
138 mercurial/mail.py: error importing module: <AttributeError> module 'email' has no attribute 'Header' (line *) (glob)
140 mercurial/manifest.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
139 mercurial/manifest.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
141 mercurial/merge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
140 mercurial/merge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
142 mercurial/namespaces.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
141 mercurial/namespaces.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
143 mercurial/patch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
142 mercurial/patch.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
144 mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line *) (glob)
143 mercurial/pure/mpatch.py: error importing module: <ImportError> cannot import name 'pycompat' (line *) (glob)
145 mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line *) (glob)
144 mercurial/pure/parsers.py: error importing module: <ImportError> No module named 'mercurial.pure.node' (line *) (glob)
146 mercurial/repair.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
145 mercurial/repair.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
147 mercurial/revlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
146 mercurial/revlog.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
148 mercurial/revset.py: error importing module: <AttributeError> 'dict' object has no attribute 'iteritems' (line *) (glob)
147 mercurial/revset.py: error importing module: <AttributeError> 'dict' object has no attribute 'iteritems' (line *) (glob)
149 mercurial/scmutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
148 mercurial/scmutil.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
150 mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
149 mercurial/scmwindows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
151 mercurial/simplemerge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
150 mercurial/simplemerge.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
152 mercurial/sshpeer.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
151 mercurial/sshpeer.py: error importing: <SyntaxError> invalid syntax (bundle*.py, line *) (error at wireproto.py:*) (glob)
153 mercurial/sshserver.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
152 mercurial/sshserver.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
154 mercurial/statichttprepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
153 mercurial/statichttprepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
155 mercurial/store.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
154 mercurial/store.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
156 mercurial/streamclone.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
155 mercurial/streamclone.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
157 mercurial/subrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
156 mercurial/subrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
158 mercurial/templatefilters.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
157 mercurial/templatefilters.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
159 mercurial/templatekw.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
158 mercurial/templatekw.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
160 mercurial/templater.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
159 mercurial/templater.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
161 mercurial/ui.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
160 mercurial/ui.py: error importing: <ImportError> No module named 'cPickle' (error at formatter.py:*) (glob)
162 mercurial/unionrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
161 mercurial/unionrepo.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
163 mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
162 mercurial/url.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
164 mercurial/verify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
163 mercurial/verify.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*) (glob)
165 mercurial/win*.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
164 mercurial/win*.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
166 mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
165 mercurial/windows.py: error importing module: <ImportError> No module named '_winreg' (line *) (glob)
167 mercurial/wireproto.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
166 mercurial/wireproto.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
168 tests/readlink.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
167 tests/readlink.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
169
168
170 #endif
169 #endif
General Comments 0
You need to be logged in to leave comments. Login now