##// END OF EJS Templates
rebase: choose default destination the same way as 'hg merge' (BC)...
Pierre-Yves David -
r28189:fac3a24b default
parent child Browse files
Show More
@@ -1,1312 +1,1328
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 mercurial import hg, util, repair, merge, cmdutil, commands, bookmarks
18 from mercurial import extensions, patch, scmutil, phases, obsolete, error
18 from mercurial import extensions, patch, scmutil, phases, obsolete, error
19 from mercurial import copies, destutil, repoview, revset
19 from mercurial import copies, destutil, repoview, revset
20 from mercurial.commands import templateopts
20 from mercurial.commands import templateopts
21 from mercurial.node import nullrev, nullid, hex, short
21 from mercurial.node import nullrev, nullid, hex, short
22 from mercurial.lock import release
22 from mercurial.lock import release
23 from mercurial.i18n import _
23 from mercurial.i18n import _
24 import os, errno
24 import os, errno
25
25
26 # The following constants are used throughout the rebase module. The ordering of
26 # The following constants are used throughout the rebase module. The ordering of
27 # their values must be maintained.
27 # their values must be maintained.
28
28
29 # Indicates that a revision needs to be rebased
29 # Indicates that a revision needs to be rebased
30 revtodo = -1
30 revtodo = -1
31 nullmerge = -2
31 nullmerge = -2
32 revignored = -3
32 revignored = -3
33 # successor in rebase destination
33 # successor in rebase destination
34 revprecursor = -4
34 revprecursor = -4
35 # plain prune (no successor)
35 # plain prune (no successor)
36 revpruned = -5
36 revpruned = -5
37 revskipped = (revignored, revprecursor, revpruned)
37 revskipped = (revignored, revprecursor, revpruned)
38
38
39 cmdtable = {}
39 cmdtable = {}
40 command = cmdutil.command(cmdtable)
40 command = cmdutil.command(cmdtable)
41 # Note for extension authors: ONLY specify testedwith = 'internal' for
41 # Note for extension authors: ONLY specify testedwith = 'internal' for
42 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
42 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
43 # be specifying the version(s) of Mercurial they are tested with, or
43 # be specifying the version(s) of Mercurial they are tested with, or
44 # leave the attribute unspecified.
44 # leave the attribute unspecified.
45 testedwith = 'internal'
45 testedwith = 'internal'
46
46
47 def _nothingtorebase():
47 def _nothingtorebase():
48 return 1
48 return 1
49
49
50 def _savegraft(ctx, extra):
50 def _savegraft(ctx, extra):
51 s = ctx.extra().get('source', None)
51 s = ctx.extra().get('source', None)
52 if s is not None:
52 if s is not None:
53 extra['source'] = s
53 extra['source'] = s
54 s = ctx.extra().get('intermediate-source', None)
54 s = ctx.extra().get('intermediate-source', None)
55 if s is not None:
55 if s is not None:
56 extra['intermediate-source'] = s
56 extra['intermediate-source'] = s
57
57
58 def _savebranch(ctx, extra):
58 def _savebranch(ctx, extra):
59 extra['branch'] = ctx.branch()
59 extra['branch'] = ctx.branch()
60
60
61 def _makeextrafn(copiers):
61 def _makeextrafn(copiers):
62 """make an extrafn out of the given copy-functions.
62 """make an extrafn out of the given copy-functions.
63
63
64 A copy function takes a context and an extra dict, and mutates the
64 A copy function takes a context and an extra dict, and mutates the
65 extra dict as needed based on the given context.
65 extra dict as needed based on the given context.
66 """
66 """
67 def extrafn(ctx, extra):
67 def extrafn(ctx, extra):
68 for c in copiers:
68 for c in copiers:
69 c(ctx, extra)
69 c(ctx, extra)
70 return extrafn
70 return extrafn
71
71
72 def _destrebase(repo):
72 def _destrebase(repo, sourceset):
73 # Destination defaults to the latest revision in the
73 """small wrapper around destmerge to pass the right extra args
74 # current branch
74
75 branch = repo[None].branch()
75 Please wrap destutil.destmerge instead."""
76 return repo[branch].rev()
76 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
77 onheadcheck=False)
77
78
78 revsetpredicate = revset.extpredicate()
79 revsetpredicate = revset.extpredicate()
79
80
80 @revsetpredicate('_destrebase')
81 @revsetpredicate('_destrebase')
81 def _revsetdestrebase(repo, subset, x):
82 def _revsetdestrebase(repo, subset, x):
82 # ``_rebasedefaultdest()``
83 # ``_rebasedefaultdest()``
83
84
84 # default destination for rebase.
85 # default destination for rebase.
85 # # XXX: Currently private because I expect the signature to change.
86 # # XXX: Currently private because I expect the signature to change.
86 # # XXX: - taking rev as arguments,
87 # # XXX: - bailing out in case of ambiguity vs returning all data.
87 # # XXX: - bailing out in case of ambiguity vs returning all data.
88 # # XXX: - probably merging with the merge destination.
89 # i18n: "_rebasedefaultdest" is a keyword
88 # i18n: "_rebasedefaultdest" is a keyword
90 revset.getargs(x, 0, 0, _("_rebasedefaultdest takes no arguments"))
89 sourceset = None
91 return subset & revset.baseset([_destrebase(repo)])
90 if x is not None:
91 sourceset = revset.getset(repo, revset.fullreposet(repo), x)
92 return subset & revset.baseset([_destrebase(repo, sourceset)])
92
93
93 @command('rebase',
94 @command('rebase',
94 [('s', 'source', '',
95 [('s', 'source', '',
95 _('rebase the specified changeset and descendants'), _('REV')),
96 _('rebase the specified changeset and descendants'), _('REV')),
96 ('b', 'base', '',
97 ('b', 'base', '',
97 _('rebase everything from branching point of specified changeset'),
98 _('rebase everything from branching point of specified changeset'),
98 _('REV')),
99 _('REV')),
99 ('r', 'rev', [],
100 ('r', 'rev', [],
100 _('rebase these revisions'),
101 _('rebase these revisions'),
101 _('REV')),
102 _('REV')),
102 ('d', 'dest', '',
103 ('d', 'dest', '',
103 _('rebase onto the specified changeset'), _('REV')),
104 _('rebase onto the specified changeset'), _('REV')),
104 ('', 'collapse', False, _('collapse the rebased changesets')),
105 ('', 'collapse', False, _('collapse the rebased changesets')),
105 ('m', 'message', '',
106 ('m', 'message', '',
106 _('use text as collapse commit message'), _('TEXT')),
107 _('use text as collapse commit message'), _('TEXT')),
107 ('e', 'edit', False, _('invoke editor on commit messages')),
108 ('e', 'edit', False, _('invoke editor on commit messages')),
108 ('l', 'logfile', '',
109 ('l', 'logfile', '',
109 _('read collapse commit message from file'), _('FILE')),
110 _('read collapse commit message from file'), _('FILE')),
110 ('k', 'keep', False, _('keep original changesets')),
111 ('k', 'keep', False, _('keep original changesets')),
111 ('', 'keepbranches', False, _('keep original branch names')),
112 ('', 'keepbranches', False, _('keep original branch names')),
112 ('D', 'detach', False, _('(DEPRECATED)')),
113 ('D', 'detach', False, _('(DEPRECATED)')),
113 ('i', 'interactive', False, _('(DEPRECATED)')),
114 ('i', 'interactive', False, _('(DEPRECATED)')),
114 ('t', 'tool', '', _('specify merge tool')),
115 ('t', 'tool', '', _('specify merge tool')),
115 ('c', 'continue', False, _('continue an interrupted rebase')),
116 ('c', 'continue', False, _('continue an interrupted rebase')),
116 ('a', 'abort', False, _('abort an interrupted rebase'))] +
117 ('a', 'abort', False, _('abort an interrupted rebase'))] +
117 templateopts,
118 templateopts,
118 _('[-s REV | -b REV] [-d REV] [OPTION]'))
119 _('[-s REV | -b REV] [-d REV] [OPTION]'))
119 def rebase(ui, repo, **opts):
120 def rebase(ui, repo, **opts):
120 """move changeset (and descendants) to a different branch
121 """move changeset (and descendants) to a different branch
121
122
122 Rebase uses repeated merging to graft changesets from one part of
123 Rebase uses repeated merging to graft changesets from one part of
123 history (the source) onto another (the destination). This can be
124 history (the source) onto another (the destination). This can be
124 useful for linearizing *local* changes relative to a master
125 useful for linearizing *local* changes relative to a master
125 development tree.
126 development tree.
126
127
127 Published commits cannot be rebased (see :hg:`help phases`).
128 Published commits cannot be rebased (see :hg:`help phases`).
128 To copy commits, see :hg:`help graft`.
129 To copy commits, see :hg:`help graft`.
129
130
130 If you don't specify a destination changeset (``-d/--dest``),
131 If you don't specify a destination changeset (``-d/--dest``), rebase
131 rebase uses the current branch tip as the destination. (The
132 will use the same logic as :hg:`merge` to pick a destination. if
132 destination changeset is not modified by rebasing, but new
133 the current branch contains exactly one other head, the other head
133 changesets are added as its descendants.)
134 is merged with by default. Otherwise, an explicit revision with
135 which to merge with must be provided. (destination changeset is not
136 modified by rebasing, but new changesets are added as its
137 descendants.)
134
138
135 Here are the ways to select changesets:
139 Here are the ways to select changesets:
136
140
137 1. Explicitly select them using ``--rev``.
141 1. Explicitly select them using ``--rev``.
138
142
139 2. Use ``--source`` to select a root changeset and include all of its
143 2. Use ``--source`` to select a root changeset and include all of its
140 descendants.
144 descendants.
141
145
142 3. Use ``--base`` to select a changeset; rebase will find ancestors
146 3. Use ``--base`` to select a changeset; rebase will find ancestors
143 and their descendants which are not also ancestors of the destination.
147 and their descendants which are not also ancestors of the destination.
144
148
145 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
149 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
146 rebase will use ``--base .`` as above.
150 rebase will use ``--base .`` as above.
147
151
148 Rebase will destroy original changesets unless you use ``--keep``.
152 Rebase will destroy original changesets unless you use ``--keep``.
149 It will also move your bookmarks (even if you do).
153 It will also move your bookmarks (even if you do).
150
154
151 Some changesets may be dropped if they do not contribute changes
155 Some changesets may be dropped if they do not contribute changes
152 (e.g. merges from the destination branch).
156 (e.g. merges from the destination branch).
153
157
154 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
158 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
155 a named branch with two heads. You will need to explicitly specify source
159 a named branch with two heads. You will need to explicitly specify source
156 and/or destination.
160 and/or destination.
157
161
158 If you need to use a tool to automate merge/conflict decisions, you
162 If you need to use a tool to automate merge/conflict decisions, you
159 can specify one with ``--tool``, see :hg:`help merge-tools`.
163 can specify one with ``--tool``, see :hg:`help merge-tools`.
160 As a caveat: the tool will not be used to mediate when a file was
164 As a caveat: the tool will not be used to mediate when a file was
161 deleted, there is no hook presently available for this.
165 deleted, there is no hook presently available for this.
162
166
163 If a rebase is interrupted to manually resolve a conflict, it can be
167 If a rebase is interrupted to manually resolve a conflict, it can be
164 continued with --continue/-c or aborted with --abort/-a.
168 continued with --continue/-c or aborted with --abort/-a.
165
169
166 .. container:: verbose
170 .. container:: verbose
167
171
168 Examples:
172 Examples:
169
173
170 - move "local changes" (current commit back to branching point)
174 - move "local changes" (current commit back to branching point)
171 to the current branch tip after a pull::
175 to the current branch tip after a pull::
172
176
173 hg rebase
177 hg rebase
174
178
175 - move a single changeset to the stable branch::
179 - move a single changeset to the stable branch::
176
180
177 hg rebase -r 5f493448 -d stable
181 hg rebase -r 5f493448 -d stable
178
182
179 - splice a commit and all its descendants onto another part of history::
183 - splice a commit and all its descendants onto another part of history::
180
184
181 hg rebase --source c0c3 --dest 4cf9
185 hg rebase --source c0c3 --dest 4cf9
182
186
183 - rebase everything on a branch marked by a bookmark onto the
187 - rebase everything on a branch marked by a bookmark onto the
184 default branch::
188 default branch::
185
189
186 hg rebase --base myfeature --dest default
190 hg rebase --base myfeature --dest default
187
191
188 - collapse a sequence of changes into a single commit::
192 - collapse a sequence of changes into a single commit::
189
193
190 hg rebase --collapse -r 1520:1525 -d .
194 hg rebase --collapse -r 1520:1525 -d .
191
195
192 - move a named branch while preserving its name::
196 - move a named branch while preserving its name::
193
197
194 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
198 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
195
199
196 Returns 0 on success, 1 if nothing to rebase or there are
200 Returns 0 on success, 1 if nothing to rebase or there are
197 unresolved conflicts.
201 unresolved conflicts.
198
202
199 """
203 """
200 originalwd = target = None
204 originalwd = target = None
201 activebookmark = None
205 activebookmark = None
202 external = nullrev
206 external = nullrev
203 # Mapping between the old revision id and either what is the new rebased
207 # Mapping between the old revision id and either what is the new rebased
204 # revision or what needs to be done with the old revision. The state dict
208 # revision or what needs to be done with the old revision. The state dict
205 # will be what contains most of the rebase progress state.
209 # will be what contains most of the rebase progress state.
206 state = {}
210 state = {}
207 skipped = set()
211 skipped = set()
208 targetancestors = set()
212 targetancestors = set()
209
213
210
214
211 lock = wlock = None
215 lock = wlock = None
212 try:
216 try:
213 wlock = repo.wlock()
217 wlock = repo.wlock()
214 lock = repo.lock()
218 lock = repo.lock()
215
219
216 # Validate input and define rebasing points
220 # Validate input and define rebasing points
217 destf = opts.get('dest', None)
221 destf = opts.get('dest', None)
218 srcf = opts.get('source', None)
222 srcf = opts.get('source', None)
219 basef = opts.get('base', None)
223 basef = opts.get('base', None)
220 revf = opts.get('rev', [])
224 revf = opts.get('rev', [])
221 contf = opts.get('continue')
225 contf = opts.get('continue')
222 abortf = opts.get('abort')
226 abortf = opts.get('abort')
223 collapsef = opts.get('collapse', False)
227 collapsef = opts.get('collapse', False)
224 collapsemsg = cmdutil.logmessage(ui, opts)
228 collapsemsg = cmdutil.logmessage(ui, opts)
225 date = opts.get('date', None)
229 date = opts.get('date', None)
226 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
230 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
227 extrafns = [_savegraft]
231 extrafns = [_savegraft]
228 if e:
232 if e:
229 extrafns = [e]
233 extrafns = [e]
230 keepf = opts.get('keep', False)
234 keepf = opts.get('keep', False)
231 keepbranchesf = opts.get('keepbranches', False)
235 keepbranchesf = opts.get('keepbranches', False)
232 # keepopen is not meant for use on the command line, but by
236 # keepopen is not meant for use on the command line, but by
233 # other extensions
237 # other extensions
234 keepopen = opts.get('keepopen', False)
238 keepopen = opts.get('keepopen', False)
235
239
236 if opts.get('interactive'):
240 if opts.get('interactive'):
237 try:
241 try:
238 if extensions.find('histedit'):
242 if extensions.find('histedit'):
239 enablehistedit = ''
243 enablehistedit = ''
240 except KeyError:
244 except KeyError:
241 enablehistedit = " --config extensions.histedit="
245 enablehistedit = " --config extensions.histedit="
242 help = "hg%s help -e histedit" % enablehistedit
246 help = "hg%s help -e histedit" % enablehistedit
243 msg = _("interactive history editing is supported by the "
247 msg = _("interactive history editing is supported by the "
244 "'histedit' extension (see \"%s\")") % help
248 "'histedit' extension (see \"%s\")") % help
245 raise error.Abort(msg)
249 raise error.Abort(msg)
246
250
247 if collapsemsg and not collapsef:
251 if collapsemsg and not collapsef:
248 raise error.Abort(
252 raise error.Abort(
249 _('message can only be specified with collapse'))
253 _('message can only be specified with collapse'))
250
254
251 if contf or abortf:
255 if contf or abortf:
252 if contf and abortf:
256 if contf and abortf:
253 raise error.Abort(_('cannot use both abort and continue'))
257 raise error.Abort(_('cannot use both abort and continue'))
254 if collapsef:
258 if collapsef:
255 raise error.Abort(
259 raise error.Abort(
256 _('cannot use collapse with continue or abort'))
260 _('cannot use collapse with continue or abort'))
257 if srcf or basef or destf:
261 if srcf or basef or destf:
258 raise error.Abort(
262 raise error.Abort(
259 _('abort and continue do not allow specifying revisions'))
263 _('abort and continue do not allow specifying revisions'))
260 if abortf and opts.get('tool', False):
264 if abortf and opts.get('tool', False):
261 ui.warn(_('tool option will be ignored\n'))
265 ui.warn(_('tool option will be ignored\n'))
262
266
263 try:
267 try:
264 (originalwd, target, state, skipped, collapsef, keepf,
268 (originalwd, target, state, skipped, collapsef, keepf,
265 keepbranchesf, external, activebookmark) = restorestatus(repo)
269 keepbranchesf, external, activebookmark) = restorestatus(repo)
266 collapsemsg = restorecollapsemsg(repo)
270 collapsemsg = restorecollapsemsg(repo)
267 except error.RepoLookupError:
271 except error.RepoLookupError:
268 if abortf:
272 if abortf:
269 clearstatus(repo)
273 clearstatus(repo)
270 clearcollapsemsg(repo)
274 clearcollapsemsg(repo)
271 repo.ui.warn(_('rebase aborted (no revision is removed,'
275 repo.ui.warn(_('rebase aborted (no revision is removed,'
272 ' only broken state is cleared)\n'))
276 ' only broken state is cleared)\n'))
273 return 0
277 return 0
274 else:
278 else:
275 msg = _('cannot continue inconsistent rebase')
279 msg = _('cannot continue inconsistent rebase')
276 hint = _('use "hg rebase --abort" to clear broken state')
280 hint = _('use "hg rebase --abort" to clear broken state')
277 raise error.Abort(msg, hint=hint)
281 raise error.Abort(msg, hint=hint)
278 if abortf:
282 if abortf:
279 return abort(repo, originalwd, target, state,
283 return abort(repo, originalwd, target, state,
280 activebookmark=activebookmark)
284 activebookmark=activebookmark)
281 else:
285 else:
282 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf)
286 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf)
283 if dest is None:
287 if dest is None:
284 return _nothingtorebase()
288 return _nothingtorebase()
285
289
286 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
290 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
287 if (not (keepf or allowunstable)
291 if (not (keepf or allowunstable)
288 and repo.revs('first(children(%ld) - %ld)',
292 and repo.revs('first(children(%ld) - %ld)',
289 rebaseset, rebaseset)):
293 rebaseset, rebaseset)):
290 raise error.Abort(
294 raise error.Abort(
291 _("can't remove original changesets with"
295 _("can't remove original changesets with"
292 " unrebased descendants"),
296 " unrebased descendants"),
293 hint=_('use --keep to keep original changesets'))
297 hint=_('use --keep to keep original changesets'))
294
298
295 obsoletenotrebased = {}
299 obsoletenotrebased = {}
296 if ui.configbool('experimental', 'rebaseskipobsolete'):
300 if ui.configbool('experimental', 'rebaseskipobsolete'):
297 rebasesetrevs = set(rebaseset)
301 rebasesetrevs = set(rebaseset)
298 rebaseobsrevs = _filterobsoleterevs(repo, rebasesetrevs)
302 rebaseobsrevs = _filterobsoleterevs(repo, rebasesetrevs)
299 obsoletenotrebased = _computeobsoletenotrebased(repo,
303 obsoletenotrebased = _computeobsoletenotrebased(repo,
300 rebaseobsrevs,
304 rebaseobsrevs,
301 dest)
305 dest)
302 rebaseobsskipped = set(obsoletenotrebased)
306 rebaseobsskipped = set(obsoletenotrebased)
303
307
304 # Obsolete node with successors not in dest leads to divergence
308 # Obsolete node with successors not in dest leads to divergence
305 divergenceok = ui.configbool('rebase',
309 divergenceok = ui.configbool('rebase',
306 'allowdivergence')
310 'allowdivergence')
307 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
311 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
308
312
309 if divergencebasecandidates and not divergenceok:
313 if divergencebasecandidates and not divergenceok:
310 divhashes = (str(repo[r])
314 divhashes = (str(repo[r])
311 for r in divergencebasecandidates)
315 for r in divergencebasecandidates)
312 msg = _("this rebase will cause "
316 msg = _("this rebase will cause "
313 "divergences from: %s")
317 "divergences from: %s")
314 h = _("to force the rebase please set "
318 h = _("to force the rebase please set "
315 "rebase.allowdivergence=True")
319 "rebase.allowdivergence=True")
316 raise error.Abort(msg % (",".join(divhashes),), hint=h)
320 raise error.Abort(msg % (",".join(divhashes),), hint=h)
317
321
318 # - plain prune (no successor) changesets are rebased
322 # - plain prune (no successor) changesets are rebased
319 # - split changesets are not rebased if at least one of the
323 # - split changesets are not rebased if at least one of the
320 # changeset resulting from the split is an ancestor of dest
324 # changeset resulting from the split is an ancestor of dest
321 rebaseset = rebasesetrevs - rebaseobsskipped
325 rebaseset = rebasesetrevs - rebaseobsskipped
322 if rebasesetrevs and not rebaseset:
326 if rebasesetrevs and not rebaseset:
323 msg = _('all requested changesets have equivalents '
327 msg = _('all requested changesets have equivalents '
324 'or were marked as obsolete')
328 'or were marked as obsolete')
325 hint = _('to force the rebase, set the config '
329 hint = _('to force the rebase, set the config '
326 'experimental.rebaseskipobsolete to False')
330 'experimental.rebaseskipobsolete to False')
327 raise error.Abort(msg, hint=hint)
331 raise error.Abort(msg, hint=hint)
328
332
329 result = buildstate(repo, dest, rebaseset, collapsef,
333 result = buildstate(repo, dest, rebaseset, collapsef,
330 obsoletenotrebased)
334 obsoletenotrebased)
331
335
332 if not result:
336 if not result:
333 # Empty state built, nothing to rebase
337 # Empty state built, nothing to rebase
334 ui.status(_('nothing to rebase\n'))
338 ui.status(_('nothing to rebase\n'))
335 return _nothingtorebase()
339 return _nothingtorebase()
336
340
337 root = min(rebaseset)
341 root = min(rebaseset)
338 if not keepf and not repo[root].mutable():
342 if not keepf and not repo[root].mutable():
339 raise error.Abort(_("can't rebase public changeset %s")
343 raise error.Abort(_("can't rebase public changeset %s")
340 % repo[root],
344 % repo[root],
341 hint=_('see "hg help phases" for details'))
345 hint=_('see "hg help phases" for details'))
342
346
343 originalwd, target, state = result
347 originalwd, target, state = result
344 if collapsef:
348 if collapsef:
345 targetancestors = repo.changelog.ancestors([target],
349 targetancestors = repo.changelog.ancestors([target],
346 inclusive=True)
350 inclusive=True)
347 external = externalparent(repo, state, targetancestors)
351 external = externalparent(repo, state, targetancestors)
348
352
349 if dest.closesbranch() and not keepbranchesf:
353 if dest.closesbranch() and not keepbranchesf:
350 ui.status(_('reopening closed branch head %s\n') % dest)
354 ui.status(_('reopening closed branch head %s\n') % dest)
351
355
352 if keepbranchesf:
356 if keepbranchesf:
353 # insert _savebranch at the start of extrafns so if
357 # insert _savebranch at the start of extrafns so if
354 # there's a user-provided extrafn it can clobber branch if
358 # there's a user-provided extrafn it can clobber branch if
355 # desired
359 # desired
356 extrafns.insert(0, _savebranch)
360 extrafns.insert(0, _savebranch)
357 if collapsef:
361 if collapsef:
358 branches = set()
362 branches = set()
359 for rev in state:
363 for rev in state:
360 branches.add(repo[rev].branch())
364 branches.add(repo[rev].branch())
361 if len(branches) > 1:
365 if len(branches) > 1:
362 raise error.Abort(_('cannot collapse multiple named '
366 raise error.Abort(_('cannot collapse multiple named '
363 'branches'))
367 'branches'))
364
368
365 # Rebase
369 # Rebase
366 if not targetancestors:
370 if not targetancestors:
367 targetancestors = repo.changelog.ancestors([target], inclusive=True)
371 targetancestors = repo.changelog.ancestors([target], inclusive=True)
368
372
369 # Keep track of the current bookmarks in order to reset them later
373 # Keep track of the current bookmarks in order to reset them later
370 currentbookmarks = repo._bookmarks.copy()
374 currentbookmarks = repo._bookmarks.copy()
371 activebookmark = activebookmark or repo._activebookmark
375 activebookmark = activebookmark or repo._activebookmark
372 if activebookmark:
376 if activebookmark:
373 bookmarks.deactivate(repo)
377 bookmarks.deactivate(repo)
374
378
375 extrafn = _makeextrafn(extrafns)
379 extrafn = _makeextrafn(extrafns)
376
380
377 sortedstate = sorted(state)
381 sortedstate = sorted(state)
378 total = len(sortedstate)
382 total = len(sortedstate)
379 pos = 0
383 pos = 0
380 for rev in sortedstate:
384 for rev in sortedstate:
381 ctx = repo[rev]
385 ctx = repo[rev]
382 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
386 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
383 ctx.description().split('\n', 1)[0])
387 ctx.description().split('\n', 1)[0])
384 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
388 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
385 if names:
389 if names:
386 desc += ' (%s)' % ' '.join(names)
390 desc += ' (%s)' % ' '.join(names)
387 pos += 1
391 pos += 1
388 if state[rev] == revtodo:
392 if state[rev] == revtodo:
389 ui.status(_('rebasing %s\n') % desc)
393 ui.status(_('rebasing %s\n') % desc)
390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
394 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
391 _('changesets'), total)
395 _('changesets'), total)
392 p1, p2, base = defineparents(repo, rev, target, state,
396 p1, p2, base = defineparents(repo, rev, target, state,
393 targetancestors)
397 targetancestors)
394 storestatus(repo, originalwd, target, state, collapsef, keepf,
398 storestatus(repo, originalwd, target, state, collapsef, keepf,
395 keepbranchesf, external, activebookmark)
399 keepbranchesf, external, activebookmark)
396 storecollapsemsg(repo, collapsemsg)
400 storecollapsemsg(repo, collapsemsg)
397 if len(repo[None].parents()) == 2:
401 if len(repo[None].parents()) == 2:
398 repo.ui.debug('resuming interrupted rebase\n')
402 repo.ui.debug('resuming interrupted rebase\n')
399 else:
403 else:
400 try:
404 try:
401 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
405 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
402 'rebase')
406 'rebase')
403 stats = rebasenode(repo, rev, p1, base, state,
407 stats = rebasenode(repo, rev, p1, base, state,
404 collapsef, target)
408 collapsef, target)
405 if stats and stats[3] > 0:
409 if stats and stats[3] > 0:
406 raise error.InterventionRequired(
410 raise error.InterventionRequired(
407 _('unresolved conflicts (see hg '
411 _('unresolved conflicts (see hg '
408 'resolve, then hg rebase --continue)'))
412 'resolve, then hg rebase --continue)'))
409 finally:
413 finally:
410 ui.setconfig('ui', 'forcemerge', '', 'rebase')
414 ui.setconfig('ui', 'forcemerge', '', 'rebase')
411 if not collapsef:
415 if not collapsef:
412 merging = p2 != nullrev
416 merging = p2 != nullrev
413 editform = cmdutil.mergeeditform(merging, 'rebase')
417 editform = cmdutil.mergeeditform(merging, 'rebase')
414 editor = cmdutil.getcommiteditor(editform=editform, **opts)
418 editor = cmdutil.getcommiteditor(editform=editform, **opts)
415 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
419 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
416 editor=editor,
420 editor=editor,
417 keepbranches=keepbranchesf,
421 keepbranches=keepbranchesf,
418 date=date)
422 date=date)
419 else:
423 else:
420 # Skip commit if we are collapsing
424 # Skip commit if we are collapsing
421 repo.dirstate.beginparentchange()
425 repo.dirstate.beginparentchange()
422 repo.setparents(repo[p1].node())
426 repo.setparents(repo[p1].node())
423 repo.dirstate.endparentchange()
427 repo.dirstate.endparentchange()
424 newnode = None
428 newnode = None
425 # Update the state
429 # Update the state
426 if newnode is not None:
430 if newnode is not None:
427 state[rev] = repo[newnode].rev()
431 state[rev] = repo[newnode].rev()
428 ui.debug('rebased as %s\n' % short(newnode))
432 ui.debug('rebased as %s\n' % short(newnode))
429 else:
433 else:
430 if not collapsef:
434 if not collapsef:
431 ui.warn(_('note: rebase of %d:%s created no changes '
435 ui.warn(_('note: rebase of %d:%s created no changes '
432 'to commit\n') % (rev, ctx))
436 'to commit\n') % (rev, ctx))
433 skipped.add(rev)
437 skipped.add(rev)
434 state[rev] = p1
438 state[rev] = p1
435 ui.debug('next revision set to %s\n' % p1)
439 ui.debug('next revision set to %s\n' % p1)
436 elif state[rev] == nullmerge:
440 elif state[rev] == nullmerge:
437 ui.debug('ignoring null merge rebase of %s\n' % rev)
441 ui.debug('ignoring null merge rebase of %s\n' % rev)
438 elif state[rev] == revignored:
442 elif state[rev] == revignored:
439 ui.status(_('not rebasing ignored %s\n') % desc)
443 ui.status(_('not rebasing ignored %s\n') % desc)
440 elif state[rev] == revprecursor:
444 elif state[rev] == revprecursor:
441 targetctx = repo[obsoletenotrebased[rev]]
445 targetctx = repo[obsoletenotrebased[rev]]
442 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
446 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
443 targetctx.description().split('\n', 1)[0])
447 targetctx.description().split('\n', 1)[0])
444 msg = _('note: not rebasing %s, already in destination as %s\n')
448 msg = _('note: not rebasing %s, already in destination as %s\n')
445 ui.status(msg % (desc, desctarget))
449 ui.status(msg % (desc, desctarget))
446 elif state[rev] == revpruned:
450 elif state[rev] == revpruned:
447 msg = _('note: not rebasing %s, it has no successor\n')
451 msg = _('note: not rebasing %s, it has no successor\n')
448 ui.status(msg % desc)
452 ui.status(msg % desc)
449 else:
453 else:
450 ui.status(_('already rebased %s as %s\n') %
454 ui.status(_('already rebased %s as %s\n') %
451 (desc, repo[state[rev]]))
455 (desc, repo[state[rev]]))
452
456
453 ui.progress(_('rebasing'), None)
457 ui.progress(_('rebasing'), None)
454 ui.note(_('rebase merging completed\n'))
458 ui.note(_('rebase merging completed\n'))
455
459
456 if collapsef and not keepopen:
460 if collapsef and not keepopen:
457 p1, p2, _base = defineparents(repo, min(state), target,
461 p1, p2, _base = defineparents(repo, min(state), target,
458 state, targetancestors)
462 state, targetancestors)
459 editopt = opts.get('edit')
463 editopt = opts.get('edit')
460 editform = 'rebase.collapse'
464 editform = 'rebase.collapse'
461 if collapsemsg:
465 if collapsemsg:
462 commitmsg = collapsemsg
466 commitmsg = collapsemsg
463 else:
467 else:
464 commitmsg = 'Collapsed revision'
468 commitmsg = 'Collapsed revision'
465 for rebased in state:
469 for rebased in state:
466 if rebased not in skipped and state[rebased] > nullmerge:
470 if rebased not in skipped and state[rebased] > nullmerge:
467 commitmsg += '\n* %s' % repo[rebased].description()
471 commitmsg += '\n* %s' % repo[rebased].description()
468 editopt = True
472 editopt = True
469 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
473 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
470 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
474 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
471 extrafn=extrafn, editor=editor,
475 extrafn=extrafn, editor=editor,
472 keepbranches=keepbranchesf,
476 keepbranches=keepbranchesf,
473 date=date)
477 date=date)
474 if newnode is None:
478 if newnode is None:
475 newrev = target
479 newrev = target
476 else:
480 else:
477 newrev = repo[newnode].rev()
481 newrev = repo[newnode].rev()
478 for oldrev in state.iterkeys():
482 for oldrev in state.iterkeys():
479 if state[oldrev] > nullmerge:
483 if state[oldrev] > nullmerge:
480 state[oldrev] = newrev
484 state[oldrev] = newrev
481
485
482 if 'qtip' in repo.tags():
486 if 'qtip' in repo.tags():
483 updatemq(repo, state, skipped, **opts)
487 updatemq(repo, state, skipped, **opts)
484
488
485 if currentbookmarks:
489 if currentbookmarks:
486 # Nodeids are needed to reset bookmarks
490 # Nodeids are needed to reset bookmarks
487 nstate = {}
491 nstate = {}
488 for k, v in state.iteritems():
492 for k, v in state.iteritems():
489 if v > nullmerge:
493 if v > nullmerge:
490 nstate[repo[k].node()] = repo[v].node()
494 nstate[repo[k].node()] = repo[v].node()
491 # XXX this is the same as dest.node() for the non-continue path --
495 # XXX this is the same as dest.node() for the non-continue path --
492 # this should probably be cleaned up
496 # this should probably be cleaned up
493 targetnode = repo[target].node()
497 targetnode = repo[target].node()
494
498
495 # restore original working directory
499 # restore original working directory
496 # (we do this before stripping)
500 # (we do this before stripping)
497 newwd = state.get(originalwd, originalwd)
501 newwd = state.get(originalwd, originalwd)
498 if newwd < 0:
502 if newwd < 0:
499 # original directory is a parent of rebase set root or ignored
503 # original directory is a parent of rebase set root or ignored
500 newwd = originalwd
504 newwd = originalwd
501 if newwd not in [c.rev() for c in repo[None].parents()]:
505 if newwd not in [c.rev() for c in repo[None].parents()]:
502 ui.note(_("update back to initial working directory parent\n"))
506 ui.note(_("update back to initial working directory parent\n"))
503 hg.updaterepo(repo, newwd, False)
507 hg.updaterepo(repo, newwd, False)
504
508
505 if not keepf:
509 if not keepf:
506 collapsedas = None
510 collapsedas = None
507 if collapsef:
511 if collapsef:
508 collapsedas = newnode
512 collapsedas = newnode
509 clearrebased(ui, repo, state, skipped, collapsedas)
513 clearrebased(ui, repo, state, skipped, collapsedas)
510
514
511 with repo.transaction('bookmark') as tr:
515 with repo.transaction('bookmark') as tr:
512 if currentbookmarks:
516 if currentbookmarks:
513 updatebookmarks(repo, targetnode, nstate, currentbookmarks, tr)
517 updatebookmarks(repo, targetnode, nstate, currentbookmarks, tr)
514 if activebookmark not in repo._bookmarks:
518 if activebookmark not in repo._bookmarks:
515 # active bookmark was divergent one and has been deleted
519 # active bookmark was divergent one and has been deleted
516 activebookmark = None
520 activebookmark = None
517 clearstatus(repo)
521 clearstatus(repo)
518 clearcollapsemsg(repo)
522 clearcollapsemsg(repo)
519
523
520 ui.note(_("rebase completed\n"))
524 ui.note(_("rebase completed\n"))
521 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
525 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
522 if skipped:
526 if skipped:
523 ui.note(_("%d revisions have been skipped\n") % len(skipped))
527 ui.note(_("%d revisions have been skipped\n") % len(skipped))
524
528
525 if (activebookmark and
529 if (activebookmark and
526 repo['.'].node() == repo._bookmarks[activebookmark]):
530 repo['.'].node() == repo._bookmarks[activebookmark]):
527 bookmarks.activate(repo, activebookmark)
531 bookmarks.activate(repo, activebookmark)
528
532
529 finally:
533 finally:
530 release(lock, wlock)
534 release(lock, wlock)
531
535
532 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=[]):
536 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=[]):
533 """use revisions argument to define destination and rebase set
537 """use revisions argument to define destination and rebase set
534 """
538 """
535 if srcf and basef:
539 if srcf and basef:
536 raise error.Abort(_('cannot specify both a source and a base'))
540 raise error.Abort(_('cannot specify both a source and a base'))
537 if revf and basef:
541 if revf and basef:
538 raise error.Abort(_('cannot specify both a revision and a base'))
542 raise error.Abort(_('cannot specify both a revision and a base'))
539 if revf and srcf:
543 if revf and srcf:
540 raise error.Abort(_('cannot specify both a revision and a source'))
544 raise error.Abort(_('cannot specify both a revision and a source'))
541
545
542 cmdutil.checkunfinished(repo)
546 cmdutil.checkunfinished(repo)
543 cmdutil.bailifchanged(repo)
547 cmdutil.bailifchanged(repo)
544
548
545 if destf:
549 if destf:
546 dest = scmutil.revsingle(repo, destf)
550 dest = scmutil.revsingle(repo, destf)
547 else:
548 dest = repo[_destrebase(repo)]
549 destf = str(dest)
550
551
551 if revf:
552 if revf:
552 rebaseset = scmutil.revrange(repo, revf)
553 rebaseset = scmutil.revrange(repo, revf)
553 if not rebaseset:
554 if not rebaseset:
554 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
555 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
555 return None, None
556 return None, None
556 elif srcf:
557 elif srcf:
557 src = scmutil.revrange(repo, [srcf])
558 src = scmutil.revrange(repo, [srcf])
558 if not src:
559 if not src:
559 ui.status(_('empty "source" revision set - nothing to rebase\n'))
560 ui.status(_('empty "source" revision set - nothing to rebase\n'))
560 return None, None
561 return None, None
561 rebaseset = repo.revs('(%ld)::', src)
562 rebaseset = repo.revs('(%ld)::', src)
562 assert rebaseset
563 assert rebaseset
563 else:
564 else:
564 base = scmutil.revrange(repo, [basef or '.'])
565 base = scmutil.revrange(repo, [basef or '.'])
565 if not base:
566 if not base:
566 ui.status(_('empty "base" revision set - '
567 ui.status(_('empty "base" revision set - '
567 "can't compute rebase set\n"))
568 "can't compute rebase set\n"))
568 return None, None
569 return None, None
570 if not destf:
571 dest = repo[_destrebase(repo, base)]
572 destf = str(dest)
573
569 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
574 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
570 if commonanc is not None:
575 if commonanc is not None:
571 rebaseset = repo.revs('(%d::(%ld) - %d)::',
576 rebaseset = repo.revs('(%d::(%ld) - %d)::',
572 commonanc, base, commonanc)
577 commonanc, base, commonanc)
573 else:
578 else:
574 rebaseset = []
579 rebaseset = []
575
580
576 if not rebaseset:
581 if not rebaseset:
577 # transform to list because smartsets are not comparable to
582 # transform to list because smartsets are not comparable to
578 # lists. This should be improved to honor laziness of
583 # lists. This should be improved to honor laziness of
579 # smartset.
584 # smartset.
580 if list(base) == [dest.rev()]:
585 if list(base) == [dest.rev()]:
581 if basef:
586 if basef:
582 ui.status(_('nothing to rebase - %s is both "base"'
587 ui.status(_('nothing to rebase - %s is both "base"'
583 ' and destination\n') % dest)
588 ' and destination\n') % dest)
584 else:
589 else:
585 ui.status(_('nothing to rebase - working directory '
590 ui.status(_('nothing to rebase - working directory '
586 'parent is also destination\n'))
591 'parent is also destination\n'))
587 elif not repo.revs('%ld - ::%d', base, dest):
592 elif not repo.revs('%ld - ::%d', base, dest):
588 if basef:
593 if basef:
589 ui.status(_('nothing to rebase - "base" %s is '
594 ui.status(_('nothing to rebase - "base" %s is '
590 'already an ancestor of destination '
595 'already an ancestor of destination '
591 '%s\n') %
596 '%s\n') %
592 ('+'.join(str(repo[r]) for r in base),
597 ('+'.join(str(repo[r]) for r in base),
593 dest))
598 dest))
594 else:
599 else:
595 ui.status(_('nothing to rebase - working '
600 ui.status(_('nothing to rebase - working '
596 'directory parent is already an '
601 'directory parent is already an '
597 'ancestor of destination %s\n') % dest)
602 'ancestor of destination %s\n') % dest)
598 else: # can it happen?
603 else: # can it happen?
599 ui.status(_('nothing to rebase from %s to %s\n') %
604 ui.status(_('nothing to rebase from %s to %s\n') %
600 ('+'.join(str(repo[r]) for r in base), dest))
605 ('+'.join(str(repo[r]) for r in base), dest))
601 return None, None
606 return None, None
607
608 if not destf:
609 dest = repo[_destrebase(repo, rebaseset)]
610 destf = str(dest)
611
602 return dest, rebaseset
612 return dest, rebaseset
603
613
604 def externalparent(repo, state, targetancestors):
614 def externalparent(repo, state, targetancestors):
605 """Return the revision that should be used as the second parent
615 """Return the revision that should be used as the second parent
606 when the revisions in state is collapsed on top of targetancestors.
616 when the revisions in state is collapsed on top of targetancestors.
607 Abort if there is more than one parent.
617 Abort if there is more than one parent.
608 """
618 """
609 parents = set()
619 parents = set()
610 source = min(state)
620 source = min(state)
611 for rev in state:
621 for rev in state:
612 if rev == source:
622 if rev == source:
613 continue
623 continue
614 for p in repo[rev].parents():
624 for p in repo[rev].parents():
615 if (p.rev() not in state
625 if (p.rev() not in state
616 and p.rev() not in targetancestors):
626 and p.rev() not in targetancestors):
617 parents.add(p.rev())
627 parents.add(p.rev())
618 if not parents:
628 if not parents:
619 return nullrev
629 return nullrev
620 if len(parents) == 1:
630 if len(parents) == 1:
621 return parents.pop()
631 return parents.pop()
622 raise error.Abort(_('unable to collapse on top of %s, there is more '
632 raise error.Abort(_('unable to collapse on top of %s, there is more '
623 'than one external parent: %s') %
633 'than one external parent: %s') %
624 (max(targetancestors),
634 (max(targetancestors),
625 ', '.join(str(p) for p in sorted(parents))))
635 ', '.join(str(p) for p in sorted(parents))))
626
636
627 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
637 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
628 keepbranches=False, date=None):
638 keepbranches=False, date=None):
629 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
639 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
630 but also store useful information in extra.
640 but also store useful information in extra.
631 Return node of committed revision.'''
641 Return node of committed revision.'''
632 dsguard = cmdutil.dirstateguard(repo, 'rebase')
642 dsguard = cmdutil.dirstateguard(repo, 'rebase')
633 try:
643 try:
634 repo.setparents(repo[p1].node(), repo[p2].node())
644 repo.setparents(repo[p1].node(), repo[p2].node())
635 ctx = repo[rev]
645 ctx = repo[rev]
636 if commitmsg is None:
646 if commitmsg is None:
637 commitmsg = ctx.description()
647 commitmsg = ctx.description()
638 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
648 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
639 extra = {'rebase_source': ctx.hex()}
649 extra = {'rebase_source': ctx.hex()}
640 if extrafn:
650 if extrafn:
641 extrafn(ctx, extra)
651 extrafn(ctx, extra)
642
652
643 backup = repo.ui.backupconfig('phases', 'new-commit')
653 backup = repo.ui.backupconfig('phases', 'new-commit')
644 try:
654 try:
645 targetphase = max(ctx.phase(), phases.draft)
655 targetphase = max(ctx.phase(), phases.draft)
646 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
656 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
647 if keepbranch:
657 if keepbranch:
648 repo.ui.setconfig('ui', 'allowemptycommit', True)
658 repo.ui.setconfig('ui', 'allowemptycommit', True)
649 # Commit might fail if unresolved files exist
659 # Commit might fail if unresolved files exist
650 if date is None:
660 if date is None:
651 date = ctx.date()
661 date = ctx.date()
652 newnode = repo.commit(text=commitmsg, user=ctx.user(),
662 newnode = repo.commit(text=commitmsg, user=ctx.user(),
653 date=date, extra=extra, editor=editor)
663 date=date, extra=extra, editor=editor)
654 finally:
664 finally:
655 repo.ui.restoreconfig(backup)
665 repo.ui.restoreconfig(backup)
656
666
657 repo.dirstate.setbranch(repo[newnode].branch())
667 repo.dirstate.setbranch(repo[newnode].branch())
658 dsguard.close()
668 dsguard.close()
659 return newnode
669 return newnode
660 finally:
670 finally:
661 release(dsguard)
671 release(dsguard)
662
672
663 def rebasenode(repo, rev, p1, base, state, collapse, target):
673 def rebasenode(repo, rev, p1, base, state, collapse, target):
664 'Rebase a single revision rev on top of p1 using base as merge ancestor'
674 'Rebase a single revision rev on top of p1 using base as merge ancestor'
665 # Merge phase
675 # Merge phase
666 # Update to target and merge it with local
676 # Update to target and merge it with local
667 if repo['.'].rev() != p1:
677 if repo['.'].rev() != p1:
668 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
678 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
669 merge.update(repo, p1, False, True)
679 merge.update(repo, p1, False, True)
670 else:
680 else:
671 repo.ui.debug(" already in target\n")
681 repo.ui.debug(" already in target\n")
672 repo.dirstate.write(repo.currenttransaction())
682 repo.dirstate.write(repo.currenttransaction())
673 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
683 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
674 if base is not None:
684 if base is not None:
675 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
685 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
676 # When collapsing in-place, the parent is the common ancestor, we
686 # When collapsing in-place, the parent is the common ancestor, we
677 # have to allow merging with it.
687 # have to allow merging with it.
678 stats = merge.update(repo, rev, True, True, base, collapse,
688 stats = merge.update(repo, rev, True, True, base, collapse,
679 labels=['dest', 'source'])
689 labels=['dest', 'source'])
680 if collapse:
690 if collapse:
681 copies.duplicatecopies(repo, rev, target)
691 copies.duplicatecopies(repo, rev, target)
682 else:
692 else:
683 # If we're not using --collapse, we need to
693 # If we're not using --collapse, we need to
684 # duplicate copies between the revision we're
694 # duplicate copies between the revision we're
685 # rebasing and its first parent, but *not*
695 # rebasing and its first parent, but *not*
686 # duplicate any copies that have already been
696 # duplicate any copies that have already been
687 # performed in the destination.
697 # performed in the destination.
688 p1rev = repo[rev].p1().rev()
698 p1rev = repo[rev].p1().rev()
689 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
699 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
690 return stats
700 return stats
691
701
692 def nearestrebased(repo, rev, state):
702 def nearestrebased(repo, rev, state):
693 """return the nearest ancestors of rev in the rebase result"""
703 """return the nearest ancestors of rev in the rebase result"""
694 rebased = [r for r in state if state[r] > nullmerge]
704 rebased = [r for r in state if state[r] > nullmerge]
695 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
705 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
696 if candidates:
706 if candidates:
697 return state[candidates.first()]
707 return state[candidates.first()]
698 else:
708 else:
699 return None
709 return None
700
710
701 def defineparents(repo, rev, target, state, targetancestors):
711 def defineparents(repo, rev, target, state, targetancestors):
702 'Return the new parent relationship of the revision that will be rebased'
712 'Return the new parent relationship of the revision that will be rebased'
703 parents = repo[rev].parents()
713 parents = repo[rev].parents()
704 p1 = p2 = nullrev
714 p1 = p2 = nullrev
705
715
706 p1n = parents[0].rev()
716 p1n = parents[0].rev()
707 if p1n in targetancestors:
717 if p1n in targetancestors:
708 p1 = target
718 p1 = target
709 elif p1n in state:
719 elif p1n in state:
710 if state[p1n] == nullmerge:
720 if state[p1n] == nullmerge:
711 p1 = target
721 p1 = target
712 elif state[p1n] in revskipped:
722 elif state[p1n] in revskipped:
713 p1 = nearestrebased(repo, p1n, state)
723 p1 = nearestrebased(repo, p1n, state)
714 if p1 is None:
724 if p1 is None:
715 p1 = target
725 p1 = target
716 else:
726 else:
717 p1 = state[p1n]
727 p1 = state[p1n]
718 else: # p1n external
728 else: # p1n external
719 p1 = target
729 p1 = target
720 p2 = p1n
730 p2 = p1n
721
731
722 if len(parents) == 2 and parents[1].rev() not in targetancestors:
732 if len(parents) == 2 and parents[1].rev() not in targetancestors:
723 p2n = parents[1].rev()
733 p2n = parents[1].rev()
724 # interesting second parent
734 # interesting second parent
725 if p2n in state:
735 if p2n in state:
726 if p1 == target: # p1n in targetancestors or external
736 if p1 == target: # p1n in targetancestors or external
727 p1 = state[p2n]
737 p1 = state[p2n]
728 elif state[p2n] in revskipped:
738 elif state[p2n] in revskipped:
729 p2 = nearestrebased(repo, p2n, state)
739 p2 = nearestrebased(repo, p2n, state)
730 if p2 is None:
740 if p2 is None:
731 # no ancestors rebased yet, detach
741 # no ancestors rebased yet, detach
732 p2 = target
742 p2 = target
733 else:
743 else:
734 p2 = state[p2n]
744 p2 = state[p2n]
735 else: # p2n external
745 else: # p2n external
736 if p2 != nullrev: # p1n external too => rev is a merged revision
746 if p2 != nullrev: # p1n external too => rev is a merged revision
737 raise error.Abort(_('cannot use revision %d as base, result '
747 raise error.Abort(_('cannot use revision %d as base, result '
738 'would have 3 parents') % rev)
748 'would have 3 parents') % rev)
739 p2 = p2n
749 p2 = p2n
740 repo.ui.debug(" future parents are %d and %d\n" %
750 repo.ui.debug(" future parents are %d and %d\n" %
741 (repo[p1].rev(), repo[p2].rev()))
751 (repo[p1].rev(), repo[p2].rev()))
742
752
743 if not any(p.rev() in state for p in parents):
753 if not any(p.rev() in state for p in parents):
744 # Case (1) root changeset of a non-detaching rebase set.
754 # Case (1) root changeset of a non-detaching rebase set.
745 # Let the merge mechanism find the base itself.
755 # Let the merge mechanism find the base itself.
746 base = None
756 base = None
747 elif not repo[rev].p2():
757 elif not repo[rev].p2():
748 # Case (2) detaching the node with a single parent, use this parent
758 # Case (2) detaching the node with a single parent, use this parent
749 base = repo[rev].p1().rev()
759 base = repo[rev].p1().rev()
750 else:
760 else:
751 # Assuming there is a p1, this is the case where there also is a p2.
761 # Assuming there is a p1, this is the case where there also is a p2.
752 # We are thus rebasing a merge and need to pick the right merge base.
762 # We are thus rebasing a merge and need to pick the right merge base.
753 #
763 #
754 # Imagine we have:
764 # Imagine we have:
755 # - M: current rebase revision in this step
765 # - M: current rebase revision in this step
756 # - A: one parent of M
766 # - A: one parent of M
757 # - B: other parent of M
767 # - B: other parent of M
758 # - D: destination of this merge step (p1 var)
768 # - D: destination of this merge step (p1 var)
759 #
769 #
760 # Consider the case where D is a descendant of A or B and the other is
770 # Consider the case where D is a descendant of A or B and the other is
761 # 'outside'. In this case, the right merge base is the D ancestor.
771 # 'outside'. In this case, the right merge base is the D ancestor.
762 #
772 #
763 # An informal proof, assuming A is 'outside' and B is the D ancestor:
773 # An informal proof, assuming A is 'outside' and B is the D ancestor:
764 #
774 #
765 # If we pick B as the base, the merge involves:
775 # If we pick B as the base, the merge involves:
766 # - changes from B to M (actual changeset payload)
776 # - changes from B to M (actual changeset payload)
767 # - changes from B to D (induced by rebase) as D is a rebased
777 # - changes from B to D (induced by rebase) as D is a rebased
768 # version of B)
778 # version of B)
769 # Which exactly represent the rebase operation.
779 # Which exactly represent the rebase operation.
770 #
780 #
771 # If we pick A as the base, the merge involves:
781 # If we pick A as the base, the merge involves:
772 # - changes from A to M (actual changeset payload)
782 # - changes from A to M (actual changeset payload)
773 # - changes from A to D (with include changes between unrelated A and B
783 # - changes from A to D (with include changes between unrelated A and B
774 # plus changes induced by rebase)
784 # plus changes induced by rebase)
775 # Which does not represent anything sensible and creates a lot of
785 # Which does not represent anything sensible and creates a lot of
776 # conflicts. A is thus not the right choice - B is.
786 # conflicts. A is thus not the right choice - B is.
777 #
787 #
778 # Note: The base found in this 'proof' is only correct in the specified
788 # Note: The base found in this 'proof' is only correct in the specified
779 # case. This base does not make sense if is not D a descendant of A or B
789 # case. This base does not make sense if is not D a descendant of A or B
780 # or if the other is not parent 'outside' (especially not if the other
790 # or if the other is not parent 'outside' (especially not if the other
781 # parent has been rebased). The current implementation does not
791 # parent has been rebased). The current implementation does not
782 # make it feasible to consider different cases separately. In these
792 # make it feasible to consider different cases separately. In these
783 # other cases we currently just leave it to the user to correctly
793 # other cases we currently just leave it to the user to correctly
784 # resolve an impossible merge using a wrong ancestor.
794 # resolve an impossible merge using a wrong ancestor.
785 for p in repo[rev].parents():
795 for p in repo[rev].parents():
786 if state.get(p.rev()) == p1:
796 if state.get(p.rev()) == p1:
787 base = p.rev()
797 base = p.rev()
788 break
798 break
789 else: # fallback when base not found
799 else: # fallback when base not found
790 base = None
800 base = None
791
801
792 # Raise because this function is called wrong (see issue 4106)
802 # Raise because this function is called wrong (see issue 4106)
793 raise AssertionError('no base found to rebase on '
803 raise AssertionError('no base found to rebase on '
794 '(defineparents called wrong)')
804 '(defineparents called wrong)')
795 return p1, p2, base
805 return p1, p2, base
796
806
797 def isagitpatch(repo, patchname):
807 def isagitpatch(repo, patchname):
798 'Return true if the given patch is in git format'
808 'Return true if the given patch is in git format'
799 mqpatch = os.path.join(repo.mq.path, patchname)
809 mqpatch = os.path.join(repo.mq.path, patchname)
800 for line in patch.linereader(file(mqpatch, 'rb')):
810 for line in patch.linereader(file(mqpatch, 'rb')):
801 if line.startswith('diff --git'):
811 if line.startswith('diff --git'):
802 return True
812 return True
803 return False
813 return False
804
814
805 def updatemq(repo, state, skipped, **opts):
815 def updatemq(repo, state, skipped, **opts):
806 'Update rebased mq patches - finalize and then import them'
816 'Update rebased mq patches - finalize and then import them'
807 mqrebase = {}
817 mqrebase = {}
808 mq = repo.mq
818 mq = repo.mq
809 original_series = mq.fullseries[:]
819 original_series = mq.fullseries[:]
810 skippedpatches = set()
820 skippedpatches = set()
811
821
812 for p in mq.applied:
822 for p in mq.applied:
813 rev = repo[p.node].rev()
823 rev = repo[p.node].rev()
814 if rev in state:
824 if rev in state:
815 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
825 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
816 (rev, p.name))
826 (rev, p.name))
817 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
827 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
818 else:
828 else:
819 # Applied but not rebased, not sure this should happen
829 # Applied but not rebased, not sure this should happen
820 skippedpatches.add(p.name)
830 skippedpatches.add(p.name)
821
831
822 if mqrebase:
832 if mqrebase:
823 mq.finish(repo, mqrebase.keys())
833 mq.finish(repo, mqrebase.keys())
824
834
825 # We must start import from the newest revision
835 # We must start import from the newest revision
826 for rev in sorted(mqrebase, reverse=True):
836 for rev in sorted(mqrebase, reverse=True):
827 if rev not in skipped:
837 if rev not in skipped:
828 name, isgit = mqrebase[rev]
838 name, isgit = mqrebase[rev]
829 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
839 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
830 (name, state[rev], repo[state[rev]]))
840 (name, state[rev], repo[state[rev]]))
831 mq.qimport(repo, (), patchname=name, git=isgit,
841 mq.qimport(repo, (), patchname=name, git=isgit,
832 rev=[str(state[rev])])
842 rev=[str(state[rev])])
833 else:
843 else:
834 # Rebased and skipped
844 # Rebased and skipped
835 skippedpatches.add(mqrebase[rev][0])
845 skippedpatches.add(mqrebase[rev][0])
836
846
837 # Patches were either applied and rebased and imported in
847 # Patches were either applied and rebased and imported in
838 # order, applied and removed or unapplied. Discard the removed
848 # order, applied and removed or unapplied. Discard the removed
839 # ones while preserving the original series order and guards.
849 # ones while preserving the original series order and guards.
840 newseries = [s for s in original_series
850 newseries = [s for s in original_series
841 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
851 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
842 mq.fullseries[:] = newseries
852 mq.fullseries[:] = newseries
843 mq.seriesdirty = True
853 mq.seriesdirty = True
844 mq.savedirty()
854 mq.savedirty()
845
855
846 def updatebookmarks(repo, targetnode, nstate, originalbookmarks, tr):
856 def updatebookmarks(repo, targetnode, nstate, originalbookmarks, tr):
847 'Move bookmarks to their correct changesets, and delete divergent ones'
857 'Move bookmarks to their correct changesets, and delete divergent ones'
848 marks = repo._bookmarks
858 marks = repo._bookmarks
849 for k, v in originalbookmarks.iteritems():
859 for k, v in originalbookmarks.iteritems():
850 if v in nstate:
860 if v in nstate:
851 # update the bookmarks for revs that have moved
861 # update the bookmarks for revs that have moved
852 marks[k] = nstate[v]
862 marks[k] = nstate[v]
853 bookmarks.deletedivergent(repo, [targetnode], k)
863 bookmarks.deletedivergent(repo, [targetnode], k)
854 marks.recordchange(tr)
864 marks.recordchange(tr)
855
865
856 def storecollapsemsg(repo, collapsemsg):
866 def storecollapsemsg(repo, collapsemsg):
857 'Store the collapse message to allow recovery'
867 'Store the collapse message to allow recovery'
858 collapsemsg = collapsemsg or ''
868 collapsemsg = collapsemsg or ''
859 f = repo.vfs("last-message.txt", "w")
869 f = repo.vfs("last-message.txt", "w")
860 f.write("%s\n" % collapsemsg)
870 f.write("%s\n" % collapsemsg)
861 f.close()
871 f.close()
862
872
863 def clearcollapsemsg(repo):
873 def clearcollapsemsg(repo):
864 'Remove collapse message file'
874 'Remove collapse message file'
865 util.unlinkpath(repo.join("last-message.txt"), ignoremissing=True)
875 util.unlinkpath(repo.join("last-message.txt"), ignoremissing=True)
866
876
867 def restorecollapsemsg(repo):
877 def restorecollapsemsg(repo):
868 'Restore previously stored collapse message'
878 'Restore previously stored collapse message'
869 try:
879 try:
870 f = repo.vfs("last-message.txt")
880 f = repo.vfs("last-message.txt")
871 collapsemsg = f.readline().strip()
881 collapsemsg = f.readline().strip()
872 f.close()
882 f.close()
873 except IOError as err:
883 except IOError as err:
874 if err.errno != errno.ENOENT:
884 if err.errno != errno.ENOENT:
875 raise
885 raise
876 raise error.Abort(_('no rebase in progress'))
886 raise error.Abort(_('no rebase in progress'))
877 return collapsemsg
887 return collapsemsg
878
888
879 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
889 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
880 external, activebookmark):
890 external, activebookmark):
881 'Store the current status to allow recovery'
891 'Store the current status to allow recovery'
882 f = repo.vfs("rebasestate", "w")
892 f = repo.vfs("rebasestate", "w")
883 f.write(repo[originalwd].hex() + '\n')
893 f.write(repo[originalwd].hex() + '\n')
884 f.write(repo[target].hex() + '\n')
894 f.write(repo[target].hex() + '\n')
885 f.write(repo[external].hex() + '\n')
895 f.write(repo[external].hex() + '\n')
886 f.write('%d\n' % int(collapse))
896 f.write('%d\n' % int(collapse))
887 f.write('%d\n' % int(keep))
897 f.write('%d\n' % int(keep))
888 f.write('%d\n' % int(keepbranches))
898 f.write('%d\n' % int(keepbranches))
889 f.write('%s\n' % (activebookmark or ''))
899 f.write('%s\n' % (activebookmark or ''))
890 for d, v in state.iteritems():
900 for d, v in state.iteritems():
891 oldrev = repo[d].hex()
901 oldrev = repo[d].hex()
892 if v >= 0:
902 if v >= 0:
893 newrev = repo[v].hex()
903 newrev = repo[v].hex()
894 elif v == revtodo:
904 elif v == revtodo:
895 # To maintain format compatibility, we have to use nullid.
905 # To maintain format compatibility, we have to use nullid.
896 # Please do remove this special case when upgrading the format.
906 # Please do remove this special case when upgrading the format.
897 newrev = hex(nullid)
907 newrev = hex(nullid)
898 else:
908 else:
899 newrev = v
909 newrev = v
900 f.write("%s:%s\n" % (oldrev, newrev))
910 f.write("%s:%s\n" % (oldrev, newrev))
901 f.close()
911 f.close()
902 repo.ui.debug('rebase status stored\n')
912 repo.ui.debug('rebase status stored\n')
903
913
904 def clearstatus(repo):
914 def clearstatus(repo):
905 'Remove the status files'
915 'Remove the status files'
906 _clearrebasesetvisibiliy(repo)
916 _clearrebasesetvisibiliy(repo)
907 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
917 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
908
918
909 def restorestatus(repo):
919 def restorestatus(repo):
910 'Restore a previously stored status'
920 'Restore a previously stored status'
911 keepbranches = None
921 keepbranches = None
912 target = None
922 target = None
913 collapse = False
923 collapse = False
914 external = nullrev
924 external = nullrev
915 activebookmark = None
925 activebookmark = None
916 state = {}
926 state = {}
917
927
918 try:
928 try:
919 f = repo.vfs("rebasestate")
929 f = repo.vfs("rebasestate")
920 for i, l in enumerate(f.read().splitlines()):
930 for i, l in enumerate(f.read().splitlines()):
921 if i == 0:
931 if i == 0:
922 originalwd = repo[l].rev()
932 originalwd = repo[l].rev()
923 elif i == 1:
933 elif i == 1:
924 target = repo[l].rev()
934 target = repo[l].rev()
925 elif i == 2:
935 elif i == 2:
926 external = repo[l].rev()
936 external = repo[l].rev()
927 elif i == 3:
937 elif i == 3:
928 collapse = bool(int(l))
938 collapse = bool(int(l))
929 elif i == 4:
939 elif i == 4:
930 keep = bool(int(l))
940 keep = bool(int(l))
931 elif i == 5:
941 elif i == 5:
932 keepbranches = bool(int(l))
942 keepbranches = bool(int(l))
933 elif i == 6 and not (len(l) == 81 and ':' in l):
943 elif i == 6 and not (len(l) == 81 and ':' in l):
934 # line 6 is a recent addition, so for backwards compatibility
944 # line 6 is a recent addition, so for backwards compatibility
935 # check that the line doesn't look like the oldrev:newrev lines
945 # check that the line doesn't look like the oldrev:newrev lines
936 activebookmark = l
946 activebookmark = l
937 else:
947 else:
938 oldrev, newrev = l.split(':')
948 oldrev, newrev = l.split(':')
939 if newrev in (str(nullmerge), str(revignored),
949 if newrev in (str(nullmerge), str(revignored),
940 str(revprecursor), str(revpruned)):
950 str(revprecursor), str(revpruned)):
941 state[repo[oldrev].rev()] = int(newrev)
951 state[repo[oldrev].rev()] = int(newrev)
942 elif newrev == nullid:
952 elif newrev == nullid:
943 state[repo[oldrev].rev()] = revtodo
953 state[repo[oldrev].rev()] = revtodo
944 # Legacy compat special case
954 # Legacy compat special case
945 else:
955 else:
946 state[repo[oldrev].rev()] = repo[newrev].rev()
956 state[repo[oldrev].rev()] = repo[newrev].rev()
947
957
948 except IOError as err:
958 except IOError as err:
949 if err.errno != errno.ENOENT:
959 if err.errno != errno.ENOENT:
950 raise
960 raise
951 cmdutil.wrongtooltocontinue(repo, _('rebase'))
961 cmdutil.wrongtooltocontinue(repo, _('rebase'))
952
962
953 if keepbranches is None:
963 if keepbranches is None:
954 raise error.Abort(_('.hg/rebasestate is incomplete'))
964 raise error.Abort(_('.hg/rebasestate is incomplete'))
955
965
956 skipped = set()
966 skipped = set()
957 # recompute the set of skipped revs
967 # recompute the set of skipped revs
958 if not collapse:
968 if not collapse:
959 seen = set([target])
969 seen = set([target])
960 for old, new in sorted(state.items()):
970 for old, new in sorted(state.items()):
961 if new != revtodo and new in seen:
971 if new != revtodo and new in seen:
962 skipped.add(old)
972 skipped.add(old)
963 seen.add(new)
973 seen.add(new)
964 repo.ui.debug('computed skipped revs: %s\n' %
974 repo.ui.debug('computed skipped revs: %s\n' %
965 (' '.join(str(r) for r in sorted(skipped)) or None))
975 (' '.join(str(r) for r in sorted(skipped)) or None))
966 repo.ui.debug('rebase status resumed\n')
976 repo.ui.debug('rebase status resumed\n')
967 _setrebasesetvisibility(repo, state.keys())
977 _setrebasesetvisibility(repo, state.keys())
968 return (originalwd, target, state, skipped,
978 return (originalwd, target, state, skipped,
969 collapse, keep, keepbranches, external, activebookmark)
979 collapse, keep, keepbranches, external, activebookmark)
970
980
971 def needupdate(repo, state):
981 def needupdate(repo, state):
972 '''check whether we should `update --clean` away from a merge, or if
982 '''check whether we should `update --clean` away from a merge, or if
973 somehow the working dir got forcibly updated, e.g. by older hg'''
983 somehow the working dir got forcibly updated, e.g. by older hg'''
974 parents = [p.rev() for p in repo[None].parents()]
984 parents = [p.rev() for p in repo[None].parents()]
975
985
976 # Are we in a merge state at all?
986 # Are we in a merge state at all?
977 if len(parents) < 2:
987 if len(parents) < 2:
978 return False
988 return False
979
989
980 # We should be standing on the first as-of-yet unrebased commit.
990 # We should be standing on the first as-of-yet unrebased commit.
981 firstunrebased = min([old for old, new in state.iteritems()
991 firstunrebased = min([old for old, new in state.iteritems()
982 if new == nullrev])
992 if new == nullrev])
983 if firstunrebased in parents:
993 if firstunrebased in parents:
984 return True
994 return True
985
995
986 return False
996 return False
987
997
988 def abort(repo, originalwd, target, state, activebookmark=None):
998 def abort(repo, originalwd, target, state, activebookmark=None):
989 '''Restore the repository to its original state. Additional args:
999 '''Restore the repository to its original state. Additional args:
990
1000
991 activebookmark: the name of the bookmark that should be active after the
1001 activebookmark: the name of the bookmark that should be active after the
992 restore'''
1002 restore'''
993
1003
994 try:
1004 try:
995 # If the first commits in the rebased set get skipped during the rebase,
1005 # If the first commits in the rebased set get skipped during the rebase,
996 # their values within the state mapping will be the target rev id. The
1006 # their values within the state mapping will be the target rev id. The
997 # dstates list must must not contain the target rev (issue4896)
1007 # dstates list must must not contain the target rev (issue4896)
998 dstates = [s for s in state.values() if s >= 0 and s != target]
1008 dstates = [s for s in state.values() if s >= 0 and s != target]
999 immutable = [d for d in dstates if not repo[d].mutable()]
1009 immutable = [d for d in dstates if not repo[d].mutable()]
1000 cleanup = True
1010 cleanup = True
1001 if immutable:
1011 if immutable:
1002 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1012 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1003 % ', '.join(str(repo[r]) for r in immutable),
1013 % ', '.join(str(repo[r]) for r in immutable),
1004 hint=_('see "hg help phases" for details'))
1014 hint=_('see "hg help phases" for details'))
1005 cleanup = False
1015 cleanup = False
1006
1016
1007 descendants = set()
1017 descendants = set()
1008 if dstates:
1018 if dstates:
1009 descendants = set(repo.changelog.descendants(dstates))
1019 descendants = set(repo.changelog.descendants(dstates))
1010 if descendants - set(dstates):
1020 if descendants - set(dstates):
1011 repo.ui.warn(_("warning: new changesets detected on target branch, "
1021 repo.ui.warn(_("warning: new changesets detected on target branch, "
1012 "can't strip\n"))
1022 "can't strip\n"))
1013 cleanup = False
1023 cleanup = False
1014
1024
1015 if cleanup:
1025 if cleanup:
1016 shouldupdate = False
1026 shouldupdate = False
1017 rebased = filter(lambda x: x >= 0 and x != target, state.values())
1027 rebased = filter(lambda x: x >= 0 and x != target, state.values())
1018 if rebased:
1028 if rebased:
1019 strippoints = [
1029 strippoints = [
1020 c.node() for c in repo.set('roots(%ld)', rebased)]
1030 c.node() for c in repo.set('roots(%ld)', rebased)]
1021 shouldupdate = len([
1031 shouldupdate = len([
1022 c.node() for c in repo.set('. & (%ld)', rebased)]) > 0
1032 c.node() for c in repo.set('. & (%ld)', rebased)]) > 0
1023
1033
1024 # Update away from the rebase if necessary
1034 # Update away from the rebase if necessary
1025 if shouldupdate or needupdate(repo, state):
1035 if shouldupdate or needupdate(repo, state):
1026 merge.update(repo, originalwd, False, True)
1036 merge.update(repo, originalwd, False, True)
1027
1037
1028 # Strip from the first rebased revision
1038 # Strip from the first rebased revision
1029 if rebased:
1039 if rebased:
1030 # no backup of rebased cset versions needed
1040 # no backup of rebased cset versions needed
1031 repair.strip(repo.ui, repo, strippoints)
1041 repair.strip(repo.ui, repo, strippoints)
1032
1042
1033 if activebookmark and activebookmark in repo._bookmarks:
1043 if activebookmark and activebookmark in repo._bookmarks:
1034 bookmarks.activate(repo, activebookmark)
1044 bookmarks.activate(repo, activebookmark)
1035
1045
1036 finally:
1046 finally:
1037 clearstatus(repo)
1047 clearstatus(repo)
1038 clearcollapsemsg(repo)
1048 clearcollapsemsg(repo)
1039 repo.ui.warn(_('rebase aborted\n'))
1049 repo.ui.warn(_('rebase aborted\n'))
1040 return 0
1050 return 0
1041
1051
1042 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1052 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1043 '''Define which revisions are going to be rebased and where
1053 '''Define which revisions are going to be rebased and where
1044
1054
1045 repo: repo
1055 repo: repo
1046 dest: context
1056 dest: context
1047 rebaseset: set of rev
1057 rebaseset: set of rev
1048 '''
1058 '''
1049 _setrebasesetvisibility(repo, rebaseset)
1059 _setrebasesetvisibility(repo, rebaseset)
1050
1060
1051 # This check isn't strictly necessary, since mq detects commits over an
1061 # This check isn't strictly necessary, since mq detects commits over an
1052 # applied patch. But it prevents messing up the working directory when
1062 # applied patch. But it prevents messing up the working directory when
1053 # a partially completed rebase is blocked by mq.
1063 # a partially completed rebase is blocked by mq.
1054 if 'qtip' in repo.tags() and (dest.node() in
1064 if 'qtip' in repo.tags() and (dest.node() in
1055 [s.node for s in repo.mq.applied]):
1065 [s.node for s in repo.mq.applied]):
1056 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1066 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1057
1067
1058 roots = list(repo.set('roots(%ld)', rebaseset))
1068 roots = list(repo.set('roots(%ld)', rebaseset))
1059 if not roots:
1069 if not roots:
1060 raise error.Abort(_('no matching revisions'))
1070 raise error.Abort(_('no matching revisions'))
1061 roots.sort()
1071 roots.sort()
1062 state = {}
1072 state = {}
1063 detachset = set()
1073 detachset = set()
1064 for root in roots:
1074 for root in roots:
1065 commonbase = root.ancestor(dest)
1075 commonbase = root.ancestor(dest)
1066 if commonbase == root:
1076 if commonbase == root:
1067 raise error.Abort(_('source is ancestor of destination'))
1077 raise error.Abort(_('source is ancestor of destination'))
1068 if commonbase == dest:
1078 if commonbase == dest:
1069 samebranch = root.branch() == dest.branch()
1079 samebranch = root.branch() == dest.branch()
1070 if not collapse and samebranch and root in dest.children():
1080 if not collapse and samebranch and root in dest.children():
1071 repo.ui.debug('source is a child of destination\n')
1081 repo.ui.debug('source is a child of destination\n')
1072 return None
1082 return None
1073
1083
1074 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
1084 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
1075 state.update(dict.fromkeys(rebaseset, revtodo))
1085 state.update(dict.fromkeys(rebaseset, revtodo))
1076 # Rebase tries to turn <dest> into a parent of <root> while
1086 # Rebase tries to turn <dest> into a parent of <root> while
1077 # preserving the number of parents of rebased changesets:
1087 # preserving the number of parents of rebased changesets:
1078 #
1088 #
1079 # - A changeset with a single parent will always be rebased as a
1089 # - A changeset with a single parent will always be rebased as a
1080 # changeset with a single parent.
1090 # changeset with a single parent.
1081 #
1091 #
1082 # - A merge will be rebased as merge unless its parents are both
1092 # - A merge will be rebased as merge unless its parents are both
1083 # ancestors of <dest> or are themselves in the rebased set and
1093 # ancestors of <dest> or are themselves in the rebased set and
1084 # pruned while rebased.
1094 # pruned while rebased.
1085 #
1095 #
1086 # If one parent of <root> is an ancestor of <dest>, the rebased
1096 # If one parent of <root> is an ancestor of <dest>, the rebased
1087 # version of this parent will be <dest>. This is always true with
1097 # version of this parent will be <dest>. This is always true with
1088 # --base option.
1098 # --base option.
1089 #
1099 #
1090 # Otherwise, we need to *replace* the original parents with
1100 # Otherwise, we need to *replace* the original parents with
1091 # <dest>. This "detaches" the rebased set from its former location
1101 # <dest>. This "detaches" the rebased set from its former location
1092 # and rebases it onto <dest>. Changes introduced by ancestors of
1102 # and rebases it onto <dest>. Changes introduced by ancestors of
1093 # <root> not common with <dest> (the detachset, marked as
1103 # <root> not common with <dest> (the detachset, marked as
1094 # nullmerge) are "removed" from the rebased changesets.
1104 # nullmerge) are "removed" from the rebased changesets.
1095 #
1105 #
1096 # - If <root> has a single parent, set it to <dest>.
1106 # - If <root> has a single parent, set it to <dest>.
1097 #
1107 #
1098 # - If <root> is a merge, we cannot decide which parent to
1108 # - If <root> is a merge, we cannot decide which parent to
1099 # replace, the rebase operation is not clearly defined.
1109 # replace, the rebase operation is not clearly defined.
1100 #
1110 #
1101 # The table below sums up this behavior:
1111 # The table below sums up this behavior:
1102 #
1112 #
1103 # +------------------+----------------------+-------------------------+
1113 # +------------------+----------------------+-------------------------+
1104 # | | one parent | merge |
1114 # | | one parent | merge |
1105 # +------------------+----------------------+-------------------------+
1115 # +------------------+----------------------+-------------------------+
1106 # | parent in | new parent is <dest> | parents in ::<dest> are |
1116 # | parent in | new parent is <dest> | parents in ::<dest> are |
1107 # | ::<dest> | | remapped to <dest> |
1117 # | ::<dest> | | remapped to <dest> |
1108 # +------------------+----------------------+-------------------------+
1118 # +------------------+----------------------+-------------------------+
1109 # | unrelated source | new parent is <dest> | ambiguous, abort |
1119 # | unrelated source | new parent is <dest> | ambiguous, abort |
1110 # +------------------+----------------------+-------------------------+
1120 # +------------------+----------------------+-------------------------+
1111 #
1121 #
1112 # The actual abort is handled by `defineparents`
1122 # The actual abort is handled by `defineparents`
1113 if len(root.parents()) <= 1:
1123 if len(root.parents()) <= 1:
1114 # ancestors of <root> not ancestors of <dest>
1124 # ancestors of <root> not ancestors of <dest>
1115 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1125 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1116 [root.rev()]))
1126 [root.rev()]))
1117 for r in detachset:
1127 for r in detachset:
1118 if r not in state:
1128 if r not in state:
1119 state[r] = nullmerge
1129 state[r] = nullmerge
1120 if len(roots) > 1:
1130 if len(roots) > 1:
1121 # If we have multiple roots, we may have "hole" in the rebase set.
1131 # If we have multiple roots, we may have "hole" in the rebase set.
1122 # Rebase roots that descend from those "hole" should not be detached as
1132 # Rebase roots that descend from those "hole" should not be detached as
1123 # other root are. We use the special `revignored` to inform rebase that
1133 # other root are. We use the special `revignored` to inform rebase that
1124 # the revision should be ignored but that `defineparents` should search
1134 # the revision should be ignored but that `defineparents` should search
1125 # a rebase destination that make sense regarding rebased topology.
1135 # a rebase destination that make sense regarding rebased topology.
1126 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1136 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1127 for ignored in set(rebasedomain) - set(rebaseset):
1137 for ignored in set(rebasedomain) - set(rebaseset):
1128 state[ignored] = revignored
1138 state[ignored] = revignored
1129 for r in obsoletenotrebased:
1139 for r in obsoletenotrebased:
1130 if obsoletenotrebased[r] is None:
1140 if obsoletenotrebased[r] is None:
1131 state[r] = revpruned
1141 state[r] = revpruned
1132 else:
1142 else:
1133 state[r] = revprecursor
1143 state[r] = revprecursor
1134 return repo['.'].rev(), dest.rev(), state
1144 return repo['.'].rev(), dest.rev(), state
1135
1145
1136 def clearrebased(ui, repo, state, skipped, collapsedas=None):
1146 def clearrebased(ui, repo, state, skipped, collapsedas=None):
1137 """dispose of rebased revision at the end of the rebase
1147 """dispose of rebased revision at the end of the rebase
1138
1148
1139 If `collapsedas` is not None, the rebase was a collapse whose result if the
1149 If `collapsedas` is not None, the rebase was a collapse whose result if the
1140 `collapsedas` node."""
1150 `collapsedas` node."""
1141 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1151 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1142 markers = []
1152 markers = []
1143 for rev, newrev in sorted(state.items()):
1153 for rev, newrev in sorted(state.items()):
1144 if newrev >= 0:
1154 if newrev >= 0:
1145 if rev in skipped:
1155 if rev in skipped:
1146 succs = ()
1156 succs = ()
1147 elif collapsedas is not None:
1157 elif collapsedas is not None:
1148 succs = (repo[collapsedas],)
1158 succs = (repo[collapsedas],)
1149 else:
1159 else:
1150 succs = (repo[newrev],)
1160 succs = (repo[newrev],)
1151 markers.append((repo[rev], succs))
1161 markers.append((repo[rev], succs))
1152 if markers:
1162 if markers:
1153 obsolete.createmarkers(repo, markers)
1163 obsolete.createmarkers(repo, markers)
1154 else:
1164 else:
1155 rebased = [rev for rev in state if state[rev] > nullmerge]
1165 rebased = [rev for rev in state if state[rev] > nullmerge]
1156 if rebased:
1166 if rebased:
1157 stripped = []
1167 stripped = []
1158 for root in repo.set('roots(%ld)', rebased):
1168 for root in repo.set('roots(%ld)', rebased):
1159 if set(repo.changelog.descendants([root.rev()])) - set(state):
1169 if set(repo.changelog.descendants([root.rev()])) - set(state):
1160 ui.warn(_("warning: new changesets detected "
1170 ui.warn(_("warning: new changesets detected "
1161 "on source branch, not stripping\n"))
1171 "on source branch, not stripping\n"))
1162 else:
1172 else:
1163 stripped.append(root.node())
1173 stripped.append(root.node())
1164 if stripped:
1174 if stripped:
1165 # backup the old csets by default
1175 # backup the old csets by default
1166 repair.strip(ui, repo, stripped, "all")
1176 repair.strip(ui, repo, stripped, "all")
1167
1177
1168
1178
1169 def pullrebase(orig, ui, repo, *args, **opts):
1179 def pullrebase(orig, ui, repo, *args, **opts):
1170 'Call rebase after pull if the latter has been invoked with --rebase'
1180 'Call rebase after pull if the latter has been invoked with --rebase'
1171 ret = None
1181 ret = None
1172 if opts.get('rebase'):
1182 if opts.get('rebase'):
1173 wlock = lock = None
1183 wlock = lock = None
1174 try:
1184 try:
1175 wlock = repo.wlock()
1185 wlock = repo.wlock()
1176 lock = repo.lock()
1186 lock = repo.lock()
1177 if opts.get('update'):
1187 if opts.get('update'):
1178 del opts['update']
1188 del opts['update']
1179 ui.debug('--update and --rebase are not compatible, ignoring '
1189 ui.debug('--update and --rebase are not compatible, ignoring '
1180 'the update flag\n')
1190 'the update flag\n')
1181
1191
1182 revsprepull = len(repo)
1192 revsprepull = len(repo)
1183 origpostincoming = commands.postincoming
1193 origpostincoming = commands.postincoming
1184 def _dummy(*args, **kwargs):
1194 def _dummy(*args, **kwargs):
1185 pass
1195 pass
1186 commands.postincoming = _dummy
1196 commands.postincoming = _dummy
1187 try:
1197 try:
1188 ret = orig(ui, repo, *args, **opts)
1198 ret = orig(ui, repo, *args, **opts)
1189 finally:
1199 finally:
1190 commands.postincoming = origpostincoming
1200 commands.postincoming = origpostincoming
1191 revspostpull = len(repo)
1201 revspostpull = len(repo)
1192 if revspostpull > revsprepull:
1202 if revspostpull > revsprepull:
1193 # --rev option from pull conflict with rebase own --rev
1203 # --rev option from pull conflict with rebase own --rev
1194 # dropping it
1204 # dropping it
1195 if 'rev' in opts:
1205 if 'rev' in opts:
1196 del opts['rev']
1206 del opts['rev']
1197 # positional argument from pull conflicts with rebase's own
1207 # positional argument from pull conflicts with rebase's own
1198 # --source.
1208 # --source.
1199 if 'source' in opts:
1209 if 'source' in opts:
1200 del opts['source']
1210 del opts['source']
1201 if rebase(ui, repo, **opts) == _nothingtorebase():
1211 try:
1212 rebase(ui, repo, **opts)
1213 except error.NoMergeDestAbort:
1214 # we can maybe update instead
1202 rev, _a, _b = destutil.destupdate(repo)
1215 rev, _a, _b = destutil.destupdate(repo)
1203 if rev != repo['.'].rev(): # we could update
1216 if rev == repo['.'].rev():
1217 ui.status(_('nothing to rebase\n'))
1218 else:
1219 ui.status(_('nothing to rebase - updating instead\n'))
1204 # not passing argument to get the bare update behavior
1220 # not passing argument to get the bare update behavior
1205 # with warning and trumpets
1221 # with warning and trumpets
1206 commands.update(ui, repo)
1222 commands.update(ui, repo)
1207 finally:
1223 finally:
1208 release(lock, wlock)
1224 release(lock, wlock)
1209 else:
1225 else:
1210 if opts.get('tool'):
1226 if opts.get('tool'):
1211 raise error.Abort(_('--tool can only be used with --rebase'))
1227 raise error.Abort(_('--tool can only be used with --rebase'))
1212 ret = orig(ui, repo, *args, **opts)
1228 ret = orig(ui, repo, *args, **opts)
1213
1229
1214 return ret
1230 return ret
1215
1231
1216 def _setrebasesetvisibility(repo, revs):
1232 def _setrebasesetvisibility(repo, revs):
1217 """store the currently rebased set on the repo object
1233 """store the currently rebased set on the repo object
1218
1234
1219 This is used by another function to prevent rebased revision to because
1235 This is used by another function to prevent rebased revision to because
1220 hidden (see issue4505)"""
1236 hidden (see issue4505)"""
1221 repo = repo.unfiltered()
1237 repo = repo.unfiltered()
1222 revs = set(revs)
1238 revs = set(revs)
1223 repo._rebaseset = revs
1239 repo._rebaseset = revs
1224 # invalidate cache if visibility changes
1240 # invalidate cache if visibility changes
1225 hiddens = repo.filteredrevcache.get('visible', set())
1241 hiddens = repo.filteredrevcache.get('visible', set())
1226 if revs & hiddens:
1242 if revs & hiddens:
1227 repo.invalidatevolatilesets()
1243 repo.invalidatevolatilesets()
1228
1244
1229 def _clearrebasesetvisibiliy(repo):
1245 def _clearrebasesetvisibiliy(repo):
1230 """remove rebaseset data from the repo"""
1246 """remove rebaseset data from the repo"""
1231 repo = repo.unfiltered()
1247 repo = repo.unfiltered()
1232 if '_rebaseset' in vars(repo):
1248 if '_rebaseset' in vars(repo):
1233 del repo._rebaseset
1249 del repo._rebaseset
1234
1250
1235 def _rebasedvisible(orig, repo):
1251 def _rebasedvisible(orig, repo):
1236 """ensure rebased revs stay visible (see issue4505)"""
1252 """ensure rebased revs stay visible (see issue4505)"""
1237 blockers = orig(repo)
1253 blockers = orig(repo)
1238 blockers.update(getattr(repo, '_rebaseset', ()))
1254 blockers.update(getattr(repo, '_rebaseset', ()))
1239 return blockers
1255 return blockers
1240
1256
1241 def _filterobsoleterevs(repo, revs):
1257 def _filterobsoleterevs(repo, revs):
1242 """returns a set of the obsolete revisions in revs"""
1258 """returns a set of the obsolete revisions in revs"""
1243 return set(r for r in revs if repo[r].obsolete())
1259 return set(r for r in revs if repo[r].obsolete())
1244
1260
1245 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1261 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1246 """return a mapping obsolete => successor for all obsolete nodes to be
1262 """return a mapping obsolete => successor for all obsolete nodes to be
1247 rebased that have a successors in the destination
1263 rebased that have a successors in the destination
1248
1264
1249 obsolete => None entries in the mapping indicate nodes with no succesor"""
1265 obsolete => None entries in the mapping indicate nodes with no succesor"""
1250 obsoletenotrebased = {}
1266 obsoletenotrebased = {}
1251
1267
1252 # Build a mapping successor => obsolete nodes for the obsolete
1268 # Build a mapping successor => obsolete nodes for the obsolete
1253 # nodes to be rebased
1269 # nodes to be rebased
1254 allsuccessors = {}
1270 allsuccessors = {}
1255 cl = repo.changelog
1271 cl = repo.changelog
1256 for r in rebaseobsrevs:
1272 for r in rebaseobsrevs:
1257 node = cl.node(r)
1273 node = cl.node(r)
1258 for s in obsolete.allsuccessors(repo.obsstore, [node]):
1274 for s in obsolete.allsuccessors(repo.obsstore, [node]):
1259 try:
1275 try:
1260 allsuccessors[cl.rev(s)] = cl.rev(node)
1276 allsuccessors[cl.rev(s)] = cl.rev(node)
1261 except LookupError:
1277 except LookupError:
1262 pass
1278 pass
1263
1279
1264 if allsuccessors:
1280 if allsuccessors:
1265 # Look for successors of obsolete nodes to be rebased among
1281 # Look for successors of obsolete nodes to be rebased among
1266 # the ancestors of dest
1282 # the ancestors of dest
1267 ancs = cl.ancestors([repo[dest].rev()],
1283 ancs = cl.ancestors([repo[dest].rev()],
1268 stoprev=min(allsuccessors),
1284 stoprev=min(allsuccessors),
1269 inclusive=True)
1285 inclusive=True)
1270 for s in allsuccessors:
1286 for s in allsuccessors:
1271 if s in ancs:
1287 if s in ancs:
1272 obsoletenotrebased[allsuccessors[s]] = s
1288 obsoletenotrebased[allsuccessors[s]] = s
1273 elif (s == allsuccessors[s] and
1289 elif (s == allsuccessors[s] and
1274 allsuccessors.values().count(s) == 1):
1290 allsuccessors.values().count(s) == 1):
1275 # plain prune
1291 # plain prune
1276 obsoletenotrebased[s] = None
1292 obsoletenotrebased[s] = None
1277
1293
1278 return obsoletenotrebased
1294 return obsoletenotrebased
1279
1295
1280 def summaryhook(ui, repo):
1296 def summaryhook(ui, repo):
1281 if not os.path.exists(repo.join('rebasestate')):
1297 if not os.path.exists(repo.join('rebasestate')):
1282 return
1298 return
1283 try:
1299 try:
1284 state = restorestatus(repo)[2]
1300 state = restorestatus(repo)[2]
1285 except error.RepoLookupError:
1301 except error.RepoLookupError:
1286 # i18n: column positioning for "hg summary"
1302 # i18n: column positioning for "hg summary"
1287 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1303 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1288 ui.write(msg)
1304 ui.write(msg)
1289 return
1305 return
1290 numrebased = len([i for i in state.itervalues() if i >= 0])
1306 numrebased = len([i for i in state.itervalues() if i >= 0])
1291 # i18n: column positioning for "hg summary"
1307 # i18n: column positioning for "hg summary"
1292 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1308 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1293 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1309 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1294 ui.label(_('%d remaining'), 'rebase.remaining') %
1310 ui.label(_('%d remaining'), 'rebase.remaining') %
1295 (len(state) - numrebased)))
1311 (len(state) - numrebased)))
1296
1312
1297 def uisetup(ui):
1313 def uisetup(ui):
1298 #Replace pull with a decorator to provide --rebase option
1314 #Replace pull with a decorator to provide --rebase option
1299 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1315 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1300 entry[1].append(('', 'rebase', None,
1316 entry[1].append(('', 'rebase', None,
1301 _("rebase working directory to branch head")))
1317 _("rebase working directory to branch head")))
1302 entry[1].append(('t', 'tool', '',
1318 entry[1].append(('t', 'tool', '',
1303 _("specify merge tool for rebase")))
1319 _("specify merge tool for rebase")))
1304 cmdutil.summaryhooks.add('rebase', summaryhook)
1320 cmdutil.summaryhooks.add('rebase', summaryhook)
1305 cmdutil.unfinishedstates.append(
1321 cmdutil.unfinishedstates.append(
1306 ['rebasestate', False, False, _('rebase in progress'),
1322 ['rebasestate', False, False, _('rebase in progress'),
1307 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1323 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1308 cmdutil.afterresolvedstates.append(
1324 cmdutil.afterresolvedstates.append(
1309 ['rebasestate', _('hg rebase --continue')])
1325 ['rebasestate', _('hg rebase --continue')])
1310 # ensure rebased rev are not hidden
1326 # ensure rebased rev are not hidden
1311 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
1327 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
1312 revsetpredicate.setup()
1328 revsetpredicate.setup()
@@ -1,344 +1,376
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from . import (
11 from . import (
12 bookmarks,
12 bookmarks,
13 error,
13 error,
14 obsolete,
14 obsolete,
15 )
15 )
16
16
17 def _destupdatevalidate(repo, rev, clean, check):
17 def _destupdatevalidate(repo, rev, clean, check):
18 """validate that the destination comply to various rules
18 """validate that the destination comply to various rules
19
19
20 This exists as its own function to help wrapping from extensions."""
20 This exists as its own function to help wrapping from extensions."""
21 wc = repo[None]
21 wc = repo[None]
22 p1 = wc.p1()
22 p1 = wc.p1()
23 if not clean:
23 if not clean:
24 # Check that the update is linear.
24 # Check that the update is linear.
25 #
25 #
26 # Mercurial do not allow update-merge for non linear pattern
26 # Mercurial do not allow update-merge for non linear pattern
27 # (that would be technically possible but was considered too confusing
27 # (that would be technically possible but was considered too confusing
28 # for user a long time ago)
28 # for user a long time ago)
29 #
29 #
30 # See mercurial.merge.update for details
30 # See mercurial.merge.update for details
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
32 dirty = wc.dirty(missing=True)
32 dirty = wc.dirty(missing=True)
33 foreground = obsolete.foreground(repo, [p1.node()])
33 foreground = obsolete.foreground(repo, [p1.node()])
34 if not repo[rev].node() in foreground:
34 if not repo[rev].node() in foreground:
35 if dirty:
35 if dirty:
36 msg = _("uncommitted changes")
36 msg = _("uncommitted changes")
37 hint = _("commit and merge, or update --clean to"
37 hint = _("commit and merge, or update --clean to"
38 " discard changes")
38 " discard changes")
39 raise error.UpdateAbort(msg, hint=hint)
39 raise error.UpdateAbort(msg, hint=hint)
40 elif not check: # destination is not a descendant.
40 elif not check: # destination is not a descendant.
41 msg = _("not a linear update")
41 msg = _("not a linear update")
42 hint = _("merge or update --check to force update")
42 hint = _("merge or update --check to force update")
43 raise error.UpdateAbort(msg, hint=hint)
43 raise error.UpdateAbort(msg, hint=hint)
44
44
45 def _destupdateobs(repo, clean, check):
45 def _destupdateobs(repo, clean, check):
46 """decide of an update destination from obsolescence markers"""
46 """decide of an update destination from obsolescence markers"""
47 node = None
47 node = None
48 wc = repo[None]
48 wc = repo[None]
49 p1 = wc.p1()
49 p1 = wc.p1()
50 movemark = None
50 movemark = None
51
51
52 if p1.obsolete() and not p1.children():
52 if p1.obsolete() and not p1.children():
53 # allow updating to successors
53 # allow updating to successors
54 successors = obsolete.successorssets(repo, p1.node())
54 successors = obsolete.successorssets(repo, p1.node())
55
55
56 # behavior of certain cases is as follows,
56 # behavior of certain cases is as follows,
57 #
57 #
58 # divergent changesets: update to highest rev, similar to what
58 # divergent changesets: update to highest rev, similar to what
59 # is currently done when there are more than one head
59 # is currently done when there are more than one head
60 # (i.e. 'tip')
60 # (i.e. 'tip')
61 #
61 #
62 # replaced changesets: same as divergent except we know there
62 # replaced changesets: same as divergent except we know there
63 # is no conflict
63 # is no conflict
64 #
64 #
65 # pruned changeset: no update is done; though, we could
65 # pruned changeset: no update is done; though, we could
66 # consider updating to the first non-obsolete parent,
66 # consider updating to the first non-obsolete parent,
67 # similar to what is current done for 'hg prune'
67 # similar to what is current done for 'hg prune'
68
68
69 if successors:
69 if successors:
70 # flatten the list here handles both divergent (len > 1)
70 # flatten the list here handles both divergent (len > 1)
71 # and the usual case (len = 1)
71 # and the usual case (len = 1)
72 successors = [n for sub in successors for n in sub]
72 successors = [n for sub in successors for n in sub]
73
73
74 # get the max revision for the given successors set,
74 # get the max revision for the given successors set,
75 # i.e. the 'tip' of a set
75 # i.e. the 'tip' of a set
76 node = repo.revs('max(%ln)', successors).first()
76 node = repo.revs('max(%ln)', successors).first()
77 if bookmarks.isactivewdirparent(repo):
77 if bookmarks.isactivewdirparent(repo):
78 movemark = repo['.'].node()
78 movemark = repo['.'].node()
79 return node, movemark, None
79 return node, movemark, None
80
80
81 def _destupdatebook(repo, clean, check):
81 def _destupdatebook(repo, clean, check):
82 """decide on an update destination from active bookmark"""
82 """decide on an update destination from active bookmark"""
83 # we also move the active bookmark, if any
83 # we also move the active bookmark, if any
84 activemark = None
84 activemark = None
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
86 if node is not None:
86 if node is not None:
87 activemark = node
87 activemark = node
88 return node, movemark, activemark
88 return node, movemark, activemark
89
89
90 def _destupdatebranch(repo, clean, check):
90 def _destupdatebranch(repo, clean, check):
91 """decide on an update destination from current branch"""
91 """decide on an update destination from current branch"""
92 wc = repo[None]
92 wc = repo[None]
93 movemark = node = None
93 movemark = node = None
94 try:
94 try:
95 node = repo.revs('max(.::(head() and branch(%s)))'
95 node = repo.revs('max(.::(head() and branch(%s)))'
96 , wc.branch()).first()
96 , wc.branch()).first()
97 if bookmarks.isactivewdirparent(repo):
97 if bookmarks.isactivewdirparent(repo):
98 movemark = repo['.'].node()
98 movemark = repo['.'].node()
99 except error.RepoLookupError:
99 except error.RepoLookupError:
100 if wc.branch() == 'default': # no default branch!
100 if wc.branch() == 'default': # no default branch!
101 node = repo.lookup('tip') # update to tip
101 node = repo.lookup('tip') # update to tip
102 else:
102 else:
103 raise error.Abort(_("branch %s not found") % wc.branch())
103 raise error.Abort(_("branch %s not found") % wc.branch())
104 return node, movemark, None
104 return node, movemark, None
105
105
106 # order in which each step should be evalutated
106 # order in which each step should be evalutated
107 # steps are run until one finds a destination
107 # steps are run until one finds a destination
108 destupdatesteps = ['evolution', 'bookmark', 'branch']
108 destupdatesteps = ['evolution', 'bookmark', 'branch']
109 # mapping to ease extension overriding steps.
109 # mapping to ease extension overriding steps.
110 destupdatestepmap = {'evolution': _destupdateobs,
110 destupdatestepmap = {'evolution': _destupdateobs,
111 'bookmark': _destupdatebook,
111 'bookmark': _destupdatebook,
112 'branch': _destupdatebranch,
112 'branch': _destupdatebranch,
113 }
113 }
114
114
115 def destupdate(repo, clean=False, check=False):
115 def destupdate(repo, clean=False, check=False):
116 """destination for bare update operation
116 """destination for bare update operation
117
117
118 return (rev, movemark, activemark)
118 return (rev, movemark, activemark)
119
119
120 - rev: the revision to update to,
120 - rev: the revision to update to,
121 - movemark: node to move the active bookmark from
121 - movemark: node to move the active bookmark from
122 (cf bookmark.calculate update),
122 (cf bookmark.calculate update),
123 - activemark: a bookmark to activate at the end of the update.
123 - activemark: a bookmark to activate at the end of the update.
124 """
124 """
125 node = movemark = activemark = None
125 node = movemark = activemark = None
126
126
127 for step in destupdatesteps:
127 for step in destupdatesteps:
128 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
128 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
129 if node is not None:
129 if node is not None:
130 break
130 break
131 rev = repo[node].rev()
131 rev = repo[node].rev()
132
132
133 _destupdatevalidate(repo, rev, clean, check)
133 _destupdatevalidate(repo, rev, clean, check)
134
134
135 return rev, movemark, activemark
135 return rev, movemark, activemark
136
136
137 msgdestmerge = {
137 msgdestmerge = {
138 # too many matching divergent bookmark
138 # too many matching divergent bookmark
139 'toomanybookmarks':
139 'toomanybookmarks':
140 {'merge':
140 {'merge':
141 (_("multiple matching bookmarks to merge -"
141 (_("multiple matching bookmarks to merge -"
142 " please merge with an explicit rev or bookmark"),
142 " please merge with an explicit rev or bookmark"),
143 _("run 'hg heads' to see all heads")),
143 _("run 'hg heads' to see all heads")),
144 'rebase':
145 (_("multiple matching bookmarks to rebase -"
146 " please rebase to an explicit rev or bookmark"),
147 _("run 'hg heads' to see all heads")),
144 },
148 },
145 # no other matching divergent bookmark
149 # no other matching divergent bookmark
146 'nootherbookmarks':
150 'nootherbookmarks':
147 {'merge':
151 {'merge':
148 (_("no matching bookmark to merge - "
152 (_("no matching bookmark to merge - "
149 "please merge with an explicit rev or bookmark"),
153 "please merge with an explicit rev or bookmark"),
150 _("run 'hg heads' to see all heads")),
154 _("run 'hg heads' to see all heads")),
155 'rebase':
156 (_("no matching bookmark to rebase - "
157 "please rebase to an explicit rev or bookmark"),
158 _("run 'hg heads' to see all heads")),
151 },
159 },
152 # branch have too many unbookmarked heads, no obvious destination
160 # branch have too many unbookmarked heads, no obvious destination
153 'toomanyheads':
161 'toomanyheads':
154 {'merge':
162 {'merge':
155 (_("branch '%s' has %d heads - please merge with an explicit rev"),
163 (_("branch '%s' has %d heads - please merge with an explicit rev"),
156 _("run 'hg heads .' to see heads")),
164 _("run 'hg heads .' to see heads")),
165 'rebase':
166 (_("branch '%s' has %d heads - please rebase to an explicit rev"),
167 _("run 'hg heads .' to see heads")),
157 },
168 },
158 # branch have no other unbookmarked heads
169 # branch have no other unbookmarked heads
159 'bookmarkedheads':
170 'bookmarkedheads':
160 {'merge':
171 {'merge':
161 (_("heads are bookmarked - please merge with an explicit rev"),
172 (_("heads are bookmarked - please merge with an explicit rev"),
162 _("run 'hg heads' to see all heads")),
173 _("run 'hg heads' to see all heads")),
174 'rebase':
175 (_("heads are bookmarked - please rebase to an explicit rev"),
176 _("run 'hg heads' to see all heads")),
163 },
177 },
164 # branch have just a single heads, but there is other branches
178 # branch have just a single heads, but there is other branches
165 'nootherbranchheads':
179 'nootherbranchheads':
166 {'merge':
180 {'merge':
167 (_("branch '%s' has one head - please merge with an explicit rev"),
181 (_("branch '%s' has one head - please merge with an explicit rev"),
168 _("run 'hg heads' to see all heads")),
182 _("run 'hg heads' to see all heads")),
183 'rebase':
184 (_("branch '%s' has one head - please rebase to an explicit rev"),
185 _("run 'hg heads' to see all heads")),
169 },
186 },
170 # repository have a single head
187 # repository have a single head
171 'nootherheads':
188 'nootherheads':
172 {'merge':
189 {'merge':
173 (_('nothing to merge'),
190 (_('nothing to merge'),
174 None),
191 None),
192 'rebase':
193 (_('nothing to rebase'),
194 None),
175 },
195 },
176 # repository have a single head and we are not on it
196 # repository have a single head and we are not on it
177 'nootherheadsbehind':
197 'nootherheadsbehind':
178 {'merge':
198 {'merge':
179 (_('nothing to merge'),
199 (_('nothing to merge'),
180 _("use 'hg update' instead")),
200 _("use 'hg update' instead")),
201 'rebase':
202 (_('nothing to rebase'),
203 _("use 'hg update' instead")),
181 },
204 },
182 # We are not on a head
205 # We are not on a head
183 'notatheads':
206 'notatheads':
184 {'merge':
207 {'merge':
185 (_('working directory not at a head revision'),
208 (_('working directory not at a head revision'),
186 _("use 'hg update' or merge with an explicit revision"))
209 _("use 'hg update' or merge with an explicit revision")),
210 'rebase':
211 (_('working directory not at a head revision'),
212 _("use 'hg update' or rebase to an explicit revision"))
187 },
213 },
188 'emptysourceset':
214 'emptysourceset':
189 {'merge':
215 {'merge':
190 (_('source set is empty'),
216 (_('source set is empty'),
191 None)
217 None),
218 'rebase':
219 (_('source set is empty'),
220 None),
192 },
221 },
193 'multiplebranchessourceset':
222 'multiplebranchessourceset':
194 {'merge':
223 {'merge':
195 (_('source set is rooted in multiple branches'),
224 (_('source set is rooted in multiple branches'),
196 None)
225 None),
226 'rebase':
227 (_('rebaseset is rooted in multiple named branches'),
228 _('specify an explicit destination with --dest')),
197 },
229 },
198 }
230 }
199
231
200 def _destmergebook(repo, action='merge', sourceset=None):
232 def _destmergebook(repo, action='merge', sourceset=None):
201 """find merge destination in the active bookmark case"""
233 """find merge destination in the active bookmark case"""
202 node = None
234 node = None
203 bmheads = repo.bookmarkheads(repo._activebookmark)
235 bmheads = repo.bookmarkheads(repo._activebookmark)
204 curhead = repo[repo._activebookmark].node()
236 curhead = repo[repo._activebookmark].node()
205 if len(bmheads) == 2:
237 if len(bmheads) == 2:
206 if curhead == bmheads[0]:
238 if curhead == bmheads[0]:
207 node = bmheads[1]
239 node = bmheads[1]
208 else:
240 else:
209 node = bmheads[0]
241 node = bmheads[0]
210 elif len(bmheads) > 2:
242 elif len(bmheads) > 2:
211 msg, hint = msgdestmerge['toomanybookmarks'][action]
243 msg, hint = msgdestmerge['toomanybookmarks'][action]
212 raise error.ManyMergeDestAbort(msg, hint=hint)
244 raise error.ManyMergeDestAbort(msg, hint=hint)
213 elif len(bmheads) <= 1:
245 elif len(bmheads) <= 1:
214 msg, hint = msgdestmerge['nootherbookmarks'][action]
246 msg, hint = msgdestmerge['nootherbookmarks'][action]
215 raise error.NoMergeDestAbort(msg, hint=hint)
247 raise error.NoMergeDestAbort(msg, hint=hint)
216 assert node is not None
248 assert node is not None
217 return node
249 return node
218
250
219 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
251 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
220 """find merge destination based on branch heads"""
252 """find merge destination based on branch heads"""
221 node = None
253 node = None
222
254
223 if sourceset is None:
255 if sourceset is None:
224 sourceset = [repo[repo.dirstate.p1()].rev()]
256 sourceset = [repo[repo.dirstate.p1()].rev()]
225 branch = repo.dirstate.branch()
257 branch = repo.dirstate.branch()
226 elif not sourceset:
258 elif not sourceset:
227 msg, hint = msgdestmerge['emptysourceset'][action]
259 msg, hint = msgdestmerge['emptysourceset'][action]
228 raise error.NoMergeDestAbort(msg, hint=hint)
260 raise error.NoMergeDestAbort(msg, hint=hint)
229 else:
261 else:
230 branch = None
262 branch = None
231 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
263 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
232 if branch is not None and ctx.branch() != branch:
264 if branch is not None and ctx.branch() != branch:
233 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
265 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
234 raise error.ManyMergeDestAbort(msg, hint=hint)
266 raise error.ManyMergeDestAbort(msg, hint=hint)
235 branch = ctx.branch()
267 branch = ctx.branch()
236
268
237 bheads = repo.branchheads(branch)
269 bheads = repo.branchheads(branch)
238 onhead = repo.revs('%ld and %ln', sourceset, bheads)
270 onhead = repo.revs('%ld and %ln', sourceset, bheads)
239 if onheadcheck and not onhead:
271 if onheadcheck and not onhead:
240 # Case A: working copy if not on a head. (merge only)
272 # Case A: working copy if not on a head. (merge only)
241 #
273 #
242 # This is probably a user mistake We bailout pointing at 'hg update'
274 # This is probably a user mistake We bailout pointing at 'hg update'
243 if len(repo.heads()) <= 1:
275 if len(repo.heads()) <= 1:
244 msg, hint = msgdestmerge['nootherheadsbehind'][action]
276 msg, hint = msgdestmerge['nootherheadsbehind'][action]
245 else:
277 else:
246 msg, hint = msgdestmerge['notatheads'][action]
278 msg, hint = msgdestmerge['notatheads'][action]
247 raise error.Abort(msg, hint=hint)
279 raise error.Abort(msg, hint=hint)
248 # remove heads descendants of source from the set
280 # remove heads descendants of source from the set
249 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
281 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
250 # filters out bookmarked heads
282 # filters out bookmarked heads
251 nbhs = list(repo.revs('%ld - bookmark()', bheads))
283 nbhs = list(repo.revs('%ld - bookmark()', bheads))
252 if len(nbhs) > 1:
284 if len(nbhs) > 1:
253 # Case B: There is more than 1 other anonymous heads
285 # Case B: There is more than 1 other anonymous heads
254 #
286 #
255 # This means that there will be more than 1 candidate. This is
287 # This means that there will be more than 1 candidate. This is
256 # ambiguous. We abort asking the user to pick as explicit destination
288 # ambiguous. We abort asking the user to pick as explicit destination
257 # instead.
289 # instead.
258 msg, hint = msgdestmerge['toomanyheads'][action]
290 msg, hint = msgdestmerge['toomanyheads'][action]
259 msg %= (branch, len(bheads) + 1)
291 msg %= (branch, len(bheads) + 1)
260 raise error.ManyMergeDestAbort(msg, hint=hint)
292 raise error.ManyMergeDestAbort(msg, hint=hint)
261 elif not nbhs:
293 elif not nbhs:
262 # Case B: There is no other anonymous heads
294 # Case B: There is no other anonymous heads
263 #
295 #
264 # This means that there is no natural candidate to merge with.
296 # This means that there is no natural candidate to merge with.
265 # We abort, with various messages for various cases.
297 # We abort, with various messages for various cases.
266 if bheads:
298 if bheads:
267 msg, hint = msgdestmerge['bookmarkedheads'][action]
299 msg, hint = msgdestmerge['bookmarkedheads'][action]
268 elif len(repo.heads()) > 1:
300 elif len(repo.heads()) > 1:
269 msg, hint = msgdestmerge['nootherbranchheads'][action]
301 msg, hint = msgdestmerge['nootherbranchheads'][action]
270 msg %= branch
302 msg %= branch
271 elif not onhead:
303 elif not onhead:
272 # if 'onheadcheck == False' (rebase case),
304 # if 'onheadcheck == False' (rebase case),
273 # this was not caught in Case A.
305 # this was not caught in Case A.
274 msg, hint = msgdestmerge['nootherheadsbehind'][action]
306 msg, hint = msgdestmerge['nootherheadsbehind'][action]
275 else:
307 else:
276 msg, hint = msgdestmerge['nootherheads'][action]
308 msg, hint = msgdestmerge['nootherheads'][action]
277 raise error.NoMergeDestAbort(msg, hint=hint)
309 raise error.NoMergeDestAbort(msg, hint=hint)
278 else:
310 else:
279 node = nbhs[0]
311 node = nbhs[0]
280 assert node is not None
312 assert node is not None
281 return node
313 return node
282
314
283 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
315 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
284 """return the default destination for a merge
316 """return the default destination for a merge
285
317
286 (or raise exception about why it can't pick one)
318 (or raise exception about why it can't pick one)
287
319
288 :action: the action being performed, controls emitted error message
320 :action: the action being performed, controls emitted error message
289 """
321 """
290 if repo._activebookmark:
322 if repo._activebookmark:
291 node = _destmergebook(repo, action=action, sourceset=sourceset)
323 node = _destmergebook(repo, action=action, sourceset=sourceset)
292 else:
324 else:
293 node = _destmergebranch(repo, action=action, sourceset=sourceset,
325 node = _destmergebranch(repo, action=action, sourceset=sourceset,
294 onheadcheck=onheadcheck)
326 onheadcheck=onheadcheck)
295 return repo[node].rev()
327 return repo[node].rev()
296
328
297 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
329 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
298
330
299 def desthistedit(ui, repo):
331 def desthistedit(ui, repo):
300 """Default base revision to edit for `hg histedit`."""
332 """Default base revision to edit for `hg histedit`."""
301 # Avoid cycle: scmutil -> revset -> destutil
333 # Avoid cycle: scmutil -> revset -> destutil
302 from . import scmutil
334 from . import scmutil
303
335
304 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
336 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
305 if default:
337 if default:
306 revs = scmutil.revrange(repo, [default])
338 revs = scmutil.revrange(repo, [default])
307 if revs:
339 if revs:
308 # The revset supplied by the user may not be in ascending order nor
340 # The revset supplied by the user may not be in ascending order nor
309 # take the first revision. So do this manually.
341 # take the first revision. So do this manually.
310 revs.sort()
342 revs.sort()
311 return revs.first()
343 return revs.first()
312
344
313 return None
345 return None
314
346
315 def _statusotherbook(ui, repo):
347 def _statusotherbook(ui, repo):
316 bmheads = repo.bookmarkheads(repo._activebookmark)
348 bmheads = repo.bookmarkheads(repo._activebookmark)
317 curhead = repo[repo._activebookmark].node()
349 curhead = repo[repo._activebookmark].node()
318 if repo.revs('%n and parents()', curhead):
350 if repo.revs('%n and parents()', curhead):
319 # we are on the active bookmark
351 # we are on the active bookmark
320 bmheads = [b for b in bmheads if curhead != b]
352 bmheads = [b for b in bmheads if curhead != b]
321 if bmheads:
353 if bmheads:
322 msg = _('%i other divergent bookmarks for "%s"\n')
354 msg = _('%i other divergent bookmarks for "%s"\n')
323 ui.status(msg % (len(bmheads), repo._activebookmark))
355 ui.status(msg % (len(bmheads), repo._activebookmark))
324
356
325 def _statusotherbranchheads(ui, repo):
357 def _statusotherbranchheads(ui, repo):
326 currentbranch = repo.dirstate.branch()
358 currentbranch = repo.dirstate.branch()
327 heads = repo.branchheads(currentbranch)
359 heads = repo.branchheads(currentbranch)
328 l = len(heads)
360 l = len(heads)
329 if repo.revs('%ln and parents()', heads):
361 if repo.revs('%ln and parents()', heads):
330 # we are on a head
362 # we are on a head
331 heads = repo.revs('%ln - parents()', heads)
363 heads = repo.revs('%ln - parents()', heads)
332 if heads and l != len(heads):
364 if heads and l != len(heads):
333 ui.status(_('%i other heads for branch "%s"\n') %
365 ui.status(_('%i other heads for branch "%s"\n') %
334 (len(heads), currentbranch))
366 (len(heads), currentbranch))
335
367
336 def statusotherdests(ui, repo):
368 def statusotherdests(ui, repo):
337 """Print message about other head"""
369 """Print message about other head"""
338 # XXX we should probably include a hint:
370 # XXX we should probably include a hint:
339 # - about what to do
371 # - about what to do
340 # - how to see such heads
372 # - how to see such heads
341 if repo._activebookmark:
373 if repo._activebookmark:
342 _statusotherbook(ui, repo)
374 _statusotherbook(ui, repo)
343 else:
375 else:
344 _statusotherbranchheads(ui, repo)
376 _statusotherbranchheads(ui, repo)
@@ -1,1101 +1,1101
1 This file contains testcases that tend to be related to special cases or less
1 This file contains testcases that tend to be related to special cases or less
2 common commands affecting largefile.
2 common commands affecting largefile.
3
3
4 Each sections should be independent of each others.
4 Each sections should be independent of each others.
5
5
6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
7 $ mkdir "${USERCACHE}"
7 $ mkdir "${USERCACHE}"
8 $ cat >> $HGRCPATH <<EOF
8 $ cat >> $HGRCPATH <<EOF
9 > [extensions]
9 > [extensions]
10 > largefiles=
10 > largefiles=
11 > purge=
11 > purge=
12 > rebase=
12 > rebase=
13 > transplant=
13 > transplant=
14 > [phases]
14 > [phases]
15 > publish=False
15 > publish=False
16 > [largefiles]
16 > [largefiles]
17 > minsize=2
17 > minsize=2
18 > patterns=glob:**.dat
18 > patterns=glob:**.dat
19 > usercache=${USERCACHE}
19 > usercache=${USERCACHE}
20 > [hooks]
20 > [hooks]
21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
22 > EOF
22 > EOF
23
23
24
24
25
25
26 Test copies and moves from a directory other than root (issue3516)
26 Test copies and moves from a directory other than root (issue3516)
27 =========================================================================
27 =========================================================================
28
28
29 $ hg init lf_cpmv
29 $ hg init lf_cpmv
30 $ cd lf_cpmv
30 $ cd lf_cpmv
31 $ mkdir dira
31 $ mkdir dira
32 $ mkdir dira/dirb
32 $ mkdir dira/dirb
33 $ touch dira/dirb/largefile
33 $ touch dira/dirb/largefile
34 $ hg add --large dira/dirb/largefile
34 $ hg add --large dira/dirb/largefile
35 $ hg commit -m "added"
35 $ hg commit -m "added"
36 Invoking status precommit hook
36 Invoking status precommit hook
37 A dira/dirb/largefile
37 A dira/dirb/largefile
38 $ cd dira
38 $ cd dira
39 $ hg cp dirb/largefile foo/largefile
39 $ hg cp dirb/largefile foo/largefile
40
40
41 TODO: Ideally, this should mention the largefile, not the standin
41 TODO: Ideally, this should mention the largefile, not the standin
42 $ hg log -T '{rev}\n' --stat 'set:clean()'
42 $ hg log -T '{rev}\n' --stat 'set:clean()'
43 0
43 0
44 .hglf/dira/dirb/largefile | 1 +
44 .hglf/dira/dirb/largefile | 1 +
45 1 files changed, 1 insertions(+), 0 deletions(-)
45 1 files changed, 1 insertions(+), 0 deletions(-)
46
46
47 $ hg ci -m "deep copy"
47 $ hg ci -m "deep copy"
48 Invoking status precommit hook
48 Invoking status precommit hook
49 A dira/foo/largefile
49 A dira/foo/largefile
50 $ find . | sort
50 $ find . | sort
51 .
51 .
52 ./dirb
52 ./dirb
53 ./dirb/largefile
53 ./dirb/largefile
54 ./foo
54 ./foo
55 ./foo/largefile
55 ./foo/largefile
56 $ hg mv foo/largefile baz/largefile
56 $ hg mv foo/largefile baz/largefile
57 $ hg ci -m "moved"
57 $ hg ci -m "moved"
58 Invoking status precommit hook
58 Invoking status precommit hook
59 A dira/baz/largefile
59 A dira/baz/largefile
60 R dira/foo/largefile
60 R dira/foo/largefile
61 $ find . | sort
61 $ find . | sort
62 .
62 .
63 ./baz
63 ./baz
64 ./baz/largefile
64 ./baz/largefile
65 ./dirb
65 ./dirb
66 ./dirb/largefile
66 ./dirb/largefile
67 $ cd ..
67 $ cd ..
68 $ hg mv dira dirc
68 $ hg mv dira dirc
69 moving .hglf/dira/baz/largefile to .hglf/dirc/baz/largefile (glob)
69 moving .hglf/dira/baz/largefile to .hglf/dirc/baz/largefile (glob)
70 moving .hglf/dira/dirb/largefile to .hglf/dirc/dirb/largefile (glob)
70 moving .hglf/dira/dirb/largefile to .hglf/dirc/dirb/largefile (glob)
71 $ find * | sort
71 $ find * | sort
72 dirc
72 dirc
73 dirc/baz
73 dirc/baz
74 dirc/baz/largefile
74 dirc/baz/largefile
75 dirc/dirb
75 dirc/dirb
76 dirc/dirb/largefile
76 dirc/dirb/largefile
77
77
78 $ hg clone -q . ../fetch
78 $ hg clone -q . ../fetch
79 $ hg --config extensions.fetch= fetch ../fetch
79 $ hg --config extensions.fetch= fetch ../fetch
80 abort: uncommitted changes
80 abort: uncommitted changes
81 [255]
81 [255]
82 $ hg up -qC
82 $ hg up -qC
83 $ cd ..
83 $ cd ..
84
84
85 Clone a local repository owned by another user
85 Clone a local repository owned by another user
86 ===================================================
86 ===================================================
87
87
88 #if unix-permissions
88 #if unix-permissions
89
89
90 We have to simulate that here by setting $HOME and removing write permissions
90 We have to simulate that here by setting $HOME and removing write permissions
91 $ ORIGHOME="$HOME"
91 $ ORIGHOME="$HOME"
92 $ mkdir alice
92 $ mkdir alice
93 $ HOME="`pwd`/alice"
93 $ HOME="`pwd`/alice"
94 $ cd alice
94 $ cd alice
95 $ hg init pubrepo
95 $ hg init pubrepo
96 $ cd pubrepo
96 $ cd pubrepo
97 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
97 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
98 $ hg add --large a-large-file
98 $ hg add --large a-large-file
99 $ hg commit -m "Add a large file"
99 $ hg commit -m "Add a large file"
100 Invoking status precommit hook
100 Invoking status precommit hook
101 A a-large-file
101 A a-large-file
102 $ cd ..
102 $ cd ..
103 $ chmod -R a-w pubrepo
103 $ chmod -R a-w pubrepo
104 $ cd ..
104 $ cd ..
105 $ mkdir bob
105 $ mkdir bob
106 $ HOME="`pwd`/bob"
106 $ HOME="`pwd`/bob"
107 $ cd bob
107 $ cd bob
108 $ hg clone --pull ../alice/pubrepo pubrepo
108 $ hg clone --pull ../alice/pubrepo pubrepo
109 requesting all changes
109 requesting all changes
110 adding changesets
110 adding changesets
111 adding manifests
111 adding manifests
112 adding file changes
112 adding file changes
113 added 1 changesets with 1 changes to 1 files
113 added 1 changesets with 1 changes to 1 files
114 updating to branch default
114 updating to branch default
115 getting changed largefiles
115 getting changed largefiles
116 1 largefiles updated, 0 removed
116 1 largefiles updated, 0 removed
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 $ cd ..
118 $ cd ..
119 $ chmod -R u+w alice/pubrepo
119 $ chmod -R u+w alice/pubrepo
120 $ HOME="$ORIGHOME"
120 $ HOME="$ORIGHOME"
121
121
122 #endif
122 #endif
123
123
124
124
125 Symlink to a large largefile should behave the same as a symlink to a normal file
125 Symlink to a large largefile should behave the same as a symlink to a normal file
126 =====================================================================================
126 =====================================================================================
127
127
128 #if symlink
128 #if symlink
129
129
130 $ hg init largesymlink
130 $ hg init largesymlink
131 $ cd largesymlink
131 $ cd largesymlink
132 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
132 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
133 $ hg add --large largefile
133 $ hg add --large largefile
134 $ hg commit -m "commit a large file"
134 $ hg commit -m "commit a large file"
135 Invoking status precommit hook
135 Invoking status precommit hook
136 A largefile
136 A largefile
137 $ ln -s largefile largelink
137 $ ln -s largefile largelink
138 $ hg add largelink
138 $ hg add largelink
139 $ hg commit -m "commit a large symlink"
139 $ hg commit -m "commit a large symlink"
140 Invoking status precommit hook
140 Invoking status precommit hook
141 A largelink
141 A largelink
142 $ rm -f largelink
142 $ rm -f largelink
143 $ hg up >/dev/null
143 $ hg up >/dev/null
144 $ test -f largelink
144 $ test -f largelink
145 [1]
145 [1]
146 $ test -L largelink
146 $ test -L largelink
147 [1]
147 [1]
148 $ rm -f largelink # make next part of the test independent of the previous
148 $ rm -f largelink # make next part of the test independent of the previous
149 $ hg up -C >/dev/null
149 $ hg up -C >/dev/null
150 $ test -f largelink
150 $ test -f largelink
151 $ test -L largelink
151 $ test -L largelink
152 $ cd ..
152 $ cd ..
153
153
154 #endif
154 #endif
155
155
156
156
157 test for pattern matching on 'hg status':
157 test for pattern matching on 'hg status':
158 ==============================================
158 ==============================================
159
159
160
160
161 to boost performance, largefiles checks whether specified patterns are
161 to boost performance, largefiles checks whether specified patterns are
162 related to largefiles in working directory (NOT to STANDIN) or not.
162 related to largefiles in working directory (NOT to STANDIN) or not.
163
163
164 $ hg init statusmatch
164 $ hg init statusmatch
165 $ cd statusmatch
165 $ cd statusmatch
166
166
167 $ mkdir -p a/b/c/d
167 $ mkdir -p a/b/c/d
168 $ echo normal > a/b/c/d/e.normal.txt
168 $ echo normal > a/b/c/d/e.normal.txt
169 $ hg add a/b/c/d/e.normal.txt
169 $ hg add a/b/c/d/e.normal.txt
170 $ echo large > a/b/c/d/e.large.txt
170 $ echo large > a/b/c/d/e.large.txt
171 $ hg add --large a/b/c/d/e.large.txt
171 $ hg add --large a/b/c/d/e.large.txt
172 $ mkdir -p a/b/c/x
172 $ mkdir -p a/b/c/x
173 $ echo normal > a/b/c/x/y.normal.txt
173 $ echo normal > a/b/c/x/y.normal.txt
174 $ hg add a/b/c/x/y.normal.txt
174 $ hg add a/b/c/x/y.normal.txt
175 $ hg commit -m 'add files'
175 $ hg commit -m 'add files'
176 Invoking status precommit hook
176 Invoking status precommit hook
177 A a/b/c/d/e.large.txt
177 A a/b/c/d/e.large.txt
178 A a/b/c/d/e.normal.txt
178 A a/b/c/d/e.normal.txt
179 A a/b/c/x/y.normal.txt
179 A a/b/c/x/y.normal.txt
180
180
181 (1) no pattern: no performance boost
181 (1) no pattern: no performance boost
182 $ hg status -A
182 $ hg status -A
183 C a/b/c/d/e.large.txt
183 C a/b/c/d/e.large.txt
184 C a/b/c/d/e.normal.txt
184 C a/b/c/d/e.normal.txt
185 C a/b/c/x/y.normal.txt
185 C a/b/c/x/y.normal.txt
186
186
187 (2) pattern not related to largefiles: performance boost
187 (2) pattern not related to largefiles: performance boost
188 $ hg status -A a/b/c/x
188 $ hg status -A a/b/c/x
189 C a/b/c/x/y.normal.txt
189 C a/b/c/x/y.normal.txt
190
190
191 (3) pattern related to largefiles: no performance boost
191 (3) pattern related to largefiles: no performance boost
192 $ hg status -A a/b/c/d
192 $ hg status -A a/b/c/d
193 C a/b/c/d/e.large.txt
193 C a/b/c/d/e.large.txt
194 C a/b/c/d/e.normal.txt
194 C a/b/c/d/e.normal.txt
195
195
196 (4) pattern related to STANDIN (not to largefiles): performance boost
196 (4) pattern related to STANDIN (not to largefiles): performance boost
197 $ hg status -A .hglf/a
197 $ hg status -A .hglf/a
198 C .hglf/a/b/c/d/e.large.txt
198 C .hglf/a/b/c/d/e.large.txt
199
199
200 (5) mixed case: no performance boost
200 (5) mixed case: no performance boost
201 $ hg status -A a/b/c/x a/b/c/d
201 $ hg status -A a/b/c/x a/b/c/d
202 C a/b/c/d/e.large.txt
202 C a/b/c/d/e.large.txt
203 C a/b/c/d/e.normal.txt
203 C a/b/c/d/e.normal.txt
204 C a/b/c/x/y.normal.txt
204 C a/b/c/x/y.normal.txt
205
205
206 verify that largefiles doesn't break filesets
206 verify that largefiles doesn't break filesets
207
207
208 $ hg log --rev . --exclude "set:binary()"
208 $ hg log --rev . --exclude "set:binary()"
209 changeset: 0:41bd42f10efa
209 changeset: 0:41bd42f10efa
210 tag: tip
210 tag: tip
211 user: test
211 user: test
212 date: Thu Jan 01 00:00:00 1970 +0000
212 date: Thu Jan 01 00:00:00 1970 +0000
213 summary: add files
213 summary: add files
214
214
215 verify that large files in subrepos handled properly
215 verify that large files in subrepos handled properly
216 $ hg init subrepo
216 $ hg init subrepo
217 $ echo "subrepo = subrepo" > .hgsub
217 $ echo "subrepo = subrepo" > .hgsub
218 $ hg add .hgsub
218 $ hg add .hgsub
219 $ hg ci -m "add subrepo"
219 $ hg ci -m "add subrepo"
220 Invoking status precommit hook
220 Invoking status precommit hook
221 A .hgsub
221 A .hgsub
222 ? .hgsubstate
222 ? .hgsubstate
223 $ echo "rev 1" > subrepo/large.txt
223 $ echo "rev 1" > subrepo/large.txt
224 $ hg add --large subrepo/large.txt
224 $ hg add --large subrepo/large.txt
225 $ hg sum
225 $ hg sum
226 parent: 1:8ee150ea2e9c tip
226 parent: 1:8ee150ea2e9c tip
227 add subrepo
227 add subrepo
228 branch: default
228 branch: default
229 commit: 1 subrepos
229 commit: 1 subrepos
230 update: (current)
230 update: (current)
231 phases: 2 draft
231 phases: 2 draft
232 $ hg st
232 $ hg st
233 $ hg st -S
233 $ hg st -S
234 A subrepo/large.txt
234 A subrepo/large.txt
235 $ hg ci -S -m "commit top repo"
235 $ hg ci -S -m "commit top repo"
236 committing subrepository subrepo
236 committing subrepository subrepo
237 Invoking status precommit hook
237 Invoking status precommit hook
238 A large.txt
238 A large.txt
239 Invoking status precommit hook
239 Invoking status precommit hook
240 M .hgsubstate
240 M .hgsubstate
241 # No differences
241 # No differences
242 $ hg st -S
242 $ hg st -S
243 $ hg sum
243 $ hg sum
244 parent: 2:ce4cd0c527a6 tip
244 parent: 2:ce4cd0c527a6 tip
245 commit top repo
245 commit top repo
246 branch: default
246 branch: default
247 commit: (clean)
247 commit: (clean)
248 update: (current)
248 update: (current)
249 phases: 3 draft
249 phases: 3 draft
250 $ echo "rev 2" > subrepo/large.txt
250 $ echo "rev 2" > subrepo/large.txt
251 $ hg st -S
251 $ hg st -S
252 M subrepo/large.txt
252 M subrepo/large.txt
253 $ hg sum
253 $ hg sum
254 parent: 2:ce4cd0c527a6 tip
254 parent: 2:ce4cd0c527a6 tip
255 commit top repo
255 commit top repo
256 branch: default
256 branch: default
257 commit: 1 subrepos
257 commit: 1 subrepos
258 update: (current)
258 update: (current)
259 phases: 3 draft
259 phases: 3 draft
260 $ hg ci -m "this commit should fail without -S"
260 $ hg ci -m "this commit should fail without -S"
261 abort: uncommitted changes in subrepository 'subrepo'
261 abort: uncommitted changes in subrepository 'subrepo'
262 (use --subrepos for recursive commit)
262 (use --subrepos for recursive commit)
263 [255]
263 [255]
264
264
265 Add a normal file to the subrepo, then test archiving
265 Add a normal file to the subrepo, then test archiving
266
266
267 $ echo 'normal file' > subrepo/normal.txt
267 $ echo 'normal file' > subrepo/normal.txt
268 $ touch large.dat
268 $ touch large.dat
269 $ mv subrepo/large.txt subrepo/renamed-large.txt
269 $ mv subrepo/large.txt subrepo/renamed-large.txt
270 $ hg addremove -S --dry-run
270 $ hg addremove -S --dry-run
271 adding large.dat as a largefile
271 adding large.dat as a largefile
272 removing subrepo/large.txt
272 removing subrepo/large.txt
273 adding subrepo/normal.txt
273 adding subrepo/normal.txt
274 adding subrepo/renamed-large.txt
274 adding subrepo/renamed-large.txt
275 $ hg status -S
275 $ hg status -S
276 ! subrepo/large.txt
276 ! subrepo/large.txt
277 ? large.dat
277 ? large.dat
278 ? subrepo/normal.txt
278 ? subrepo/normal.txt
279 ? subrepo/renamed-large.txt
279 ? subrepo/renamed-large.txt
280
280
281 $ hg addremove --dry-run subrepo
281 $ hg addremove --dry-run subrepo
282 removing subrepo/large.txt (glob)
282 removing subrepo/large.txt (glob)
283 adding subrepo/normal.txt (glob)
283 adding subrepo/normal.txt (glob)
284 adding subrepo/renamed-large.txt (glob)
284 adding subrepo/renamed-large.txt (glob)
285 $ hg status -S
285 $ hg status -S
286 ! subrepo/large.txt
286 ! subrepo/large.txt
287 ? large.dat
287 ? large.dat
288 ? subrepo/normal.txt
288 ? subrepo/normal.txt
289 ? subrepo/renamed-large.txt
289 ? subrepo/renamed-large.txt
290 $ cd ..
290 $ cd ..
291
291
292 $ hg -R statusmatch addremove --dry-run statusmatch/subrepo
292 $ hg -R statusmatch addremove --dry-run statusmatch/subrepo
293 removing statusmatch/subrepo/large.txt (glob)
293 removing statusmatch/subrepo/large.txt (glob)
294 adding statusmatch/subrepo/normal.txt (glob)
294 adding statusmatch/subrepo/normal.txt (glob)
295 adding statusmatch/subrepo/renamed-large.txt (glob)
295 adding statusmatch/subrepo/renamed-large.txt (glob)
296 $ hg -R statusmatch status -S
296 $ hg -R statusmatch status -S
297 ! subrepo/large.txt
297 ! subrepo/large.txt
298 ? large.dat
298 ? large.dat
299 ? subrepo/normal.txt
299 ? subrepo/normal.txt
300 ? subrepo/renamed-large.txt
300 ? subrepo/renamed-large.txt
301
301
302 $ hg -R statusmatch addremove --dry-run -S
302 $ hg -R statusmatch addremove --dry-run -S
303 adding large.dat as a largefile
303 adding large.dat as a largefile
304 removing subrepo/large.txt
304 removing subrepo/large.txt
305 adding subrepo/normal.txt
305 adding subrepo/normal.txt
306 adding subrepo/renamed-large.txt
306 adding subrepo/renamed-large.txt
307 $ cd statusmatch
307 $ cd statusmatch
308
308
309 $ mv subrepo/renamed-large.txt subrepo/large.txt
309 $ mv subrepo/renamed-large.txt subrepo/large.txt
310 $ hg addremove subrepo
310 $ hg addremove subrepo
311 adding subrepo/normal.txt (glob)
311 adding subrepo/normal.txt (glob)
312 $ hg forget subrepo/normal.txt
312 $ hg forget subrepo/normal.txt
313
313
314 $ hg addremove -S
314 $ hg addremove -S
315 adding large.dat as a largefile
315 adding large.dat as a largefile
316 adding subrepo/normal.txt
316 adding subrepo/normal.txt
317 $ rm large.dat
317 $ rm large.dat
318
318
319 $ hg addremove subrepo
319 $ hg addremove subrepo
320 $ hg addremove -S
320 $ hg addremove -S
321 removing large.dat
321 removing large.dat
322
322
323 Lock in subrepo, otherwise the change isn't archived
323 Lock in subrepo, otherwise the change isn't archived
324
324
325 $ hg ci -S -m "add normal file to top level"
325 $ hg ci -S -m "add normal file to top level"
326 committing subrepository subrepo
326 committing subrepository subrepo
327 Invoking status precommit hook
327 Invoking status precommit hook
328 M large.txt
328 M large.txt
329 A normal.txt
329 A normal.txt
330 Invoking status precommit hook
330 Invoking status precommit hook
331 M .hgsubstate
331 M .hgsubstate
332 $ hg archive -S ../lf_subrepo_archive
332 $ hg archive -S ../lf_subrepo_archive
333 $ find ../lf_subrepo_archive | sort
333 $ find ../lf_subrepo_archive | sort
334 ../lf_subrepo_archive
334 ../lf_subrepo_archive
335 ../lf_subrepo_archive/.hg_archival.txt
335 ../lf_subrepo_archive/.hg_archival.txt
336 ../lf_subrepo_archive/.hgsub
336 ../lf_subrepo_archive/.hgsub
337 ../lf_subrepo_archive/.hgsubstate
337 ../lf_subrepo_archive/.hgsubstate
338 ../lf_subrepo_archive/a
338 ../lf_subrepo_archive/a
339 ../lf_subrepo_archive/a/b
339 ../lf_subrepo_archive/a/b
340 ../lf_subrepo_archive/a/b/c
340 ../lf_subrepo_archive/a/b/c
341 ../lf_subrepo_archive/a/b/c/d
341 ../lf_subrepo_archive/a/b/c/d
342 ../lf_subrepo_archive/a/b/c/d/e.large.txt
342 ../lf_subrepo_archive/a/b/c/d/e.large.txt
343 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
343 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
344 ../lf_subrepo_archive/a/b/c/x
344 ../lf_subrepo_archive/a/b/c/x
345 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
345 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
346 ../lf_subrepo_archive/subrepo
346 ../lf_subrepo_archive/subrepo
347 ../lf_subrepo_archive/subrepo/large.txt
347 ../lf_subrepo_archive/subrepo/large.txt
348 ../lf_subrepo_archive/subrepo/normal.txt
348 ../lf_subrepo_archive/subrepo/normal.txt
349 $ cat ../lf_subrepo_archive/.hg_archival.txt
349 $ cat ../lf_subrepo_archive/.hg_archival.txt
350 repo: 41bd42f10efa43698cc02052ea0977771cba506d
350 repo: 41bd42f10efa43698cc02052ea0977771cba506d
351 node: d56a95e6522858bc08a724c4fe2bdee066d1c30b
351 node: d56a95e6522858bc08a724c4fe2bdee066d1c30b
352 branch: default
352 branch: default
353 latesttag: null
353 latesttag: null
354 latesttagdistance: 4
354 latesttagdistance: 4
355 changessincelatesttag: 4
355 changessincelatesttag: 4
356
356
357 Test update with subrepos.
357 Test update with subrepos.
358
358
359 $ hg update 0
359 $ hg update 0
360 getting changed largefiles
360 getting changed largefiles
361 0 largefiles updated, 1 removed
361 0 largefiles updated, 1 removed
362 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
362 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
363 $ hg status -S
363 $ hg status -S
364 $ hg update tip
364 $ hg update tip
365 getting changed largefiles
365 getting changed largefiles
366 1 largefiles updated, 0 removed
366 1 largefiles updated, 0 removed
367 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 $ hg status -S
368 $ hg status -S
369 # modify a large file
369 # modify a large file
370 $ echo "modified" > subrepo/large.txt
370 $ echo "modified" > subrepo/large.txt
371 $ hg st -S
371 $ hg st -S
372 M subrepo/large.txt
372 M subrepo/large.txt
373 # update -C should revert the change.
373 # update -C should revert the change.
374 $ hg update -C
374 $ hg update -C
375 getting changed largefiles
375 getting changed largefiles
376 1 largefiles updated, 0 removed
376 1 largefiles updated, 0 removed
377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 $ hg status -S
378 $ hg status -S
379
379
380 $ hg forget -v subrepo/large.txt
380 $ hg forget -v subrepo/large.txt
381 removing subrepo/large.txt (glob)
381 removing subrepo/large.txt (glob)
382
382
383 Test reverting a forgotten file
383 Test reverting a forgotten file
384 $ hg revert -R subrepo subrepo/large.txt
384 $ hg revert -R subrepo subrepo/large.txt
385 $ hg status -SA subrepo/large.txt
385 $ hg status -SA subrepo/large.txt
386 C subrepo/large.txt
386 C subrepo/large.txt
387
387
388 $ hg rm -v subrepo/large.txt
388 $ hg rm -v subrepo/large.txt
389 removing subrepo/large.txt (glob)
389 removing subrepo/large.txt (glob)
390 $ hg revert -R subrepo subrepo/large.txt
390 $ hg revert -R subrepo subrepo/large.txt
391 $ rm subrepo/large.txt
391 $ rm subrepo/large.txt
392 $ hg addremove -S
392 $ hg addremove -S
393 removing subrepo/large.txt
393 removing subrepo/large.txt
394 $ hg st -S
394 $ hg st -S
395 R subrepo/large.txt
395 R subrepo/large.txt
396
396
397 Test archiving a revision that references a subrepo that is not yet
397 Test archiving a revision that references a subrepo that is not yet
398 cloned (see test-subrepo-recursion.t):
398 cloned (see test-subrepo-recursion.t):
399
399
400 $ hg clone -U . ../empty
400 $ hg clone -U . ../empty
401 $ cd ../empty
401 $ cd ../empty
402 $ hg archive --subrepos -r tip ../archive.tar.gz
402 $ hg archive --subrepos -r tip ../archive.tar.gz
403 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
403 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
404 $ cd ..
404 $ cd ..
405
405
406
406
407
407
408
408
409
409
410
410
411 Test addremove, forget and others
411 Test addremove, forget and others
412 ==============================================
412 ==============================================
413
413
414 Test that addremove picks up largefiles prior to the initial commit (issue3541)
414 Test that addremove picks up largefiles prior to the initial commit (issue3541)
415
415
416 $ hg init addrm2
416 $ hg init addrm2
417 $ cd addrm2
417 $ cd addrm2
418 $ touch large.dat
418 $ touch large.dat
419 $ touch large2.dat
419 $ touch large2.dat
420 $ touch normal
420 $ touch normal
421 $ hg add --large large.dat
421 $ hg add --large large.dat
422 $ hg addremove -v
422 $ hg addremove -v
423 adding large2.dat as a largefile
423 adding large2.dat as a largefile
424 adding normal
424 adding normal
425
425
426 Test that forgetting all largefiles reverts to islfilesrepo() == False
426 Test that forgetting all largefiles reverts to islfilesrepo() == False
427 (addremove will add *.dat as normal files now)
427 (addremove will add *.dat as normal files now)
428 $ hg forget large.dat
428 $ hg forget large.dat
429 $ hg forget large2.dat
429 $ hg forget large2.dat
430 $ hg addremove -v
430 $ hg addremove -v
431 adding large.dat
431 adding large.dat
432 adding large2.dat
432 adding large2.dat
433
433
434 Test commit's addremove option prior to the first commit
434 Test commit's addremove option prior to the first commit
435 $ hg forget large.dat
435 $ hg forget large.dat
436 $ hg forget large2.dat
436 $ hg forget large2.dat
437 $ hg add --large large.dat
437 $ hg add --large large.dat
438 $ hg ci -Am "commit"
438 $ hg ci -Am "commit"
439 adding large2.dat as a largefile
439 adding large2.dat as a largefile
440 Invoking status precommit hook
440 Invoking status precommit hook
441 A large.dat
441 A large.dat
442 A large2.dat
442 A large2.dat
443 A normal
443 A normal
444 $ find .hglf | sort
444 $ find .hglf | sort
445 .hglf
445 .hglf
446 .hglf/large.dat
446 .hglf/large.dat
447 .hglf/large2.dat
447 .hglf/large2.dat
448
448
449 Test actions on largefiles using relative paths from subdir
449 Test actions on largefiles using relative paths from subdir
450
450
451 $ mkdir sub
451 $ mkdir sub
452 $ cd sub
452 $ cd sub
453 $ echo anotherlarge > anotherlarge
453 $ echo anotherlarge > anotherlarge
454 $ hg add --large anotherlarge
454 $ hg add --large anotherlarge
455 $ hg st
455 $ hg st
456 A sub/anotherlarge
456 A sub/anotherlarge
457 $ hg st anotherlarge
457 $ hg st anotherlarge
458 A anotherlarge
458 A anotherlarge
459 $ hg commit -m anotherlarge anotherlarge
459 $ hg commit -m anotherlarge anotherlarge
460 Invoking status precommit hook
460 Invoking status precommit hook
461 A sub/anotherlarge
461 A sub/anotherlarge
462 $ hg log anotherlarge
462 $ hg log anotherlarge
463 changeset: 1:9627a577c5e9
463 changeset: 1:9627a577c5e9
464 tag: tip
464 tag: tip
465 user: test
465 user: test
466 date: Thu Jan 01 00:00:00 1970 +0000
466 date: Thu Jan 01 00:00:00 1970 +0000
467 summary: anotherlarge
467 summary: anotherlarge
468
468
469 $ hg --debug log -T '{rev}: {desc}\n' ../sub/anotherlarge
469 $ hg --debug log -T '{rev}: {desc}\n' ../sub/anotherlarge
470 updated patterns: ['../.hglf/sub/../sub/anotherlarge', '../sub/anotherlarge']
470 updated patterns: ['../.hglf/sub/../sub/anotherlarge', '../sub/anotherlarge']
471 1: anotherlarge
471 1: anotherlarge
472
472
473 $ hg log -G anotherlarge
473 $ hg log -G anotherlarge
474 @ changeset: 1:9627a577c5e9
474 @ changeset: 1:9627a577c5e9
475 | tag: tip
475 | tag: tip
476 | user: test
476 | user: test
477 | date: Thu Jan 01 00:00:00 1970 +0000
477 | date: Thu Jan 01 00:00:00 1970 +0000
478 | summary: anotherlarge
478 | summary: anotherlarge
479 |
479 |
480
480
481 $ hg log glob:another*
481 $ hg log glob:another*
482 changeset: 1:9627a577c5e9
482 changeset: 1:9627a577c5e9
483 tag: tip
483 tag: tip
484 user: test
484 user: test
485 date: Thu Jan 01 00:00:00 1970 +0000
485 date: Thu Jan 01 00:00:00 1970 +0000
486 summary: anotherlarge
486 summary: anotherlarge
487
487
488 $ hg --debug log -T '{rev}: {desc}\n' -G glob:another*
488 $ hg --debug log -T '{rev}: {desc}\n' -G glob:another*
489 updated patterns: ['glob:../.hglf/sub/another*', 'glob:another*']
489 updated patterns: ['glob:../.hglf/sub/another*', 'glob:another*']
490 @ 1: anotherlarge
490 @ 1: anotherlarge
491 |
491 |
492
492
493 #if no-msys
493 #if no-msys
494 $ hg --debug log -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
494 $ hg --debug log -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
495 updated patterns: ['glob:../.hglf/sub/another*']
495 updated patterns: ['glob:../.hglf/sub/another*']
496 1: anotherlarge
496 1: anotherlarge
497
497
498 $ hg --debug log -G -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
498 $ hg --debug log -G -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
499 updated patterns: ['glob:../.hglf/sub/another*']
499 updated patterns: ['glob:../.hglf/sub/another*']
500 @ 1: anotherlarge
500 @ 1: anotherlarge
501 |
501 |
502 #endif
502 #endif
503
503
504 $ echo more >> anotherlarge
504 $ echo more >> anotherlarge
505 $ hg st .
505 $ hg st .
506 M anotherlarge
506 M anotherlarge
507 $ hg cat anotherlarge
507 $ hg cat anotherlarge
508 anotherlarge
508 anotherlarge
509 $ hg revert anotherlarge
509 $ hg revert anotherlarge
510 $ hg st
510 $ hg st
511 ? sub/anotherlarge.orig
511 ? sub/anotherlarge.orig
512
512
513 Test orig files go where we want them
513 Test orig files go where we want them
514 $ echo moremore >> anotherlarge
514 $ echo moremore >> anotherlarge
515 $ hg revert anotherlarge -v --config 'ui.origbackuppath=.hg/origbackups'
515 $ hg revert anotherlarge -v --config 'ui.origbackuppath=.hg/origbackups'
516 creating directory: $TESTTMP/addrm2/.hg/origbackups/.hglf/sub (glob)
516 creating directory: $TESTTMP/addrm2/.hg/origbackups/.hglf/sub (glob)
517 saving current version of ../.hglf/sub/anotherlarge as $TESTTMP/addrm2/.hg/origbackups/.hglf/sub/anotherlarge.orig (glob)
517 saving current version of ../.hglf/sub/anotherlarge as $TESTTMP/addrm2/.hg/origbackups/.hglf/sub/anotherlarge.orig (glob)
518 reverting ../.hglf/sub/anotherlarge (glob)
518 reverting ../.hglf/sub/anotherlarge (glob)
519 creating directory: $TESTTMP/addrm2/.hg/origbackups/sub (glob)
519 creating directory: $TESTTMP/addrm2/.hg/origbackups/sub (glob)
520 found 90c622cf65cebe75c5842f9136c459333faf392e in store
520 found 90c622cf65cebe75c5842f9136c459333faf392e in store
521 found 90c622cf65cebe75c5842f9136c459333faf392e in store
521 found 90c622cf65cebe75c5842f9136c459333faf392e in store
522 $ ls ../.hg/origbackups/sub
522 $ ls ../.hg/origbackups/sub
523 anotherlarge.orig
523 anotherlarge.orig
524 $ cd ..
524 $ cd ..
525
525
526 Test glob logging from the root dir
526 Test glob logging from the root dir
527 $ hg log glob:**another*
527 $ hg log glob:**another*
528 changeset: 1:9627a577c5e9
528 changeset: 1:9627a577c5e9
529 tag: tip
529 tag: tip
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
532 summary: anotherlarge
532 summary: anotherlarge
533
533
534 $ hg log -G glob:**another*
534 $ hg log -G glob:**another*
535 @ changeset: 1:9627a577c5e9
535 @ changeset: 1:9627a577c5e9
536 | tag: tip
536 | tag: tip
537 | user: test
537 | user: test
538 | date: Thu Jan 01 00:00:00 1970 +0000
538 | date: Thu Jan 01 00:00:00 1970 +0000
539 | summary: anotherlarge
539 | summary: anotherlarge
540 |
540 |
541
541
542 $ cd ..
542 $ cd ..
543
543
544 Log from outer space
544 Log from outer space
545 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/sub/anotherlarge'
545 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/sub/anotherlarge'
546 updated patterns: ['addrm2/.hglf/sub/anotherlarge', 'addrm2/sub/anotherlarge']
546 updated patterns: ['addrm2/.hglf/sub/anotherlarge', 'addrm2/sub/anotherlarge']
547 1: anotherlarge
547 1: anotherlarge
548 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/.hglf/sub/anotherlarge'
548 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/.hglf/sub/anotherlarge'
549 updated patterns: ['addrm2/.hglf/sub/anotherlarge']
549 updated patterns: ['addrm2/.hglf/sub/anotherlarge']
550 1: anotherlarge
550 1: anotherlarge
551
551
552
552
553 Check error message while exchange
553 Check error message while exchange
554 =========================================================
554 =========================================================
555
555
556 issue3651: summary/outgoing with largefiles shows "no remote repo"
556 issue3651: summary/outgoing with largefiles shows "no remote repo"
557 unexpectedly
557 unexpectedly
558
558
559 $ mkdir issue3651
559 $ mkdir issue3651
560 $ cd issue3651
560 $ cd issue3651
561
561
562 $ hg init src
562 $ hg init src
563 $ echo a > src/a
563 $ echo a > src/a
564 $ hg -R src add --large src/a
564 $ hg -R src add --large src/a
565 $ hg -R src commit -m '#0'
565 $ hg -R src commit -m '#0'
566 Invoking status precommit hook
566 Invoking status precommit hook
567 A a
567 A a
568
568
569 check messages when no remote repository is specified:
569 check messages when no remote repository is specified:
570 "no remote repo" route for "hg outgoing --large" is not tested here,
570 "no remote repo" route for "hg outgoing --large" is not tested here,
571 because it can't be reproduced easily.
571 because it can't be reproduced easily.
572
572
573 $ hg init clone1
573 $ hg init clone1
574 $ hg -R clone1 -q pull src
574 $ hg -R clone1 -q pull src
575 $ hg -R clone1 -q update
575 $ hg -R clone1 -q update
576 $ hg -R clone1 paths | grep default
576 $ hg -R clone1 paths | grep default
577 [1]
577 [1]
578
578
579 $ hg -R clone1 summary --large
579 $ hg -R clone1 summary --large
580 parent: 0:fc0bd45326d3 tip
580 parent: 0:fc0bd45326d3 tip
581 #0
581 #0
582 branch: default
582 branch: default
583 commit: (clean)
583 commit: (clean)
584 update: (current)
584 update: (current)
585 phases: 1 draft
585 phases: 1 draft
586 largefiles: (no remote repo)
586 largefiles: (no remote repo)
587
587
588 check messages when there is no files to upload:
588 check messages when there is no files to upload:
589
589
590 $ hg -q clone src clone2
590 $ hg -q clone src clone2
591 $ hg -R clone2 paths | grep default
591 $ hg -R clone2 paths | grep default
592 default = $TESTTMP/issue3651/src (glob)
592 default = $TESTTMP/issue3651/src (glob)
593
593
594 $ hg -R clone2 summary --large
594 $ hg -R clone2 summary --large
595 parent: 0:fc0bd45326d3 tip
595 parent: 0:fc0bd45326d3 tip
596 #0
596 #0
597 branch: default
597 branch: default
598 commit: (clean)
598 commit: (clean)
599 update: (current)
599 update: (current)
600 phases: 1 draft
600 phases: 1 draft
601 largefiles: (no files to upload)
601 largefiles: (no files to upload)
602 $ hg -R clone2 outgoing --large
602 $ hg -R clone2 outgoing --large
603 comparing with $TESTTMP/issue3651/src (glob)
603 comparing with $TESTTMP/issue3651/src (glob)
604 searching for changes
604 searching for changes
605 no changes found
605 no changes found
606 largefiles: no files to upload
606 largefiles: no files to upload
607 [1]
607 [1]
608
608
609 $ hg -R clone2 outgoing --large --graph --template "{rev}"
609 $ hg -R clone2 outgoing --large --graph --template "{rev}"
610 comparing with $TESTTMP/issue3651/src (glob)
610 comparing with $TESTTMP/issue3651/src (glob)
611 searching for changes
611 searching for changes
612 no changes found
612 no changes found
613 largefiles: no files to upload
613 largefiles: no files to upload
614
614
615 check messages when there are files to upload:
615 check messages when there are files to upload:
616
616
617 $ echo b > clone2/b
617 $ echo b > clone2/b
618 $ hg -R clone2 add --large clone2/b
618 $ hg -R clone2 add --large clone2/b
619 $ hg -R clone2 commit -m '#1'
619 $ hg -R clone2 commit -m '#1'
620 Invoking status precommit hook
620 Invoking status precommit hook
621 A b
621 A b
622 $ hg -R clone2 summary --large
622 $ hg -R clone2 summary --large
623 parent: 1:1acbe71ce432 tip
623 parent: 1:1acbe71ce432 tip
624 #1
624 #1
625 branch: default
625 branch: default
626 commit: (clean)
626 commit: (clean)
627 update: (current)
627 update: (current)
628 phases: 2 draft
628 phases: 2 draft
629 largefiles: 1 entities for 1 files to upload
629 largefiles: 1 entities for 1 files to upload
630 $ hg -R clone2 outgoing --large
630 $ hg -R clone2 outgoing --large
631 comparing with $TESTTMP/issue3651/src (glob)
631 comparing with $TESTTMP/issue3651/src (glob)
632 searching for changes
632 searching for changes
633 changeset: 1:1acbe71ce432
633 changeset: 1:1acbe71ce432
634 tag: tip
634 tag: tip
635 user: test
635 user: test
636 date: Thu Jan 01 00:00:00 1970 +0000
636 date: Thu Jan 01 00:00:00 1970 +0000
637 summary: #1
637 summary: #1
638
638
639 largefiles to upload (1 entities):
639 largefiles to upload (1 entities):
640 b
640 b
641
641
642 $ hg -R clone2 outgoing --large --graph --template "{rev}"
642 $ hg -R clone2 outgoing --large --graph --template "{rev}"
643 comparing with $TESTTMP/issue3651/src (glob)
643 comparing with $TESTTMP/issue3651/src (glob)
644 searching for changes
644 searching for changes
645 @ 1
645 @ 1
646
646
647 largefiles to upload (1 entities):
647 largefiles to upload (1 entities):
648 b
648 b
649
649
650
650
651 $ cp clone2/b clone2/b1
651 $ cp clone2/b clone2/b1
652 $ cp clone2/b clone2/b2
652 $ cp clone2/b clone2/b2
653 $ hg -R clone2 add --large clone2/b1 clone2/b2
653 $ hg -R clone2 add --large clone2/b1 clone2/b2
654 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
654 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
655 Invoking status precommit hook
655 Invoking status precommit hook
656 A b1
656 A b1
657 A b2
657 A b2
658 $ hg -R clone2 summary --large
658 $ hg -R clone2 summary --large
659 parent: 2:6095d0695d70 tip
659 parent: 2:6095d0695d70 tip
660 #2: add largefiles referring same entity
660 #2: add largefiles referring same entity
661 branch: default
661 branch: default
662 commit: (clean)
662 commit: (clean)
663 update: (current)
663 update: (current)
664 phases: 3 draft
664 phases: 3 draft
665 largefiles: 1 entities for 3 files to upload
665 largefiles: 1 entities for 3 files to upload
666 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
666 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
667 comparing with $TESTTMP/issue3651/src (glob)
667 comparing with $TESTTMP/issue3651/src (glob)
668 searching for changes
668 searching for changes
669 1:1acbe71ce432
669 1:1acbe71ce432
670 2:6095d0695d70
670 2:6095d0695d70
671 largefiles to upload (1 entities):
671 largefiles to upload (1 entities):
672 b
672 b
673 b1
673 b1
674 b2
674 b2
675
675
676 $ hg -R clone2 cat -r 1 clone2/.hglf/b
676 $ hg -R clone2 cat -r 1 clone2/.hglf/b
677 89e6c98d92887913cadf06b2adb97f26cde4849b
677 89e6c98d92887913cadf06b2adb97f26cde4849b
678 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
678 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
679 comparing with $TESTTMP/issue3651/src (glob)
679 comparing with $TESTTMP/issue3651/src (glob)
680 query 1; heads
680 query 1; heads
681 searching for changes
681 searching for changes
682 all remote heads known locally
682 all remote heads known locally
683 1:1acbe71ce432
683 1:1acbe71ce432
684 2:6095d0695d70
684 2:6095d0695d70
685 finding outgoing largefiles: 0/2 revision (0.00%)
685 finding outgoing largefiles: 0/2 revision (0.00%)
686 finding outgoing largefiles: 1/2 revision (50.00%)
686 finding outgoing largefiles: 1/2 revision (50.00%)
687 largefiles to upload (1 entities):
687 largefiles to upload (1 entities):
688 b
688 b
689 89e6c98d92887913cadf06b2adb97f26cde4849b
689 89e6c98d92887913cadf06b2adb97f26cde4849b
690 b1
690 b1
691 89e6c98d92887913cadf06b2adb97f26cde4849b
691 89e6c98d92887913cadf06b2adb97f26cde4849b
692 b2
692 b2
693 89e6c98d92887913cadf06b2adb97f26cde4849b
693 89e6c98d92887913cadf06b2adb97f26cde4849b
694
694
695
695
696 $ echo bbb > clone2/b
696 $ echo bbb > clone2/b
697 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
697 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
698 Invoking status precommit hook
698 Invoking status precommit hook
699 M b
699 M b
700 $ echo bbbb > clone2/b
700 $ echo bbbb > clone2/b
701 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
701 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
702 Invoking status precommit hook
702 Invoking status precommit hook
703 M b
703 M b
704 $ cp clone2/b1 clone2/b
704 $ cp clone2/b1 clone2/b
705 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
705 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
706 Invoking status precommit hook
706 Invoking status precommit hook
707 M b
707 M b
708 $ hg -R clone2 summary --large
708 $ hg -R clone2 summary --large
709 parent: 5:036794ea641c tip
709 parent: 5:036794ea641c tip
710 #5: refer existing largefile entity again
710 #5: refer existing largefile entity again
711 branch: default
711 branch: default
712 commit: (clean)
712 commit: (clean)
713 update: (current)
713 update: (current)
714 phases: 6 draft
714 phases: 6 draft
715 largefiles: 3 entities for 3 files to upload
715 largefiles: 3 entities for 3 files to upload
716 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
716 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
717 comparing with $TESTTMP/issue3651/src (glob)
717 comparing with $TESTTMP/issue3651/src (glob)
718 searching for changes
718 searching for changes
719 1:1acbe71ce432
719 1:1acbe71ce432
720 2:6095d0695d70
720 2:6095d0695d70
721 3:7983dce246cc
721 3:7983dce246cc
722 4:233f12ada4ae
722 4:233f12ada4ae
723 5:036794ea641c
723 5:036794ea641c
724 largefiles to upload (3 entities):
724 largefiles to upload (3 entities):
725 b
725 b
726 b1
726 b1
727 b2
727 b2
728
728
729 $ hg -R clone2 cat -r 3 clone2/.hglf/b
729 $ hg -R clone2 cat -r 3 clone2/.hglf/b
730 c801c9cfe94400963fcb683246217d5db77f9a9a
730 c801c9cfe94400963fcb683246217d5db77f9a9a
731 $ hg -R clone2 cat -r 4 clone2/.hglf/b
731 $ hg -R clone2 cat -r 4 clone2/.hglf/b
732 13f9ed0898e315bf59dc2973fec52037b6f441a2
732 13f9ed0898e315bf59dc2973fec52037b6f441a2
733 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
733 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
734 comparing with $TESTTMP/issue3651/src (glob)
734 comparing with $TESTTMP/issue3651/src (glob)
735 query 1; heads
735 query 1; heads
736 searching for changes
736 searching for changes
737 all remote heads known locally
737 all remote heads known locally
738 1:1acbe71ce432
738 1:1acbe71ce432
739 2:6095d0695d70
739 2:6095d0695d70
740 3:7983dce246cc
740 3:7983dce246cc
741 4:233f12ada4ae
741 4:233f12ada4ae
742 5:036794ea641c
742 5:036794ea641c
743 finding outgoing largefiles: 0/5 revision (0.00%)
743 finding outgoing largefiles: 0/5 revision (0.00%)
744 finding outgoing largefiles: 1/5 revision (20.00%)
744 finding outgoing largefiles: 1/5 revision (20.00%)
745 finding outgoing largefiles: 2/5 revision (40.00%)
745 finding outgoing largefiles: 2/5 revision (40.00%)
746 finding outgoing largefiles: 3/5 revision (60.00%)
746 finding outgoing largefiles: 3/5 revision (60.00%)
747 finding outgoing largefiles: 4/5 revision (80.00%)
747 finding outgoing largefiles: 4/5 revision (80.00%)
748 largefiles to upload (3 entities):
748 largefiles to upload (3 entities):
749 b
749 b
750 13f9ed0898e315bf59dc2973fec52037b6f441a2
750 13f9ed0898e315bf59dc2973fec52037b6f441a2
751 89e6c98d92887913cadf06b2adb97f26cde4849b
751 89e6c98d92887913cadf06b2adb97f26cde4849b
752 c801c9cfe94400963fcb683246217d5db77f9a9a
752 c801c9cfe94400963fcb683246217d5db77f9a9a
753 b1
753 b1
754 89e6c98d92887913cadf06b2adb97f26cde4849b
754 89e6c98d92887913cadf06b2adb97f26cde4849b
755 b2
755 b2
756 89e6c98d92887913cadf06b2adb97f26cde4849b
756 89e6c98d92887913cadf06b2adb97f26cde4849b
757
757
758
758
759 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
759 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
760 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
760 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
761
761
762 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
762 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
763 summary" and "hg outgoing", even though files in outgoing revision #2
763 summary" and "hg outgoing", even though files in outgoing revision #2
764 and #5 refer it.
764 and #5 refer it.
765
765
766 $ hg -R clone2 push -r 1 -q
766 $ hg -R clone2 push -r 1 -q
767 $ hg -R clone2 summary --large
767 $ hg -R clone2 summary --large
768 parent: 5:036794ea641c tip
768 parent: 5:036794ea641c tip
769 #5: refer existing largefile entity again
769 #5: refer existing largefile entity again
770 branch: default
770 branch: default
771 commit: (clean)
771 commit: (clean)
772 update: (current)
772 update: (current)
773 phases: 6 draft
773 phases: 6 draft
774 largefiles: 2 entities for 1 files to upload
774 largefiles: 2 entities for 1 files to upload
775 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
775 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
776 comparing with $TESTTMP/issue3651/src (glob)
776 comparing with $TESTTMP/issue3651/src (glob)
777 searching for changes
777 searching for changes
778 2:6095d0695d70
778 2:6095d0695d70
779 3:7983dce246cc
779 3:7983dce246cc
780 4:233f12ada4ae
780 4:233f12ada4ae
781 5:036794ea641c
781 5:036794ea641c
782 largefiles to upload (2 entities):
782 largefiles to upload (2 entities):
783 b
783 b
784
784
785 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
785 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
786 comparing with $TESTTMP/issue3651/src (glob)
786 comparing with $TESTTMP/issue3651/src (glob)
787 query 1; heads
787 query 1; heads
788 searching for changes
788 searching for changes
789 all remote heads known locally
789 all remote heads known locally
790 2:6095d0695d70
790 2:6095d0695d70
791 3:7983dce246cc
791 3:7983dce246cc
792 4:233f12ada4ae
792 4:233f12ada4ae
793 5:036794ea641c
793 5:036794ea641c
794 finding outgoing largefiles: 0/4 revision (0.00%)
794 finding outgoing largefiles: 0/4 revision (0.00%)
795 finding outgoing largefiles: 1/4 revision (25.00%)
795 finding outgoing largefiles: 1/4 revision (25.00%)
796 finding outgoing largefiles: 2/4 revision (50.00%)
796 finding outgoing largefiles: 2/4 revision (50.00%)
797 finding outgoing largefiles: 3/4 revision (75.00%)
797 finding outgoing largefiles: 3/4 revision (75.00%)
798 largefiles to upload (2 entities):
798 largefiles to upload (2 entities):
799 b
799 b
800 13f9ed0898e315bf59dc2973fec52037b6f441a2
800 13f9ed0898e315bf59dc2973fec52037b6f441a2
801 c801c9cfe94400963fcb683246217d5db77f9a9a
801 c801c9cfe94400963fcb683246217d5db77f9a9a
802
802
803
803
804 $ cd ..
804 $ cd ..
805
805
806 merge action 'd' for 'local renamed directory to d2/g' which has no filename
806 merge action 'd' for 'local renamed directory to d2/g' which has no filename
807 ==================================================================================
807 ==================================================================================
808
808
809 $ hg init merge-action
809 $ hg init merge-action
810 $ cd merge-action
810 $ cd merge-action
811 $ touch l
811 $ touch l
812 $ hg add --large l
812 $ hg add --large l
813 $ mkdir d1
813 $ mkdir d1
814 $ touch d1/f
814 $ touch d1/f
815 $ hg ci -Aqm0
815 $ hg ci -Aqm0
816 Invoking status precommit hook
816 Invoking status precommit hook
817 A d1/f
817 A d1/f
818 A l
818 A l
819 $ echo > d1/f
819 $ echo > d1/f
820 $ touch d1/g
820 $ touch d1/g
821 $ hg ci -Aqm1
821 $ hg ci -Aqm1
822 Invoking status precommit hook
822 Invoking status precommit hook
823 M d1/f
823 M d1/f
824 A d1/g
824 A d1/g
825 $ hg up -qr0
825 $ hg up -qr0
826 $ hg mv d1 d2
826 $ hg mv d1 d2
827 moving d1/f to d2/f (glob)
827 moving d1/f to d2/f (glob)
828 $ hg ci -qm2
828 $ hg ci -qm2
829 Invoking status precommit hook
829 Invoking status precommit hook
830 A d2/f
830 A d2/f
831 R d1/f
831 R d1/f
832 $ hg merge
832 $ hg merge
833 merging d2/f and d1/f to d2/f
833 merging d2/f and d1/f to d2/f
834 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
834 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
835 (branch merge, don't forget to commit)
835 (branch merge, don't forget to commit)
836 $ cd ..
836 $ cd ..
837
837
838
838
839 Merge conflicts:
839 Merge conflicts:
840 =====================
840 =====================
841
841
842 $ hg init merge
842 $ hg init merge
843 $ cd merge
843 $ cd merge
844 $ echo 0 > f-different
844 $ echo 0 > f-different
845 $ echo 0 > f-same
845 $ echo 0 > f-same
846 $ echo 0 > f-unchanged-1
846 $ echo 0 > f-unchanged-1
847 $ echo 0 > f-unchanged-2
847 $ echo 0 > f-unchanged-2
848 $ hg add --large *
848 $ hg add --large *
849 $ hg ci -m0
849 $ hg ci -m0
850 Invoking status precommit hook
850 Invoking status precommit hook
851 A f-different
851 A f-different
852 A f-same
852 A f-same
853 A f-unchanged-1
853 A f-unchanged-1
854 A f-unchanged-2
854 A f-unchanged-2
855 $ echo tmp1 > f-unchanged-1
855 $ echo tmp1 > f-unchanged-1
856 $ echo tmp1 > f-unchanged-2
856 $ echo tmp1 > f-unchanged-2
857 $ echo tmp1 > f-same
857 $ echo tmp1 > f-same
858 $ hg ci -m1
858 $ hg ci -m1
859 Invoking status precommit hook
859 Invoking status precommit hook
860 M f-same
860 M f-same
861 M f-unchanged-1
861 M f-unchanged-1
862 M f-unchanged-2
862 M f-unchanged-2
863 $ echo 2 > f-different
863 $ echo 2 > f-different
864 $ echo 0 > f-unchanged-1
864 $ echo 0 > f-unchanged-1
865 $ echo 1 > f-unchanged-2
865 $ echo 1 > f-unchanged-2
866 $ echo 1 > f-same
866 $ echo 1 > f-same
867 $ hg ci -m2
867 $ hg ci -m2
868 Invoking status precommit hook
868 Invoking status precommit hook
869 M f-different
869 M f-different
870 M f-same
870 M f-same
871 M f-unchanged-1
871 M f-unchanged-1
872 M f-unchanged-2
872 M f-unchanged-2
873 $ hg up -qr0
873 $ hg up -qr0
874 $ echo tmp2 > f-unchanged-1
874 $ echo tmp2 > f-unchanged-1
875 $ echo tmp2 > f-unchanged-2
875 $ echo tmp2 > f-unchanged-2
876 $ echo tmp2 > f-same
876 $ echo tmp2 > f-same
877 $ hg ci -m3
877 $ hg ci -m3
878 Invoking status precommit hook
878 Invoking status precommit hook
879 M f-same
879 M f-same
880 M f-unchanged-1
880 M f-unchanged-1
881 M f-unchanged-2
881 M f-unchanged-2
882 created new head
882 created new head
883 $ echo 1 > f-different
883 $ echo 1 > f-different
884 $ echo 1 > f-unchanged-1
884 $ echo 1 > f-unchanged-1
885 $ echo 0 > f-unchanged-2
885 $ echo 0 > f-unchanged-2
886 $ echo 1 > f-same
886 $ echo 1 > f-same
887 $ hg ci -m4
887 $ hg ci -m4
888 Invoking status precommit hook
888 Invoking status precommit hook
889 M f-different
889 M f-different
890 M f-same
890 M f-same
891 M f-unchanged-1
891 M f-unchanged-1
892 M f-unchanged-2
892 M f-unchanged-2
893 $ hg merge
893 $ hg merge
894 largefile f-different has a merge conflict
894 largefile f-different has a merge conflict
895 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
895 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
896 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
896 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
897 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
897 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
898 getting changed largefiles
898 getting changed largefiles
899 1 largefiles updated, 0 removed
899 1 largefiles updated, 0 removed
900 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
900 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
901 (branch merge, don't forget to commit)
901 (branch merge, don't forget to commit)
902 $ cat f-different
902 $ cat f-different
903 1
903 1
904 $ cat f-same
904 $ cat f-same
905 1
905 1
906 $ cat f-unchanged-1
906 $ cat f-unchanged-1
907 1
907 1
908 $ cat f-unchanged-2
908 $ cat f-unchanged-2
909 1
909 1
910 $ cd ..
910 $ cd ..
911
911
912 Test largefile insulation (do not enabled a side effect
912 Test largefile insulation (do not enabled a side effect
913 ========================================================
913 ========================================================
914
914
915 Check whether "largefiles" feature is supported only in repositories
915 Check whether "largefiles" feature is supported only in repositories
916 enabling largefiles extension.
916 enabling largefiles extension.
917
917
918 $ mkdir individualenabling
918 $ mkdir individualenabling
919 $ cd individualenabling
919 $ cd individualenabling
920
920
921 $ hg init enabledlocally
921 $ hg init enabledlocally
922 $ echo large > enabledlocally/large
922 $ echo large > enabledlocally/large
923 $ hg -R enabledlocally add --large enabledlocally/large
923 $ hg -R enabledlocally add --large enabledlocally/large
924 $ hg -R enabledlocally commit -m '#0'
924 $ hg -R enabledlocally commit -m '#0'
925 Invoking status precommit hook
925 Invoking status precommit hook
926 A large
926 A large
927
927
928 $ hg init notenabledlocally
928 $ hg init notenabledlocally
929 $ echo large > notenabledlocally/large
929 $ echo large > notenabledlocally/large
930 $ hg -R notenabledlocally add --large notenabledlocally/large
930 $ hg -R notenabledlocally add --large notenabledlocally/large
931 $ hg -R notenabledlocally commit -m '#0'
931 $ hg -R notenabledlocally commit -m '#0'
932 Invoking status precommit hook
932 Invoking status precommit hook
933 A large
933 A large
934
934
935 $ cat >> $HGRCPATH <<EOF
935 $ cat >> $HGRCPATH <<EOF
936 > [extensions]
936 > [extensions]
937 > # disable globally
937 > # disable globally
938 > largefiles=!
938 > largefiles=!
939 > EOF
939 > EOF
940 $ cat >> enabledlocally/.hg/hgrc <<EOF
940 $ cat >> enabledlocally/.hg/hgrc <<EOF
941 > [extensions]
941 > [extensions]
942 > # enable locally
942 > # enable locally
943 > largefiles=
943 > largefiles=
944 > EOF
944 > EOF
945 $ hg -R enabledlocally root
945 $ hg -R enabledlocally root
946 $TESTTMP/individualenabling/enabledlocally (glob)
946 $TESTTMP/individualenabling/enabledlocally (glob)
947 $ hg -R notenabledlocally root
947 $ hg -R notenabledlocally root
948 abort: repository requires features unknown to this Mercurial: largefiles!
948 abort: repository requires features unknown to this Mercurial: largefiles!
949 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
949 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
950 [255]
950 [255]
951
951
952 $ hg init push-dst
952 $ hg init push-dst
953 $ hg -R enabledlocally push push-dst
953 $ hg -R enabledlocally push push-dst
954 pushing to push-dst
954 pushing to push-dst
955 abort: required features are not supported in the destination: largefiles
955 abort: required features are not supported in the destination: largefiles
956 [255]
956 [255]
957
957
958 $ hg init pull-src
958 $ hg init pull-src
959 $ hg -R pull-src pull enabledlocally
959 $ hg -R pull-src pull enabledlocally
960 pulling from enabledlocally
960 pulling from enabledlocally
961 abort: required features are not supported in the destination: largefiles
961 abort: required features are not supported in the destination: largefiles
962 [255]
962 [255]
963
963
964 $ hg clone enabledlocally clone-dst
964 $ hg clone enabledlocally clone-dst
965 abort: repository requires features unknown to this Mercurial: largefiles!
965 abort: repository requires features unknown to this Mercurial: largefiles!
966 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
966 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
967 [255]
967 [255]
968 $ test -d clone-dst
968 $ test -d clone-dst
969 [1]
969 [1]
970 $ hg clone --pull enabledlocally clone-pull-dst
970 $ hg clone --pull enabledlocally clone-pull-dst
971 abort: required features are not supported in the destination: largefiles
971 abort: required features are not supported in the destination: largefiles
972 [255]
972 [255]
973 $ test -d clone-pull-dst
973 $ test -d clone-pull-dst
974 [1]
974 [1]
975
975
976 #if serve
976 #if serve
977
977
978 Test largefiles specific peer setup, when largefiles is enabled
978 Test largefiles specific peer setup, when largefiles is enabled
979 locally (issue4109)
979 locally (issue4109)
980
980
981 $ hg showconfig extensions | grep largefiles
981 $ hg showconfig extensions | grep largefiles
982 extensions.largefiles=!
982 extensions.largefiles=!
983 $ mkdir -p $TESTTMP/individualenabling/usercache
983 $ mkdir -p $TESTTMP/individualenabling/usercache
984
984
985 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
985 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
986 $ cat hg.pid >> $DAEMON_PIDS
986 $ cat hg.pid >> $DAEMON_PIDS
987
987
988 $ hg init pull-dst
988 $ hg init pull-dst
989 $ cat > pull-dst/.hg/hgrc <<EOF
989 $ cat > pull-dst/.hg/hgrc <<EOF
990 > [extensions]
990 > [extensions]
991 > # enable locally
991 > # enable locally
992 > largefiles=
992 > largefiles=
993 > [largefiles]
993 > [largefiles]
994 > # ignore system cache to force largefiles specific wire proto access
994 > # ignore system cache to force largefiles specific wire proto access
995 > usercache=$TESTTMP/individualenabling/usercache
995 > usercache=$TESTTMP/individualenabling/usercache
996 > EOF
996 > EOF
997 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
997 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
998
998
999 $ killdaemons.py
999 $ killdaemons.py
1000 #endif
1000 #endif
1001
1001
1002 Test overridden functions work correctly even for repos disabling
1002 Test overridden functions work correctly even for repos disabling
1003 largefiles (issue4547)
1003 largefiles (issue4547)
1004
1004
1005 $ hg showconfig extensions | grep largefiles
1005 $ hg showconfig extensions | grep largefiles
1006 extensions.largefiles=!
1006 extensions.largefiles=!
1007
1007
1008 (test updating implied by clone)
1008 (test updating implied by clone)
1009
1009
1010 $ hg init enabled-but-no-largefiles
1010 $ hg init enabled-but-no-largefiles
1011 $ echo normal1 > enabled-but-no-largefiles/normal1
1011 $ echo normal1 > enabled-but-no-largefiles/normal1
1012 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
1012 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
1013 $ hg -R enabled-but-no-largefiles commit -m '#0@enabled-but-no-largefiles'
1013 $ hg -R enabled-but-no-largefiles commit -m '#0@enabled-but-no-largefiles'
1014 Invoking status precommit hook
1014 Invoking status precommit hook
1015 A normal1
1015 A normal1
1016 $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
1016 $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
1017 > [extensions]
1017 > [extensions]
1018 > # enable locally
1018 > # enable locally
1019 > largefiles=
1019 > largefiles=
1020 > EOF
1020 > EOF
1021 $ hg clone -q enabled-but-no-largefiles no-largefiles
1021 $ hg clone -q enabled-but-no-largefiles no-largefiles
1022
1022
1023 $ echo normal2 > enabled-but-no-largefiles/normal2
1023 $ echo normal2 > enabled-but-no-largefiles/normal2
1024 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
1024 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
1025 $ hg -R enabled-but-no-largefiles commit -m '#1@enabled-but-no-largefiles'
1025 $ hg -R enabled-but-no-largefiles commit -m '#1@enabled-but-no-largefiles'
1026 Invoking status precommit hook
1026 Invoking status precommit hook
1027 A normal2
1027 A normal2
1028
1028
1029 $ echo normal3 > no-largefiles/normal3
1029 $ echo normal3 > no-largefiles/normal3
1030 $ hg -R no-largefiles add no-largefiles/normal3
1030 $ hg -R no-largefiles add no-largefiles/normal3
1031 $ hg -R no-largefiles commit -m '#1@no-largefiles'
1031 $ hg -R no-largefiles commit -m '#1@no-largefiles'
1032 Invoking status precommit hook
1032 Invoking status precommit hook
1033 A normal3
1033 A normal3
1034
1034
1035 $ hg -R no-largefiles -q pull --rebase
1035 $ hg -R no-largefiles -q pull --rebase
1036 Invoking status precommit hook
1036 Invoking status precommit hook
1037 A normal3
1037 A normal3
1038
1038
1039 (test reverting)
1039 (test reverting)
1040
1040
1041 $ hg init subrepo-root
1041 $ hg init subrepo-root
1042 $ cat >> subrepo-root/.hg/hgrc <<EOF
1042 $ cat >> subrepo-root/.hg/hgrc <<EOF
1043 > [extensions]
1043 > [extensions]
1044 > # enable locally
1044 > # enable locally
1045 > largefiles=
1045 > largefiles=
1046 > EOF
1046 > EOF
1047 $ echo large > subrepo-root/large
1047 $ echo large > subrepo-root/large
1048 $ hg -R subrepo-root add --large subrepo-root/large
1048 $ hg -R subrepo-root add --large subrepo-root/large
1049 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1049 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1050 $ cat > subrepo-root/.hgsub <<EOF
1050 $ cat > subrepo-root/.hgsub <<EOF
1051 > no-largefiles = no-largefiles
1051 > no-largefiles = no-largefiles
1052 > EOF
1052 > EOF
1053 $ hg -R subrepo-root add subrepo-root/.hgsub
1053 $ hg -R subrepo-root add subrepo-root/.hgsub
1054 $ hg -R subrepo-root commit -m '#0'
1054 $ hg -R subrepo-root commit -m '#0'
1055 Invoking status precommit hook
1055 Invoking status precommit hook
1056 A .hgsub
1056 A .hgsub
1057 A large
1057 A large
1058 ? .hgsubstate
1058 ? .hgsubstate
1059 $ echo dirty >> subrepo-root/large
1059 $ echo dirty >> subrepo-root/large
1060 $ echo dirty >> subrepo-root/no-largefiles/normal1
1060 $ echo dirty >> subrepo-root/no-largefiles/normal1
1061 $ hg -R subrepo-root status -S
1061 $ hg -R subrepo-root status -S
1062 M large
1062 M large
1063 M no-largefiles/normal1
1063 M no-largefiles/normal1
1064 $ hg -R subrepo-root revert --all
1064 $ hg -R subrepo-root revert --all
1065 reverting subrepo-root/.hglf/large (glob)
1065 reverting subrepo-root/.hglf/large (glob)
1066 reverting subrepo no-largefiles
1066 reverting subrepo no-largefiles
1067 reverting subrepo-root/no-largefiles/normal1 (glob)
1067 reverting subrepo-root/no-largefiles/normal1 (glob)
1068
1068
1069 $ cd ..
1069 $ cd ..
1070
1070
1071
1071
1072 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1072 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1073 =========================================================================
1073 =========================================================================
1074
1074
1075 $ hg showconfig extensions | grep largefiles
1075 $ hg showconfig extensions | grep largefiles
1076 extensions.largefiles=!
1076 extensions.largefiles=!
1077
1077
1078 $ mkdir issue3861
1078 $ mkdir issue3861
1079 $ cd issue3861
1079 $ cd issue3861
1080 $ hg init src
1080 $ hg init src
1081 $ hg clone -q src dst
1081 $ hg clone -q src dst
1082 $ echo a > src/a
1082 $ echo a > src/a
1083 $ hg -R src commit -Aqm "#0"
1083 $ hg -R src commit -Aqm "#0"
1084 Invoking status precommit hook
1084 Invoking status precommit hook
1085 A a
1085 A a
1086
1086
1087 $ cat >> dst/.hg/hgrc <<EOF
1087 $ cat >> dst/.hg/hgrc <<EOF
1088 > [extensions]
1088 > [extensions]
1089 > largefiles=
1089 > largefiles=
1090 > EOF
1090 > EOF
1091 $ hg -R dst pull --rebase
1091 $ hg -R dst pull --rebase
1092 pulling from $TESTTMP/issue3861/src (glob)
1092 pulling from $TESTTMP/issue3861/src (glob)
1093 requesting all changes
1093 requesting all changes
1094 adding changesets
1094 adding changesets
1095 adding manifests
1095 adding manifests
1096 adding file changes
1096 adding file changes
1097 added 1 changesets with 1 changes to 1 files
1097 added 1 changesets with 1 changes to 1 files
1098 nothing to rebase - working directory parent is already an ancestor of destination bf5e395ced2c
1098 nothing to rebase - updating instead
1099 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1099 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1100
1100
1101 $ cd ..
1101 $ cd ..
@@ -1,390 +1,390
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 >
4 >
5 > [phases]
5 > [phases]
6 > publish=False
6 > publish=False
7 >
7 >
8 > [alias]
8 > [alias]
9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 > EOF
10 > EOF
11
11
12 $ hg init a
12 $ hg init a
13 $ cd a
13 $ cd a
14 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
14 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
15 adding changesets
15 adding changesets
16 adding manifests
16 adding manifests
17 adding file changes
17 adding file changes
18 added 8 changesets with 7 changes to 7 files (+2 heads)
18 added 8 changesets with 7 changes to 7 files (+2 heads)
19 (run 'hg heads' to see heads, 'hg merge' to merge)
19 (run 'hg heads' to see heads, 'hg merge' to merge)
20 $ hg up tip
20 $ hg up tip
21 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ cd ..
22 $ cd ..
23
23
24 $ hg clone -q -u . a a1
24 $ hg clone -q -u . a a1
25
25
26 $ cd a1
26 $ cd a1
27
27
28 $ hg update 3
28 $ hg update 3
29 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
30 $ hg branch dev-one
30 $ hg branch dev-one
31 marked working directory as branch dev-one
31 marked working directory as branch dev-one
32 (branches are permanent and global, did you want a bookmark?)
32 (branches are permanent and global, did you want a bookmark?)
33 $ hg ci -m 'dev-one named branch'
33 $ hg ci -m 'dev-one named branch'
34
34
35 $ hg update 7
35 $ hg update 7
36 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
36 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
37 $ hg branch dev-two
37 $ hg branch dev-two
38 marked working directory as branch dev-two
38 marked working directory as branch dev-two
39
39
40 $ echo x > x
40 $ echo x > x
41
41
42 $ hg add x
42 $ hg add x
43
43
44 $ hg ci -m 'dev-two named branch'
44 $ hg ci -m 'dev-two named branch'
45
45
46 $ hg tglog
46 $ hg tglog
47 @ 9: 'dev-two named branch' dev-two
47 @ 9: 'dev-two named branch' dev-two
48 |
48 |
49 | o 8: 'dev-one named branch' dev-one
49 | o 8: 'dev-one named branch' dev-one
50 | |
50 | |
51 o | 7: 'H'
51 o | 7: 'H'
52 | |
52 | |
53 +---o 6: 'G'
53 +---o 6: 'G'
54 | | |
54 | | |
55 o | | 5: 'F'
55 o | | 5: 'F'
56 | | |
56 | | |
57 +---o 4: 'E'
57 +---o 4: 'E'
58 | |
58 | |
59 | o 3: 'D'
59 | o 3: 'D'
60 | |
60 | |
61 | o 2: 'C'
61 | o 2: 'C'
62 | |
62 | |
63 | o 1: 'B'
63 | o 1: 'B'
64 |/
64 |/
65 o 0: 'A'
65 o 0: 'A'
66
66
67
67
68 Branch name containing a dash (issue3181)
68 Branch name containing a dash (issue3181)
69
69
70 $ hg rebase -b dev-two -d dev-one --keepbranches
70 $ hg rebase -b dev-two -d dev-one --keepbranches
71 rebasing 5:24b6387c8c8c "F"
71 rebasing 5:24b6387c8c8c "F"
72 rebasing 6:eea13746799a "G"
72 rebasing 6:eea13746799a "G"
73 rebasing 7:02de42196ebe "H"
73 rebasing 7:02de42196ebe "H"
74 rebasing 9:cb039b7cae8e "dev-two named branch" (tip)
74 rebasing 9:cb039b7cae8e "dev-two named branch" (tip)
75 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/24b6387c8c8c-24cb8001-backup.hg (glob)
75 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/24b6387c8c8c-24cb8001-backup.hg (glob)
76
76
77 $ hg tglog
77 $ hg tglog
78 @ 9: 'dev-two named branch' dev-two
78 @ 9: 'dev-two named branch' dev-two
79 |
79 |
80 o 8: 'H'
80 o 8: 'H'
81 |
81 |
82 | o 7: 'G'
82 | o 7: 'G'
83 |/|
83 |/|
84 o | 6: 'F'
84 o | 6: 'F'
85 | |
85 | |
86 o | 5: 'dev-one named branch' dev-one
86 o | 5: 'dev-one named branch' dev-one
87 | |
87 | |
88 | o 4: 'E'
88 | o 4: 'E'
89 | |
89 | |
90 o | 3: 'D'
90 o | 3: 'D'
91 | |
91 | |
92 o | 2: 'C'
92 o | 2: 'C'
93 | |
93 | |
94 o | 1: 'B'
94 o | 1: 'B'
95 |/
95 |/
96 o 0: 'A'
96 o 0: 'A'
97
97
98 $ hg rebase -s dev-one -d 0 --keepbranches
98 $ hg rebase -s dev-one -d 0 --keepbranches
99 rebasing 5:643fc9128048 "dev-one named branch"
99 rebasing 5:643fc9128048 "dev-one named branch"
100 rebasing 6:24de4aff8e28 "F"
100 rebasing 6:24de4aff8e28 "F"
101 rebasing 7:4b988a958030 "G"
101 rebasing 7:4b988a958030 "G"
102 rebasing 8:31d0e4ba75e6 "H"
102 rebasing 8:31d0e4ba75e6 "H"
103 rebasing 9:9e70cd31750f "dev-two named branch" (tip)
103 rebasing 9:9e70cd31750f "dev-two named branch" (tip)
104 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-c4ee9ef5-backup.hg (glob)
104 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-c4ee9ef5-backup.hg (glob)
105
105
106 $ hg tglog
106 $ hg tglog
107 @ 9: 'dev-two named branch' dev-two
107 @ 9: 'dev-two named branch' dev-two
108 |
108 |
109 o 8: 'H'
109 o 8: 'H'
110 |
110 |
111 | o 7: 'G'
111 | o 7: 'G'
112 |/|
112 |/|
113 o | 6: 'F'
113 o | 6: 'F'
114 | |
114 | |
115 o | 5: 'dev-one named branch' dev-one
115 o | 5: 'dev-one named branch' dev-one
116 | |
116 | |
117 | o 4: 'E'
117 | o 4: 'E'
118 |/
118 |/
119 | o 3: 'D'
119 | o 3: 'D'
120 | |
120 | |
121 | o 2: 'C'
121 | o 2: 'C'
122 | |
122 | |
123 | o 1: 'B'
123 | o 1: 'B'
124 |/
124 |/
125 o 0: 'A'
125 o 0: 'A'
126
126
127 $ hg update 3
127 $ hg update 3
128 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
128 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
129 $ hg branch -f dev-one
129 $ hg branch -f dev-one
130 marked working directory as branch dev-one
130 marked working directory as branch dev-one
131 $ hg ci -m 'dev-one named branch'
131 $ hg ci -m 'dev-one named branch'
132 created new head
132 created new head
133
133
134 $ hg tglog
134 $ hg tglog
135 @ 10: 'dev-one named branch' dev-one
135 @ 10: 'dev-one named branch' dev-one
136 |
136 |
137 | o 9: 'dev-two named branch' dev-two
137 | o 9: 'dev-two named branch' dev-two
138 | |
138 | |
139 | o 8: 'H'
139 | o 8: 'H'
140 | |
140 | |
141 | | o 7: 'G'
141 | | o 7: 'G'
142 | |/|
142 | |/|
143 | o | 6: 'F'
143 | o | 6: 'F'
144 | | |
144 | | |
145 | o | 5: 'dev-one named branch' dev-one
145 | o | 5: 'dev-one named branch' dev-one
146 | | |
146 | | |
147 | | o 4: 'E'
147 | | o 4: 'E'
148 | |/
148 | |/
149 o | 3: 'D'
149 o | 3: 'D'
150 | |
150 | |
151 o | 2: 'C'
151 o | 2: 'C'
152 | |
152 | |
153 o | 1: 'B'
153 o | 1: 'B'
154 |/
154 |/
155 o 0: 'A'
155 o 0: 'A'
156
156
157 $ hg rebase -b 'max(branch("dev-two"))' -d dev-one --keepbranches
157 $ hg rebase -b 'max(branch("dev-two"))' -d dev-one --keepbranches
158 rebasing 5:bc8139ee757c "dev-one named branch"
158 rebasing 5:bc8139ee757c "dev-one named branch"
159 note: rebase of 5:bc8139ee757c created no changes to commit
159 note: rebase of 5:bc8139ee757c created no changes to commit
160 rebasing 6:42aa3cf0fa7a "F"
160 rebasing 6:42aa3cf0fa7a "F"
161 rebasing 7:1a1e6f72ec38 "G"
161 rebasing 7:1a1e6f72ec38 "G"
162 rebasing 8:904590360559 "H"
162 rebasing 8:904590360559 "H"
163 rebasing 9:59c2e59309fe "dev-two named branch"
163 rebasing 9:59c2e59309fe "dev-two named branch"
164 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/bc8139ee757c-f11c1080-backup.hg (glob)
164 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/bc8139ee757c-f11c1080-backup.hg (glob)
165
165
166 $ hg tglog
166 $ hg tglog
167 o 9: 'dev-two named branch' dev-two
167 o 9: 'dev-two named branch' dev-two
168 |
168 |
169 o 8: 'H'
169 o 8: 'H'
170 |
170 |
171 | o 7: 'G'
171 | o 7: 'G'
172 |/|
172 |/|
173 o | 6: 'F'
173 o | 6: 'F'
174 | |
174 | |
175 @ | 5: 'dev-one named branch' dev-one
175 @ | 5: 'dev-one named branch' dev-one
176 | |
176 | |
177 | o 4: 'E'
177 | o 4: 'E'
178 | |
178 | |
179 o | 3: 'D'
179 o | 3: 'D'
180 | |
180 | |
181 o | 2: 'C'
181 o | 2: 'C'
182 | |
182 | |
183 o | 1: 'B'
183 o | 1: 'B'
184 |/
184 |/
185 o 0: 'A'
185 o 0: 'A'
186
186
187 $ hg rebase -s 'max(branch("dev-one"))' -d 0 --keepbranches
187 $ hg rebase -s 'max(branch("dev-one"))' -d 0 --keepbranches
188 rebasing 5:643fc9128048 "dev-one named branch"
188 rebasing 5:643fc9128048 "dev-one named branch"
189 rebasing 6:679f28760620 "F"
189 rebasing 6:679f28760620 "F"
190 rebasing 7:549f007a9f5f "G"
190 rebasing 7:549f007a9f5f "G"
191 rebasing 8:12b2bc666e20 "H"
191 rebasing 8:12b2bc666e20 "H"
192 rebasing 9:71325f8bc082 "dev-two named branch" (tip)
192 rebasing 9:71325f8bc082 "dev-two named branch" (tip)
193 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-6cdd1a52-backup.hg (glob)
193 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-6cdd1a52-backup.hg (glob)
194
194
195 $ hg tglog
195 $ hg tglog
196 o 9: 'dev-two named branch' dev-two
196 o 9: 'dev-two named branch' dev-two
197 |
197 |
198 o 8: 'H'
198 o 8: 'H'
199 |
199 |
200 | o 7: 'G'
200 | o 7: 'G'
201 |/|
201 |/|
202 o | 6: 'F'
202 o | 6: 'F'
203 | |
203 | |
204 @ | 5: 'dev-one named branch' dev-one
204 @ | 5: 'dev-one named branch' dev-one
205 | |
205 | |
206 | o 4: 'E'
206 | o 4: 'E'
207 |/
207 |/
208 | o 3: 'D'
208 | o 3: 'D'
209 | |
209 | |
210 | o 2: 'C'
210 | o 2: 'C'
211 | |
211 | |
212 | o 1: 'B'
212 | o 1: 'B'
213 |/
213 |/
214 o 0: 'A'
214 o 0: 'A'
215
215
216 $ hg up -r 0 > /dev/null
216 $ hg up -r 0 > /dev/null
217
217
218 Rebasing descendant onto ancestor across different named branches
218 Rebasing descendant onto ancestor across different named branches
219
219
220 $ hg rebase -s 1 -d 9 --keepbranches
220 $ hg rebase -s 1 -d 9 --keepbranches
221 rebasing 1:42ccdea3bb16 "B"
221 rebasing 1:42ccdea3bb16 "B"
222 rebasing 2:5fddd98957c8 "C"
222 rebasing 2:5fddd98957c8 "C"
223 rebasing 3:32af7686d403 "D"
223 rebasing 3:32af7686d403 "D"
224 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/42ccdea3bb16-3cb021d3-backup.hg (glob)
224 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/42ccdea3bb16-3cb021d3-backup.hg (glob)
225
225
226 $ hg tglog
226 $ hg tglog
227 o 9: 'D'
227 o 9: 'D'
228 |
228 |
229 o 8: 'C'
229 o 8: 'C'
230 |
230 |
231 o 7: 'B'
231 o 7: 'B'
232 |
232 |
233 o 6: 'dev-two named branch' dev-two
233 o 6: 'dev-two named branch' dev-two
234 |
234 |
235 o 5: 'H'
235 o 5: 'H'
236 |
236 |
237 | o 4: 'G'
237 | o 4: 'G'
238 |/|
238 |/|
239 o | 3: 'F'
239 o | 3: 'F'
240 | |
240 | |
241 o | 2: 'dev-one named branch' dev-one
241 o | 2: 'dev-one named branch' dev-one
242 | |
242 | |
243 | o 1: 'E'
243 | o 1: 'E'
244 |/
244 |/
245 @ 0: 'A'
245 @ 0: 'A'
246
246
247 $ hg rebase -s 5 -d 6
247 $ hg rebase -s 5 -d 6
248 abort: source is ancestor of destination
248 abort: source is ancestor of destination
249 [255]
249 [255]
250
250
251 $ hg rebase -s 6 -d 5
251 $ hg rebase -s 6 -d 5
252 rebasing 6:3944801ae4ea "dev-two named branch"
252 rebasing 6:3944801ae4ea "dev-two named branch"
253 rebasing 7:3bdb949809d9 "B"
253 rebasing 7:3bdb949809d9 "B"
254 rebasing 8:a0d543090fa4 "C"
254 rebasing 8:a0d543090fa4 "C"
255 rebasing 9:e9f862ce8bad "D" (tip)
255 rebasing 9:e9f862ce8bad "D" (tip)
256 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/3944801ae4ea-fb46ed74-backup.hg (glob)
256 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/3944801ae4ea-fb46ed74-backup.hg (glob)
257
257
258 $ hg tglog
258 $ hg tglog
259 o 9: 'D'
259 o 9: 'D'
260 |
260 |
261 o 8: 'C'
261 o 8: 'C'
262 |
262 |
263 o 7: 'B'
263 o 7: 'B'
264 |
264 |
265 o 6: 'dev-two named branch'
265 o 6: 'dev-two named branch'
266 |
266 |
267 o 5: 'H'
267 o 5: 'H'
268 |
268 |
269 | o 4: 'G'
269 | o 4: 'G'
270 |/|
270 |/|
271 o | 3: 'F'
271 o | 3: 'F'
272 | |
272 | |
273 o | 2: 'dev-one named branch' dev-one
273 o | 2: 'dev-one named branch' dev-one
274 | |
274 | |
275 | o 1: 'E'
275 | o 1: 'E'
276 |/
276 |/
277 @ 0: 'A'
277 @ 0: 'A'
278
278
279
279
280 Reopen branch by rebase
280 Reopen branch by rebase
281
281
282 $ hg up -qr3
282 $ hg up -qr3
283 $ hg branch -q b
283 $ hg branch -q b
284 $ hg ci -m 'create b'
284 $ hg ci -m 'create b'
285 $ hg ci -m 'close b' --close
285 $ hg ci -m 'close b' --close
286 $ hg rebase -b 8 -d b
286 $ hg rebase -b 8 -d b
287 reopening closed branch head 2b586e70108d
287 reopening closed branch head 2b586e70108d
288 rebasing 5:8e279d293175 "H"
288 rebasing 5:8e279d293175 "H"
289 rebasing 6:c57724c84928 "dev-two named branch"
289 rebasing 6:c57724c84928 "dev-two named branch"
290 rebasing 7:160b0930ccc6 "B"
290 rebasing 7:160b0930ccc6 "B"
291 rebasing 8:810110211f50 "C"
291 rebasing 8:810110211f50 "C"
292 rebasing 9:e522577ccdbd "D"
292 rebasing 9:e522577ccdbd "D"
293 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/8e279d293175-b023e27c-backup.hg (glob)
293 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/8e279d293175-b023e27c-backup.hg (glob)
294
294
295 $ cd ..
295 $ cd ..
296
296
297 Rebase to other head on branch
297 Rebase to other head on branch
298
298
299 Set up a case:
299 Set up a case:
300
300
301 $ hg init case1
301 $ hg init case1
302 $ cd case1
302 $ cd case1
303 $ touch f
303 $ touch f
304 $ hg ci -qAm0
304 $ hg ci -qAm0
305 $ hg branch -q b
305 $ hg branch -q b
306 $ echo >> f
306 $ echo >> f
307 $ hg ci -qAm 'b1'
307 $ hg ci -qAm 'b1'
308 $ hg up -qr -2
308 $ hg up -qr -2
309 $ hg branch -qf b
309 $ hg branch -qf b
310 $ hg ci -qm 'b2'
310 $ hg ci -qm 'b2'
311 $ hg up -qr -3
311 $ hg up -qr -3
312 $ hg branch -q c
312 $ hg branch -q c
313 $ hg ci -m 'c1'
313 $ hg ci -m 'c1'
314
314
315 $ hg tglog
315 $ hg tglog
316 @ 3: 'c1' c
316 @ 3: 'c1' c
317 |
317 |
318 | o 2: 'b2' b
318 | o 2: 'b2' b
319 |/
319 |/
320 | o 1: 'b1' b
320 | o 1: 'b1' b
321 |/
321 |/
322 o 0: '0'
322 o 0: '0'
323
323
324 $ hg clone -q . ../case2
324 $ hg clone -q . ../case2
325
325
326 rebase 'b2' to another lower branch head
326 rebase 'b2' to another lower branch head
327
327
328 $ hg up -qr 2
328 $ hg up -qr 2
329 $ hg rebase
329 $ hg rebase
330 nothing to rebase - working directory parent is also destination
330 rebasing 2:792845bb77ee "b2"
331 [1]
331 note: rebase of 2:792845bb77ee created no changes to commit
332 saved backup bundle to $TESTTMP/case1/.hg/strip-backup/792845bb77ee-627120ee-backup.hg (glob)
332 $ hg tglog
333 $ hg tglog
333 o 3: 'c1' c
334 o 2: 'c1' c
334 |
335 |
335 | @ 2: 'b2' b
336 | @ 1: 'b1' b
336 |/
337 | o 1: 'b1' b
338 |/
337 |/
339 o 0: '0'
338 o 0: '0'
340
339
341
340
342 rebase 'b1' on top of the tip of the branch ('b2') - ignoring the tip branch ('c1')
341 rebase 'b1' on top of the tip of the branch ('b2') - ignoring the tip branch ('c1')
343
342
344 $ cd ../case2
343 $ cd ../case2
345 $ hg up -qr 1
344 $ hg up -qr 1
346 $ hg rebase
345 $ hg rebase
347 rebasing 1:40039acb7ca5 "b1"
346 rebasing 1:40039acb7ca5 "b1"
348 saved backup bundle to $TESTTMP/case2/.hg/strip-backup/40039acb7ca5-342b72d1-backup.hg (glob)
347 saved backup bundle to $TESTTMP/case2/.hg/strip-backup/40039acb7ca5-342b72d1-backup.hg (glob)
349 $ hg tglog
348 $ hg tglog
350 @ 3: 'b1' b
349 @ 3: 'b1' b
351 |
350 |
352 | o 2: 'c1' c
351 | o 2: 'c1' c
353 | |
352 | |
354 o | 1: 'b2' b
353 o | 1: 'b2' b
355 |/
354 |/
356 o 0: '0'
355 o 0: '0'
357
356
358
357
359 rebase 'c1' to the branch head 'c2' that is closed
358 rebase 'c1' to the branch head 'c2' that is closed
360
359
361 $ hg branch -qf c
360 $ hg branch -qf c
362 $ hg ci -qm 'c2 closed' --close
361 $ hg ci -qm 'c2 closed' --close
363 $ hg up -qr 2
362 $ hg up -qr 2
364 $ hg tglog
363 $ hg tglog
365 _ 4: 'c2 closed' c
364 _ 4: 'c2 closed' c
366 |
365 |
367 o 3: 'b1' b
366 o 3: 'b1' b
368 |
367 |
369 | @ 2: 'c1' c
368 | @ 2: 'c1' c
370 | |
369 | |
371 o | 1: 'b2' b
370 o | 1: 'b2' b
372 |/
371 |/
373 o 0: '0'
372 o 0: '0'
374
373
375 $ hg rebase
374 $ hg rebase
376 nothing to rebase - working directory parent is also destination
375 abort: branch 'c' has one head - please rebase to an explicit rev
377 [1]
376 (run 'hg heads' to see all heads)
377 [255]
378 $ hg tglog
378 $ hg tglog
379 _ 4: 'c2 closed' c
379 _ 4: 'c2 closed' c
380 |
380 |
381 o 3: 'b1' b
381 o 3: 'b1' b
382 |
382 |
383 | @ 2: 'c1' c
383 | @ 2: 'c1' c
384 | |
384 | |
385 o | 1: 'b2' b
385 o | 1: 'b2' b
386 |/
386 |/
387 o 0: '0'
387 o 0: '0'
388
388
389
389
390 $ cd ..
390 $ cd ..
@@ -1,311 +1,311
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 >
4 >
5 > [alias]
5 > [alias]
6 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
6 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
7 > EOF
7 > EOF
8
8
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12
12
13 $ echo C1 > C1
13 $ echo C1 > C1
14 $ hg ci -Am C1
14 $ hg ci -Am C1
15 adding C1
15 adding C1
16
16
17 $ echo C2 > C2
17 $ echo C2 > C2
18 $ hg ci -Am C2
18 $ hg ci -Am C2
19 adding C2
19 adding C2
20
20
21 $ cd ..
21 $ cd ..
22
22
23 $ hg clone a b
23 $ hg clone a b
24 updating to branch default
24 updating to branch default
25 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
25 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
26
26
27 $ hg clone a c
27 $ hg clone a c
28 updating to branch default
28 updating to branch default
29 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
30
30
31 $ cd b
31 $ cd b
32
32
33 $ echo L1 > L1
33 $ echo L1 > L1
34 $ hg ci -Am L1
34 $ hg ci -Am L1
35 adding L1
35 adding L1
36
36
37
37
38 $ cd ../a
38 $ cd ../a
39
39
40 $ echo R1 > R1
40 $ echo R1 > R1
41 $ hg ci -Am R1
41 $ hg ci -Am R1
42 adding R1
42 adding R1
43
43
44
44
45 $ cd ../b
45 $ cd ../b
46
46
47 Now b has one revision to be pulled from a:
47 Now b has one revision to be pulled from a:
48
48
49 $ hg pull --rebase
49 $ hg pull --rebase
50 pulling from $TESTTMP/a (glob)
50 pulling from $TESTTMP/a (glob)
51 searching for changes
51 searching for changes
52 adding changesets
52 adding changesets
53 adding manifests
53 adding manifests
54 adding file changes
54 adding file changes
55 added 1 changesets with 1 changes to 1 files (+1 heads)
55 added 1 changesets with 1 changes to 1 files (+1 heads)
56 rebasing 2:ff8d69a621f9 "L1"
56 rebasing 2:ff8d69a621f9 "L1"
57 saved backup bundle to $TESTTMP/b/.hg/strip-backup/ff8d69a621f9-160fa373-backup.hg (glob)
57 saved backup bundle to $TESTTMP/b/.hg/strip-backup/ff8d69a621f9-160fa373-backup.hg (glob)
58
58
59 $ hg tglog
59 $ hg tglog
60 @ 3: 'L1'
60 @ 3: 'L1'
61 |
61 |
62 o 2: 'R1'
62 o 2: 'R1'
63 |
63 |
64 o 1: 'C2'
64 o 1: 'C2'
65 |
65 |
66 o 0: 'C1'
66 o 0: 'C1'
67
67
68 Re-run:
68 Re-run:
69
69
70 $ hg pull --rebase
70 $ hg pull --rebase
71 pulling from $TESTTMP/a (glob)
71 pulling from $TESTTMP/a (glob)
72 searching for changes
72 searching for changes
73 no changes found
73 no changes found
74
74
75
75
76 Invoke pull --rebase and nothing to rebase:
76 Invoke pull --rebase and nothing to rebase:
77
77
78 $ cd ../c
78 $ cd ../c
79
79
80 $ hg book norebase
80 $ hg book norebase
81 $ hg pull --rebase
81 $ hg pull --rebase
82 pulling from $TESTTMP/a (glob)
82 pulling from $TESTTMP/a (glob)
83 searching for changes
83 searching for changes
84 adding changesets
84 adding changesets
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 added 1 changesets with 1 changes to 1 files
87 added 1 changesets with 1 changes to 1 files
88 nothing to rebase - working directory parent is already an ancestor of destination 77ae9631bcca
88 nothing to rebase - updating instead
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 updating bookmark norebase
90 updating bookmark norebase
91
91
92 $ hg tglog -l 1
92 $ hg tglog -l 1
93 @ 2: 'R1'
93 @ 2: 'R1'
94 |
94 |
95
95
96 pull --rebase --update should ignore --update:
96 pull --rebase --update should ignore --update:
97
97
98 $ hg pull --rebase --update
98 $ hg pull --rebase --update
99 pulling from $TESTTMP/a (glob)
99 pulling from $TESTTMP/a (glob)
100 searching for changes
100 searching for changes
101 no changes found
101 no changes found
102
102
103 pull --rebase doesn't update if nothing has been pulled:
103 pull --rebase doesn't update if nothing has been pulled:
104
104
105 $ hg up -q 1
105 $ hg up -q 1
106
106
107 $ hg pull --rebase
107 $ hg pull --rebase
108 pulling from $TESTTMP/a (glob)
108 pulling from $TESTTMP/a (glob)
109 searching for changes
109 searching for changes
110 no changes found
110 no changes found
111
111
112 $ hg tglog -l 1
112 $ hg tglog -l 1
113 o 2: 'R1'
113 o 2: 'R1'
114 |
114 |
115
115
116 $ cd ..
116 $ cd ..
117
117
118 pull --rebase works when a specific revision is pulled (issue3619)
118 pull --rebase works when a specific revision is pulled (issue3619)
119
119
120 $ cd a
120 $ cd a
121 $ hg tglog
121 $ hg tglog
122 @ 2: 'R1'
122 @ 2: 'R1'
123 |
123 |
124 o 1: 'C2'
124 o 1: 'C2'
125 |
125 |
126 o 0: 'C1'
126 o 0: 'C1'
127
127
128 $ echo R2 > R2
128 $ echo R2 > R2
129 $ hg ci -Am R2
129 $ hg ci -Am R2
130 adding R2
130 adding R2
131 $ echo R3 > R3
131 $ echo R3 > R3
132 $ hg ci -Am R3
132 $ hg ci -Am R3
133 adding R3
133 adding R3
134 $ cd ../c
134 $ cd ../c
135 $ hg tglog
135 $ hg tglog
136 o 2: 'R1'
136 o 2: 'R1'
137 |
137 |
138 @ 1: 'C2'
138 @ 1: 'C2'
139 |
139 |
140 o 0: 'C1'
140 o 0: 'C1'
141
141
142 $ echo L1 > L1
142 $ echo L1 > L1
143 $ hg ci -Am L1
143 $ hg ci -Am L1
144 adding L1
144 adding L1
145 created new head
145 created new head
146 $ hg pull --rev tip --rebase
146 $ hg pull --rev tip --rebase
147 pulling from $TESTTMP/a (glob)
147 pulling from $TESTTMP/a (glob)
148 searching for changes
148 searching for changes
149 adding changesets
149 adding changesets
150 adding manifests
150 adding manifests
151 adding file changes
151 adding file changes
152 added 2 changesets with 2 changes to 2 files
152 added 2 changesets with 2 changes to 2 files
153 rebasing 3:ff8d69a621f9 "L1"
153 rebasing 3:ff8d69a621f9 "L1"
154 saved backup bundle to $TESTTMP/c/.hg/strip-backup/ff8d69a621f9-160fa373-backup.hg (glob)
154 saved backup bundle to $TESTTMP/c/.hg/strip-backup/ff8d69a621f9-160fa373-backup.hg (glob)
155 $ hg tglog
155 $ hg tglog
156 @ 5: 'L1'
156 @ 5: 'L1'
157 |
157 |
158 o 4: 'R3'
158 o 4: 'R3'
159 |
159 |
160 o 3: 'R2'
160 o 3: 'R2'
161 |
161 |
162 o 2: 'R1'
162 o 2: 'R1'
163 |
163 |
164 o 1: 'C2'
164 o 1: 'C2'
165 |
165 |
166 o 0: 'C1'
166 o 0: 'C1'
167
167
168 pull --rebase works with bundle2 turned on
168 pull --rebase works with bundle2 turned on
169
169
170 $ cd ../a
170 $ cd ../a
171 $ echo R4 > R4
171 $ echo R4 > R4
172 $ hg ci -Am R4
172 $ hg ci -Am R4
173 adding R4
173 adding R4
174 $ hg tglog
174 $ hg tglog
175 @ 5: 'R4'
175 @ 5: 'R4'
176 |
176 |
177 o 4: 'R3'
177 o 4: 'R3'
178 |
178 |
179 o 3: 'R2'
179 o 3: 'R2'
180 |
180 |
181 o 2: 'R1'
181 o 2: 'R1'
182 |
182 |
183 o 1: 'C2'
183 o 1: 'C2'
184 |
184 |
185 o 0: 'C1'
185 o 0: 'C1'
186
186
187 $ cd ../c
187 $ cd ../c
188 $ hg pull --rebase
188 $ hg pull --rebase
189 pulling from $TESTTMP/a (glob)
189 pulling from $TESTTMP/a (glob)
190 searching for changes
190 searching for changes
191 adding changesets
191 adding changesets
192 adding manifests
192 adding manifests
193 adding file changes
193 adding file changes
194 added 1 changesets with 1 changes to 1 files (+1 heads)
194 added 1 changesets with 1 changes to 1 files (+1 heads)
195 rebasing 5:518d153c0ba3 "L1"
195 rebasing 5:518d153c0ba3 "L1"
196 saved backup bundle to $TESTTMP/c/.hg/strip-backup/518d153c0ba3-73407f14-backup.hg (glob)
196 saved backup bundle to $TESTTMP/c/.hg/strip-backup/518d153c0ba3-73407f14-backup.hg (glob)
197 $ hg tglog
197 $ hg tglog
198 @ 6: 'L1'
198 @ 6: 'L1'
199 |
199 |
200 o 5: 'R4'
200 o 5: 'R4'
201 |
201 |
202 o 4: 'R3'
202 o 4: 'R3'
203 |
203 |
204 o 3: 'R2'
204 o 3: 'R2'
205 |
205 |
206 o 2: 'R1'
206 o 2: 'R1'
207 |
207 |
208 o 1: 'C2'
208 o 1: 'C2'
209 |
209 |
210 o 0: 'C1'
210 o 0: 'C1'
211
211
212
212
213 pull --rebase only update if there is nothing to rebase
213 pull --rebase only update if there is nothing to rebase
214
214
215 $ cd ../a
215 $ cd ../a
216 $ echo R5 > R5
216 $ echo R5 > R5
217 $ hg ci -Am R5
217 $ hg ci -Am R5
218 adding R5
218 adding R5
219 $ hg tglog
219 $ hg tglog
220 @ 6: 'R5'
220 @ 6: 'R5'
221 |
221 |
222 o 5: 'R4'
222 o 5: 'R4'
223 |
223 |
224 o 4: 'R3'
224 o 4: 'R3'
225 |
225 |
226 o 3: 'R2'
226 o 3: 'R2'
227 |
227 |
228 o 2: 'R1'
228 o 2: 'R1'
229 |
229 |
230 o 1: 'C2'
230 o 1: 'C2'
231 |
231 |
232 o 0: 'C1'
232 o 0: 'C1'
233
233
234 $ cd ../c
234 $ cd ../c
235 $ echo L2 > L2
235 $ echo L2 > L2
236 $ hg ci -Am L2
236 $ hg ci -Am L2
237 adding L2
237 adding L2
238 $ hg up 'desc(L1)'
238 $ hg up 'desc(L1)'
239 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
239 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
240 $ hg pull --rebase
240 $ hg pull --rebase
241 pulling from $TESTTMP/a (glob)
241 pulling from $TESTTMP/a (glob)
242 searching for changes
242 searching for changes
243 adding changesets
243 adding changesets
244 adding manifests
244 adding manifests
245 adding file changes
245 adding file changes
246 added 1 changesets with 1 changes to 1 files (+1 heads)
246 added 1 changesets with 1 changes to 1 files (+1 heads)
247 rebasing 6:0d0727eb7ce0 "L1"
247 rebasing 6:0d0727eb7ce0 "L1"
248 rebasing 7:c1f58876e3bf "L2"
248 rebasing 7:c1f58876e3bf "L2"
249 saved backup bundle to $TESTTMP/c/.hg/strip-backup/0d0727eb7ce0-ef61ccb2-backup.hg (glob)
249 saved backup bundle to $TESTTMP/c/.hg/strip-backup/0d0727eb7ce0-ef61ccb2-backup.hg (glob)
250 $ hg tglog
250 $ hg tglog
251 o 8: 'L2'
251 o 8: 'L2'
252 |
252 |
253 @ 7: 'L1'
253 @ 7: 'L1'
254 |
254 |
255 o 6: 'R5'
255 o 6: 'R5'
256 |
256 |
257 o 5: 'R4'
257 o 5: 'R4'
258 |
258 |
259 o 4: 'R3'
259 o 4: 'R3'
260 |
260 |
261 o 3: 'R2'
261 o 3: 'R2'
262 |
262 |
263 o 2: 'R1'
263 o 2: 'R1'
264 |
264 |
265 o 1: 'C2'
265 o 1: 'C2'
266 |
266 |
267 o 0: 'C1'
267 o 0: 'C1'
268
268
269
269
270 pull --rebase update (no rebase) use proper update:
270 pull --rebase update (no rebase) use proper update:
271
271
272 - warn about other head.
272 - warn about other head.
273
273
274 $ cd ../a
274 $ cd ../a
275 $ echo R6 > R6
275 $ echo R6 > R6
276 $ hg ci -Am R6
276 $ hg ci -Am R6
277 adding R6
277 adding R6
278 $ cd ../c
278 $ cd ../c
279 $ hg up 'desc(R5)'
279 $ hg up 'desc(R5)'
280 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
280 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
281 $ hg pull --rebase
281 $ hg pull --rebase
282 pulling from $TESTTMP/a (glob)
282 pulling from $TESTTMP/a (glob)
283 searching for changes
283 searching for changes
284 adding changesets
284 adding changesets
285 adding manifests
285 adding manifests
286 adding file changes
286 adding file changes
287 added 1 changesets with 1 changes to 1 files (+1 heads)
287 added 1 changesets with 1 changes to 1 files (+1 heads)
288 nothing to rebase - working directory parent is already an ancestor of destination 65bc164c1d9b
288 nothing to rebase - updating instead
289 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
290 1 other heads for branch "default"
290 1 other heads for branch "default"
291 $ hg tglog
291 $ hg tglog
292 @ 9: 'R6'
292 @ 9: 'R6'
293 |
293 |
294 | o 8: 'L2'
294 | o 8: 'L2'
295 | |
295 | |
296 | o 7: 'L1'
296 | o 7: 'L1'
297 |/
297 |/
298 o 6: 'R5'
298 o 6: 'R5'
299 |
299 |
300 o 5: 'R4'
300 o 5: 'R4'
301 |
301 |
302 o 4: 'R3'
302 o 4: 'R3'
303 |
303 |
304 o 3: 'R2'
304 o 3: 'R2'
305 |
305 |
306 o 2: 'R1'
306 o 2: 'R1'
307 |
307 |
308 o 1: 'C2'
308 o 1: 'C2'
309 |
309 |
310 o 0: 'C1'
310 o 0: 'C1'
311
311
@@ -1,830 +1,834
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 >
4 >
5 > [phases]
5 > [phases]
6 > publish=False
6 > publish=False
7 >
7 >
8 > [alias]
8 > [alias]
9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 > EOF
10 > EOF
11
11
12
12
13 $ hg init a
13 $ hg init a
14 $ cd a
14 $ cd a
15 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
15 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
16 adding changesets
16 adding changesets
17 adding manifests
17 adding manifests
18 adding file changes
18 adding file changes
19 added 8 changesets with 7 changes to 7 files (+2 heads)
19 added 8 changesets with 7 changes to 7 files (+2 heads)
20 (run 'hg heads' to see heads, 'hg merge' to merge)
20 (run 'hg heads' to see heads, 'hg merge' to merge)
21 $ hg up tip
21 $ hg up tip
22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 $ cd ..
23 $ cd ..
24
24
25
25
26 Rebasing
26 Rebasing
27 D onto H - simple rebase:
27 D onto H - simple rebase:
28 (this also tests that editor is invoked if '--edit' is specified, and that we
28 (this also tests that editor is invoked if '--edit' is specified, and that we
29 can abort or warn for colliding untracked files)
29 can abort or warn for colliding untracked files)
30
30
31 $ hg clone -q -u . a a1
31 $ hg clone -q -u . a a1
32 $ cd a1
32 $ cd a1
33
33
34 $ hg tglog
34 $ hg tglog
35 @ 7: 'H'
35 @ 7: 'H'
36 |
36 |
37 | o 6: 'G'
37 | o 6: 'G'
38 |/|
38 |/|
39 o | 5: 'F'
39 o | 5: 'F'
40 | |
40 | |
41 | o 4: 'E'
41 | o 4: 'E'
42 |/
42 |/
43 | o 3: 'D'
43 | o 3: 'D'
44 | |
44 | |
45 | o 2: 'C'
45 | o 2: 'C'
46 | |
46 | |
47 | o 1: 'B'
47 | o 1: 'B'
48 |/
48 |/
49 o 0: 'A'
49 o 0: 'A'
50
50
51
51
52 $ hg status --rev "3^1" --rev 3
52 $ hg status --rev "3^1" --rev 3
53 A D
53 A D
54 $ echo collide > D
54 $ echo collide > D
55 $ HGEDITOR=cat hg rebase -s 3 -d 7 --edit --config merge.checkunknown=warn
55 $ HGEDITOR=cat hg rebase -s 3 -d 7 --edit --config merge.checkunknown=warn
56 rebasing 3:32af7686d403 "D"
56 rebasing 3:32af7686d403 "D"
57 D: replacing untracked file
57 D: replacing untracked file
58 D
58 D
59
59
60
60
61 HG: Enter commit message. Lines beginning with 'HG:' are removed.
61 HG: Enter commit message. Lines beginning with 'HG:' are removed.
62 HG: Leave message empty to abort commit.
62 HG: Leave message empty to abort commit.
63 HG: --
63 HG: --
64 HG: user: Nicolas Dumazet <nicdumz.commits@gmail.com>
64 HG: user: Nicolas Dumazet <nicdumz.commits@gmail.com>
65 HG: branch 'default'
65 HG: branch 'default'
66 HG: added D
66 HG: added D
67 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/32af7686d403-6f7dface-backup.hg (glob)
67 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/32af7686d403-6f7dface-backup.hg (glob)
68 $ cat D.orig
68 $ cat D.orig
69 collide
69 collide
70 $ rm D.orig
70 $ rm D.orig
71
71
72 $ hg tglog
72 $ hg tglog
73 o 7: 'D'
73 o 7: 'D'
74 |
74 |
75 @ 6: 'H'
75 @ 6: 'H'
76 |
76 |
77 | o 5: 'G'
77 | o 5: 'G'
78 |/|
78 |/|
79 o | 4: 'F'
79 o | 4: 'F'
80 | |
80 | |
81 | o 3: 'E'
81 | o 3: 'E'
82 |/
82 |/
83 | o 2: 'C'
83 | o 2: 'C'
84 | |
84 | |
85 | o 1: 'B'
85 | o 1: 'B'
86 |/
86 |/
87 o 0: 'A'
87 o 0: 'A'
88
88
89 $ cd ..
89 $ cd ..
90
90
91
91
92 D onto F - intermediate point:
92 D onto F - intermediate point:
93 (this also tests that editor is not invoked if '--edit' is not specified, and
93 (this also tests that editor is not invoked if '--edit' is not specified, and
94 that we can ignore for colliding untracked files)
94 that we can ignore for colliding untracked files)
95
95
96 $ hg clone -q -u . a a2
96 $ hg clone -q -u . a a2
97 $ cd a2
97 $ cd a2
98 $ echo collide > D
98 $ echo collide > D
99
99
100 $ HGEDITOR=cat hg rebase -s 3 -d 5 --config merge.checkunknown=ignore
100 $ HGEDITOR=cat hg rebase -s 3 -d 5 --config merge.checkunknown=ignore
101 rebasing 3:32af7686d403 "D"
101 rebasing 3:32af7686d403 "D"
102 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/32af7686d403-6f7dface-backup.hg (glob)
102 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/32af7686d403-6f7dface-backup.hg (glob)
103 $ cat D.orig
103 $ cat D.orig
104 collide
104 collide
105 $ rm D.orig
105 $ rm D.orig
106
106
107 $ hg tglog
107 $ hg tglog
108 o 7: 'D'
108 o 7: 'D'
109 |
109 |
110 | @ 6: 'H'
110 | @ 6: 'H'
111 |/
111 |/
112 | o 5: 'G'
112 | o 5: 'G'
113 |/|
113 |/|
114 o | 4: 'F'
114 o | 4: 'F'
115 | |
115 | |
116 | o 3: 'E'
116 | o 3: 'E'
117 |/
117 |/
118 | o 2: 'C'
118 | o 2: 'C'
119 | |
119 | |
120 | o 1: 'B'
120 | o 1: 'B'
121 |/
121 |/
122 o 0: 'A'
122 o 0: 'A'
123
123
124 $ cd ..
124 $ cd ..
125
125
126
126
127 E onto H - skip of G:
127 E onto H - skip of G:
128 (this also tests that we can overwrite untracked files and don't create backups
128 (this also tests that we can overwrite untracked files and don't create backups
129 if they have the same contents)
129 if they have the same contents)
130
130
131 $ hg clone -q -u . a a3
131 $ hg clone -q -u . a a3
132 $ cd a3
132 $ cd a3
133 $ hg cat -r 4 E | tee E
133 $ hg cat -r 4 E | tee E
134 E
134 E
135
135
136 $ hg rebase -s 4 -d 7
136 $ hg rebase -s 4 -d 7
137 rebasing 4:9520eea781bc "E"
137 rebasing 4:9520eea781bc "E"
138 rebasing 6:eea13746799a "G"
138 rebasing 6:eea13746799a "G"
139 note: rebase of 6:eea13746799a created no changes to commit
139 note: rebase of 6:eea13746799a created no changes to commit
140 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/9520eea781bc-fcd8edd4-backup.hg (glob)
140 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/9520eea781bc-fcd8edd4-backup.hg (glob)
141 $ f E.orig
141 $ f E.orig
142 E.orig: file not found
142 E.orig: file not found
143
143
144 $ hg tglog
144 $ hg tglog
145 o 6: 'E'
145 o 6: 'E'
146 |
146 |
147 @ 5: 'H'
147 @ 5: 'H'
148 |
148 |
149 o 4: 'F'
149 o 4: 'F'
150 |
150 |
151 | o 3: 'D'
151 | o 3: 'D'
152 | |
152 | |
153 | o 2: 'C'
153 | o 2: 'C'
154 | |
154 | |
155 | o 1: 'B'
155 | o 1: 'B'
156 |/
156 |/
157 o 0: 'A'
157 o 0: 'A'
158
158
159 $ cd ..
159 $ cd ..
160
160
161
161
162 F onto E - rebase of a branching point (skip G):
162 F onto E - rebase of a branching point (skip G):
163
163
164 $ hg clone -q -u . a a4
164 $ hg clone -q -u . a a4
165 $ cd a4
165 $ cd a4
166
166
167 $ hg rebase -s 5 -d 4
167 $ hg rebase -s 5 -d 4
168 rebasing 5:24b6387c8c8c "F"
168 rebasing 5:24b6387c8c8c "F"
169 rebasing 6:eea13746799a "G"
169 rebasing 6:eea13746799a "G"
170 note: rebase of 6:eea13746799a created no changes to commit
170 note: rebase of 6:eea13746799a created no changes to commit
171 rebasing 7:02de42196ebe "H" (tip)
171 rebasing 7:02de42196ebe "H" (tip)
172 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/24b6387c8c8c-c3fe765d-backup.hg (glob)
172 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/24b6387c8c8c-c3fe765d-backup.hg (glob)
173
173
174 $ hg tglog
174 $ hg tglog
175 @ 6: 'H'
175 @ 6: 'H'
176 |
176 |
177 o 5: 'F'
177 o 5: 'F'
178 |
178 |
179 o 4: 'E'
179 o 4: 'E'
180 |
180 |
181 | o 3: 'D'
181 | o 3: 'D'
182 | |
182 | |
183 | o 2: 'C'
183 | o 2: 'C'
184 | |
184 | |
185 | o 1: 'B'
185 | o 1: 'B'
186 |/
186 |/
187 o 0: 'A'
187 o 0: 'A'
188
188
189 $ cd ..
189 $ cd ..
190
190
191
191
192 G onto H - merged revision having a parent in ancestors of target:
192 G onto H - merged revision having a parent in ancestors of target:
193
193
194 $ hg clone -q -u . a a5
194 $ hg clone -q -u . a a5
195 $ cd a5
195 $ cd a5
196
196
197 $ hg rebase -s 6 -d 7
197 $ hg rebase -s 6 -d 7
198 rebasing 6:eea13746799a "G"
198 rebasing 6:eea13746799a "G"
199 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/eea13746799a-883828ed-backup.hg (glob)
199 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/eea13746799a-883828ed-backup.hg (glob)
200
200
201 $ hg tglog
201 $ hg tglog
202 o 7: 'G'
202 o 7: 'G'
203 |\
203 |\
204 | @ 6: 'H'
204 | @ 6: 'H'
205 | |
205 | |
206 | o 5: 'F'
206 | o 5: 'F'
207 | |
207 | |
208 o | 4: 'E'
208 o | 4: 'E'
209 |/
209 |/
210 | o 3: 'D'
210 | o 3: 'D'
211 | |
211 | |
212 | o 2: 'C'
212 | o 2: 'C'
213 | |
213 | |
214 | o 1: 'B'
214 | o 1: 'B'
215 |/
215 |/
216 o 0: 'A'
216 o 0: 'A'
217
217
218 $ cd ..
218 $ cd ..
219
219
220
220
221 F onto B - G maintains E as parent:
221 F onto B - G maintains E as parent:
222
222
223 $ hg clone -q -u . a a6
223 $ hg clone -q -u . a a6
224 $ cd a6
224 $ cd a6
225
225
226 $ hg rebase -s 5 -d 1
226 $ hg rebase -s 5 -d 1
227 rebasing 5:24b6387c8c8c "F"
227 rebasing 5:24b6387c8c8c "F"
228 rebasing 6:eea13746799a "G"
228 rebasing 6:eea13746799a "G"
229 rebasing 7:02de42196ebe "H" (tip)
229 rebasing 7:02de42196ebe "H" (tip)
230 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/24b6387c8c8c-c3fe765d-backup.hg (glob)
230 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/24b6387c8c8c-c3fe765d-backup.hg (glob)
231
231
232 $ hg tglog
232 $ hg tglog
233 @ 7: 'H'
233 @ 7: 'H'
234 |
234 |
235 | o 6: 'G'
235 | o 6: 'G'
236 |/|
236 |/|
237 o | 5: 'F'
237 o | 5: 'F'
238 | |
238 | |
239 | o 4: 'E'
239 | o 4: 'E'
240 | |
240 | |
241 | | o 3: 'D'
241 | | o 3: 'D'
242 | | |
242 | | |
243 +---o 2: 'C'
243 +---o 2: 'C'
244 | |
244 | |
245 o | 1: 'B'
245 o | 1: 'B'
246 |/
246 |/
247 o 0: 'A'
247 o 0: 'A'
248
248
249 $ cd ..
249 $ cd ..
250
250
251
251
252 These will fail (using --source):
252 These will fail (using --source):
253
253
254 G onto F - rebase onto an ancestor:
254 G onto F - rebase onto an ancestor:
255
255
256 $ hg clone -q -u . a a7
256 $ hg clone -q -u . a a7
257 $ cd a7
257 $ cd a7
258
258
259 $ hg rebase -s 6 -d 5
259 $ hg rebase -s 6 -d 5
260 nothing to rebase
260 nothing to rebase
261 [1]
261 [1]
262
262
263 F onto G - rebase onto a descendant:
263 F onto G - rebase onto a descendant:
264
264
265 $ hg rebase -s 5 -d 6
265 $ hg rebase -s 5 -d 6
266 abort: source is ancestor of destination
266 abort: source is ancestor of destination
267 [255]
267 [255]
268
268
269 G onto B - merge revision with both parents not in ancestors of target:
269 G onto B - merge revision with both parents not in ancestors of target:
270
270
271 $ hg rebase -s 6 -d 1
271 $ hg rebase -s 6 -d 1
272 rebasing 6:eea13746799a "G"
272 rebasing 6:eea13746799a "G"
273 abort: cannot use revision 6 as base, result would have 3 parents
273 abort: cannot use revision 6 as base, result would have 3 parents
274 [255]
274 [255]
275
275
276
276
277 These will abort gracefully (using --base):
277 These will abort gracefully (using --base):
278
278
279 G onto G - rebase onto same changeset:
279 G onto G - rebase onto same changeset:
280
280
281 $ hg rebase -b 6 -d 6
281 $ hg rebase -b 6 -d 6
282 nothing to rebase - eea13746799a is both "base" and destination
282 nothing to rebase - eea13746799a is both "base" and destination
283 [1]
283 [1]
284
284
285 G onto F - rebase onto an ancestor:
285 G onto F - rebase onto an ancestor:
286
286
287 $ hg rebase -b 6 -d 5
287 $ hg rebase -b 6 -d 5
288 nothing to rebase
288 nothing to rebase
289 [1]
289 [1]
290
290
291 F onto G - rebase onto a descendant:
291 F onto G - rebase onto a descendant:
292
292
293 $ hg rebase -b 5 -d 6
293 $ hg rebase -b 5 -d 6
294 nothing to rebase - "base" 24b6387c8c8c is already an ancestor of destination eea13746799a
294 nothing to rebase - "base" 24b6387c8c8c is already an ancestor of destination eea13746799a
295 [1]
295 [1]
296
296
297 C onto A - rebase onto an ancestor:
297 C onto A - rebase onto an ancestor:
298
298
299 $ hg rebase -d 0 -s 2
299 $ hg rebase -d 0 -s 2
300 rebasing 2:5fddd98957c8 "C"
300 rebasing 2:5fddd98957c8 "C"
301 rebasing 3:32af7686d403 "D"
301 rebasing 3:32af7686d403 "D"
302 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-f9244fa1-backup.hg (glob)
302 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-f9244fa1-backup.hg (glob)
303 $ hg tglog
303 $ hg tglog
304 o 7: 'D'
304 o 7: 'D'
305 |
305 |
306 o 6: 'C'
306 o 6: 'C'
307 |
307 |
308 | @ 5: 'H'
308 | @ 5: 'H'
309 | |
309 | |
310 | | o 4: 'G'
310 | | o 4: 'G'
311 | |/|
311 | |/|
312 | o | 3: 'F'
312 | o | 3: 'F'
313 |/ /
313 |/ /
314 | o 2: 'E'
314 | o 2: 'E'
315 |/
315 |/
316 | o 1: 'B'
316 | o 1: 'B'
317 |/
317 |/
318 o 0: 'A'
318 o 0: 'A'
319
319
320
320
321 Check rebasing public changeset
321 Check rebasing public changeset
322
322
323 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
323 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
324 $ hg rebase -d 0 -b 6
324 $ hg rebase -d 0 -b 6
325 nothing to rebase
325 nothing to rebase
326 [1]
326 [1]
327 $ hg rebase -d 5 -b 6
327 $ hg rebase -d 5 -b 6
328 abort: can't rebase public changeset e1c4361dd923
328 abort: can't rebase public changeset e1c4361dd923
329 (see "hg help phases" for details)
329 (see "hg help phases" for details)
330 [255]
330 [255]
331
331
332 $ hg rebase -d 5 -b 6 --keep
332 $ hg rebase -d 5 -b 6 --keep
333 rebasing 6:e1c4361dd923 "C"
333 rebasing 6:e1c4361dd923 "C"
334 rebasing 7:c9659aac0000 "D" (tip)
334 rebasing 7:c9659aac0000 "D" (tip)
335
335
336 Check rebasing mutable changeset
336 Check rebasing mutable changeset
337 Source phase greater or equal to destination phase: new changeset get the phase of source:
337 Source phase greater or equal to destination phase: new changeset get the phase of source:
338 $ hg id -n
338 $ hg id -n
339 5
339 5
340 $ hg rebase -s9 -d0
340 $ hg rebase -s9 -d0
341 rebasing 9:2b23e52411f4 "D" (tip)
341 rebasing 9:2b23e52411f4 "D" (tip)
342 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-f942decf-backup.hg (glob)
342 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-f942decf-backup.hg (glob)
343 $ hg id -n # check we updated back to parent
343 $ hg id -n # check we updated back to parent
344 5
344 5
345 $ hg log --template "{phase}\n" -r 9
345 $ hg log --template "{phase}\n" -r 9
346 draft
346 draft
347 $ hg rebase -s9 -d1
347 $ hg rebase -s9 -d1
348 rebasing 9:2cb10d0cfc6c "D" (tip)
348 rebasing 9:2cb10d0cfc6c "D" (tip)
349 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-ddb0f256-backup.hg (glob)
349 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-ddb0f256-backup.hg (glob)
350 $ hg log --template "{phase}\n" -r 9
350 $ hg log --template "{phase}\n" -r 9
351 draft
351 draft
352 $ hg phase --force --secret 9
352 $ hg phase --force --secret 9
353 $ hg rebase -s9 -d0
353 $ hg rebase -s9 -d0
354 rebasing 9:c5b12b67163a "D" (tip)
354 rebasing 9:c5b12b67163a "D" (tip)
355 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-4e372053-backup.hg (glob)
355 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-4e372053-backup.hg (glob)
356 $ hg log --template "{phase}\n" -r 9
356 $ hg log --template "{phase}\n" -r 9
357 secret
357 secret
358 $ hg rebase -s9 -d1
358 $ hg rebase -s9 -d1
359 rebasing 9:2a0524f868ac "D" (tip)
359 rebasing 9:2a0524f868ac "D" (tip)
360 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-cefd8574-backup.hg (glob)
360 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-cefd8574-backup.hg (glob)
361 $ hg log --template "{phase}\n" -r 9
361 $ hg log --template "{phase}\n" -r 9
362 secret
362 secret
363 Source phase lower than destination phase: new changeset get the phase of destination:
363 Source phase lower than destination phase: new changeset get the phase of destination:
364 $ hg rebase -s8 -d9
364 $ hg rebase -s8 -d9
365 rebasing 8:6d4f22462821 "C"
365 rebasing 8:6d4f22462821 "C"
366 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-3441f70b-backup.hg (glob)
366 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-3441f70b-backup.hg (glob)
367 $ hg log --template "{phase}\n" -r 'rev(9)'
367 $ hg log --template "{phase}\n" -r 'rev(9)'
368 secret
368 secret
369
369
370 $ cd ..
370 $ cd ..
371
371
372 Test for revset
372 Test for revset
373
373
374 We need a bit different graph
374 We need a bit different graph
375 All destination are B
375 All destination are B
376
376
377 $ hg init ah
377 $ hg init ah
378 $ cd ah
378 $ cd ah
379 $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
379 $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
380 adding changesets
380 adding changesets
381 adding manifests
381 adding manifests
382 adding file changes
382 adding file changes
383 added 9 changesets with 9 changes to 9 files (+2 heads)
383 added 9 changesets with 9 changes to 9 files (+2 heads)
384 (run 'hg heads' to see heads, 'hg merge' to merge)
384 (run 'hg heads' to see heads, 'hg merge' to merge)
385 $ hg tglog
385 $ hg tglog
386 o 8: 'I'
386 o 8: 'I'
387 |
387 |
388 o 7: 'H'
388 o 7: 'H'
389 |
389 |
390 o 6: 'G'
390 o 6: 'G'
391 |
391 |
392 | o 5: 'F'
392 | o 5: 'F'
393 | |
393 | |
394 | o 4: 'E'
394 | o 4: 'E'
395 |/
395 |/
396 o 3: 'D'
396 o 3: 'D'
397 |
397 |
398 o 2: 'C'
398 o 2: 'C'
399 |
399 |
400 | o 1: 'B'
400 | o 1: 'B'
401 |/
401 |/
402 o 0: 'A'
402 o 0: 'A'
403
403
404 $ cd ..
404 $ cd ..
405
405
406
406
407 Simple case with keep:
407 Simple case with keep:
408
408
409 Source on have two descendant heads but ask for one
409 Source on have two descendant heads but ask for one
410
410
411 $ hg clone -q -u . ah ah1
411 $ hg clone -q -u . ah ah1
412 $ cd ah1
412 $ cd ah1
413 $ hg rebase -r '2::8' -d 1
413 $ hg rebase -r '2::8' -d 1
414 abort: can't remove original changesets with unrebased descendants
414 abort: can't remove original changesets with unrebased descendants
415 (use --keep to keep original changesets)
415 (use --keep to keep original changesets)
416 [255]
416 [255]
417 $ hg rebase -r '2::8' -d 1 -k
417 $ hg rebase -r '2::8' -d 1 -k
418 rebasing 2:c9e50f6cdc55 "C"
418 rebasing 2:c9e50f6cdc55 "C"
419 rebasing 3:ffd453c31098 "D"
419 rebasing 3:ffd453c31098 "D"
420 rebasing 6:3d8a618087a7 "G"
420 rebasing 6:3d8a618087a7 "G"
421 rebasing 7:72434a4e60b0 "H"
421 rebasing 7:72434a4e60b0 "H"
422 rebasing 8:479ddb54a924 "I" (tip)
422 rebasing 8:479ddb54a924 "I" (tip)
423 $ hg tglog
423 $ hg tglog
424 o 13: 'I'
424 o 13: 'I'
425 |
425 |
426 o 12: 'H'
426 o 12: 'H'
427 |
427 |
428 o 11: 'G'
428 o 11: 'G'
429 |
429 |
430 o 10: 'D'
430 o 10: 'D'
431 |
431 |
432 o 9: 'C'
432 o 9: 'C'
433 |
433 |
434 | o 8: 'I'
434 | o 8: 'I'
435 | |
435 | |
436 | o 7: 'H'
436 | o 7: 'H'
437 | |
437 | |
438 | o 6: 'G'
438 | o 6: 'G'
439 | |
439 | |
440 | | o 5: 'F'
440 | | o 5: 'F'
441 | | |
441 | | |
442 | | o 4: 'E'
442 | | o 4: 'E'
443 | |/
443 | |/
444 | o 3: 'D'
444 | o 3: 'D'
445 | |
445 | |
446 | o 2: 'C'
446 | o 2: 'C'
447 | |
447 | |
448 o | 1: 'B'
448 o | 1: 'B'
449 |/
449 |/
450 o 0: 'A'
450 o 0: 'A'
451
451
452
452
453 $ cd ..
453 $ cd ..
454
454
455 Base on have one descendant heads we ask for but common ancestor have two
455 Base on have one descendant heads we ask for but common ancestor have two
456
456
457 $ hg clone -q -u . ah ah2
457 $ hg clone -q -u . ah ah2
458 $ cd ah2
458 $ cd ah2
459 $ hg rebase -r '3::8' -d 1
459 $ hg rebase -r '3::8' -d 1
460 abort: can't remove original changesets with unrebased descendants
460 abort: can't remove original changesets with unrebased descendants
461 (use --keep to keep original changesets)
461 (use --keep to keep original changesets)
462 [255]
462 [255]
463 $ hg rebase -r '3::8' -d 1 --keep
463 $ hg rebase -r '3::8' -d 1 --keep
464 rebasing 3:ffd453c31098 "D"
464 rebasing 3:ffd453c31098 "D"
465 rebasing 6:3d8a618087a7 "G"
465 rebasing 6:3d8a618087a7 "G"
466 rebasing 7:72434a4e60b0 "H"
466 rebasing 7:72434a4e60b0 "H"
467 rebasing 8:479ddb54a924 "I" (tip)
467 rebasing 8:479ddb54a924 "I" (tip)
468 $ hg tglog
468 $ hg tglog
469 o 12: 'I'
469 o 12: 'I'
470 |
470 |
471 o 11: 'H'
471 o 11: 'H'
472 |
472 |
473 o 10: 'G'
473 o 10: 'G'
474 |
474 |
475 o 9: 'D'
475 o 9: 'D'
476 |
476 |
477 | o 8: 'I'
477 | o 8: 'I'
478 | |
478 | |
479 | o 7: 'H'
479 | o 7: 'H'
480 | |
480 | |
481 | o 6: 'G'
481 | o 6: 'G'
482 | |
482 | |
483 | | o 5: 'F'
483 | | o 5: 'F'
484 | | |
484 | | |
485 | | o 4: 'E'
485 | | o 4: 'E'
486 | |/
486 | |/
487 | o 3: 'D'
487 | o 3: 'D'
488 | |
488 | |
489 | o 2: 'C'
489 | o 2: 'C'
490 | |
490 | |
491 o | 1: 'B'
491 o | 1: 'B'
492 |/
492 |/
493 o 0: 'A'
493 o 0: 'A'
494
494
495
495
496 $ cd ..
496 $ cd ..
497
497
498 rebase subset
498 rebase subset
499
499
500 $ hg clone -q -u . ah ah3
500 $ hg clone -q -u . ah ah3
501 $ cd ah3
501 $ cd ah3
502 $ hg rebase -r '3::7' -d 1
502 $ hg rebase -r '3::7' -d 1
503 abort: can't remove original changesets with unrebased descendants
503 abort: can't remove original changesets with unrebased descendants
504 (use --keep to keep original changesets)
504 (use --keep to keep original changesets)
505 [255]
505 [255]
506 $ hg rebase -r '3::7' -d 1 --keep
506 $ hg rebase -r '3::7' -d 1 --keep
507 rebasing 3:ffd453c31098 "D"
507 rebasing 3:ffd453c31098 "D"
508 rebasing 6:3d8a618087a7 "G"
508 rebasing 6:3d8a618087a7 "G"
509 rebasing 7:72434a4e60b0 "H"
509 rebasing 7:72434a4e60b0 "H"
510 $ hg tglog
510 $ hg tglog
511 o 11: 'H'
511 o 11: 'H'
512 |
512 |
513 o 10: 'G'
513 o 10: 'G'
514 |
514 |
515 o 9: 'D'
515 o 9: 'D'
516 |
516 |
517 | o 8: 'I'
517 | o 8: 'I'
518 | |
518 | |
519 | o 7: 'H'
519 | o 7: 'H'
520 | |
520 | |
521 | o 6: 'G'
521 | o 6: 'G'
522 | |
522 | |
523 | | o 5: 'F'
523 | | o 5: 'F'
524 | | |
524 | | |
525 | | o 4: 'E'
525 | | o 4: 'E'
526 | |/
526 | |/
527 | o 3: 'D'
527 | o 3: 'D'
528 | |
528 | |
529 | o 2: 'C'
529 | o 2: 'C'
530 | |
530 | |
531 o | 1: 'B'
531 o | 1: 'B'
532 |/
532 |/
533 o 0: 'A'
533 o 0: 'A'
534
534
535
535
536 $ cd ..
536 $ cd ..
537
537
538 rebase subset with multiple head
538 rebase subset with multiple head
539
539
540 $ hg clone -q -u . ah ah4
540 $ hg clone -q -u . ah ah4
541 $ cd ah4
541 $ cd ah4
542 $ hg rebase -r '3::(7+5)' -d 1
542 $ hg rebase -r '3::(7+5)' -d 1
543 abort: can't remove original changesets with unrebased descendants
543 abort: can't remove original changesets with unrebased descendants
544 (use --keep to keep original changesets)
544 (use --keep to keep original changesets)
545 [255]
545 [255]
546 $ hg rebase -r '3::(7+5)' -d 1 --keep
546 $ hg rebase -r '3::(7+5)' -d 1 --keep
547 rebasing 3:ffd453c31098 "D"
547 rebasing 3:ffd453c31098 "D"
548 rebasing 4:c01897464e7f "E"
548 rebasing 4:c01897464e7f "E"
549 rebasing 5:41bfcc75ed73 "F"
549 rebasing 5:41bfcc75ed73 "F"
550 rebasing 6:3d8a618087a7 "G"
550 rebasing 6:3d8a618087a7 "G"
551 rebasing 7:72434a4e60b0 "H"
551 rebasing 7:72434a4e60b0 "H"
552 $ hg tglog
552 $ hg tglog
553 o 13: 'H'
553 o 13: 'H'
554 |
554 |
555 o 12: 'G'
555 o 12: 'G'
556 |
556 |
557 | o 11: 'F'
557 | o 11: 'F'
558 | |
558 | |
559 | o 10: 'E'
559 | o 10: 'E'
560 |/
560 |/
561 o 9: 'D'
561 o 9: 'D'
562 |
562 |
563 | o 8: 'I'
563 | o 8: 'I'
564 | |
564 | |
565 | o 7: 'H'
565 | o 7: 'H'
566 | |
566 | |
567 | o 6: 'G'
567 | o 6: 'G'
568 | |
568 | |
569 | | o 5: 'F'
569 | | o 5: 'F'
570 | | |
570 | | |
571 | | o 4: 'E'
571 | | o 4: 'E'
572 | |/
572 | |/
573 | o 3: 'D'
573 | o 3: 'D'
574 | |
574 | |
575 | o 2: 'C'
575 | o 2: 'C'
576 | |
576 | |
577 o | 1: 'B'
577 o | 1: 'B'
578 |/
578 |/
579 o 0: 'A'
579 o 0: 'A'
580
580
581
581
582 $ cd ..
582 $ cd ..
583
583
584 More advanced tests
584 More advanced tests
585
585
586 rebase on ancestor with revset
586 rebase on ancestor with revset
587
587
588 $ hg clone -q -u . ah ah5
588 $ hg clone -q -u . ah ah5
589 $ cd ah5
589 $ cd ah5
590 $ hg rebase -r '6::' -d 2
590 $ hg rebase -r '6::' -d 2
591 rebasing 6:3d8a618087a7 "G"
591 rebasing 6:3d8a618087a7 "G"
592 rebasing 7:72434a4e60b0 "H"
592 rebasing 7:72434a4e60b0 "H"
593 rebasing 8:479ddb54a924 "I" (tip)
593 rebasing 8:479ddb54a924 "I" (tip)
594 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-b4f73f31-backup.hg (glob)
594 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-b4f73f31-backup.hg (glob)
595 $ hg tglog
595 $ hg tglog
596 o 8: 'I'
596 o 8: 'I'
597 |
597 |
598 o 7: 'H'
598 o 7: 'H'
599 |
599 |
600 o 6: 'G'
600 o 6: 'G'
601 |
601 |
602 | o 5: 'F'
602 | o 5: 'F'
603 | |
603 | |
604 | o 4: 'E'
604 | o 4: 'E'
605 | |
605 | |
606 | o 3: 'D'
606 | o 3: 'D'
607 |/
607 |/
608 o 2: 'C'
608 o 2: 'C'
609 |
609 |
610 | o 1: 'B'
610 | o 1: 'B'
611 |/
611 |/
612 o 0: 'A'
612 o 0: 'A'
613
613
614 $ cd ..
614 $ cd ..
615
615
616
616
617 rebase with multiple root.
617 rebase with multiple root.
618 We rebase E and G on B
618 We rebase E and G on B
619 We would expect heads are I, F if it was supported
619 We would expect heads are I, F if it was supported
620
620
621 $ hg clone -q -u . ah ah6
621 $ hg clone -q -u . ah ah6
622 $ cd ah6
622 $ cd ah6
623 $ hg rebase -r '(4+6)::' -d 1
623 $ hg rebase -r '(4+6)::' -d 1
624 rebasing 4:c01897464e7f "E"
624 rebasing 4:c01897464e7f "E"
625 rebasing 5:41bfcc75ed73 "F"
625 rebasing 5:41bfcc75ed73 "F"
626 rebasing 6:3d8a618087a7 "G"
626 rebasing 6:3d8a618087a7 "G"
627 rebasing 7:72434a4e60b0 "H"
627 rebasing 7:72434a4e60b0 "H"
628 rebasing 8:479ddb54a924 "I" (tip)
628 rebasing 8:479ddb54a924 "I" (tip)
629 saved backup bundle to $TESTTMP/ah6/.hg/strip-backup/3d8a618087a7-aae93a24-backup.hg (glob)
629 saved backup bundle to $TESTTMP/ah6/.hg/strip-backup/3d8a618087a7-aae93a24-backup.hg (glob)
630 $ hg tglog
630 $ hg tglog
631 o 8: 'I'
631 o 8: 'I'
632 |
632 |
633 o 7: 'H'
633 o 7: 'H'
634 |
634 |
635 o 6: 'G'
635 o 6: 'G'
636 |
636 |
637 | o 5: 'F'
637 | o 5: 'F'
638 | |
638 | |
639 | o 4: 'E'
639 | o 4: 'E'
640 |/
640 |/
641 | o 3: 'D'
641 | o 3: 'D'
642 | |
642 | |
643 | o 2: 'C'
643 | o 2: 'C'
644 | |
644 | |
645 o | 1: 'B'
645 o | 1: 'B'
646 |/
646 |/
647 o 0: 'A'
647 o 0: 'A'
648
648
649 $ cd ..
649 $ cd ..
650
650
651 More complex rebase with multiple roots
651 More complex rebase with multiple roots
652 each root have a different common ancestor with the destination and this is a detach
652 each root have a different common ancestor with the destination and this is a detach
653
653
654 (setup)
654 (setup)
655
655
656 $ hg clone -q -u . a a8
656 $ hg clone -q -u . a a8
657 $ cd a8
657 $ cd a8
658 $ echo I > I
658 $ echo I > I
659 $ hg add I
659 $ hg add I
660 $ hg commit -m I
660 $ hg commit -m I
661 $ hg up 4
661 $ hg up 4
662 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
662 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
663 $ echo I > J
663 $ echo I > J
664 $ hg add J
664 $ hg add J
665 $ hg commit -m J
665 $ hg commit -m J
666 created new head
666 created new head
667 $ echo I > K
667 $ echo I > K
668 $ hg add K
668 $ hg add K
669 $ hg commit -m K
669 $ hg commit -m K
670 $ hg tglog
670 $ hg tglog
671 @ 10: 'K'
671 @ 10: 'K'
672 |
672 |
673 o 9: 'J'
673 o 9: 'J'
674 |
674 |
675 | o 8: 'I'
675 | o 8: 'I'
676 | |
676 | |
677 | o 7: 'H'
677 | o 7: 'H'
678 | |
678 | |
679 +---o 6: 'G'
679 +---o 6: 'G'
680 | |/
680 | |/
681 | o 5: 'F'
681 | o 5: 'F'
682 | |
682 | |
683 o | 4: 'E'
683 o | 4: 'E'
684 |/
684 |/
685 | o 3: 'D'
685 | o 3: 'D'
686 | |
686 | |
687 | o 2: 'C'
687 | o 2: 'C'
688 | |
688 | |
689 | o 1: 'B'
689 | o 1: 'B'
690 |/
690 |/
691 o 0: 'A'
691 o 0: 'A'
692
692
693 (actual test)
693 (actual test)
694
694
695 $ hg rebase --dest 'desc(G)' --rev 'desc(K) + desc(I)'
695 $ hg rebase --dest 'desc(G)' --rev 'desc(K) + desc(I)'
696 rebasing 8:e7ec4e813ba6 "I"
696 rebasing 8:e7ec4e813ba6 "I"
697 rebasing 10:23a4ace37988 "K" (tip)
697 rebasing 10:23a4ace37988 "K" (tip)
698 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/23a4ace37988-b06984b3-backup.hg (glob)
698 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/23a4ace37988-b06984b3-backup.hg (glob)
699 $ hg log --rev 'children(desc(G))'
699 $ hg log --rev 'children(desc(G))'
700 changeset: 9:adb617877056
700 changeset: 9:adb617877056
701 parent: 6:eea13746799a
701 parent: 6:eea13746799a
702 user: test
702 user: test
703 date: Thu Jan 01 00:00:00 1970 +0000
703 date: Thu Jan 01 00:00:00 1970 +0000
704 summary: I
704 summary: I
705
705
706 changeset: 10:882431a34a0e
706 changeset: 10:882431a34a0e
707 tag: tip
707 tag: tip
708 parent: 6:eea13746799a
708 parent: 6:eea13746799a
709 user: test
709 user: test
710 date: Thu Jan 01 00:00:00 1970 +0000
710 date: Thu Jan 01 00:00:00 1970 +0000
711 summary: K
711 summary: K
712
712
713 $ hg tglog
713 $ hg tglog
714 @ 10: 'K'
714 @ 10: 'K'
715 |
715 |
716 | o 9: 'I'
716 | o 9: 'I'
717 |/
717 |/
718 | o 8: 'J'
718 | o 8: 'J'
719 | |
719 | |
720 | | o 7: 'H'
720 | | o 7: 'H'
721 | | |
721 | | |
722 o---+ 6: 'G'
722 o---+ 6: 'G'
723 |/ /
723 |/ /
724 | o 5: 'F'
724 | o 5: 'F'
725 | |
725 | |
726 o | 4: 'E'
726 o | 4: 'E'
727 |/
727 |/
728 | o 3: 'D'
728 | o 3: 'D'
729 | |
729 | |
730 | o 2: 'C'
730 | o 2: 'C'
731 | |
731 | |
732 | o 1: 'B'
732 | o 1: 'B'
733 |/
733 |/
734 o 0: 'A'
734 o 0: 'A'
735
735
736
736
737 Test that rebase is not confused by $CWD disappearing during rebase (issue4121)
737 Test that rebase is not confused by $CWD disappearing during rebase (issue4121)
738
738
739 $ cd ..
739 $ cd ..
740 $ hg init cwd-vanish
740 $ hg init cwd-vanish
741 $ cd cwd-vanish
741 $ cd cwd-vanish
742 $ touch initial-file
742 $ touch initial-file
743 $ hg add initial-file
743 $ hg add initial-file
744 $ hg commit -m 'initial commit'
744 $ hg commit -m 'initial commit'
745 $ touch dest-file
745 $ touch dest-file
746 $ hg add dest-file
746 $ hg add dest-file
747 $ hg commit -m 'dest commit'
747 $ hg commit -m 'dest commit'
748 $ hg up 0
748 $ hg up 0
749 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
749 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
750 $ touch other-file
750 $ touch other-file
751 $ hg add other-file
751 $ hg add other-file
752 $ hg commit -m 'first source commit'
752 $ hg commit -m 'first source commit'
753 created new head
753 created new head
754 $ mkdir subdir
754 $ mkdir subdir
755 $ cd subdir
755 $ cd subdir
756 $ touch subfile
756 $ touch subfile
757 $ hg add subfile
757 $ hg add subfile
758 $ hg commit -m 'second source with subdir'
758 $ hg commit -m 'second source with subdir'
759 $ hg rebase -b . -d 1 --traceback
759 $ hg rebase -b . -d 1 --traceback
760 rebasing 2:779a07b1b7a0 "first source commit"
760 rebasing 2:779a07b1b7a0 "first source commit"
761 rebasing 3:a7d6f3a00bf3 "second source with subdir" (tip)
761 rebasing 3:a7d6f3a00bf3 "second source with subdir" (tip)
762 saved backup bundle to $TESTTMP/cwd-vanish/.hg/strip-backup/779a07b1b7a0-853e0073-backup.hg (glob)
762 saved backup bundle to $TESTTMP/cwd-vanish/.hg/strip-backup/779a07b1b7a0-853e0073-backup.hg (glob)
763
763
764 Test experimental revset
764 Test experimental revset
765 ========================
765 ========================
766
766
767 $ cd ..
767 $ cd ..
768
768
769 Make the repo a bit more interresting
769 Make the repo a bit more interresting
770
770
771 $ hg up 1
771 $ hg up 1
772 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
772 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
773 $ echo aaa > aaa
773 $ echo aaa > aaa
774 $ hg add aaa
774 $ hg add aaa
775 $ hg commit -m aaa
775 $ hg commit -m aaa
776 created new head
776 created new head
777 $ hg log -G
777 $ hg log -G
778 @ changeset: 4:5f7bc9025ed2
778 @ changeset: 4:5f7bc9025ed2
779 | tag: tip
779 | tag: tip
780 | parent: 1:58d79cc1cf43
780 | parent: 1:58d79cc1cf43
781 | user: test
781 | user: test
782 | date: Thu Jan 01 00:00:00 1970 +0000
782 | date: Thu Jan 01 00:00:00 1970 +0000
783 | summary: aaa
783 | summary: aaa
784 |
784 |
785 | o changeset: 3:1910d5ff34ea
785 | o changeset: 3:1910d5ff34ea
786 | | user: test
786 | | user: test
787 | | date: Thu Jan 01 00:00:00 1970 +0000
787 | | date: Thu Jan 01 00:00:00 1970 +0000
788 | | summary: second source with subdir
788 | | summary: second source with subdir
789 | |
789 | |
790 | o changeset: 2:82901330b6ef
790 | o changeset: 2:82901330b6ef
791 |/ user: test
791 |/ user: test
792 | date: Thu Jan 01 00:00:00 1970 +0000
792 | date: Thu Jan 01 00:00:00 1970 +0000
793 | summary: first source commit
793 | summary: first source commit
794 |
794 |
795 o changeset: 1:58d79cc1cf43
795 o changeset: 1:58d79cc1cf43
796 | user: test
796 | user: test
797 | date: Thu Jan 01 00:00:00 1970 +0000
797 | date: Thu Jan 01 00:00:00 1970 +0000
798 | summary: dest commit
798 | summary: dest commit
799 |
799 |
800 o changeset: 0:e94b687f7da3
800 o changeset: 0:e94b687f7da3
801 user: test
801 user: test
802 date: Thu Jan 01 00:00:00 1970 +0000
802 date: Thu Jan 01 00:00:00 1970 +0000
803 summary: initial commit
803 summary: initial commit
804
804
805
805
806 Testing from lower head
806 Testing from lower head
807
807
808 $ hg up 3
808 $ hg up 3
809 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
809 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
810 $ hg log -r '_destrebase()'
810 $ hg log -r '_destrebase()'
811 changeset: 4:5f7bc9025ed2
811 changeset: 4:5f7bc9025ed2
812 tag: tip
812 tag: tip
813 parent: 1:58d79cc1cf43
813 parent: 1:58d79cc1cf43
814 user: test
814 user: test
815 date: Thu Jan 01 00:00:00 1970 +0000
815 date: Thu Jan 01 00:00:00 1970 +0000
816 summary: aaa
816 summary: aaa
817
817
818
818
819 Testing from upper head
819 Testing from upper head
820
820
821 $ hg log -r '_destrebase(4)'
822 changeset: 3:1910d5ff34ea
823 user: test
824 date: Thu Jan 01 00:00:00 1970 +0000
825 summary: second source with subdir
826
821 $ hg up 4
827 $ hg up 4
822 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
828 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
823 $ hg log -r '_destrebase()'
829 $ hg log -r '_destrebase()'
824 changeset: 4:5f7bc9025ed2
830 changeset: 3:1910d5ff34ea
825 tag: tip
826 parent: 1:58d79cc1cf43
827 user: test
831 user: test
828 date: Thu Jan 01 00:00:00 1970 +0000
832 date: Thu Jan 01 00:00:00 1970 +0000
829 summary: aaa
833 summary: second source with subdir
830
834
General Comments 0
You need to be logged in to leave comments. Login now