##// END OF EJS Templates
rebase: use dirstateguard instead of dirstate.invalidate...
FUJIWARA Katsunori -
r24998:c8a97fa7 default
parent child Browse files
Show More
@@ -1,1116 +1,1114
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 http://mercurial.selenic.com/wiki/RebaseExtension
14 http://mercurial.selenic.com/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, repoview
19 from mercurial import copies, repoview
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 revtodo = -1
26 revtodo = -1
27 nullmerge = -2
27 nullmerge = -2
28 revignored = -3
28 revignored = -3
29
29
30 cmdtable = {}
30 cmdtable = {}
31 command = cmdutil.command(cmdtable)
31 command = cmdutil.command(cmdtable)
32 testedwith = 'internal'
32 testedwith = 'internal'
33
33
34 def _savegraft(ctx, extra):
34 def _savegraft(ctx, extra):
35 s = ctx.extra().get('source', None)
35 s = ctx.extra().get('source', None)
36 if s is not None:
36 if s is not None:
37 extra['source'] = s
37 extra['source'] = s
38
38
39 def _savebranch(ctx, extra):
39 def _savebranch(ctx, extra):
40 extra['branch'] = ctx.branch()
40 extra['branch'] = ctx.branch()
41
41
42 def _makeextrafn(copiers):
42 def _makeextrafn(copiers):
43 """make an extrafn out of the given copy-functions.
43 """make an extrafn out of the given copy-functions.
44
44
45 A copy function takes a context and an extra dict, and mutates the
45 A copy function takes a context and an extra dict, and mutates the
46 extra dict as needed based on the given context.
46 extra dict as needed based on the given context.
47 """
47 """
48 def extrafn(ctx, extra):
48 def extrafn(ctx, extra):
49 for c in copiers:
49 for c in copiers:
50 c(ctx, extra)
50 c(ctx, extra)
51 return extrafn
51 return extrafn
52
52
53 @command('rebase',
53 @command('rebase',
54 [('s', 'source', '',
54 [('s', 'source', '',
55 _('rebase the specified changeset and descendants'), _('REV')),
55 _('rebase the specified changeset and descendants'), _('REV')),
56 ('b', 'base', '',
56 ('b', 'base', '',
57 _('rebase everything from branching point of specified changeset'),
57 _('rebase everything from branching point of specified changeset'),
58 _('REV')),
58 _('REV')),
59 ('r', 'rev', [],
59 ('r', 'rev', [],
60 _('rebase these revisions'),
60 _('rebase these revisions'),
61 _('REV')),
61 _('REV')),
62 ('d', 'dest', '',
62 ('d', 'dest', '',
63 _('rebase onto the specified changeset'), _('REV')),
63 _('rebase onto the specified changeset'), _('REV')),
64 ('', 'collapse', False, _('collapse the rebased changesets')),
64 ('', 'collapse', False, _('collapse the rebased changesets')),
65 ('m', 'message', '',
65 ('m', 'message', '',
66 _('use text as collapse commit message'), _('TEXT')),
66 _('use text as collapse commit message'), _('TEXT')),
67 ('e', 'edit', False, _('invoke editor on commit messages')),
67 ('e', 'edit', False, _('invoke editor on commit messages')),
68 ('l', 'logfile', '',
68 ('l', 'logfile', '',
69 _('read collapse commit message from file'), _('FILE')),
69 _('read collapse commit message from file'), _('FILE')),
70 ('', 'keep', False, _('keep original changesets')),
70 ('', 'keep', False, _('keep original changesets')),
71 ('', 'keepbranches', False, _('keep original branch names')),
71 ('', 'keepbranches', False, _('keep original branch names')),
72 ('D', 'detach', False, _('(DEPRECATED)')),
72 ('D', 'detach', False, _('(DEPRECATED)')),
73 ('i', 'interactive', False, _('(DEPRECATED)')),
73 ('i', 'interactive', False, _('(DEPRECATED)')),
74 ('t', 'tool', '', _('specify merge tool')),
74 ('t', 'tool', '', _('specify merge tool')),
75 ('c', 'continue', False, _('continue an interrupted rebase')),
75 ('c', 'continue', False, _('continue an interrupted rebase')),
76 ('a', 'abort', False, _('abort an interrupted rebase'))] +
76 ('a', 'abort', False, _('abort an interrupted rebase'))] +
77 templateopts,
77 templateopts,
78 _('[-s REV | -b REV] [-d REV] [OPTION]'))
78 _('[-s REV | -b REV] [-d REV] [OPTION]'))
79 def rebase(ui, repo, **opts):
79 def rebase(ui, repo, **opts):
80 """move changeset (and descendants) to a different branch
80 """move changeset (and descendants) to a different branch
81
81
82 Rebase uses repeated merging to graft changesets from one part of
82 Rebase uses repeated merging to graft changesets from one part of
83 history (the source) onto another (the destination). This can be
83 history (the source) onto another (the destination). This can be
84 useful for linearizing *local* changes relative to a master
84 useful for linearizing *local* changes relative to a master
85 development tree.
85 development tree.
86
86
87 You should not rebase changesets that have already been shared
87 You should not rebase changesets that have already been shared
88 with others. Doing so will force everybody else to perform the
88 with others. Doing so will force everybody else to perform the
89 same rebase or they will end up with duplicated changesets after
89 same rebase or they will end up with duplicated changesets after
90 pulling in your rebased changesets.
90 pulling in your rebased changesets.
91
91
92 In its default configuration, Mercurial will prevent you from
92 In its default configuration, Mercurial will prevent you from
93 rebasing published changes. See :hg:`help phases` for details.
93 rebasing published changes. See :hg:`help phases` for details.
94
94
95 If you don't specify a destination changeset (``-d/--dest``),
95 If you don't specify a destination changeset (``-d/--dest``),
96 rebase uses the current branch tip as the destination. (The
96 rebase uses the current branch tip as the destination. (The
97 destination changeset is not modified by rebasing, but new
97 destination changeset is not modified by rebasing, but new
98 changesets are added as its descendants.)
98 changesets are added as its descendants.)
99
99
100 You can specify which changesets to rebase in two ways: as a
100 You can specify which changesets to rebase in two ways: as a
101 "source" changeset or as a "base" changeset. Both are shorthand
101 "source" changeset or as a "base" changeset. Both are shorthand
102 for a topologically related set of changesets (the "source
102 for a topologically related set of changesets (the "source
103 branch"). If you specify source (``-s/--source``), rebase will
103 branch"). If you specify source (``-s/--source``), rebase will
104 rebase that changeset and all of its descendants onto dest. If you
104 rebase that changeset and all of its descendants onto dest. If you
105 specify base (``-b/--base``), rebase will select ancestors of base
105 specify base (``-b/--base``), rebase will select ancestors of base
106 back to but not including the common ancestor with dest. Thus,
106 back to but not including the common ancestor with dest. Thus,
107 ``-b`` is less precise but more convenient than ``-s``: you can
107 ``-b`` is less precise but more convenient than ``-s``: you can
108 specify any changeset in the source branch, and rebase will select
108 specify any changeset in the source branch, and rebase will select
109 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
109 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
110 uses the parent of the working directory as the base.
110 uses the parent of the working directory as the base.
111
111
112 For advanced usage, a third way is available through the ``--rev``
112 For advanced usage, a third way is available through the ``--rev``
113 option. It allows you to specify an arbitrary set of changesets to
113 option. It allows you to specify an arbitrary set of changesets to
114 rebase. Descendants of revs you specify with this option are not
114 rebase. Descendants of revs you specify with this option are not
115 automatically included in the rebase.
115 automatically included in the rebase.
116
116
117 By default, rebase recreates the changesets in the source branch
117 By default, rebase recreates the changesets in the source branch
118 as descendants of dest and then destroys the originals. Use
118 as descendants of dest and then destroys the originals. Use
119 ``--keep`` to preserve the original source changesets. Some
119 ``--keep`` to preserve the original source changesets. Some
120 changesets in the source branch (e.g. merges from the destination
120 changesets in the source branch (e.g. merges from the destination
121 branch) may be dropped if they no longer contribute any change.
121 branch) may be dropped if they no longer contribute any change.
122
122
123 One result of the rules for selecting the destination changeset
123 One result of the rules for selecting the destination changeset
124 and source branch is that, unlike ``merge``, rebase will do
124 and source branch is that, unlike ``merge``, rebase will do
125 nothing if you are at the branch tip of a named branch
125 nothing if you are at the branch tip of a named branch
126 with two heads. You need to explicitly specify source and/or
126 with two heads. You need to explicitly specify source and/or
127 destination (or ``update`` to the other head, if it's the head of
127 destination (or ``update`` to the other head, if it's the head of
128 the intended source branch).
128 the intended source branch).
129
129
130 If a rebase is interrupted to manually resolve a merge, it can be
130 If a rebase is interrupted to manually resolve a merge, it can be
131 continued with --continue/-c or aborted with --abort/-a.
131 continued with --continue/-c or aborted with --abort/-a.
132
132
133 .. container:: verbose
133 .. container:: verbose
134
134
135 Examples:
135 Examples:
136
136
137 - move "local changes" (current commit back to branching point)
137 - move "local changes" (current commit back to branching point)
138 to the current branch tip after a pull::
138 to the current branch tip after a pull::
139
139
140 hg rebase
140 hg rebase
141
141
142 - move a single changeset to the stable branch::
142 - move a single changeset to the stable branch::
143
143
144 hg rebase -r 5f493448 -d stable
144 hg rebase -r 5f493448 -d stable
145
145
146 - splice a commit and all its descendants onto another part of history::
146 - splice a commit and all its descendants onto another part of history::
147
147
148 hg rebase --source c0c3 --dest 4cf9
148 hg rebase --source c0c3 --dest 4cf9
149
149
150 - rebase everything on a branch marked by a bookmark onto the
150 - rebase everything on a branch marked by a bookmark onto the
151 default branch::
151 default branch::
152
152
153 hg rebase --base myfeature --dest default
153 hg rebase --base myfeature --dest default
154
154
155 - collapse a sequence of changes into a single commit::
155 - collapse a sequence of changes into a single commit::
156
156
157 hg rebase --collapse -r 1520:1525 -d .
157 hg rebase --collapse -r 1520:1525 -d .
158
158
159 - move a named branch while preserving its name::
159 - move a named branch while preserving its name::
160
160
161 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
161 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
162
162
163 Returns 0 on success, 1 if nothing to rebase or there are
163 Returns 0 on success, 1 if nothing to rebase or there are
164 unresolved conflicts.
164 unresolved conflicts.
165
165
166 """
166 """
167 originalwd = target = None
167 originalwd = target = None
168 activebookmark = None
168 activebookmark = None
169 external = nullrev
169 external = nullrev
170 state = {}
170 state = {}
171 skipped = set()
171 skipped = set()
172 targetancestors = set()
172 targetancestors = set()
173
173
174
174
175 lock = wlock = None
175 lock = wlock = None
176 try:
176 try:
177 wlock = repo.wlock()
177 wlock = repo.wlock()
178 lock = repo.lock()
178 lock = repo.lock()
179
179
180 # Validate input and define rebasing points
180 # Validate input and define rebasing points
181 destf = opts.get('dest', None)
181 destf = opts.get('dest', None)
182 srcf = opts.get('source', None)
182 srcf = opts.get('source', None)
183 basef = opts.get('base', None)
183 basef = opts.get('base', None)
184 revf = opts.get('rev', [])
184 revf = opts.get('rev', [])
185 contf = opts.get('continue')
185 contf = opts.get('continue')
186 abortf = opts.get('abort')
186 abortf = opts.get('abort')
187 collapsef = opts.get('collapse', False)
187 collapsef = opts.get('collapse', False)
188 collapsemsg = cmdutil.logmessage(ui, opts)
188 collapsemsg = cmdutil.logmessage(ui, opts)
189 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
189 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
190 extrafns = [_savegraft]
190 extrafns = [_savegraft]
191 if e:
191 if e:
192 extrafns = [e]
192 extrafns = [e]
193 keepf = opts.get('keep', False)
193 keepf = opts.get('keep', False)
194 keepbranchesf = opts.get('keepbranches', False)
194 keepbranchesf = opts.get('keepbranches', False)
195 # keepopen is not meant for use on the command line, but by
195 # keepopen is not meant for use on the command line, but by
196 # other extensions
196 # other extensions
197 keepopen = opts.get('keepopen', False)
197 keepopen = opts.get('keepopen', False)
198
198
199 if opts.get('interactive'):
199 if opts.get('interactive'):
200 msg = _("interactive history editing is supported by the "
200 msg = _("interactive history editing is supported by the "
201 "'histedit' extension (see \"hg help histedit\")")
201 "'histedit' extension (see \"hg help histedit\")")
202 raise util.Abort(msg)
202 raise util.Abort(msg)
203
203
204 if collapsemsg and not collapsef:
204 if collapsemsg and not collapsef:
205 raise util.Abort(
205 raise util.Abort(
206 _('message can only be specified with collapse'))
206 _('message can only be specified with collapse'))
207
207
208 if contf or abortf:
208 if contf or abortf:
209 if contf and abortf:
209 if contf and abortf:
210 raise util.Abort(_('cannot use both abort and continue'))
210 raise util.Abort(_('cannot use both abort and continue'))
211 if collapsef:
211 if collapsef:
212 raise util.Abort(
212 raise util.Abort(
213 _('cannot use collapse with continue or abort'))
213 _('cannot use collapse with continue or abort'))
214 if srcf or basef or destf:
214 if srcf or basef or destf:
215 raise util.Abort(
215 raise util.Abort(
216 _('abort and continue do not allow specifying revisions'))
216 _('abort and continue do not allow specifying revisions'))
217 if opts.get('tool', False):
217 if opts.get('tool', False):
218 ui.warn(_('tool option will be ignored\n'))
218 ui.warn(_('tool option will be ignored\n'))
219
219
220 try:
220 try:
221 (originalwd, target, state, skipped, collapsef, keepf,
221 (originalwd, target, state, skipped, collapsef, keepf,
222 keepbranchesf, external, activebookmark) = restorestatus(repo)
222 keepbranchesf, external, activebookmark) = restorestatus(repo)
223 except error.RepoLookupError:
223 except error.RepoLookupError:
224 if abortf:
224 if abortf:
225 clearstatus(repo)
225 clearstatus(repo)
226 repo.ui.warn(_('rebase aborted (no revision is removed,'
226 repo.ui.warn(_('rebase aborted (no revision is removed,'
227 ' only broken state is cleared)\n'))
227 ' only broken state is cleared)\n'))
228 return 0
228 return 0
229 else:
229 else:
230 msg = _('cannot continue inconsistent rebase')
230 msg = _('cannot continue inconsistent rebase')
231 hint = _('use "hg rebase --abort" to clear broken state')
231 hint = _('use "hg rebase --abort" to clear broken state')
232 raise util.Abort(msg, hint=hint)
232 raise util.Abort(msg, hint=hint)
233 if abortf:
233 if abortf:
234 return abort(repo, originalwd, target, state,
234 return abort(repo, originalwd, target, state,
235 activebookmark=activebookmark)
235 activebookmark=activebookmark)
236 else:
236 else:
237 if srcf and basef:
237 if srcf and basef:
238 raise util.Abort(_('cannot specify both a '
238 raise util.Abort(_('cannot specify both a '
239 'source and a base'))
239 'source and a base'))
240 if revf and basef:
240 if revf and basef:
241 raise util.Abort(_('cannot specify both a '
241 raise util.Abort(_('cannot specify both a '
242 'revision and a base'))
242 'revision and a base'))
243 if revf and srcf:
243 if revf and srcf:
244 raise util.Abort(_('cannot specify both a '
244 raise util.Abort(_('cannot specify both a '
245 'revision and a source'))
245 'revision and a source'))
246
246
247 cmdutil.checkunfinished(repo)
247 cmdutil.checkunfinished(repo)
248 cmdutil.bailifchanged(repo)
248 cmdutil.bailifchanged(repo)
249
249
250 if not destf:
250 if not destf:
251 # Destination defaults to the latest revision in the
251 # Destination defaults to the latest revision in the
252 # current branch
252 # current branch
253 branch = repo[None].branch()
253 branch = repo[None].branch()
254 dest = repo[branch]
254 dest = repo[branch]
255 else:
255 else:
256 dest = scmutil.revsingle(repo, destf)
256 dest = scmutil.revsingle(repo, destf)
257
257
258 if revf:
258 if revf:
259 rebaseset = scmutil.revrange(repo, revf)
259 rebaseset = scmutil.revrange(repo, revf)
260 if not rebaseset:
260 if not rebaseset:
261 ui.status(_('empty "rev" revision set - '
261 ui.status(_('empty "rev" revision set - '
262 'nothing to rebase\n'))
262 'nothing to rebase\n'))
263 return 1
263 return 1
264 elif srcf:
264 elif srcf:
265 src = scmutil.revrange(repo, [srcf])
265 src = scmutil.revrange(repo, [srcf])
266 if not src:
266 if not src:
267 ui.status(_('empty "source" revision set - '
267 ui.status(_('empty "source" revision set - '
268 'nothing to rebase\n'))
268 'nothing to rebase\n'))
269 return 1
269 return 1
270 rebaseset = repo.revs('(%ld)::', src)
270 rebaseset = repo.revs('(%ld)::', src)
271 assert rebaseset
271 assert rebaseset
272 else:
272 else:
273 base = scmutil.revrange(repo, [basef or '.'])
273 base = scmutil.revrange(repo, [basef or '.'])
274 if not base:
274 if not base:
275 ui.status(_('empty "base" revision set - '
275 ui.status(_('empty "base" revision set - '
276 "can't compute rebase set\n"))
276 "can't compute rebase set\n"))
277 return 1
277 return 1
278 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
278 commonanc = repo.revs('ancestor(%ld, %d)', base, dest).first()
279 if commonanc is not None:
279 if commonanc is not None:
280 rebaseset = repo.revs('(%d::(%ld) - %d)::',
280 rebaseset = repo.revs('(%d::(%ld) - %d)::',
281 commonanc, base, commonanc)
281 commonanc, base, commonanc)
282 else:
282 else:
283 rebaseset = []
283 rebaseset = []
284
284
285 if not rebaseset:
285 if not rebaseset:
286 # transform to list because smartsets are not comparable to
286 # transform to list because smartsets are not comparable to
287 # lists. This should be improved to honor laziness of
287 # lists. This should be improved to honor laziness of
288 # smartset.
288 # smartset.
289 if list(base) == [dest.rev()]:
289 if list(base) == [dest.rev()]:
290 if basef:
290 if basef:
291 ui.status(_('nothing to rebase - %s is both "base"'
291 ui.status(_('nothing to rebase - %s is both "base"'
292 ' and destination\n') % dest)
292 ' and destination\n') % dest)
293 else:
293 else:
294 ui.status(_('nothing to rebase - working directory '
294 ui.status(_('nothing to rebase - working directory '
295 'parent is also destination\n'))
295 'parent is also destination\n'))
296 elif not repo.revs('%ld - ::%d', base, dest):
296 elif not repo.revs('%ld - ::%d', base, dest):
297 if basef:
297 if basef:
298 ui.status(_('nothing to rebase - "base" %s is '
298 ui.status(_('nothing to rebase - "base" %s is '
299 'already an ancestor of destination '
299 'already an ancestor of destination '
300 '%s\n') %
300 '%s\n') %
301 ('+'.join(str(repo[r]) for r in base),
301 ('+'.join(str(repo[r]) for r in base),
302 dest))
302 dest))
303 else:
303 else:
304 ui.status(_('nothing to rebase - working '
304 ui.status(_('nothing to rebase - working '
305 'directory parent is already an '
305 'directory parent is already an '
306 'ancestor of destination %s\n') % dest)
306 'ancestor of destination %s\n') % dest)
307 else: # can it happen?
307 else: # can it happen?
308 ui.status(_('nothing to rebase from %s to %s\n') %
308 ui.status(_('nothing to rebase from %s to %s\n') %
309 ('+'.join(str(repo[r]) for r in base), dest))
309 ('+'.join(str(repo[r]) for r in base), dest))
310 return 1
310 return 1
311
311
312 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
312 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
313 if (not (keepf or allowunstable)
313 if (not (keepf or allowunstable)
314 and repo.revs('first(children(%ld) - %ld)',
314 and repo.revs('first(children(%ld) - %ld)',
315 rebaseset, rebaseset)):
315 rebaseset, rebaseset)):
316 raise util.Abort(
316 raise util.Abort(
317 _("can't remove original changesets with"
317 _("can't remove original changesets with"
318 " unrebased descendants"),
318 " unrebased descendants"),
319 hint=_('use --keep to keep original changesets'))
319 hint=_('use --keep to keep original changesets'))
320
320
321 result = buildstate(repo, dest, rebaseset, collapsef)
321 result = buildstate(repo, dest, rebaseset, collapsef)
322 if not result:
322 if not result:
323 # Empty state built, nothing to rebase
323 # Empty state built, nothing to rebase
324 ui.status(_('nothing to rebase\n'))
324 ui.status(_('nothing to rebase\n'))
325 return 1
325 return 1
326
326
327 root = min(rebaseset)
327 root = min(rebaseset)
328 if not keepf and not repo[root].mutable():
328 if not keepf and not repo[root].mutable():
329 raise util.Abort(_("can't rebase immutable changeset %s")
329 raise util.Abort(_("can't rebase immutable changeset %s")
330 % repo[root],
330 % repo[root],
331 hint=_('see "hg help phases" for details'))
331 hint=_('see "hg help phases" for details'))
332
332
333 originalwd, target, state = result
333 originalwd, target, state = result
334 if collapsef:
334 if collapsef:
335 targetancestors = repo.changelog.ancestors([target],
335 targetancestors = repo.changelog.ancestors([target],
336 inclusive=True)
336 inclusive=True)
337 external = externalparent(repo, state, targetancestors)
337 external = externalparent(repo, state, targetancestors)
338
338
339 if dest.closesbranch() and not keepbranchesf:
339 if dest.closesbranch() and not keepbranchesf:
340 ui.status(_('reopening closed branch head %s\n') % dest)
340 ui.status(_('reopening closed branch head %s\n') % dest)
341
341
342 if keepbranchesf:
342 if keepbranchesf:
343 # insert _savebranch at the start of extrafns so if
343 # insert _savebranch at the start of extrafns so if
344 # there's a user-provided extrafn it can clobber branch if
344 # there's a user-provided extrafn it can clobber branch if
345 # desired
345 # desired
346 extrafns.insert(0, _savebranch)
346 extrafns.insert(0, _savebranch)
347 if collapsef:
347 if collapsef:
348 branches = set()
348 branches = set()
349 for rev in state:
349 for rev in state:
350 branches.add(repo[rev].branch())
350 branches.add(repo[rev].branch())
351 if len(branches) > 1:
351 if len(branches) > 1:
352 raise util.Abort(_('cannot collapse multiple named '
352 raise util.Abort(_('cannot collapse multiple named '
353 'branches'))
353 'branches'))
354
354
355 # Rebase
355 # Rebase
356 if not targetancestors:
356 if not targetancestors:
357 targetancestors = repo.changelog.ancestors([target], inclusive=True)
357 targetancestors = repo.changelog.ancestors([target], inclusive=True)
358
358
359 # Keep track of the current bookmarks in order to reset them later
359 # Keep track of the current bookmarks in order to reset them later
360 currentbookmarks = repo._bookmarks.copy()
360 currentbookmarks = repo._bookmarks.copy()
361 activebookmark = activebookmark or repo._activebookmark
361 activebookmark = activebookmark or repo._activebookmark
362 if activebookmark:
362 if activebookmark:
363 bookmarks.deactivate(repo)
363 bookmarks.deactivate(repo)
364
364
365 extrafn = _makeextrafn(extrafns)
365 extrafn = _makeextrafn(extrafns)
366
366
367 sortedstate = sorted(state)
367 sortedstate = sorted(state)
368 total = len(sortedstate)
368 total = len(sortedstate)
369 pos = 0
369 pos = 0
370 for rev in sortedstate:
370 for rev in sortedstate:
371 ctx = repo[rev]
371 ctx = repo[rev]
372 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
372 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
373 ctx.description().split('\n', 1)[0])
373 ctx.description().split('\n', 1)[0])
374 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
374 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
375 if names:
375 if names:
376 desc += ' (%s)' % ' '.join(names)
376 desc += ' (%s)' % ' '.join(names)
377 pos += 1
377 pos += 1
378 if state[rev] == revtodo:
378 if state[rev] == revtodo:
379 ui.status(_('rebasing %s\n') % desc)
379 ui.status(_('rebasing %s\n') % desc)
380 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
380 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
381 _('changesets'), total)
381 _('changesets'), total)
382 p1, p2, base = defineparents(repo, rev, target, state,
382 p1, p2, base = defineparents(repo, rev, target, state,
383 targetancestors)
383 targetancestors)
384 storestatus(repo, originalwd, target, state, collapsef, keepf,
384 storestatus(repo, originalwd, target, state, collapsef, keepf,
385 keepbranchesf, external, activebookmark)
385 keepbranchesf, external, activebookmark)
386 if len(repo.parents()) == 2:
386 if len(repo.parents()) == 2:
387 repo.ui.debug('resuming interrupted rebase\n')
387 repo.ui.debug('resuming interrupted rebase\n')
388 else:
388 else:
389 try:
389 try:
390 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
390 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
391 'rebase')
391 'rebase')
392 stats = rebasenode(repo, rev, p1, base, state,
392 stats = rebasenode(repo, rev, p1, base, state,
393 collapsef, target)
393 collapsef, target)
394 if stats and stats[3] > 0:
394 if stats and stats[3] > 0:
395 raise error.InterventionRequired(
395 raise error.InterventionRequired(
396 _('unresolved conflicts (see hg '
396 _('unresolved conflicts (see hg '
397 'resolve, then hg rebase --continue)'))
397 'resolve, then hg rebase --continue)'))
398 finally:
398 finally:
399 ui.setconfig('ui', 'forcemerge', '', 'rebase')
399 ui.setconfig('ui', 'forcemerge', '', 'rebase')
400 if not collapsef:
400 if not collapsef:
401 merging = p2 != nullrev
401 merging = p2 != nullrev
402 editform = cmdutil.mergeeditform(merging, 'rebase')
402 editform = cmdutil.mergeeditform(merging, 'rebase')
403 editor = cmdutil.getcommiteditor(editform=editform, **opts)
403 editor = cmdutil.getcommiteditor(editform=editform, **opts)
404 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
404 newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
405 editor=editor)
405 editor=editor)
406 else:
406 else:
407 # Skip commit if we are collapsing
407 # Skip commit if we are collapsing
408 repo.dirstate.beginparentchange()
408 repo.dirstate.beginparentchange()
409 repo.setparents(repo[p1].node())
409 repo.setparents(repo[p1].node())
410 repo.dirstate.endparentchange()
410 repo.dirstate.endparentchange()
411 newnode = None
411 newnode = None
412 # Update the state
412 # Update the state
413 if newnode is not None:
413 if newnode is not None:
414 state[rev] = repo[newnode].rev()
414 state[rev] = repo[newnode].rev()
415 ui.debug('rebased as %s\n' % short(newnode))
415 ui.debug('rebased as %s\n' % short(newnode))
416 else:
416 else:
417 ui.warn(_('note: rebase of %d:%s created no changes '
417 ui.warn(_('note: rebase of %d:%s created no changes '
418 'to commit\n') % (rev, ctx))
418 'to commit\n') % (rev, ctx))
419 if not collapsef:
419 if not collapsef:
420 skipped.add(rev)
420 skipped.add(rev)
421 state[rev] = p1
421 state[rev] = p1
422 ui.debug('next revision set to %s\n' % p1)
422 ui.debug('next revision set to %s\n' % p1)
423 elif state[rev] == nullmerge:
423 elif state[rev] == nullmerge:
424 ui.debug('ignoring null merge rebase of %s\n' % rev)
424 ui.debug('ignoring null merge rebase of %s\n' % rev)
425 elif state[rev] == revignored:
425 elif state[rev] == revignored:
426 ui.status(_('not rebasing ignored %s\n') % desc)
426 ui.status(_('not rebasing ignored %s\n') % desc)
427 else:
427 else:
428 ui.status(_('already rebased %s as %s\n') %
428 ui.status(_('already rebased %s as %s\n') %
429 (desc, repo[state[rev]]))
429 (desc, repo[state[rev]]))
430
430
431 ui.progress(_('rebasing'), None)
431 ui.progress(_('rebasing'), None)
432 ui.note(_('rebase merging completed\n'))
432 ui.note(_('rebase merging completed\n'))
433
433
434 if collapsef and not keepopen:
434 if collapsef and not keepopen:
435 p1, p2, _base = defineparents(repo, min(state), target,
435 p1, p2, _base = defineparents(repo, min(state), target,
436 state, targetancestors)
436 state, targetancestors)
437 editopt = opts.get('edit')
437 editopt = opts.get('edit')
438 editform = 'rebase.collapse'
438 editform = 'rebase.collapse'
439 if collapsemsg:
439 if collapsemsg:
440 commitmsg = collapsemsg
440 commitmsg = collapsemsg
441 else:
441 else:
442 commitmsg = 'Collapsed revision'
442 commitmsg = 'Collapsed revision'
443 for rebased in state:
443 for rebased in state:
444 if rebased not in skipped and state[rebased] > nullmerge:
444 if rebased not in skipped and state[rebased] > nullmerge:
445 commitmsg += '\n* %s' % repo[rebased].description()
445 commitmsg += '\n* %s' % repo[rebased].description()
446 editopt = True
446 editopt = True
447 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
447 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
448 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
448 newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
449 extrafn=extrafn, editor=editor)
449 extrafn=extrafn, editor=editor)
450 if newnode is None:
450 if newnode is None:
451 newrev = target
451 newrev = target
452 else:
452 else:
453 newrev = repo[newnode].rev()
453 newrev = repo[newnode].rev()
454 for oldrev in state.iterkeys():
454 for oldrev in state.iterkeys():
455 if state[oldrev] > nullmerge:
455 if state[oldrev] > nullmerge:
456 state[oldrev] = newrev
456 state[oldrev] = newrev
457
457
458 if 'qtip' in repo.tags():
458 if 'qtip' in repo.tags():
459 updatemq(repo, state, skipped, **opts)
459 updatemq(repo, state, skipped, **opts)
460
460
461 if currentbookmarks:
461 if currentbookmarks:
462 # Nodeids are needed to reset bookmarks
462 # Nodeids are needed to reset bookmarks
463 nstate = {}
463 nstate = {}
464 for k, v in state.iteritems():
464 for k, v in state.iteritems():
465 if v > nullmerge:
465 if v > nullmerge:
466 nstate[repo[k].node()] = repo[v].node()
466 nstate[repo[k].node()] = repo[v].node()
467 # XXX this is the same as dest.node() for the non-continue path --
467 # XXX this is the same as dest.node() for the non-continue path --
468 # this should probably be cleaned up
468 # this should probably be cleaned up
469 targetnode = repo[target].node()
469 targetnode = repo[target].node()
470
470
471 # restore original working directory
471 # restore original working directory
472 # (we do this before stripping)
472 # (we do this before stripping)
473 newwd = state.get(originalwd, originalwd)
473 newwd = state.get(originalwd, originalwd)
474 if newwd < 0:
474 if newwd < 0:
475 # original directory is a parent of rebase set root or ignored
475 # original directory is a parent of rebase set root or ignored
476 newwd = originalwd
476 newwd = originalwd
477 if newwd not in [c.rev() for c in repo[None].parents()]:
477 if newwd not in [c.rev() for c in repo[None].parents()]:
478 ui.note(_("update back to initial working directory parent\n"))
478 ui.note(_("update back to initial working directory parent\n"))
479 hg.updaterepo(repo, newwd, False)
479 hg.updaterepo(repo, newwd, False)
480
480
481 if not keepf:
481 if not keepf:
482 collapsedas = None
482 collapsedas = None
483 if collapsef:
483 if collapsef:
484 collapsedas = newnode
484 collapsedas = newnode
485 clearrebased(ui, repo, state, skipped, collapsedas)
485 clearrebased(ui, repo, state, skipped, collapsedas)
486
486
487 if currentbookmarks:
487 if currentbookmarks:
488 updatebookmarks(repo, targetnode, nstate, currentbookmarks)
488 updatebookmarks(repo, targetnode, nstate, currentbookmarks)
489 if activebookmark not in repo._bookmarks:
489 if activebookmark not in repo._bookmarks:
490 # active bookmark was divergent one and has been deleted
490 # active bookmark was divergent one and has been deleted
491 activebookmark = None
491 activebookmark = None
492
492
493 clearstatus(repo)
493 clearstatus(repo)
494 ui.note(_("rebase completed\n"))
494 ui.note(_("rebase completed\n"))
495 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
495 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
496 if skipped:
496 if skipped:
497 ui.note(_("%d revisions have been skipped\n") % len(skipped))
497 ui.note(_("%d revisions have been skipped\n") % len(skipped))
498
498
499 if (activebookmark and
499 if (activebookmark and
500 repo['.'].node() == repo._bookmarks[activebookmark]):
500 repo['.'].node() == repo._bookmarks[activebookmark]):
501 bookmarks.activate(repo, activebookmark)
501 bookmarks.activate(repo, activebookmark)
502
502
503 finally:
503 finally:
504 release(lock, wlock)
504 release(lock, wlock)
505
505
506 def externalparent(repo, state, targetancestors):
506 def externalparent(repo, state, targetancestors):
507 """Return the revision that should be used as the second parent
507 """Return the revision that should be used as the second parent
508 when the revisions in state is collapsed on top of targetancestors.
508 when the revisions in state is collapsed on top of targetancestors.
509 Abort if there is more than one parent.
509 Abort if there is more than one parent.
510 """
510 """
511 parents = set()
511 parents = set()
512 source = min(state)
512 source = min(state)
513 for rev in state:
513 for rev in state:
514 if rev == source:
514 if rev == source:
515 continue
515 continue
516 for p in repo[rev].parents():
516 for p in repo[rev].parents():
517 if (p.rev() not in state
517 if (p.rev() not in state
518 and p.rev() not in targetancestors):
518 and p.rev() not in targetancestors):
519 parents.add(p.rev())
519 parents.add(p.rev())
520 if not parents:
520 if not parents:
521 return nullrev
521 return nullrev
522 if len(parents) == 1:
522 if len(parents) == 1:
523 return parents.pop()
523 return parents.pop()
524 raise util.Abort(_('unable to collapse on top of %s, there is more '
524 raise util.Abort(_('unable to collapse on top of %s, there is more '
525 'than one external parent: %s') %
525 'than one external parent: %s') %
526 (max(targetancestors),
526 (max(targetancestors),
527 ', '.join(str(p) for p in sorted(parents))))
527 ', '.join(str(p) for p in sorted(parents))))
528
528
529 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
529 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
530 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
530 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
531 but also store useful information in extra.
531 but also store useful information in extra.
532 Return node of committed revision.'''
532 Return node of committed revision.'''
533 dsguard = cmdutil.dirstateguard(repo, 'rebase')
533 try:
534 try:
534 repo.dirstate.beginparentchange()
535 repo.setparents(repo[p1].node(), repo[p2].node())
535 repo.setparents(repo[p1].node(), repo[p2].node())
536 repo.dirstate.endparentchange()
537 ctx = repo[rev]
536 ctx = repo[rev]
538 if commitmsg is None:
537 if commitmsg is None:
539 commitmsg = ctx.description()
538 commitmsg = ctx.description()
540 extra = {'rebase_source': ctx.hex()}
539 extra = {'rebase_source': ctx.hex()}
541 if extrafn:
540 if extrafn:
542 extrafn(ctx, extra)
541 extrafn(ctx, extra)
543
542
544 backup = repo.ui.backupconfig('phases', 'new-commit')
543 backup = repo.ui.backupconfig('phases', 'new-commit')
545 try:
544 try:
546 targetphase = max(ctx.phase(), phases.draft)
545 targetphase = max(ctx.phase(), phases.draft)
547 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
546 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
548 # Commit might fail if unresolved files exist
547 # Commit might fail if unresolved files exist
549 newnode = repo.commit(text=commitmsg, user=ctx.user(),
548 newnode = repo.commit(text=commitmsg, user=ctx.user(),
550 date=ctx.date(), extra=extra, editor=editor)
549 date=ctx.date(), extra=extra, editor=editor)
551 finally:
550 finally:
552 repo.ui.restoreconfig(backup)
551 repo.ui.restoreconfig(backup)
553
552
554 repo.dirstate.setbranch(repo[newnode].branch())
553 repo.dirstate.setbranch(repo[newnode].branch())
554 dsguard.close()
555 return newnode
555 return newnode
556 except util.Abort:
556 finally:
557 # Invalidate the previous setparents
557 release(dsguard)
558 repo.dirstate.invalidate()
559 raise
560
558
561 def rebasenode(repo, rev, p1, base, state, collapse, target):
559 def rebasenode(repo, rev, p1, base, state, collapse, target):
562 'Rebase a single revision rev on top of p1 using base as merge ancestor'
560 'Rebase a single revision rev on top of p1 using base as merge ancestor'
563 # Merge phase
561 # Merge phase
564 # Update to target and merge it with local
562 # Update to target and merge it with local
565 if repo['.'].rev() != p1:
563 if repo['.'].rev() != p1:
566 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
564 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
567 merge.update(repo, p1, False, True, False)
565 merge.update(repo, p1, False, True, False)
568 else:
566 else:
569 repo.ui.debug(" already in target\n")
567 repo.ui.debug(" already in target\n")
570 repo.dirstate.write()
568 repo.dirstate.write()
571 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
569 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
572 if base is not None:
570 if base is not None:
573 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
571 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
574 # When collapsing in-place, the parent is the common ancestor, we
572 # When collapsing in-place, the parent is the common ancestor, we
575 # have to allow merging with it.
573 # have to allow merging with it.
576 stats = merge.update(repo, rev, True, True, False, base, collapse,
574 stats = merge.update(repo, rev, True, True, False, base, collapse,
577 labels=['dest', 'source'])
575 labels=['dest', 'source'])
578 if collapse:
576 if collapse:
579 copies.duplicatecopies(repo, rev, target)
577 copies.duplicatecopies(repo, rev, target)
580 else:
578 else:
581 # If we're not using --collapse, we need to
579 # If we're not using --collapse, we need to
582 # duplicate copies between the revision we're
580 # duplicate copies between the revision we're
583 # rebasing and its first parent, but *not*
581 # rebasing and its first parent, but *not*
584 # duplicate any copies that have already been
582 # duplicate any copies that have already been
585 # performed in the destination.
583 # performed in the destination.
586 p1rev = repo[rev].p1().rev()
584 p1rev = repo[rev].p1().rev()
587 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
585 copies.duplicatecopies(repo, rev, p1rev, skiprev=target)
588 return stats
586 return stats
589
587
590 def nearestrebased(repo, rev, state):
588 def nearestrebased(repo, rev, state):
591 """return the nearest ancestors of rev in the rebase result"""
589 """return the nearest ancestors of rev in the rebase result"""
592 rebased = [r for r in state if state[r] > nullmerge]
590 rebased = [r for r in state if state[r] > nullmerge]
593 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
591 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
594 if candidates:
592 if candidates:
595 return state[candidates.first()]
593 return state[candidates.first()]
596 else:
594 else:
597 return None
595 return None
598
596
599 def defineparents(repo, rev, target, state, targetancestors):
597 def defineparents(repo, rev, target, state, targetancestors):
600 'Return the new parent relationship of the revision that will be rebased'
598 'Return the new parent relationship of the revision that will be rebased'
601 parents = repo[rev].parents()
599 parents = repo[rev].parents()
602 p1 = p2 = nullrev
600 p1 = p2 = nullrev
603
601
604 p1n = parents[0].rev()
602 p1n = parents[0].rev()
605 if p1n in targetancestors:
603 if p1n in targetancestors:
606 p1 = target
604 p1 = target
607 elif p1n in state:
605 elif p1n in state:
608 if state[p1n] == nullmerge:
606 if state[p1n] == nullmerge:
609 p1 = target
607 p1 = target
610 elif state[p1n] == revignored:
608 elif state[p1n] == revignored:
611 p1 = nearestrebased(repo, p1n, state)
609 p1 = nearestrebased(repo, p1n, state)
612 if p1 is None:
610 if p1 is None:
613 p1 = target
611 p1 = target
614 else:
612 else:
615 p1 = state[p1n]
613 p1 = state[p1n]
616 else: # p1n external
614 else: # p1n external
617 p1 = target
615 p1 = target
618 p2 = p1n
616 p2 = p1n
619
617
620 if len(parents) == 2 and parents[1].rev() not in targetancestors:
618 if len(parents) == 2 and parents[1].rev() not in targetancestors:
621 p2n = parents[1].rev()
619 p2n = parents[1].rev()
622 # interesting second parent
620 # interesting second parent
623 if p2n in state:
621 if p2n in state:
624 if p1 == target: # p1n in targetancestors or external
622 if p1 == target: # p1n in targetancestors or external
625 p1 = state[p2n]
623 p1 = state[p2n]
626 elif state[p2n] == revignored:
624 elif state[p2n] == revignored:
627 p2 = nearestrebased(repo, p2n, state)
625 p2 = nearestrebased(repo, p2n, state)
628 if p2 is None:
626 if p2 is None:
629 # no ancestors rebased yet, detach
627 # no ancestors rebased yet, detach
630 p2 = target
628 p2 = target
631 else:
629 else:
632 p2 = state[p2n]
630 p2 = state[p2n]
633 else: # p2n external
631 else: # p2n external
634 if p2 != nullrev: # p1n external too => rev is a merged revision
632 if p2 != nullrev: # p1n external too => rev is a merged revision
635 raise util.Abort(_('cannot use revision %d as base, result '
633 raise util.Abort(_('cannot use revision %d as base, result '
636 'would have 3 parents') % rev)
634 'would have 3 parents') % rev)
637 p2 = p2n
635 p2 = p2n
638 repo.ui.debug(" future parents are %d and %d\n" %
636 repo.ui.debug(" future parents are %d and %d\n" %
639 (repo[p1].rev(), repo[p2].rev()))
637 (repo[p1].rev(), repo[p2].rev()))
640
638
641 if rev == min(state):
639 if rev == min(state):
642 # Case (1) initial changeset of a non-detaching rebase.
640 # Case (1) initial changeset of a non-detaching rebase.
643 # Let the merge mechanism find the base itself.
641 # Let the merge mechanism find the base itself.
644 base = None
642 base = None
645 elif not repo[rev].p2():
643 elif not repo[rev].p2():
646 # Case (2) detaching the node with a single parent, use this parent
644 # Case (2) detaching the node with a single parent, use this parent
647 base = repo[rev].p1().rev()
645 base = repo[rev].p1().rev()
648 else:
646 else:
649 # Assuming there is a p1, this is the case where there also is a p2.
647 # Assuming there is a p1, this is the case where there also is a p2.
650 # We are thus rebasing a merge and need to pick the right merge base.
648 # We are thus rebasing a merge and need to pick the right merge base.
651 #
649 #
652 # Imagine we have:
650 # Imagine we have:
653 # - M: current rebase revision in this step
651 # - M: current rebase revision in this step
654 # - A: one parent of M
652 # - A: one parent of M
655 # - B: other parent of M
653 # - B: other parent of M
656 # - D: destination of this merge step (p1 var)
654 # - D: destination of this merge step (p1 var)
657 #
655 #
658 # Consider the case where D is a descendant of A or B and the other is
656 # Consider the case where D is a descendant of A or B and the other is
659 # 'outside'. In this case, the right merge base is the D ancestor.
657 # 'outside'. In this case, the right merge base is the D ancestor.
660 #
658 #
661 # An informal proof, assuming A is 'outside' and B is the D ancestor:
659 # An informal proof, assuming A is 'outside' and B is the D ancestor:
662 #
660 #
663 # If we pick B as the base, the merge involves:
661 # If we pick B as the base, the merge involves:
664 # - changes from B to M (actual changeset payload)
662 # - changes from B to M (actual changeset payload)
665 # - changes from B to D (induced by rebase) as D is a rebased
663 # - changes from B to D (induced by rebase) as D is a rebased
666 # version of B)
664 # version of B)
667 # Which exactly represent the rebase operation.
665 # Which exactly represent the rebase operation.
668 #
666 #
669 # If we pick A as the base, the merge involves:
667 # If we pick A as the base, the merge involves:
670 # - changes from A to M (actual changeset payload)
668 # - changes from A to M (actual changeset payload)
671 # - changes from A to D (with include changes between unrelated A and B
669 # - changes from A to D (with include changes between unrelated A and B
672 # plus changes induced by rebase)
670 # plus changes induced by rebase)
673 # Which does not represent anything sensible and creates a lot of
671 # Which does not represent anything sensible and creates a lot of
674 # conflicts. A is thus not the right choice - B is.
672 # conflicts. A is thus not the right choice - B is.
675 #
673 #
676 # Note: The base found in this 'proof' is only correct in the specified
674 # Note: The base found in this 'proof' is only correct in the specified
677 # case. This base does not make sense if is not D a descendant of A or B
675 # case. This base does not make sense if is not D a descendant of A or B
678 # or if the other is not parent 'outside' (especially not if the other
676 # or if the other is not parent 'outside' (especially not if the other
679 # parent has been rebased). The current implementation does not
677 # parent has been rebased). The current implementation does not
680 # make it feasible to consider different cases separately. In these
678 # make it feasible to consider different cases separately. In these
681 # other cases we currently just leave it to the user to correctly
679 # other cases we currently just leave it to the user to correctly
682 # resolve an impossible merge using a wrong ancestor.
680 # resolve an impossible merge using a wrong ancestor.
683 for p in repo[rev].parents():
681 for p in repo[rev].parents():
684 if state.get(p.rev()) == p1:
682 if state.get(p.rev()) == p1:
685 base = p.rev()
683 base = p.rev()
686 break
684 break
687 else: # fallback when base not found
685 else: # fallback when base not found
688 base = None
686 base = None
689
687
690 # Raise because this function is called wrong (see issue 4106)
688 # Raise because this function is called wrong (see issue 4106)
691 raise AssertionError('no base found to rebase on '
689 raise AssertionError('no base found to rebase on '
692 '(defineparents called wrong)')
690 '(defineparents called wrong)')
693 return p1, p2, base
691 return p1, p2, base
694
692
695 def isagitpatch(repo, patchname):
693 def isagitpatch(repo, patchname):
696 'Return true if the given patch is in git format'
694 'Return true if the given patch is in git format'
697 mqpatch = os.path.join(repo.mq.path, patchname)
695 mqpatch = os.path.join(repo.mq.path, patchname)
698 for line in patch.linereader(file(mqpatch, 'rb')):
696 for line in patch.linereader(file(mqpatch, 'rb')):
699 if line.startswith('diff --git'):
697 if line.startswith('diff --git'):
700 return True
698 return True
701 return False
699 return False
702
700
703 def updatemq(repo, state, skipped, **opts):
701 def updatemq(repo, state, skipped, **opts):
704 'Update rebased mq patches - finalize and then import them'
702 'Update rebased mq patches - finalize and then import them'
705 mqrebase = {}
703 mqrebase = {}
706 mq = repo.mq
704 mq = repo.mq
707 original_series = mq.fullseries[:]
705 original_series = mq.fullseries[:]
708 skippedpatches = set()
706 skippedpatches = set()
709
707
710 for p in mq.applied:
708 for p in mq.applied:
711 rev = repo[p.node].rev()
709 rev = repo[p.node].rev()
712 if rev in state:
710 if rev in state:
713 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
711 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
714 (rev, p.name))
712 (rev, p.name))
715 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
713 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
716 else:
714 else:
717 # Applied but not rebased, not sure this should happen
715 # Applied but not rebased, not sure this should happen
718 skippedpatches.add(p.name)
716 skippedpatches.add(p.name)
719
717
720 if mqrebase:
718 if mqrebase:
721 mq.finish(repo, mqrebase.keys())
719 mq.finish(repo, mqrebase.keys())
722
720
723 # We must start import from the newest revision
721 # We must start import from the newest revision
724 for rev in sorted(mqrebase, reverse=True):
722 for rev in sorted(mqrebase, reverse=True):
725 if rev not in skipped:
723 if rev not in skipped:
726 name, isgit = mqrebase[rev]
724 name, isgit = mqrebase[rev]
727 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
725 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
728 (name, state[rev], repo[state[rev]]))
726 (name, state[rev], repo[state[rev]]))
729 mq.qimport(repo, (), patchname=name, git=isgit,
727 mq.qimport(repo, (), patchname=name, git=isgit,
730 rev=[str(state[rev])])
728 rev=[str(state[rev])])
731 else:
729 else:
732 # Rebased and skipped
730 # Rebased and skipped
733 skippedpatches.add(mqrebase[rev][0])
731 skippedpatches.add(mqrebase[rev][0])
734
732
735 # Patches were either applied and rebased and imported in
733 # Patches were either applied and rebased and imported in
736 # order, applied and removed or unapplied. Discard the removed
734 # order, applied and removed or unapplied. Discard the removed
737 # ones while preserving the original series order and guards.
735 # ones while preserving the original series order and guards.
738 newseries = [s for s in original_series
736 newseries = [s for s in original_series
739 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
737 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
740 mq.fullseries[:] = newseries
738 mq.fullseries[:] = newseries
741 mq.seriesdirty = True
739 mq.seriesdirty = True
742 mq.savedirty()
740 mq.savedirty()
743
741
744 def updatebookmarks(repo, targetnode, nstate, originalbookmarks):
742 def updatebookmarks(repo, targetnode, nstate, originalbookmarks):
745 'Move bookmarks to their correct changesets, and delete divergent ones'
743 'Move bookmarks to their correct changesets, and delete divergent ones'
746 marks = repo._bookmarks
744 marks = repo._bookmarks
747 for k, v in originalbookmarks.iteritems():
745 for k, v in originalbookmarks.iteritems():
748 if v in nstate:
746 if v in nstate:
749 # update the bookmarks for revs that have moved
747 # update the bookmarks for revs that have moved
750 marks[k] = nstate[v]
748 marks[k] = nstate[v]
751 bookmarks.deletedivergent(repo, [targetnode], k)
749 bookmarks.deletedivergent(repo, [targetnode], k)
752
750
753 marks.write()
751 marks.write()
754
752
755 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
753 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
756 external, activebookmark):
754 external, activebookmark):
757 'Store the current status to allow recovery'
755 'Store the current status to allow recovery'
758 f = repo.vfs("rebasestate", "w")
756 f = repo.vfs("rebasestate", "w")
759 f.write(repo[originalwd].hex() + '\n')
757 f.write(repo[originalwd].hex() + '\n')
760 f.write(repo[target].hex() + '\n')
758 f.write(repo[target].hex() + '\n')
761 f.write(repo[external].hex() + '\n')
759 f.write(repo[external].hex() + '\n')
762 f.write('%d\n' % int(collapse))
760 f.write('%d\n' % int(collapse))
763 f.write('%d\n' % int(keep))
761 f.write('%d\n' % int(keep))
764 f.write('%d\n' % int(keepbranches))
762 f.write('%d\n' % int(keepbranches))
765 f.write('%s\n' % (activebookmark or ''))
763 f.write('%s\n' % (activebookmark or ''))
766 for d, v in state.iteritems():
764 for d, v in state.iteritems():
767 oldrev = repo[d].hex()
765 oldrev = repo[d].hex()
768 if v >= 0:
766 if v >= 0:
769 newrev = repo[v].hex()
767 newrev = repo[v].hex()
770 elif v == revtodo:
768 elif v == revtodo:
771 # To maintain format compatibility, we have to use nullid.
769 # To maintain format compatibility, we have to use nullid.
772 # Please do remove this special case when upgrading the format.
770 # Please do remove this special case when upgrading the format.
773 newrev = hex(nullid)
771 newrev = hex(nullid)
774 else:
772 else:
775 newrev = v
773 newrev = v
776 f.write("%s:%s\n" % (oldrev, newrev))
774 f.write("%s:%s\n" % (oldrev, newrev))
777 f.close()
775 f.close()
778 repo.ui.debug('rebase status stored\n')
776 repo.ui.debug('rebase status stored\n')
779
777
780 def clearstatus(repo):
778 def clearstatus(repo):
781 'Remove the status files'
779 'Remove the status files'
782 _clearrebasesetvisibiliy(repo)
780 _clearrebasesetvisibiliy(repo)
783 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
781 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
784
782
785 def restorestatus(repo):
783 def restorestatus(repo):
786 'Restore a previously stored status'
784 'Restore a previously stored status'
787 try:
785 try:
788 keepbranches = None
786 keepbranches = None
789 target = None
787 target = None
790 collapse = False
788 collapse = False
791 external = nullrev
789 external = nullrev
792 activebookmark = None
790 activebookmark = None
793 state = {}
791 state = {}
794 f = repo.vfs("rebasestate")
792 f = repo.vfs("rebasestate")
795 for i, l in enumerate(f.read().splitlines()):
793 for i, l in enumerate(f.read().splitlines()):
796 if i == 0:
794 if i == 0:
797 originalwd = repo[l].rev()
795 originalwd = repo[l].rev()
798 elif i == 1:
796 elif i == 1:
799 target = repo[l].rev()
797 target = repo[l].rev()
800 elif i == 2:
798 elif i == 2:
801 external = repo[l].rev()
799 external = repo[l].rev()
802 elif i == 3:
800 elif i == 3:
803 collapse = bool(int(l))
801 collapse = bool(int(l))
804 elif i == 4:
802 elif i == 4:
805 keep = bool(int(l))
803 keep = bool(int(l))
806 elif i == 5:
804 elif i == 5:
807 keepbranches = bool(int(l))
805 keepbranches = bool(int(l))
808 elif i == 6 and not (len(l) == 81 and ':' in l):
806 elif i == 6 and not (len(l) == 81 and ':' in l):
809 # line 6 is a recent addition, so for backwards compatibility
807 # line 6 is a recent addition, so for backwards compatibility
810 # check that the line doesn't look like the oldrev:newrev lines
808 # check that the line doesn't look like the oldrev:newrev lines
811 activebookmark = l
809 activebookmark = l
812 else:
810 else:
813 oldrev, newrev = l.split(':')
811 oldrev, newrev = l.split(':')
814 if newrev in (str(nullmerge), str(revignored)):
812 if newrev in (str(nullmerge), str(revignored)):
815 state[repo[oldrev].rev()] = int(newrev)
813 state[repo[oldrev].rev()] = int(newrev)
816 elif newrev == nullid:
814 elif newrev == nullid:
817 state[repo[oldrev].rev()] = revtodo
815 state[repo[oldrev].rev()] = revtodo
818 # Legacy compat special case
816 # Legacy compat special case
819 else:
817 else:
820 state[repo[oldrev].rev()] = repo[newrev].rev()
818 state[repo[oldrev].rev()] = repo[newrev].rev()
821
819
822 if keepbranches is None:
820 if keepbranches is None:
823 raise util.Abort(_('.hg/rebasestate is incomplete'))
821 raise util.Abort(_('.hg/rebasestate is incomplete'))
824
822
825 skipped = set()
823 skipped = set()
826 # recompute the set of skipped revs
824 # recompute the set of skipped revs
827 if not collapse:
825 if not collapse:
828 seen = set([target])
826 seen = set([target])
829 for old, new in sorted(state.items()):
827 for old, new in sorted(state.items()):
830 if new != revtodo and new in seen:
828 if new != revtodo and new in seen:
831 skipped.add(old)
829 skipped.add(old)
832 seen.add(new)
830 seen.add(new)
833 repo.ui.debug('computed skipped revs: %s\n' %
831 repo.ui.debug('computed skipped revs: %s\n' %
834 (' '.join(str(r) for r in sorted(skipped)) or None))
832 (' '.join(str(r) for r in sorted(skipped)) or None))
835 repo.ui.debug('rebase status resumed\n')
833 repo.ui.debug('rebase status resumed\n')
836 _setrebasesetvisibility(repo, state.keys())
834 _setrebasesetvisibility(repo, state.keys())
837 return (originalwd, target, state, skipped,
835 return (originalwd, target, state, skipped,
838 collapse, keep, keepbranches, external, activebookmark)
836 collapse, keep, keepbranches, external, activebookmark)
839 except IOError, err:
837 except IOError, err:
840 if err.errno != errno.ENOENT:
838 if err.errno != errno.ENOENT:
841 raise
839 raise
842 raise util.Abort(_('no rebase in progress'))
840 raise util.Abort(_('no rebase in progress'))
843
841
844 def inrebase(repo, originalwd, state):
842 def inrebase(repo, originalwd, state):
845 '''check whether the working dir is in an interrupted rebase'''
843 '''check whether the working dir is in an interrupted rebase'''
846 parents = [p.rev() for p in repo.parents()]
844 parents = [p.rev() for p in repo.parents()]
847 if originalwd in parents:
845 if originalwd in parents:
848 return True
846 return True
849
847
850 for newrev in state.itervalues():
848 for newrev in state.itervalues():
851 if newrev in parents:
849 if newrev in parents:
852 return True
850 return True
853
851
854 return False
852 return False
855
853
856 def abort(repo, originalwd, target, state, activebookmark=None):
854 def abort(repo, originalwd, target, state, activebookmark=None):
857 '''Restore the repository to its original state. Additional args:
855 '''Restore the repository to its original state. Additional args:
858
856
859 activebookmark: the name of the bookmark that should be active after the
857 activebookmark: the name of the bookmark that should be active after the
860 restore'''
858 restore'''
861 dstates = [s for s in state.values() if s >= 0]
859 dstates = [s for s in state.values() if s >= 0]
862 immutable = [d for d in dstates if not repo[d].mutable()]
860 immutable = [d for d in dstates if not repo[d].mutable()]
863 cleanup = True
861 cleanup = True
864 if immutable:
862 if immutable:
865 repo.ui.warn(_("warning: can't clean up immutable changesets %s\n")
863 repo.ui.warn(_("warning: can't clean up immutable changesets %s\n")
866 % ', '.join(str(repo[r]) for r in immutable),
864 % ', '.join(str(repo[r]) for r in immutable),
867 hint=_('see "hg help phases" for details'))
865 hint=_('see "hg help phases" for details'))
868 cleanup = False
866 cleanup = False
869
867
870 descendants = set()
868 descendants = set()
871 if dstates:
869 if dstates:
872 descendants = set(repo.changelog.descendants(dstates))
870 descendants = set(repo.changelog.descendants(dstates))
873 if descendants - set(dstates):
871 if descendants - set(dstates):
874 repo.ui.warn(_("warning: new changesets detected on target branch, "
872 repo.ui.warn(_("warning: new changesets detected on target branch, "
875 "can't strip\n"))
873 "can't strip\n"))
876 cleanup = False
874 cleanup = False
877
875
878 if cleanup:
876 if cleanup:
879 # Update away from the rebase if necessary
877 # Update away from the rebase if necessary
880 if inrebase(repo, originalwd, state):
878 if inrebase(repo, originalwd, state):
881 merge.update(repo, originalwd, False, True, False)
879 merge.update(repo, originalwd, False, True, False)
882
880
883 # Strip from the first rebased revision
881 # Strip from the first rebased revision
884 rebased = filter(lambda x: x >= 0 and x != target, state.values())
882 rebased = filter(lambda x: x >= 0 and x != target, state.values())
885 if rebased:
883 if rebased:
886 strippoints = [c.node() for c in repo.set('roots(%ld)', rebased)]
884 strippoints = [c.node() for c in repo.set('roots(%ld)', rebased)]
887 # no backup of rebased cset versions needed
885 # no backup of rebased cset versions needed
888 repair.strip(repo.ui, repo, strippoints)
886 repair.strip(repo.ui, repo, strippoints)
889
887
890 if activebookmark:
888 if activebookmark:
891 bookmarks.activate(repo, activebookmark)
889 bookmarks.activate(repo, activebookmark)
892
890
893 clearstatus(repo)
891 clearstatus(repo)
894 repo.ui.warn(_('rebase aborted\n'))
892 repo.ui.warn(_('rebase aborted\n'))
895 return 0
893 return 0
896
894
897 def buildstate(repo, dest, rebaseset, collapse):
895 def buildstate(repo, dest, rebaseset, collapse):
898 '''Define which revisions are going to be rebased and where
896 '''Define which revisions are going to be rebased and where
899
897
900 repo: repo
898 repo: repo
901 dest: context
899 dest: context
902 rebaseset: set of rev
900 rebaseset: set of rev
903 '''
901 '''
904 _setrebasesetvisibility(repo, rebaseset)
902 _setrebasesetvisibility(repo, rebaseset)
905
903
906 # This check isn't strictly necessary, since mq detects commits over an
904 # This check isn't strictly necessary, since mq detects commits over an
907 # applied patch. But it prevents messing up the working directory when
905 # applied patch. But it prevents messing up the working directory when
908 # a partially completed rebase is blocked by mq.
906 # a partially completed rebase is blocked by mq.
909 if 'qtip' in repo.tags() and (dest.node() in
907 if 'qtip' in repo.tags() and (dest.node() in
910 [s.node for s in repo.mq.applied]):
908 [s.node for s in repo.mq.applied]):
911 raise util.Abort(_('cannot rebase onto an applied mq patch'))
909 raise util.Abort(_('cannot rebase onto an applied mq patch'))
912
910
913 roots = list(repo.set('roots(%ld)', rebaseset))
911 roots = list(repo.set('roots(%ld)', rebaseset))
914 if not roots:
912 if not roots:
915 raise util.Abort(_('no matching revisions'))
913 raise util.Abort(_('no matching revisions'))
916 roots.sort()
914 roots.sort()
917 state = {}
915 state = {}
918 detachset = set()
916 detachset = set()
919 for root in roots:
917 for root in roots:
920 commonbase = root.ancestor(dest)
918 commonbase = root.ancestor(dest)
921 if commonbase == root:
919 if commonbase == root:
922 raise util.Abort(_('source is ancestor of destination'))
920 raise util.Abort(_('source is ancestor of destination'))
923 if commonbase == dest:
921 if commonbase == dest:
924 samebranch = root.branch() == dest.branch()
922 samebranch = root.branch() == dest.branch()
925 if not collapse and samebranch and root in dest.children():
923 if not collapse and samebranch and root in dest.children():
926 repo.ui.debug('source is a child of destination\n')
924 repo.ui.debug('source is a child of destination\n')
927 return None
925 return None
928
926
929 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
927 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, root))
930 state.update(dict.fromkeys(rebaseset, revtodo))
928 state.update(dict.fromkeys(rebaseset, revtodo))
931 # Rebase tries to turn <dest> into a parent of <root> while
929 # Rebase tries to turn <dest> into a parent of <root> while
932 # preserving the number of parents of rebased changesets:
930 # preserving the number of parents of rebased changesets:
933 #
931 #
934 # - A changeset with a single parent will always be rebased as a
932 # - A changeset with a single parent will always be rebased as a
935 # changeset with a single parent.
933 # changeset with a single parent.
936 #
934 #
937 # - A merge will be rebased as merge unless its parents are both
935 # - A merge will be rebased as merge unless its parents are both
938 # ancestors of <dest> or are themselves in the rebased set and
936 # ancestors of <dest> or are themselves in the rebased set and
939 # pruned while rebased.
937 # pruned while rebased.
940 #
938 #
941 # If one parent of <root> is an ancestor of <dest>, the rebased
939 # If one parent of <root> is an ancestor of <dest>, the rebased
942 # version of this parent will be <dest>. This is always true with
940 # version of this parent will be <dest>. This is always true with
943 # --base option.
941 # --base option.
944 #
942 #
945 # Otherwise, we need to *replace* the original parents with
943 # Otherwise, we need to *replace* the original parents with
946 # <dest>. This "detaches" the rebased set from its former location
944 # <dest>. This "detaches" the rebased set from its former location
947 # and rebases it onto <dest>. Changes introduced by ancestors of
945 # and rebases it onto <dest>. Changes introduced by ancestors of
948 # <root> not common with <dest> (the detachset, marked as
946 # <root> not common with <dest> (the detachset, marked as
949 # nullmerge) are "removed" from the rebased changesets.
947 # nullmerge) are "removed" from the rebased changesets.
950 #
948 #
951 # - If <root> has a single parent, set it to <dest>.
949 # - If <root> has a single parent, set it to <dest>.
952 #
950 #
953 # - If <root> is a merge, we cannot decide which parent to
951 # - If <root> is a merge, we cannot decide which parent to
954 # replace, the rebase operation is not clearly defined.
952 # replace, the rebase operation is not clearly defined.
955 #
953 #
956 # The table below sums up this behavior:
954 # The table below sums up this behavior:
957 #
955 #
958 # +------------------+----------------------+-------------------------+
956 # +------------------+----------------------+-------------------------+
959 # | | one parent | merge |
957 # | | one parent | merge |
960 # +------------------+----------------------+-------------------------+
958 # +------------------+----------------------+-------------------------+
961 # | parent in | new parent is <dest> | parents in ::<dest> are |
959 # | parent in | new parent is <dest> | parents in ::<dest> are |
962 # | ::<dest> | | remapped to <dest> |
960 # | ::<dest> | | remapped to <dest> |
963 # +------------------+----------------------+-------------------------+
961 # +------------------+----------------------+-------------------------+
964 # | unrelated source | new parent is <dest> | ambiguous, abort |
962 # | unrelated source | new parent is <dest> | ambiguous, abort |
965 # +------------------+----------------------+-------------------------+
963 # +------------------+----------------------+-------------------------+
966 #
964 #
967 # The actual abort is handled by `defineparents`
965 # The actual abort is handled by `defineparents`
968 if len(root.parents()) <= 1:
966 if len(root.parents()) <= 1:
969 # ancestors of <root> not ancestors of <dest>
967 # ancestors of <root> not ancestors of <dest>
970 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
968 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
971 [root.rev()]))
969 [root.rev()]))
972 for r in detachset:
970 for r in detachset:
973 if r not in state:
971 if r not in state:
974 state[r] = nullmerge
972 state[r] = nullmerge
975 if len(roots) > 1:
973 if len(roots) > 1:
976 # If we have multiple roots, we may have "hole" in the rebase set.
974 # If we have multiple roots, we may have "hole" in the rebase set.
977 # Rebase roots that descend from those "hole" should not be detached as
975 # Rebase roots that descend from those "hole" should not be detached as
978 # other root are. We use the special `revignored` to inform rebase that
976 # other root are. We use the special `revignored` to inform rebase that
979 # the revision should be ignored but that `defineparents` should search
977 # the revision should be ignored but that `defineparents` should search
980 # a rebase destination that make sense regarding rebased topology.
978 # a rebase destination that make sense regarding rebased topology.
981 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
979 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
982 for ignored in set(rebasedomain) - set(rebaseset):
980 for ignored in set(rebasedomain) - set(rebaseset):
983 state[ignored] = revignored
981 state[ignored] = revignored
984 return repo['.'].rev(), dest.rev(), state
982 return repo['.'].rev(), dest.rev(), state
985
983
986 def clearrebased(ui, repo, state, skipped, collapsedas=None):
984 def clearrebased(ui, repo, state, skipped, collapsedas=None):
987 """dispose of rebased revision at the end of the rebase
985 """dispose of rebased revision at the end of the rebase
988
986
989 If `collapsedas` is not None, the rebase was a collapse whose result if the
987 If `collapsedas` is not None, the rebase was a collapse whose result if the
990 `collapsedas` node."""
988 `collapsedas` node."""
991 if obsolete.isenabled(repo, obsolete.createmarkersopt):
989 if obsolete.isenabled(repo, obsolete.createmarkersopt):
992 markers = []
990 markers = []
993 for rev, newrev in sorted(state.items()):
991 for rev, newrev in sorted(state.items()):
994 if newrev >= 0:
992 if newrev >= 0:
995 if rev in skipped:
993 if rev in skipped:
996 succs = ()
994 succs = ()
997 elif collapsedas is not None:
995 elif collapsedas is not None:
998 succs = (repo[collapsedas],)
996 succs = (repo[collapsedas],)
999 else:
997 else:
1000 succs = (repo[newrev],)
998 succs = (repo[newrev],)
1001 markers.append((repo[rev], succs))
999 markers.append((repo[rev], succs))
1002 if markers:
1000 if markers:
1003 obsolete.createmarkers(repo, markers)
1001 obsolete.createmarkers(repo, markers)
1004 else:
1002 else:
1005 rebased = [rev for rev in state if state[rev] > nullmerge]
1003 rebased = [rev for rev in state if state[rev] > nullmerge]
1006 if rebased:
1004 if rebased:
1007 stripped = []
1005 stripped = []
1008 for root in repo.set('roots(%ld)', rebased):
1006 for root in repo.set('roots(%ld)', rebased):
1009 if set(repo.changelog.descendants([root.rev()])) - set(state):
1007 if set(repo.changelog.descendants([root.rev()])) - set(state):
1010 ui.warn(_("warning: new changesets detected "
1008 ui.warn(_("warning: new changesets detected "
1011 "on source branch, not stripping\n"))
1009 "on source branch, not stripping\n"))
1012 else:
1010 else:
1013 stripped.append(root.node())
1011 stripped.append(root.node())
1014 if stripped:
1012 if stripped:
1015 # backup the old csets by default
1013 # backup the old csets by default
1016 repair.strip(ui, repo, stripped, "all")
1014 repair.strip(ui, repo, stripped, "all")
1017
1015
1018
1016
1019 def pullrebase(orig, ui, repo, *args, **opts):
1017 def pullrebase(orig, ui, repo, *args, **opts):
1020 'Call rebase after pull if the latter has been invoked with --rebase'
1018 'Call rebase after pull if the latter has been invoked with --rebase'
1021 if opts.get('rebase'):
1019 if opts.get('rebase'):
1022 if opts.get('update'):
1020 if opts.get('update'):
1023 del opts['update']
1021 del opts['update']
1024 ui.debug('--update and --rebase are not compatible, ignoring '
1022 ui.debug('--update and --rebase are not compatible, ignoring '
1025 'the update flag\n')
1023 'the update flag\n')
1026
1024
1027 movemarkfrom = repo['.'].node()
1025 movemarkfrom = repo['.'].node()
1028 revsprepull = len(repo)
1026 revsprepull = len(repo)
1029 origpostincoming = commands.postincoming
1027 origpostincoming = commands.postincoming
1030 def _dummy(*args, **kwargs):
1028 def _dummy(*args, **kwargs):
1031 pass
1029 pass
1032 commands.postincoming = _dummy
1030 commands.postincoming = _dummy
1033 try:
1031 try:
1034 orig(ui, repo, *args, **opts)
1032 orig(ui, repo, *args, **opts)
1035 finally:
1033 finally:
1036 commands.postincoming = origpostincoming
1034 commands.postincoming = origpostincoming
1037 revspostpull = len(repo)
1035 revspostpull = len(repo)
1038 if revspostpull > revsprepull:
1036 if revspostpull > revsprepull:
1039 # --rev option from pull conflict with rebase own --rev
1037 # --rev option from pull conflict with rebase own --rev
1040 # dropping it
1038 # dropping it
1041 if 'rev' in opts:
1039 if 'rev' in opts:
1042 del opts['rev']
1040 del opts['rev']
1043 # positional argument from pull conflicts with rebase's own
1041 # positional argument from pull conflicts with rebase's own
1044 # --source.
1042 # --source.
1045 if 'source' in opts:
1043 if 'source' in opts:
1046 del opts['source']
1044 del opts['source']
1047 rebase(ui, repo, **opts)
1045 rebase(ui, repo, **opts)
1048 branch = repo[None].branch()
1046 branch = repo[None].branch()
1049 dest = repo[branch].rev()
1047 dest = repo[branch].rev()
1050 if dest != repo['.'].rev():
1048 if dest != repo['.'].rev():
1051 # there was nothing to rebase we force an update
1049 # there was nothing to rebase we force an update
1052 hg.update(repo, dest)
1050 hg.update(repo, dest)
1053 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
1051 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
1054 ui.status(_("updating bookmark %s\n")
1052 ui.status(_("updating bookmark %s\n")
1055 % repo._activebookmark)
1053 % repo._activebookmark)
1056 else:
1054 else:
1057 if opts.get('tool'):
1055 if opts.get('tool'):
1058 raise util.Abort(_('--tool can only be used with --rebase'))
1056 raise util.Abort(_('--tool can only be used with --rebase'))
1059 orig(ui, repo, *args, **opts)
1057 orig(ui, repo, *args, **opts)
1060
1058
1061 def _setrebasesetvisibility(repo, revs):
1059 def _setrebasesetvisibility(repo, revs):
1062 """store the currently rebased set on the repo object
1060 """store the currently rebased set on the repo object
1063
1061
1064 This is used by another function to prevent rebased revision to because
1062 This is used by another function to prevent rebased revision to because
1065 hidden (see issue4505)"""
1063 hidden (see issue4505)"""
1066 repo = repo.unfiltered()
1064 repo = repo.unfiltered()
1067 revs = set(revs)
1065 revs = set(revs)
1068 repo._rebaseset = revs
1066 repo._rebaseset = revs
1069 # invalidate cache if visibility changes
1067 # invalidate cache if visibility changes
1070 hiddens = repo.filteredrevcache.get('visible', set())
1068 hiddens = repo.filteredrevcache.get('visible', set())
1071 if revs & hiddens:
1069 if revs & hiddens:
1072 repo.invalidatevolatilesets()
1070 repo.invalidatevolatilesets()
1073
1071
1074 def _clearrebasesetvisibiliy(repo):
1072 def _clearrebasesetvisibiliy(repo):
1075 """remove rebaseset data from the repo"""
1073 """remove rebaseset data from the repo"""
1076 repo = repo.unfiltered()
1074 repo = repo.unfiltered()
1077 if '_rebaseset' in vars(repo):
1075 if '_rebaseset' in vars(repo):
1078 del repo._rebaseset
1076 del repo._rebaseset
1079
1077
1080 def _rebasedvisible(orig, repo):
1078 def _rebasedvisible(orig, repo):
1081 """ensure rebased revs stay visible (see issue4505)"""
1079 """ensure rebased revs stay visible (see issue4505)"""
1082 blockers = orig(repo)
1080 blockers = orig(repo)
1083 blockers.update(getattr(repo, '_rebaseset', ()))
1081 blockers.update(getattr(repo, '_rebaseset', ()))
1084 return blockers
1082 return blockers
1085
1083
1086 def summaryhook(ui, repo):
1084 def summaryhook(ui, repo):
1087 if not os.path.exists(repo.join('rebasestate')):
1085 if not os.path.exists(repo.join('rebasestate')):
1088 return
1086 return
1089 try:
1087 try:
1090 state = restorestatus(repo)[2]
1088 state = restorestatus(repo)[2]
1091 except error.RepoLookupError:
1089 except error.RepoLookupError:
1092 # i18n: column positioning for "hg summary"
1090 # i18n: column positioning for "hg summary"
1093 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1091 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1094 ui.write(msg)
1092 ui.write(msg)
1095 return
1093 return
1096 numrebased = len([i for i in state.itervalues() if i >= 0])
1094 numrebased = len([i for i in state.itervalues() if i >= 0])
1097 # i18n: column positioning for "hg summary"
1095 # i18n: column positioning for "hg summary"
1098 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1096 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1099 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1097 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1100 ui.label(_('%d remaining'), 'rebase.remaining') %
1098 ui.label(_('%d remaining'), 'rebase.remaining') %
1101 (len(state) - numrebased)))
1099 (len(state) - numrebased)))
1102
1100
1103 def uisetup(ui):
1101 def uisetup(ui):
1104 #Replace pull with a decorator to provide --rebase option
1102 #Replace pull with a decorator to provide --rebase option
1105 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1103 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1106 entry[1].append(('', 'rebase', None,
1104 entry[1].append(('', 'rebase', None,
1107 _("rebase working directory to branch head")))
1105 _("rebase working directory to branch head")))
1108 entry[1].append(('t', 'tool', '',
1106 entry[1].append(('t', 'tool', '',
1109 _("specify merge tool for rebase")))
1107 _("specify merge tool for rebase")))
1110 cmdutil.summaryhooks.add('rebase', summaryhook)
1108 cmdutil.summaryhooks.add('rebase', summaryhook)
1111 cmdutil.unfinishedstates.append(
1109 cmdutil.unfinishedstates.append(
1112 ['rebasestate', False, False, _('rebase in progress'),
1110 ['rebasestate', False, False, _('rebase in progress'),
1113 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1111 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1114 # ensure rebased rev are not hidden
1112 # ensure rebased rev are not hidden
1115 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
1113 extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
1116
1114
@@ -1,1084 +1,1084
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 $ hg st
231 $ hg st
232 $ hg st -S
232 $ hg st -S
233 A subrepo/large.txt
233 A subrepo/large.txt
234 $ hg ci -S -m "commit top repo"
234 $ hg ci -S -m "commit top repo"
235 committing subrepository subrepo
235 committing subrepository subrepo
236 Invoking status precommit hook
236 Invoking status precommit hook
237 A large.txt
237 A large.txt
238 Invoking status precommit hook
238 Invoking status precommit hook
239 M .hgsubstate
239 M .hgsubstate
240 # No differences
240 # No differences
241 $ hg st -S
241 $ hg st -S
242 $ hg sum
242 $ hg sum
243 parent: 2:ce4cd0c527a6 tip
243 parent: 2:ce4cd0c527a6 tip
244 commit top repo
244 commit top repo
245 branch: default
245 branch: default
246 commit: (clean)
246 commit: (clean)
247 update: (current)
247 update: (current)
248 $ echo "rev 2" > subrepo/large.txt
248 $ echo "rev 2" > subrepo/large.txt
249 $ hg st -S
249 $ hg st -S
250 M subrepo/large.txt
250 M subrepo/large.txt
251 $ hg sum
251 $ hg sum
252 parent: 2:ce4cd0c527a6 tip
252 parent: 2:ce4cd0c527a6 tip
253 commit top repo
253 commit top repo
254 branch: default
254 branch: default
255 commit: 1 subrepos
255 commit: 1 subrepos
256 update: (current)
256 update: (current)
257 $ hg ci -m "this commit should fail without -S"
257 $ hg ci -m "this commit should fail without -S"
258 abort: uncommitted changes in subrepository 'subrepo'
258 abort: uncommitted changes in subrepository 'subrepo'
259 (use --subrepos for recursive commit)
259 (use --subrepos for recursive commit)
260 [255]
260 [255]
261
261
262 Add a normal file to the subrepo, then test archiving
262 Add a normal file to the subrepo, then test archiving
263
263
264 $ echo 'normal file' > subrepo/normal.txt
264 $ echo 'normal file' > subrepo/normal.txt
265 $ touch large.dat
265 $ touch large.dat
266 $ mv subrepo/large.txt subrepo/renamed-large.txt
266 $ mv subrepo/large.txt subrepo/renamed-large.txt
267 $ hg addremove -S --dry-run
267 $ hg addremove -S --dry-run
268 adding large.dat as a largefile
268 adding large.dat as a largefile
269 removing subrepo/large.txt
269 removing subrepo/large.txt
270 adding subrepo/normal.txt
270 adding subrepo/normal.txt
271 adding subrepo/renamed-large.txt
271 adding subrepo/renamed-large.txt
272 $ hg status -S
272 $ hg status -S
273 ! subrepo/large.txt
273 ! subrepo/large.txt
274 ? large.dat
274 ? large.dat
275 ? subrepo/normal.txt
275 ? subrepo/normal.txt
276 ? subrepo/renamed-large.txt
276 ? subrepo/renamed-large.txt
277
277
278 $ hg addremove --dry-run subrepo
278 $ hg addremove --dry-run subrepo
279 removing subrepo/large.txt (glob)
279 removing subrepo/large.txt (glob)
280 adding subrepo/normal.txt (glob)
280 adding subrepo/normal.txt (glob)
281 adding subrepo/renamed-large.txt (glob)
281 adding subrepo/renamed-large.txt (glob)
282 $ hg status -S
282 $ hg status -S
283 ! subrepo/large.txt
283 ! subrepo/large.txt
284 ? large.dat
284 ? large.dat
285 ? subrepo/normal.txt
285 ? subrepo/normal.txt
286 ? subrepo/renamed-large.txt
286 ? subrepo/renamed-large.txt
287 $ cd ..
287 $ cd ..
288
288
289 $ hg -R statusmatch addremove --dry-run statusmatch/subrepo
289 $ hg -R statusmatch addremove --dry-run statusmatch/subrepo
290 removing statusmatch/subrepo/large.txt (glob)
290 removing statusmatch/subrepo/large.txt (glob)
291 adding statusmatch/subrepo/normal.txt (glob)
291 adding statusmatch/subrepo/normal.txt (glob)
292 adding statusmatch/subrepo/renamed-large.txt (glob)
292 adding statusmatch/subrepo/renamed-large.txt (glob)
293 $ hg -R statusmatch status -S
293 $ hg -R statusmatch status -S
294 ! subrepo/large.txt
294 ! subrepo/large.txt
295 ? large.dat
295 ? large.dat
296 ? subrepo/normal.txt
296 ? subrepo/normal.txt
297 ? subrepo/renamed-large.txt
297 ? subrepo/renamed-large.txt
298
298
299 $ hg -R statusmatch addremove --dry-run -S
299 $ hg -R statusmatch addremove --dry-run -S
300 adding large.dat as a largefile
300 adding large.dat as a largefile
301 removing subrepo/large.txt
301 removing subrepo/large.txt
302 adding subrepo/normal.txt
302 adding subrepo/normal.txt
303 adding subrepo/renamed-large.txt
303 adding subrepo/renamed-large.txt
304 $ cd statusmatch
304 $ cd statusmatch
305
305
306 $ mv subrepo/renamed-large.txt subrepo/large.txt
306 $ mv subrepo/renamed-large.txt subrepo/large.txt
307 $ hg addremove subrepo
307 $ hg addremove subrepo
308 adding subrepo/normal.txt (glob)
308 adding subrepo/normal.txt (glob)
309 $ hg forget subrepo/normal.txt
309 $ hg forget subrepo/normal.txt
310
310
311 $ hg addremove -S
311 $ hg addremove -S
312 adding large.dat as a largefile
312 adding large.dat as a largefile
313 adding subrepo/normal.txt
313 adding subrepo/normal.txt
314 $ rm large.dat
314 $ rm large.dat
315
315
316 $ hg addremove subrepo
316 $ hg addremove subrepo
317 $ hg addremove -S
317 $ hg addremove -S
318 removing large.dat
318 removing large.dat
319
319
320 Lock in subrepo, otherwise the change isn't archived
320 Lock in subrepo, otherwise the change isn't archived
321
321
322 $ hg ci -S -m "add normal file to top level"
322 $ hg ci -S -m "add normal file to top level"
323 committing subrepository subrepo
323 committing subrepository subrepo
324 Invoking status precommit hook
324 Invoking status precommit hook
325 M large.txt
325 M large.txt
326 A normal.txt
326 A normal.txt
327 Invoking status precommit hook
327 Invoking status precommit hook
328 M .hgsubstate
328 M .hgsubstate
329 $ hg archive -S ../lf_subrepo_archive
329 $ hg archive -S ../lf_subrepo_archive
330 $ find ../lf_subrepo_archive | sort
330 $ find ../lf_subrepo_archive | sort
331 ../lf_subrepo_archive
331 ../lf_subrepo_archive
332 ../lf_subrepo_archive/.hg_archival.txt
332 ../lf_subrepo_archive/.hg_archival.txt
333 ../lf_subrepo_archive/.hgsub
333 ../lf_subrepo_archive/.hgsub
334 ../lf_subrepo_archive/.hgsubstate
334 ../lf_subrepo_archive/.hgsubstate
335 ../lf_subrepo_archive/a
335 ../lf_subrepo_archive/a
336 ../lf_subrepo_archive/a/b
336 ../lf_subrepo_archive/a/b
337 ../lf_subrepo_archive/a/b/c
337 ../lf_subrepo_archive/a/b/c
338 ../lf_subrepo_archive/a/b/c/d
338 ../lf_subrepo_archive/a/b/c/d
339 ../lf_subrepo_archive/a/b/c/d/e.large.txt
339 ../lf_subrepo_archive/a/b/c/d/e.large.txt
340 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
340 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
341 ../lf_subrepo_archive/a/b/c/x
341 ../lf_subrepo_archive/a/b/c/x
342 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
342 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
343 ../lf_subrepo_archive/subrepo
343 ../lf_subrepo_archive/subrepo
344 ../lf_subrepo_archive/subrepo/large.txt
344 ../lf_subrepo_archive/subrepo/large.txt
345 ../lf_subrepo_archive/subrepo/normal.txt
345 ../lf_subrepo_archive/subrepo/normal.txt
346 $ cat ../lf_subrepo_archive/.hg_archival.txt
346 $ cat ../lf_subrepo_archive/.hg_archival.txt
347 repo: 41bd42f10efa43698cc02052ea0977771cba506d
347 repo: 41bd42f10efa43698cc02052ea0977771cba506d
348 node: d56a95e6522858bc08a724c4fe2bdee066d1c30b
348 node: d56a95e6522858bc08a724c4fe2bdee066d1c30b
349 branch: default
349 branch: default
350 latesttag: null
350 latesttag: null
351 latesttagdistance: 4
351 latesttagdistance: 4
352 changessincelatesttag: 4
352 changessincelatesttag: 4
353
353
354 Test update with subrepos.
354 Test update with subrepos.
355
355
356 $ hg update 0
356 $ hg update 0
357 getting changed largefiles
357 getting changed largefiles
358 0 largefiles updated, 1 removed
358 0 largefiles updated, 1 removed
359 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
359 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
360 $ hg status -S
360 $ hg status -S
361 $ hg update tip
361 $ hg update tip
362 getting changed largefiles
362 getting changed largefiles
363 1 largefiles updated, 0 removed
363 1 largefiles updated, 0 removed
364 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 $ hg status -S
365 $ hg status -S
366 # modify a large file
366 # modify a large file
367 $ echo "modified" > subrepo/large.txt
367 $ echo "modified" > subrepo/large.txt
368 $ hg st -S
368 $ hg st -S
369 M subrepo/large.txt
369 M subrepo/large.txt
370 # update -C should revert the change.
370 # update -C should revert the change.
371 $ hg update -C
371 $ hg update -C
372 getting changed largefiles
372 getting changed largefiles
373 1 largefiles updated, 0 removed
373 1 largefiles updated, 0 removed
374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 $ hg status -S
375 $ hg status -S
376
376
377 $ hg forget -v subrepo/large.txt
377 $ hg forget -v subrepo/large.txt
378 removing subrepo/large.txt (glob)
378 removing subrepo/large.txt (glob)
379
379
380 Test reverting a forgotten file
380 Test reverting a forgotten file
381 $ hg revert -R subrepo subrepo/large.txt
381 $ hg revert -R subrepo subrepo/large.txt
382 $ hg status -SA subrepo/large.txt
382 $ hg status -SA subrepo/large.txt
383 C subrepo/large.txt
383 C subrepo/large.txt
384
384
385 $ hg rm -v subrepo/large.txt
385 $ hg rm -v subrepo/large.txt
386 removing subrepo/large.txt (glob)
386 removing subrepo/large.txt (glob)
387 $ hg revert -R subrepo subrepo/large.txt
387 $ hg revert -R subrepo subrepo/large.txt
388 $ rm subrepo/large.txt
388 $ rm subrepo/large.txt
389 $ hg addremove -S
389 $ hg addremove -S
390 removing subrepo/large.txt
390 removing subrepo/large.txt
391 $ hg st -S
391 $ hg st -S
392 R subrepo/large.txt
392 R subrepo/large.txt
393
393
394 Test archiving a revision that references a subrepo that is not yet
394 Test archiving a revision that references a subrepo that is not yet
395 cloned (see test-subrepo-recursion.t):
395 cloned (see test-subrepo-recursion.t):
396
396
397 $ hg clone -U . ../empty
397 $ hg clone -U . ../empty
398 $ cd ../empty
398 $ cd ../empty
399 $ hg archive --subrepos -r tip ../archive.tar.gz
399 $ hg archive --subrepos -r tip ../archive.tar.gz
400 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
400 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
401 $ cd ..
401 $ cd ..
402
402
403
403
404
404
405
405
406
406
407
407
408 Test addremove, forget and others
408 Test addremove, forget and others
409 ==============================================
409 ==============================================
410
410
411 Test that addremove picks up largefiles prior to the initial commit (issue3541)
411 Test that addremove picks up largefiles prior to the initial commit (issue3541)
412
412
413 $ hg init addrm2
413 $ hg init addrm2
414 $ cd addrm2
414 $ cd addrm2
415 $ touch large.dat
415 $ touch large.dat
416 $ touch large2.dat
416 $ touch large2.dat
417 $ touch normal
417 $ touch normal
418 $ hg add --large large.dat
418 $ hg add --large large.dat
419 $ hg addremove -v
419 $ hg addremove -v
420 adding large2.dat as a largefile
420 adding large2.dat as a largefile
421 adding normal
421 adding normal
422
422
423 Test that forgetting all largefiles reverts to islfilesrepo() == False
423 Test that forgetting all largefiles reverts to islfilesrepo() == False
424 (addremove will add *.dat as normal files now)
424 (addremove will add *.dat as normal files now)
425 $ hg forget large.dat
425 $ hg forget large.dat
426 $ hg forget large2.dat
426 $ hg forget large2.dat
427 $ hg addremove -v
427 $ hg addremove -v
428 adding large.dat
428 adding large.dat
429 adding large2.dat
429 adding large2.dat
430
430
431 Test commit's addremove option prior to the first commit
431 Test commit's addremove option prior to the first commit
432 $ hg forget large.dat
432 $ hg forget large.dat
433 $ hg forget large2.dat
433 $ hg forget large2.dat
434 $ hg add --large large.dat
434 $ hg add --large large.dat
435 $ hg ci -Am "commit"
435 $ hg ci -Am "commit"
436 adding large2.dat as a largefile
436 adding large2.dat as a largefile
437 Invoking status precommit hook
437 Invoking status precommit hook
438 A large.dat
438 A large.dat
439 A large2.dat
439 A large2.dat
440 A normal
440 A normal
441 $ find .hglf | sort
441 $ find .hglf | sort
442 .hglf
442 .hglf
443 .hglf/large.dat
443 .hglf/large.dat
444 .hglf/large2.dat
444 .hglf/large2.dat
445
445
446 Test actions on largefiles using relative paths from subdir
446 Test actions on largefiles using relative paths from subdir
447
447
448 $ mkdir sub
448 $ mkdir sub
449 $ cd sub
449 $ cd sub
450 $ echo anotherlarge > anotherlarge
450 $ echo anotherlarge > anotherlarge
451 $ hg add --large anotherlarge
451 $ hg add --large anotherlarge
452 $ hg st
452 $ hg st
453 A sub/anotherlarge
453 A sub/anotherlarge
454 $ hg st anotherlarge
454 $ hg st anotherlarge
455 A anotherlarge
455 A anotherlarge
456 $ hg commit -m anotherlarge anotherlarge
456 $ hg commit -m anotherlarge anotherlarge
457 Invoking status precommit hook
457 Invoking status precommit hook
458 A sub/anotherlarge
458 A sub/anotherlarge
459 $ hg log anotherlarge
459 $ hg log anotherlarge
460 changeset: 1:9627a577c5e9
460 changeset: 1:9627a577c5e9
461 tag: tip
461 tag: tip
462 user: test
462 user: test
463 date: Thu Jan 01 00:00:00 1970 +0000
463 date: Thu Jan 01 00:00:00 1970 +0000
464 summary: anotherlarge
464 summary: anotherlarge
465
465
466 $ hg --debug log -T '{rev}: {desc}\n' ../sub/anotherlarge
466 $ hg --debug log -T '{rev}: {desc}\n' ../sub/anotherlarge
467 updated patterns: ['../.hglf/sub/../sub/anotherlarge', '../sub/anotherlarge']
467 updated patterns: ['../.hglf/sub/../sub/anotherlarge', '../sub/anotherlarge']
468 1: anotherlarge
468 1: anotherlarge
469
469
470 $ hg log -G anotherlarge
470 $ hg log -G anotherlarge
471 @ changeset: 1:9627a577c5e9
471 @ changeset: 1:9627a577c5e9
472 | tag: tip
472 | tag: tip
473 | user: test
473 | user: test
474 | date: Thu Jan 01 00:00:00 1970 +0000
474 | date: Thu Jan 01 00:00:00 1970 +0000
475 | summary: anotherlarge
475 | summary: anotherlarge
476 |
476 |
477
477
478 $ hg log glob:another*
478 $ hg log glob:another*
479 changeset: 1:9627a577c5e9
479 changeset: 1:9627a577c5e9
480 tag: tip
480 tag: tip
481 user: test
481 user: test
482 date: Thu Jan 01 00:00:00 1970 +0000
482 date: Thu Jan 01 00:00:00 1970 +0000
483 summary: anotherlarge
483 summary: anotherlarge
484
484
485 $ hg --debug log -T '{rev}: {desc}\n' -G glob:another*
485 $ hg --debug log -T '{rev}: {desc}\n' -G glob:another*
486 updated patterns: ['glob:../.hglf/sub/another*', 'glob:another*']
486 updated patterns: ['glob:../.hglf/sub/another*', 'glob:another*']
487 @ 1: anotherlarge
487 @ 1: anotherlarge
488 |
488 |
489
489
490 #if no-msys
490 #if no-msys
491 $ hg --debug log -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
491 $ hg --debug log -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
492 updated patterns: ['glob:../.hglf/sub/another*']
492 updated patterns: ['glob:../.hglf/sub/another*']
493 1: anotherlarge
493 1: anotherlarge
494
494
495 $ hg --debug log -G -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
495 $ hg --debug log -G -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
496 updated patterns: ['glob:../.hglf/sub/another*']
496 updated patterns: ['glob:../.hglf/sub/another*']
497 @ 1: anotherlarge
497 @ 1: anotherlarge
498 |
498 |
499 #endif
499 #endif
500
500
501 $ echo more >> anotherlarge
501 $ echo more >> anotherlarge
502 $ hg st .
502 $ hg st .
503 M anotherlarge
503 M anotherlarge
504 $ hg cat anotherlarge
504 $ hg cat anotherlarge
505 anotherlarge
505 anotherlarge
506 $ hg revert anotherlarge
506 $ hg revert anotherlarge
507 $ hg st
507 $ hg st
508 ? sub/anotherlarge.orig
508 ? sub/anotherlarge.orig
509 $ cd ..
509 $ cd ..
510
510
511 Test glob logging from the root dir
511 Test glob logging from the root dir
512 $ hg log glob:**another*
512 $ hg log glob:**another*
513 changeset: 1:9627a577c5e9
513 changeset: 1:9627a577c5e9
514 tag: tip
514 tag: tip
515 user: test
515 user: test
516 date: Thu Jan 01 00:00:00 1970 +0000
516 date: Thu Jan 01 00:00:00 1970 +0000
517 summary: anotherlarge
517 summary: anotherlarge
518
518
519 $ hg log -G glob:**another*
519 $ hg log -G glob:**another*
520 @ changeset: 1:9627a577c5e9
520 @ changeset: 1:9627a577c5e9
521 | tag: tip
521 | tag: tip
522 | user: test
522 | user: test
523 | date: Thu Jan 01 00:00:00 1970 +0000
523 | date: Thu Jan 01 00:00:00 1970 +0000
524 | summary: anotherlarge
524 | summary: anotherlarge
525 |
525 |
526
526
527 $ cd ..
527 $ cd ..
528
528
529 Log from outer space
529 Log from outer space
530 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/sub/anotherlarge'
530 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/sub/anotherlarge'
531 updated patterns: ['addrm2/.hglf/sub/anotherlarge', 'addrm2/sub/anotherlarge']
531 updated patterns: ['addrm2/.hglf/sub/anotherlarge', 'addrm2/sub/anotherlarge']
532 1: anotherlarge
532 1: anotherlarge
533 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/.hglf/sub/anotherlarge'
533 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/.hglf/sub/anotherlarge'
534 updated patterns: ['addrm2/.hglf/sub/anotherlarge']
534 updated patterns: ['addrm2/.hglf/sub/anotherlarge']
535 1: anotherlarge
535 1: anotherlarge
536
536
537
537
538 Check error message while exchange
538 Check error message while exchange
539 =========================================================
539 =========================================================
540
540
541 issue3651: summary/outgoing with largefiles shows "no remote repo"
541 issue3651: summary/outgoing with largefiles shows "no remote repo"
542 unexpectedly
542 unexpectedly
543
543
544 $ mkdir issue3651
544 $ mkdir issue3651
545 $ cd issue3651
545 $ cd issue3651
546
546
547 $ hg init src
547 $ hg init src
548 $ echo a > src/a
548 $ echo a > src/a
549 $ hg -R src add --large src/a
549 $ hg -R src add --large src/a
550 $ hg -R src commit -m '#0'
550 $ hg -R src commit -m '#0'
551 Invoking status precommit hook
551 Invoking status precommit hook
552 A a
552 A a
553
553
554 check messages when no remote repository is specified:
554 check messages when no remote repository is specified:
555 "no remote repo" route for "hg outgoing --large" is not tested here,
555 "no remote repo" route for "hg outgoing --large" is not tested here,
556 because it can't be reproduced easily.
556 because it can't be reproduced easily.
557
557
558 $ hg init clone1
558 $ hg init clone1
559 $ hg -R clone1 -q pull src
559 $ hg -R clone1 -q pull src
560 $ hg -R clone1 -q update
560 $ hg -R clone1 -q update
561 $ hg -R clone1 paths | grep default
561 $ hg -R clone1 paths | grep default
562 [1]
562 [1]
563
563
564 $ hg -R clone1 summary --large
564 $ hg -R clone1 summary --large
565 parent: 0:fc0bd45326d3 tip
565 parent: 0:fc0bd45326d3 tip
566 #0
566 #0
567 branch: default
567 branch: default
568 commit: (clean)
568 commit: (clean)
569 update: (current)
569 update: (current)
570 largefiles: (no remote repo)
570 largefiles: (no remote repo)
571
571
572 check messages when there is no files to upload:
572 check messages when there is no files to upload:
573
573
574 $ hg -q clone src clone2
574 $ hg -q clone src clone2
575 $ hg -R clone2 paths | grep default
575 $ hg -R clone2 paths | grep default
576 default = $TESTTMP/issue3651/src (glob)
576 default = $TESTTMP/issue3651/src (glob)
577
577
578 $ hg -R clone2 summary --large
578 $ hg -R clone2 summary --large
579 parent: 0:fc0bd45326d3 tip
579 parent: 0:fc0bd45326d3 tip
580 #0
580 #0
581 branch: default
581 branch: default
582 commit: (clean)
582 commit: (clean)
583 update: (current)
583 update: (current)
584 largefiles: (no files to upload)
584 largefiles: (no files to upload)
585 $ hg -R clone2 outgoing --large
585 $ hg -R clone2 outgoing --large
586 comparing with $TESTTMP/issue3651/src (glob)
586 comparing with $TESTTMP/issue3651/src (glob)
587 searching for changes
587 searching for changes
588 no changes found
588 no changes found
589 largefiles: no files to upload
589 largefiles: no files to upload
590 [1]
590 [1]
591
591
592 $ hg -R clone2 outgoing --large --graph --template "{rev}"
592 $ hg -R clone2 outgoing --large --graph --template "{rev}"
593 comparing with $TESTTMP/issue3651/src (glob)
593 comparing with $TESTTMP/issue3651/src (glob)
594 searching for changes
594 searching for changes
595 no changes found
595 no changes found
596 largefiles: no files to upload
596 largefiles: no files to upload
597
597
598 check messages when there are files to upload:
598 check messages when there are files to upload:
599
599
600 $ echo b > clone2/b
600 $ echo b > clone2/b
601 $ hg -R clone2 add --large clone2/b
601 $ hg -R clone2 add --large clone2/b
602 $ hg -R clone2 commit -m '#1'
602 $ hg -R clone2 commit -m '#1'
603 Invoking status precommit hook
603 Invoking status precommit hook
604 A b
604 A b
605 $ hg -R clone2 summary --large
605 $ hg -R clone2 summary --large
606 parent: 1:1acbe71ce432 tip
606 parent: 1:1acbe71ce432 tip
607 #1
607 #1
608 branch: default
608 branch: default
609 commit: (clean)
609 commit: (clean)
610 update: (current)
610 update: (current)
611 largefiles: 1 entities for 1 files to upload
611 largefiles: 1 entities for 1 files to upload
612 $ hg -R clone2 outgoing --large
612 $ hg -R clone2 outgoing --large
613 comparing with $TESTTMP/issue3651/src (glob)
613 comparing with $TESTTMP/issue3651/src (glob)
614 searching for changes
614 searching for changes
615 changeset: 1:1acbe71ce432
615 changeset: 1:1acbe71ce432
616 tag: tip
616 tag: tip
617 user: test
617 user: test
618 date: Thu Jan 01 00:00:00 1970 +0000
618 date: Thu Jan 01 00:00:00 1970 +0000
619 summary: #1
619 summary: #1
620
620
621 largefiles to upload (1 entities):
621 largefiles to upload (1 entities):
622 b
622 b
623
623
624 $ hg -R clone2 outgoing --large --graph --template "{rev}"
624 $ hg -R clone2 outgoing --large --graph --template "{rev}"
625 comparing with $TESTTMP/issue3651/src (glob)
625 comparing with $TESTTMP/issue3651/src (glob)
626 searching for changes
626 searching for changes
627 @ 1
627 @ 1
628
628
629 largefiles to upload (1 entities):
629 largefiles to upload (1 entities):
630 b
630 b
631
631
632
632
633 $ cp clone2/b clone2/b1
633 $ cp clone2/b clone2/b1
634 $ cp clone2/b clone2/b2
634 $ cp clone2/b clone2/b2
635 $ hg -R clone2 add --large clone2/b1 clone2/b2
635 $ hg -R clone2 add --large clone2/b1 clone2/b2
636 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
636 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
637 Invoking status precommit hook
637 Invoking status precommit hook
638 A b1
638 A b1
639 A b2
639 A b2
640 $ hg -R clone2 summary --large
640 $ hg -R clone2 summary --large
641 parent: 2:6095d0695d70 tip
641 parent: 2:6095d0695d70 tip
642 #2: add largefiles referring same entity
642 #2: add largefiles referring same entity
643 branch: default
643 branch: default
644 commit: (clean)
644 commit: (clean)
645 update: (current)
645 update: (current)
646 largefiles: 1 entities for 3 files to upload
646 largefiles: 1 entities for 3 files to upload
647 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
647 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
648 comparing with $TESTTMP/issue3651/src (glob)
648 comparing with $TESTTMP/issue3651/src (glob)
649 searching for changes
649 searching for changes
650 1:1acbe71ce432
650 1:1acbe71ce432
651 2:6095d0695d70
651 2:6095d0695d70
652 largefiles to upload (1 entities):
652 largefiles to upload (1 entities):
653 b
653 b
654 b1
654 b1
655 b2
655 b2
656
656
657 $ hg -R clone2 cat -r 1 clone2/.hglf/b
657 $ hg -R clone2 cat -r 1 clone2/.hglf/b
658 89e6c98d92887913cadf06b2adb97f26cde4849b
658 89e6c98d92887913cadf06b2adb97f26cde4849b
659 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
659 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
660 comparing with $TESTTMP/issue3651/src (glob)
660 comparing with $TESTTMP/issue3651/src (glob)
661 query 1; heads
661 query 1; heads
662 searching for changes
662 searching for changes
663 all remote heads known locally
663 all remote heads known locally
664 1:1acbe71ce432
664 1:1acbe71ce432
665 2:6095d0695d70
665 2:6095d0695d70
666 finding outgoing largefiles: 0/2 revision (0.00%)
666 finding outgoing largefiles: 0/2 revision (0.00%)
667 finding outgoing largefiles: 1/2 revision (50.00%)
667 finding outgoing largefiles: 1/2 revision (50.00%)
668 largefiles to upload (1 entities):
668 largefiles to upload (1 entities):
669 b
669 b
670 89e6c98d92887913cadf06b2adb97f26cde4849b
670 89e6c98d92887913cadf06b2adb97f26cde4849b
671 b1
671 b1
672 89e6c98d92887913cadf06b2adb97f26cde4849b
672 89e6c98d92887913cadf06b2adb97f26cde4849b
673 b2
673 b2
674 89e6c98d92887913cadf06b2adb97f26cde4849b
674 89e6c98d92887913cadf06b2adb97f26cde4849b
675
675
676
676
677 $ echo bbb > clone2/b
677 $ echo bbb > clone2/b
678 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
678 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
679 Invoking status precommit hook
679 Invoking status precommit hook
680 M b
680 M b
681 $ echo bbbb > clone2/b
681 $ echo bbbb > clone2/b
682 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
682 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
683 Invoking status precommit hook
683 Invoking status precommit hook
684 M b
684 M b
685 $ cp clone2/b1 clone2/b
685 $ cp clone2/b1 clone2/b
686 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
686 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
687 Invoking status precommit hook
687 Invoking status precommit hook
688 M b
688 M b
689 $ hg -R clone2 summary --large
689 $ hg -R clone2 summary --large
690 parent: 5:036794ea641c tip
690 parent: 5:036794ea641c tip
691 #5: refer existing largefile entity again
691 #5: refer existing largefile entity again
692 branch: default
692 branch: default
693 commit: (clean)
693 commit: (clean)
694 update: (current)
694 update: (current)
695 largefiles: 3 entities for 3 files to upload
695 largefiles: 3 entities for 3 files to upload
696 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
696 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
697 comparing with $TESTTMP/issue3651/src (glob)
697 comparing with $TESTTMP/issue3651/src (glob)
698 searching for changes
698 searching for changes
699 1:1acbe71ce432
699 1:1acbe71ce432
700 2:6095d0695d70
700 2:6095d0695d70
701 3:7983dce246cc
701 3:7983dce246cc
702 4:233f12ada4ae
702 4:233f12ada4ae
703 5:036794ea641c
703 5:036794ea641c
704 largefiles to upload (3 entities):
704 largefiles to upload (3 entities):
705 b
705 b
706 b1
706 b1
707 b2
707 b2
708
708
709 $ hg -R clone2 cat -r 3 clone2/.hglf/b
709 $ hg -R clone2 cat -r 3 clone2/.hglf/b
710 c801c9cfe94400963fcb683246217d5db77f9a9a
710 c801c9cfe94400963fcb683246217d5db77f9a9a
711 $ hg -R clone2 cat -r 4 clone2/.hglf/b
711 $ hg -R clone2 cat -r 4 clone2/.hglf/b
712 13f9ed0898e315bf59dc2973fec52037b6f441a2
712 13f9ed0898e315bf59dc2973fec52037b6f441a2
713 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
713 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
714 comparing with $TESTTMP/issue3651/src (glob)
714 comparing with $TESTTMP/issue3651/src (glob)
715 query 1; heads
715 query 1; heads
716 searching for changes
716 searching for changes
717 all remote heads known locally
717 all remote heads known locally
718 1:1acbe71ce432
718 1:1acbe71ce432
719 2:6095d0695d70
719 2:6095d0695d70
720 3:7983dce246cc
720 3:7983dce246cc
721 4:233f12ada4ae
721 4:233f12ada4ae
722 5:036794ea641c
722 5:036794ea641c
723 finding outgoing largefiles: 0/5 revision (0.00%)
723 finding outgoing largefiles: 0/5 revision (0.00%)
724 finding outgoing largefiles: 1/5 revision (20.00%)
724 finding outgoing largefiles: 1/5 revision (20.00%)
725 finding outgoing largefiles: 2/5 revision (40.00%)
725 finding outgoing largefiles: 2/5 revision (40.00%)
726 finding outgoing largefiles: 3/5 revision (60.00%)
726 finding outgoing largefiles: 3/5 revision (60.00%)
727 finding outgoing largefiles: 4/5 revision (80.00%)
727 finding outgoing largefiles: 4/5 revision (80.00%)
728 largefiles to upload (3 entities):
728 largefiles to upload (3 entities):
729 b
729 b
730 13f9ed0898e315bf59dc2973fec52037b6f441a2
730 13f9ed0898e315bf59dc2973fec52037b6f441a2
731 89e6c98d92887913cadf06b2adb97f26cde4849b
731 89e6c98d92887913cadf06b2adb97f26cde4849b
732 c801c9cfe94400963fcb683246217d5db77f9a9a
732 c801c9cfe94400963fcb683246217d5db77f9a9a
733 b1
733 b1
734 89e6c98d92887913cadf06b2adb97f26cde4849b
734 89e6c98d92887913cadf06b2adb97f26cde4849b
735 b2
735 b2
736 89e6c98d92887913cadf06b2adb97f26cde4849b
736 89e6c98d92887913cadf06b2adb97f26cde4849b
737
737
738
738
739 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
739 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
740 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
740 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
741
741
742 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
742 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
743 summary" and "hg outgoing", even though files in outgoing revision #2
743 summary" and "hg outgoing", even though files in outgoing revision #2
744 and #5 refer it.
744 and #5 refer it.
745
745
746 $ hg -R clone2 push -r 1 -q
746 $ hg -R clone2 push -r 1 -q
747 $ hg -R clone2 summary --large
747 $ hg -R clone2 summary --large
748 parent: 5:036794ea641c tip
748 parent: 5:036794ea641c tip
749 #5: refer existing largefile entity again
749 #5: refer existing largefile entity again
750 branch: default
750 branch: default
751 commit: (clean)
751 commit: (clean)
752 update: (current)
752 update: (current)
753 largefiles: 2 entities for 1 files to upload
753 largefiles: 2 entities for 1 files to upload
754 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
754 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
755 comparing with $TESTTMP/issue3651/src (glob)
755 comparing with $TESTTMP/issue3651/src (glob)
756 searching for changes
756 searching for changes
757 2:6095d0695d70
757 2:6095d0695d70
758 3:7983dce246cc
758 3:7983dce246cc
759 4:233f12ada4ae
759 4:233f12ada4ae
760 5:036794ea641c
760 5:036794ea641c
761 largefiles to upload (2 entities):
761 largefiles to upload (2 entities):
762 b
762 b
763
763
764 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
764 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
765 comparing with $TESTTMP/issue3651/src (glob)
765 comparing with $TESTTMP/issue3651/src (glob)
766 query 1; heads
766 query 1; heads
767 searching for changes
767 searching for changes
768 all remote heads known locally
768 all remote heads known locally
769 2:6095d0695d70
769 2:6095d0695d70
770 3:7983dce246cc
770 3:7983dce246cc
771 4:233f12ada4ae
771 4:233f12ada4ae
772 5:036794ea641c
772 5:036794ea641c
773 finding outgoing largefiles: 0/4 revision (0.00%)
773 finding outgoing largefiles: 0/4 revision (0.00%)
774 finding outgoing largefiles: 1/4 revision (25.00%)
774 finding outgoing largefiles: 1/4 revision (25.00%)
775 finding outgoing largefiles: 2/4 revision (50.00%)
775 finding outgoing largefiles: 2/4 revision (50.00%)
776 finding outgoing largefiles: 3/4 revision (75.00%)
776 finding outgoing largefiles: 3/4 revision (75.00%)
777 largefiles to upload (2 entities):
777 largefiles to upload (2 entities):
778 b
778 b
779 13f9ed0898e315bf59dc2973fec52037b6f441a2
779 13f9ed0898e315bf59dc2973fec52037b6f441a2
780 c801c9cfe94400963fcb683246217d5db77f9a9a
780 c801c9cfe94400963fcb683246217d5db77f9a9a
781
781
782
782
783 $ cd ..
783 $ cd ..
784
784
785 merge action 'd' for 'local renamed directory to d2/g' which has no filename
785 merge action 'd' for 'local renamed directory to d2/g' which has no filename
786 ==================================================================================
786 ==================================================================================
787
787
788 $ hg init merge-action
788 $ hg init merge-action
789 $ cd merge-action
789 $ cd merge-action
790 $ touch l
790 $ touch l
791 $ hg add --large l
791 $ hg add --large l
792 $ mkdir d1
792 $ mkdir d1
793 $ touch d1/f
793 $ touch d1/f
794 $ hg ci -Aqm0
794 $ hg ci -Aqm0
795 Invoking status precommit hook
795 Invoking status precommit hook
796 A d1/f
796 A d1/f
797 A l
797 A l
798 $ echo > d1/f
798 $ echo > d1/f
799 $ touch d1/g
799 $ touch d1/g
800 $ hg ci -Aqm1
800 $ hg ci -Aqm1
801 Invoking status precommit hook
801 Invoking status precommit hook
802 M d1/f
802 M d1/f
803 A d1/g
803 A d1/g
804 $ hg up -qr0
804 $ hg up -qr0
805 $ hg mv d1 d2
805 $ hg mv d1 d2
806 moving d1/f to d2/f (glob)
806 moving d1/f to d2/f (glob)
807 $ hg ci -qm2
807 $ hg ci -qm2
808 Invoking status precommit hook
808 Invoking status precommit hook
809 A d2/f
809 A d2/f
810 R d1/f
810 R d1/f
811 $ hg merge
811 $ hg merge
812 merging d2/f and d1/f to d2/f
812 merging d2/f and d1/f to d2/f
813 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
813 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
814 (branch merge, don't forget to commit)
814 (branch merge, don't forget to commit)
815 $ cd ..
815 $ cd ..
816
816
817
817
818 Merge conflicts:
818 Merge conflicts:
819 =====================
819 =====================
820
820
821 $ hg init merge
821 $ hg init merge
822 $ cd merge
822 $ cd merge
823 $ echo 0 > f-different
823 $ echo 0 > f-different
824 $ echo 0 > f-same
824 $ echo 0 > f-same
825 $ echo 0 > f-unchanged-1
825 $ echo 0 > f-unchanged-1
826 $ echo 0 > f-unchanged-2
826 $ echo 0 > f-unchanged-2
827 $ hg add --large *
827 $ hg add --large *
828 $ hg ci -m0
828 $ hg ci -m0
829 Invoking status precommit hook
829 Invoking status precommit hook
830 A f-different
830 A f-different
831 A f-same
831 A f-same
832 A f-unchanged-1
832 A f-unchanged-1
833 A f-unchanged-2
833 A f-unchanged-2
834 $ echo tmp1 > f-unchanged-1
834 $ echo tmp1 > f-unchanged-1
835 $ echo tmp1 > f-unchanged-2
835 $ echo tmp1 > f-unchanged-2
836 $ echo tmp1 > f-same
836 $ echo tmp1 > f-same
837 $ hg ci -m1
837 $ hg ci -m1
838 Invoking status precommit hook
838 Invoking status precommit hook
839 M f-same
839 M f-same
840 M f-unchanged-1
840 M f-unchanged-1
841 M f-unchanged-2
841 M f-unchanged-2
842 $ echo 2 > f-different
842 $ echo 2 > f-different
843 $ echo 0 > f-unchanged-1
843 $ echo 0 > f-unchanged-1
844 $ echo 1 > f-unchanged-2
844 $ echo 1 > f-unchanged-2
845 $ echo 1 > f-same
845 $ echo 1 > f-same
846 $ hg ci -m2
846 $ hg ci -m2
847 Invoking status precommit hook
847 Invoking status precommit hook
848 M f-different
848 M f-different
849 M f-same
849 M f-same
850 M f-unchanged-1
850 M f-unchanged-1
851 M f-unchanged-2
851 M f-unchanged-2
852 $ hg up -qr0
852 $ hg up -qr0
853 $ echo tmp2 > f-unchanged-1
853 $ echo tmp2 > f-unchanged-1
854 $ echo tmp2 > f-unchanged-2
854 $ echo tmp2 > f-unchanged-2
855 $ echo tmp2 > f-same
855 $ echo tmp2 > f-same
856 $ hg ci -m3
856 $ hg ci -m3
857 Invoking status precommit hook
857 Invoking status precommit hook
858 M f-same
858 M f-same
859 M f-unchanged-1
859 M f-unchanged-1
860 M f-unchanged-2
860 M f-unchanged-2
861 created new head
861 created new head
862 $ echo 1 > f-different
862 $ echo 1 > f-different
863 $ echo 1 > f-unchanged-1
863 $ echo 1 > f-unchanged-1
864 $ echo 0 > f-unchanged-2
864 $ echo 0 > f-unchanged-2
865 $ echo 1 > f-same
865 $ echo 1 > f-same
866 $ hg ci -m4
866 $ hg ci -m4
867 Invoking status precommit hook
867 Invoking status precommit hook
868 M f-different
868 M f-different
869 M f-same
869 M f-same
870 M f-unchanged-1
870 M f-unchanged-1
871 M f-unchanged-2
871 M f-unchanged-2
872 $ hg merge
872 $ hg merge
873 largefile f-different has a merge conflict
873 largefile f-different has a merge conflict
874 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
874 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
875 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
875 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
876 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
876 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
877 getting changed largefiles
877 getting changed largefiles
878 1 largefiles updated, 0 removed
878 1 largefiles updated, 0 removed
879 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
879 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
880 (branch merge, don't forget to commit)
880 (branch merge, don't forget to commit)
881 $ cat f-different
881 $ cat f-different
882 1
882 1
883 $ cat f-same
883 $ cat f-same
884 1
884 1
885 $ cat f-unchanged-1
885 $ cat f-unchanged-1
886 1
886 1
887 $ cat f-unchanged-2
887 $ cat f-unchanged-2
888 1
888 1
889 $ cd ..
889 $ cd ..
890
890
891 Test largefile insulation (do not enabled a side effect
891 Test largefile insulation (do not enabled a side effect
892 ========================================================
892 ========================================================
893
893
894 Check whether "largefiles" feature is supported only in repositories
894 Check whether "largefiles" feature is supported only in repositories
895 enabling largefiles extension.
895 enabling largefiles extension.
896
896
897 $ mkdir individualenabling
897 $ mkdir individualenabling
898 $ cd individualenabling
898 $ cd individualenabling
899
899
900 $ hg init enabledlocally
900 $ hg init enabledlocally
901 $ echo large > enabledlocally/large
901 $ echo large > enabledlocally/large
902 $ hg -R enabledlocally add --large enabledlocally/large
902 $ hg -R enabledlocally add --large enabledlocally/large
903 $ hg -R enabledlocally commit -m '#0'
903 $ hg -R enabledlocally commit -m '#0'
904 Invoking status precommit hook
904 Invoking status precommit hook
905 A large
905 A large
906
906
907 $ hg init notenabledlocally
907 $ hg init notenabledlocally
908 $ echo large > notenabledlocally/large
908 $ echo large > notenabledlocally/large
909 $ hg -R notenabledlocally add --large notenabledlocally/large
909 $ hg -R notenabledlocally add --large notenabledlocally/large
910 $ hg -R notenabledlocally commit -m '#0'
910 $ hg -R notenabledlocally commit -m '#0'
911 Invoking status precommit hook
911 Invoking status precommit hook
912 A large
912 A large
913
913
914 $ cat >> $HGRCPATH <<EOF
914 $ cat >> $HGRCPATH <<EOF
915 > [extensions]
915 > [extensions]
916 > # disable globally
916 > # disable globally
917 > largefiles=!
917 > largefiles=!
918 > EOF
918 > EOF
919 $ cat >> enabledlocally/.hg/hgrc <<EOF
919 $ cat >> enabledlocally/.hg/hgrc <<EOF
920 > [extensions]
920 > [extensions]
921 > # enable locally
921 > # enable locally
922 > largefiles=
922 > largefiles=
923 > EOF
923 > EOF
924 $ hg -R enabledlocally root
924 $ hg -R enabledlocally root
925 $TESTTMP/individualenabling/enabledlocally (glob)
925 $TESTTMP/individualenabling/enabledlocally (glob)
926 $ hg -R notenabledlocally root
926 $ hg -R notenabledlocally root
927 abort: repository requires features unknown to this Mercurial: largefiles!
927 abort: repository requires features unknown to this Mercurial: largefiles!
928 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
928 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
929 [255]
929 [255]
930
930
931 $ hg init push-dst
931 $ hg init push-dst
932 $ hg -R enabledlocally push push-dst
932 $ hg -R enabledlocally push push-dst
933 pushing to push-dst
933 pushing to push-dst
934 abort: required features are not supported in the destination: largefiles
934 abort: required features are not supported in the destination: largefiles
935 [255]
935 [255]
936
936
937 $ hg init pull-src
937 $ hg init pull-src
938 $ hg -R pull-src pull enabledlocally
938 $ hg -R pull-src pull enabledlocally
939 pulling from enabledlocally
939 pulling from enabledlocally
940 abort: required features are not supported in the destination: largefiles
940 abort: required features are not supported in the destination: largefiles
941 [255]
941 [255]
942
942
943 $ hg clone enabledlocally clone-dst
943 $ hg clone enabledlocally clone-dst
944 abort: repository requires features unknown to this Mercurial: largefiles!
944 abort: repository requires features unknown to this Mercurial: largefiles!
945 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
945 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
946 [255]
946 [255]
947 $ test -d clone-dst
947 $ test -d clone-dst
948 [1]
948 [1]
949 $ hg clone --pull enabledlocally clone-pull-dst
949 $ hg clone --pull enabledlocally clone-pull-dst
950 abort: required features are not supported in the destination: largefiles
950 abort: required features are not supported in the destination: largefiles
951 [255]
951 [255]
952 $ test -d clone-pull-dst
952 $ test -d clone-pull-dst
953 [1]
953 [1]
954
954
955 #if serve
955 #if serve
956
956
957 Test largefiles specific peer setup, when largefiles is enabled
957 Test largefiles specific peer setup, when largefiles is enabled
958 locally (issue4109)
958 locally (issue4109)
959
959
960 $ hg showconfig extensions | grep largefiles
960 $ hg showconfig extensions | grep largefiles
961 extensions.largefiles=!
961 extensions.largefiles=!
962 $ mkdir -p $TESTTMP/individualenabling/usercache
962 $ mkdir -p $TESTTMP/individualenabling/usercache
963
963
964 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
964 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
965 $ cat hg.pid >> $DAEMON_PIDS
965 $ cat hg.pid >> $DAEMON_PIDS
966
966
967 $ hg init pull-dst
967 $ hg init pull-dst
968 $ cat > pull-dst/.hg/hgrc <<EOF
968 $ cat > pull-dst/.hg/hgrc <<EOF
969 > [extensions]
969 > [extensions]
970 > # enable locally
970 > # enable locally
971 > largefiles=
971 > largefiles=
972 > [largefiles]
972 > [largefiles]
973 > # ignore system cache to force largefiles specific wire proto access
973 > # ignore system cache to force largefiles specific wire proto access
974 > usercache=$TESTTMP/individualenabling/usercache
974 > usercache=$TESTTMP/individualenabling/usercache
975 > EOF
975 > EOF
976 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
976 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
977
977
978 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
978 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
979 #endif
979 #endif
980
980
981 Test overridden functions work correctly even for repos disabling
981 Test overridden functions work correctly even for repos disabling
982 largefiles (issue4547)
982 largefiles (issue4547)
983
983
984 $ hg showconfig extensions | grep largefiles
984 $ hg showconfig extensions | grep largefiles
985 extensions.largefiles=!
985 extensions.largefiles=!
986
986
987 (test updating implied by clone)
987 (test updating implied by clone)
988
988
989 $ hg init enabled-but-no-largefiles
989 $ hg init enabled-but-no-largefiles
990 $ echo normal1 > enabled-but-no-largefiles/normal1
990 $ echo normal1 > enabled-but-no-largefiles/normal1
991 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
991 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
992 $ hg -R enabled-but-no-largefiles commit -m '#0@enabled-but-no-largefiles'
992 $ hg -R enabled-but-no-largefiles commit -m '#0@enabled-but-no-largefiles'
993 Invoking status precommit hook
993 Invoking status precommit hook
994 A normal1
994 A normal1
995 $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
995 $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
996 > [extensions]
996 > [extensions]
997 > # enable locally
997 > # enable locally
998 > largefiles=
998 > largefiles=
999 > EOF
999 > EOF
1000 $ hg clone -q enabled-but-no-largefiles no-largefiles
1000 $ hg clone -q enabled-but-no-largefiles no-largefiles
1001
1001
1002 (test rebasing implied by pull: precommit while rebasing unexpectedly
1002 (test rebasing implied by pull: precommit while rebasing unexpectedly
1003 shows "normal3" as "?", because lfdirstate isn't yet written out at
1003 shows "normal3" as "?", because lfdirstate isn't yet written out at
1004 that time)
1004 that time)
1005
1005
1006 $ echo normal2 > enabled-but-no-largefiles/normal2
1006 $ echo normal2 > enabled-but-no-largefiles/normal2
1007 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
1007 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
1008 $ hg -R enabled-but-no-largefiles commit -m '#1@enabled-but-no-largefiles'
1008 $ hg -R enabled-but-no-largefiles commit -m '#1@enabled-but-no-largefiles'
1009 Invoking status precommit hook
1009 Invoking status precommit hook
1010 A normal2
1010 A normal2
1011
1011
1012 $ echo normal3 > no-largefiles/normal3
1012 $ echo normal3 > no-largefiles/normal3
1013 $ hg -R no-largefiles add no-largefiles/normal3
1013 $ hg -R no-largefiles add no-largefiles/normal3
1014 $ hg -R no-largefiles commit -m '#1@no-largefiles'
1014 $ hg -R no-largefiles commit -m '#1@no-largefiles'
1015 Invoking status precommit hook
1015 Invoking status precommit hook
1016 A normal3
1016 A normal3
1017
1017
1018 $ hg -R no-largefiles -q pull --rebase
1018 $ hg -R no-largefiles -q pull --rebase
1019 Invoking status precommit hook
1019 Invoking status precommit hook
1020 ? normal3
1020 M normal3
1021
1021
1022 (test reverting)
1022 (test reverting)
1023
1023
1024 $ hg init subrepo-root
1024 $ hg init subrepo-root
1025 $ cat >> subrepo-root/.hg/hgrc <<EOF
1025 $ cat >> subrepo-root/.hg/hgrc <<EOF
1026 > [extensions]
1026 > [extensions]
1027 > # enable locally
1027 > # enable locally
1028 > largefiles=
1028 > largefiles=
1029 > EOF
1029 > EOF
1030 $ echo large > subrepo-root/large
1030 $ echo large > subrepo-root/large
1031 $ hg -R subrepo-root add --large subrepo-root/large
1031 $ hg -R subrepo-root add --large subrepo-root/large
1032 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1032 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1033 $ cat > subrepo-root/.hgsub <<EOF
1033 $ cat > subrepo-root/.hgsub <<EOF
1034 > no-largefiles = no-largefiles
1034 > no-largefiles = no-largefiles
1035 > EOF
1035 > EOF
1036 $ hg -R subrepo-root add subrepo-root/.hgsub
1036 $ hg -R subrepo-root add subrepo-root/.hgsub
1037 $ hg -R subrepo-root commit -m '#0'
1037 $ hg -R subrepo-root commit -m '#0'
1038 Invoking status precommit hook
1038 Invoking status precommit hook
1039 A .hgsub
1039 A .hgsub
1040 A large
1040 A large
1041 ? .hgsubstate
1041 ? .hgsubstate
1042 $ echo dirty >> subrepo-root/large
1042 $ echo dirty >> subrepo-root/large
1043 $ echo dirty >> subrepo-root/no-largefiles/normal1
1043 $ echo dirty >> subrepo-root/no-largefiles/normal1
1044 $ hg -R subrepo-root status -S
1044 $ hg -R subrepo-root status -S
1045 M large
1045 M large
1046 M no-largefiles/normal1
1046 M no-largefiles/normal1
1047 $ hg -R subrepo-root revert --all
1047 $ hg -R subrepo-root revert --all
1048 reverting subrepo-root/.hglf/large (glob)
1048 reverting subrepo-root/.hglf/large (glob)
1049 reverting subrepo no-largefiles
1049 reverting subrepo no-largefiles
1050 reverting subrepo-root/no-largefiles/normal1 (glob)
1050 reverting subrepo-root/no-largefiles/normal1 (glob)
1051
1051
1052 $ cd ..
1052 $ cd ..
1053
1053
1054
1054
1055 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1055 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1056 =========================================================================
1056 =========================================================================
1057
1057
1058 $ hg showconfig extensions | grep largefiles
1058 $ hg showconfig extensions | grep largefiles
1059 extensions.largefiles=!
1059 extensions.largefiles=!
1060
1060
1061 $ mkdir issue3861
1061 $ mkdir issue3861
1062 $ cd issue3861
1062 $ cd issue3861
1063 $ hg init src
1063 $ hg init src
1064 $ hg clone -q src dst
1064 $ hg clone -q src dst
1065 $ echo a > src/a
1065 $ echo a > src/a
1066 $ hg -R src commit -Aqm "#0"
1066 $ hg -R src commit -Aqm "#0"
1067 Invoking status precommit hook
1067 Invoking status precommit hook
1068 A a
1068 A a
1069
1069
1070 $ cat >> dst/.hg/hgrc <<EOF
1070 $ cat >> dst/.hg/hgrc <<EOF
1071 > [extensions]
1071 > [extensions]
1072 > largefiles=
1072 > largefiles=
1073 > EOF
1073 > EOF
1074 $ hg -R dst pull --rebase
1074 $ hg -R dst pull --rebase
1075 pulling from $TESTTMP/issue3861/src (glob)
1075 pulling from $TESTTMP/issue3861/src (glob)
1076 requesting all changes
1076 requesting all changes
1077 adding changesets
1077 adding changesets
1078 adding manifests
1078 adding manifests
1079 adding file changes
1079 adding file changes
1080 added 1 changesets with 1 changes to 1 files
1080 added 1 changesets with 1 changes to 1 files
1081 nothing to rebase - working directory parent is already an ancestor of destination bf5e395ced2c
1081 nothing to rebase - working directory parent is already an ancestor of destination bf5e395ced2c
1082 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1082 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1083
1083
1084 $ cd ..
1084 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now