##// END OF EJS Templates
narrow: use narrow_widen wireproto command to widen in case of ellipses...
Pulkit Goyal -
r42605:c767e655 default
parent child Browse files
Show More
@@ -1,463 +1,493 b''
1 # narrowcommands.py - command modifications for narrowhg extension
1 # narrowcommands.py - command modifications for narrowhg extension
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, Inc.
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 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import itertools
9 import itertools
10 import os
10 import os
11
11
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 from mercurial import (
13 from mercurial import (
14 bundle2,
14 bundle2,
15 cmdutil,
15 cmdutil,
16 commands,
16 commands,
17 discovery,
17 discovery,
18 encoding,
18 encoding,
19 error,
19 error,
20 exchange,
20 exchange,
21 extensions,
21 extensions,
22 hg,
22 hg,
23 narrowspec,
23 narrowspec,
24 node,
24 node,
25 pycompat,
25 pycompat,
26 registrar,
26 registrar,
27 repair,
27 repair,
28 repository,
28 repository,
29 repoview,
29 repoview,
30 sparse,
30 sparse,
31 util,
31 util,
32 wireprototypes,
32 wireprototypes,
33 )
33 )
34
34
35 table = {}
35 table = {}
36 command = registrar.command(table)
36 command = registrar.command(table)
37
37
38 def setup():
38 def setup():
39 """Wraps user-facing mercurial commands with narrow-aware versions."""
39 """Wraps user-facing mercurial commands with narrow-aware versions."""
40
40
41 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
41 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
42 entry[1].append(('', 'narrow', None,
42 entry[1].append(('', 'narrow', None,
43 _("create a narrow clone of select files")))
43 _("create a narrow clone of select files")))
44 entry[1].append(('', 'depth', '',
44 entry[1].append(('', 'depth', '',
45 _("limit the history fetched by distance from heads")))
45 _("limit the history fetched by distance from heads")))
46 entry[1].append(('', 'narrowspec', '',
46 entry[1].append(('', 'narrowspec', '',
47 _("read narrowspecs from file")))
47 _("read narrowspecs from file")))
48 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
48 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
49 if 'sparse' not in extensions.enabled():
49 if 'sparse' not in extensions.enabled():
50 entry[1].append(('', 'include', [],
50 entry[1].append(('', 'include', [],
51 _("specifically fetch this file/directory")))
51 _("specifically fetch this file/directory")))
52 entry[1].append(
52 entry[1].append(
53 ('', 'exclude', [],
53 ('', 'exclude', [],
54 _("do not fetch this file/directory, even if included")))
54 _("do not fetch this file/directory, even if included")))
55
55
56 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
56 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
57 entry[1].append(('', 'depth', '',
57 entry[1].append(('', 'depth', '',
58 _("limit the history fetched by distance from heads")))
58 _("limit the history fetched by distance from heads")))
59
59
60 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
60 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
61
61
62 def clonenarrowcmd(orig, ui, repo, *args, **opts):
62 def clonenarrowcmd(orig, ui, repo, *args, **opts):
63 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
63 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
64 opts = pycompat.byteskwargs(opts)
64 opts = pycompat.byteskwargs(opts)
65 wrappedextraprepare = util.nullcontextmanager()
65 wrappedextraprepare = util.nullcontextmanager()
66 narrowspecfile = opts['narrowspec']
66 narrowspecfile = opts['narrowspec']
67
67
68 if narrowspecfile:
68 if narrowspecfile:
69 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
69 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
70 ui.status(_("reading narrowspec from '%s'\n") % filepath)
70 ui.status(_("reading narrowspec from '%s'\n") % filepath)
71 try:
71 try:
72 fdata = util.readfile(filepath)
72 fdata = util.readfile(filepath)
73 except IOError as inst:
73 except IOError as inst:
74 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
74 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
75 (filepath, encoding.strtolocal(inst.strerror)))
75 (filepath, encoding.strtolocal(inst.strerror)))
76
76
77 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow')
77 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow')
78 if profiles:
78 if profiles:
79 raise error.Abort(_("cannot specify other files using '%include' in"
79 raise error.Abort(_("cannot specify other files using '%include' in"
80 " narrowspec"))
80 " narrowspec"))
81
81
82 narrowspec.validatepatterns(includes)
82 narrowspec.validatepatterns(includes)
83 narrowspec.validatepatterns(excludes)
83 narrowspec.validatepatterns(excludes)
84
84
85 # narrowspec is passed so we should assume that user wants narrow clone
85 # narrowspec is passed so we should assume that user wants narrow clone
86 opts['narrow'] = True
86 opts['narrow'] = True
87 opts['include'].extend(includes)
87 opts['include'].extend(includes)
88 opts['exclude'].extend(excludes)
88 opts['exclude'].extend(excludes)
89
89
90 if opts['narrow']:
90 if opts['narrow']:
91 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
91 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
92 orig(pullop, kwargs)
92 orig(pullop, kwargs)
93
93
94 if opts.get('depth'):
94 if opts.get('depth'):
95 kwargs['depth'] = opts['depth']
95 kwargs['depth'] = opts['depth']
96 wrappedextraprepare = extensions.wrappedfunction(exchange,
96 wrappedextraprepare = extensions.wrappedfunction(exchange,
97 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
97 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
98
98
99 with wrappedextraprepare:
99 with wrappedextraprepare:
100 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
100 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
101
101
102 def pullnarrowcmd(orig, ui, repo, *args, **opts):
102 def pullnarrowcmd(orig, ui, repo, *args, **opts):
103 """Wraps pull command to allow modifying narrow spec."""
103 """Wraps pull command to allow modifying narrow spec."""
104 wrappedextraprepare = util.nullcontextmanager()
104 wrappedextraprepare = util.nullcontextmanager()
105 if repository.NARROW_REQUIREMENT in repo.requirements:
105 if repository.NARROW_REQUIREMENT in repo.requirements:
106
106
107 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
107 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
108 orig(pullop, kwargs)
108 orig(pullop, kwargs)
109 if opts.get(r'depth'):
109 if opts.get(r'depth'):
110 kwargs['depth'] = opts[r'depth']
110 kwargs['depth'] = opts[r'depth']
111 wrappedextraprepare = extensions.wrappedfunction(exchange,
111 wrappedextraprepare = extensions.wrappedfunction(exchange,
112 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
112 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
113
113
114 with wrappedextraprepare:
114 with wrappedextraprepare:
115 return orig(ui, repo, *args, **opts)
115 return orig(ui, repo, *args, **opts)
116
116
117 def archivenarrowcmd(orig, ui, repo, *args, **opts):
117 def archivenarrowcmd(orig, ui, repo, *args, **opts):
118 """Wraps archive command to narrow the default includes."""
118 """Wraps archive command to narrow the default includes."""
119 if repository.NARROW_REQUIREMENT in repo.requirements:
119 if repository.NARROW_REQUIREMENT in repo.requirements:
120 repo_includes, repo_excludes = repo.narrowpats
120 repo_includes, repo_excludes = repo.narrowpats
121 includes = set(opts.get(r'include', []))
121 includes = set(opts.get(r'include', []))
122 excludes = set(opts.get(r'exclude', []))
122 excludes = set(opts.get(r'exclude', []))
123 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
123 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
124 includes, excludes, repo_includes, repo_excludes)
124 includes, excludes, repo_includes, repo_excludes)
125 if includes:
125 if includes:
126 opts[r'include'] = includes
126 opts[r'include'] = includes
127 if excludes:
127 if excludes:
128 opts[r'exclude'] = excludes
128 opts[r'exclude'] = excludes
129 return orig(ui, repo, *args, **opts)
129 return orig(ui, repo, *args, **opts)
130
130
131 def pullbundle2extraprepare(orig, pullop, kwargs):
131 def pullbundle2extraprepare(orig, pullop, kwargs):
132 repo = pullop.repo
132 repo = pullop.repo
133 if repository.NARROW_REQUIREMENT not in repo.requirements:
133 if repository.NARROW_REQUIREMENT not in repo.requirements:
134 return orig(pullop, kwargs)
134 return orig(pullop, kwargs)
135
135
136 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
136 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
137 raise error.Abort(_("server does not support narrow clones"))
137 raise error.Abort(_("server does not support narrow clones"))
138 orig(pullop, kwargs)
138 orig(pullop, kwargs)
139 kwargs['narrow'] = True
139 kwargs['narrow'] = True
140 include, exclude = repo.narrowpats
140 include, exclude = repo.narrowpats
141 kwargs['oldincludepats'] = include
141 kwargs['oldincludepats'] = include
142 kwargs['oldexcludepats'] = exclude
142 kwargs['oldexcludepats'] = exclude
143 if include:
143 if include:
144 kwargs['includepats'] = include
144 kwargs['includepats'] = include
145 if exclude:
145 if exclude:
146 kwargs['excludepats'] = exclude
146 kwargs['excludepats'] = exclude
147 # calculate known nodes only in ellipses cases because in non-ellipses cases
147 # calculate known nodes only in ellipses cases because in non-ellipses cases
148 # we have all the nodes
148 # we have all the nodes
149 if wireprototypes.ELLIPSESCAP in pullop.remote.capabilities():
149 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities():
150 kwargs['known'] = [node.hex(ctx.node()) for ctx in
150 kwargs['known'] = [node.hex(ctx.node()) for ctx in
151 repo.set('::%ln', pullop.common)
151 repo.set('::%ln', pullop.common)
152 if ctx.node() != node.nullid]
152 if ctx.node() != node.nullid]
153 if not kwargs['known']:
153 if not kwargs['known']:
154 # Mercurial serializes an empty list as '' and deserializes it as
154 # Mercurial serializes an empty list as '' and deserializes it as
155 # [''], so delete it instead to avoid handling the empty string on
155 # [''], so delete it instead to avoid handling the empty string on
156 # the server.
156 # the server.
157 del kwargs['known']
157 del kwargs['known']
158
158
159 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
159 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
160 pullbundle2extraprepare)
160 pullbundle2extraprepare)
161
161
162 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
162 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
163 newincludes, newexcludes, force):
163 newincludes, newexcludes, force):
164 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
164 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
165 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
165 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
166
166
167 # This is essentially doing "hg outgoing" to find all local-only
167 # This is essentially doing "hg outgoing" to find all local-only
168 # commits. We will then check that the local-only commits don't
168 # commits. We will then check that the local-only commits don't
169 # have any changes to files that will be untracked.
169 # have any changes to files that will be untracked.
170 unfi = repo.unfiltered()
170 unfi = repo.unfiltered()
171 outgoing = discovery.findcommonoutgoing(unfi, remote,
171 outgoing = discovery.findcommonoutgoing(unfi, remote,
172 commoninc=commoninc)
172 commoninc=commoninc)
173 ui.status(_('looking for local changes to affected paths\n'))
173 ui.status(_('looking for local changes to affected paths\n'))
174 localnodes = []
174 localnodes = []
175 for n in itertools.chain(outgoing.missing, outgoing.excluded):
175 for n in itertools.chain(outgoing.missing, outgoing.excluded):
176 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
176 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
177 localnodes.append(n)
177 localnodes.append(n)
178 revstostrip = unfi.revs('descendants(%ln)', localnodes)
178 revstostrip = unfi.revs('descendants(%ln)', localnodes)
179 hiddenrevs = repoview.filterrevs(repo, 'visible')
179 hiddenrevs = repoview.filterrevs(repo, 'visible')
180 visibletostrip = list(repo.changelog.node(r)
180 visibletostrip = list(repo.changelog.node(r)
181 for r in (revstostrip - hiddenrevs))
181 for r in (revstostrip - hiddenrevs))
182 if visibletostrip:
182 if visibletostrip:
183 ui.status(_('The following changeset(s) or their ancestors have '
183 ui.status(_('The following changeset(s) or their ancestors have '
184 'local changes not on the remote:\n'))
184 'local changes not on the remote:\n'))
185 maxnodes = 10
185 maxnodes = 10
186 if ui.verbose or len(visibletostrip) <= maxnodes:
186 if ui.verbose or len(visibletostrip) <= maxnodes:
187 for n in visibletostrip:
187 for n in visibletostrip:
188 ui.status('%s\n' % node.short(n))
188 ui.status('%s\n' % node.short(n))
189 else:
189 else:
190 for n in visibletostrip[:maxnodes]:
190 for n in visibletostrip[:maxnodes]:
191 ui.status('%s\n' % node.short(n))
191 ui.status('%s\n' % node.short(n))
192 ui.status(_('...and %d more, use --verbose to list all\n') %
192 ui.status(_('...and %d more, use --verbose to list all\n') %
193 (len(visibletostrip) - maxnodes))
193 (len(visibletostrip) - maxnodes))
194 if not force:
194 if not force:
195 raise error.Abort(_('local changes found'),
195 raise error.Abort(_('local changes found'),
196 hint=_('use --force-delete-local-changes to '
196 hint=_('use --force-delete-local-changes to '
197 'ignore'))
197 'ignore'))
198
198
199 with ui.uninterruptible():
199 with ui.uninterruptible():
200 if revstostrip:
200 if revstostrip:
201 tostrip = [unfi.changelog.node(r) for r in revstostrip]
201 tostrip = [unfi.changelog.node(r) for r in revstostrip]
202 if repo['.'].node() in tostrip:
202 if repo['.'].node() in tostrip:
203 # stripping working copy, so move to a different commit first
203 # stripping working copy, so move to a different commit first
204 urev = max(repo.revs('(::%n) - %ln + null',
204 urev = max(repo.revs('(::%n) - %ln + null',
205 repo['.'].node(), visibletostrip))
205 repo['.'].node(), visibletostrip))
206 hg.clean(repo, urev)
206 hg.clean(repo, urev)
207 overrides = {('devel', 'strip-obsmarkers'): False}
207 overrides = {('devel', 'strip-obsmarkers'): False}
208 with ui.configoverride(overrides, 'narrow'):
208 with ui.configoverride(overrides, 'narrow'):
209 repair.strip(ui, unfi, tostrip, topic='narrow')
209 repair.strip(ui, unfi, tostrip, topic='narrow')
210
210
211 todelete = []
211 todelete = []
212 for f, f2, size in repo.store.datafiles():
212 for f, f2, size in repo.store.datafiles():
213 if f.startswith('data/'):
213 if f.startswith('data/'):
214 file = f[5:-2]
214 file = f[5:-2]
215 if not newmatch(file):
215 if not newmatch(file):
216 todelete.append(f)
216 todelete.append(f)
217 elif f.startswith('meta/'):
217 elif f.startswith('meta/'):
218 dir = f[5:-13]
218 dir = f[5:-13]
219 dirs = sorted(util.dirs({dir})) + [dir]
219 dirs = sorted(util.dirs({dir})) + [dir]
220 include = True
220 include = True
221 for d in dirs:
221 for d in dirs:
222 visit = newmatch.visitdir(d)
222 visit = newmatch.visitdir(d)
223 if not visit:
223 if not visit:
224 include = False
224 include = False
225 break
225 break
226 if visit == 'all':
226 if visit == 'all':
227 break
227 break
228 if not include:
228 if not include:
229 todelete.append(f)
229 todelete.append(f)
230
230
231 repo.destroying()
231 repo.destroying()
232
232
233 with repo.transaction('narrowing'):
233 with repo.transaction('narrowing'):
234 # Update narrowspec before removing revlogs, so repo won't be
234 # Update narrowspec before removing revlogs, so repo won't be
235 # corrupt in case of crash
235 # corrupt in case of crash
236 repo.setnarrowpats(newincludes, newexcludes)
236 repo.setnarrowpats(newincludes, newexcludes)
237
237
238 for f in todelete:
238 for f in todelete:
239 ui.status(_('deleting %s\n') % f)
239 ui.status(_('deleting %s\n') % f)
240 util.unlinkpath(repo.svfs.join(f))
240 util.unlinkpath(repo.svfs.join(f))
241 repo.store.markremoved(f)
241 repo.store.markremoved(f)
242
242
243 narrowspec.updateworkingcopy(repo, assumeclean=True)
243 narrowspec.updateworkingcopy(repo, assumeclean=True)
244 narrowspec.copytoworkingcopy(repo)
244 narrowspec.copytoworkingcopy(repo)
245
245
246 repo.destroyed()
246 repo.destroyed()
247
247
248 def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
248 def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
249 newincludes, newexcludes):
249 newincludes, newexcludes):
250 # for now we assume that if a server has ellipses enabled, we will be
250 # for now we assume that if a server has ellipses enabled, we will be
251 # exchanging ellipses nodes. In future we should add ellipses as a client
251 # exchanging ellipses nodes. In future we should add ellipses as a client
252 # side requirement (maybe) to distinguish a client is shallow or not and
252 # side requirement (maybe) to distinguish a client is shallow or not and
253 # then send that information to server whether we want ellipses or not.
253 # then send that information to server whether we want ellipses or not.
254 # Theoretically a non-ellipses repo should be able to use narrow
254 # Theoretically a non-ellipses repo should be able to use narrow
255 # functionality from an ellipses enabled server
255 # functionality from an ellipses enabled server
256 ellipsesremote = wireprototypes.ELLIPSESCAP in remote.capabilities()
256 remotecap = remote.capabilities()
257 ellipsesremote = any(cap in remotecap
258 for cap in wireprototypes.SUPPORTED_ELLIPSESCAP)
259
260 # check whether we are talking to a server which supports old version of
261 # ellipses capabilities
262 isoldellipses = (ellipsesremote and wireprototypes.ELLIPSESCAP1 in
263 remotecap and wireprototypes.ELLIPSESCAP not in remotecap)
257
264
258 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
265 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
259 orig(pullop, kwargs)
266 orig(pullop, kwargs)
260 # The old{in,ex}cludepats have already been set by orig()
267 # The old{in,ex}cludepats have already been set by orig()
261 kwargs['includepats'] = newincludes
268 kwargs['includepats'] = newincludes
262 kwargs['excludepats'] = newexcludes
269 kwargs['excludepats'] = newexcludes
263 wrappedextraprepare = extensions.wrappedfunction(exchange,
270 wrappedextraprepare = extensions.wrappedfunction(exchange,
264 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
271 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
265
272
266 # define a function that narrowbundle2 can call after creating the
273 # define a function that narrowbundle2 can call after creating the
267 # backup bundle, but before applying the bundle from the server
274 # backup bundle, but before applying the bundle from the server
268 def setnewnarrowpats():
275 def setnewnarrowpats():
269 repo.setnarrowpats(newincludes, newexcludes)
276 repo.setnarrowpats(newincludes, newexcludes)
270 repo.setnewnarrowpats = setnewnarrowpats
277 repo.setnewnarrowpats = setnewnarrowpats
271 # silence the devel-warning of applying an empty changegroup
278 # silence the devel-warning of applying an empty changegroup
272 overrides = {('devel', 'all-warnings'): False}
279 overrides = {('devel', 'all-warnings'): False}
273
280
274 with ui.uninterruptible():
281 with ui.uninterruptible():
275 common = commoninc[0]
282 common = commoninc[0]
276 if ellipsesremote:
283 if ellipsesremote:
277 ds = repo.dirstate
284 ds = repo.dirstate
278 p1, p2 = ds.p1(), ds.p2()
285 p1, p2 = ds.p1(), ds.p2()
279 with ds.parentchange():
286 with ds.parentchange():
280 ds.setparents(node.nullid, node.nullid)
287 ds.setparents(node.nullid, node.nullid)
281 with wrappedextraprepare:
288 with wrappedextraprepare:
282 with repo.ui.configoverride(overrides, 'widen'):
289 if isoldellipses:
283 exchange.pull(repo, remote, heads=common)
290 exchange.pull(repo, remote, heads=common)
291 else:
292 known = [node.hex(ctx.node()) for ctx in
293 repo.set('::%ln', common)
294 if ctx.node() != node.nullid]
295
296 with remote.commandexecutor() as e:
297 bundle = e.callcommand('narrow_widen', {
298 'oldincludes': oldincludes,
299 'oldexcludes': oldexcludes,
300 'newincludes': newincludes,
301 'newexcludes': newexcludes,
302 'cgversion': '03',
303 'commonheads': common,
304 'known': known,
305 'ellipses': True,
306 }).result()
307 trmanager = exchange.transactionmanager(repo, 'widen',
308 remote.url())
309 with trmanager:
310 op = bundle2.bundleoperation(repo,
311 trmanager.transaction, source='widen')
312 bundle2.processbundle(repo, bundle, op=op)
313
284 with ds.parentchange():
314 with ds.parentchange():
285 ds.setparents(p1, p2)
315 ds.setparents(p1, p2)
286 else:
316 else:
287 with remote.commandexecutor() as e:
317 with remote.commandexecutor() as e:
288 bundle = e.callcommand('narrow_widen', {
318 bundle = e.callcommand('narrow_widen', {
289 'oldincludes': oldincludes,
319 'oldincludes': oldincludes,
290 'oldexcludes': oldexcludes,
320 'oldexcludes': oldexcludes,
291 'newincludes': newincludes,
321 'newincludes': newincludes,
292 'newexcludes': newexcludes,
322 'newexcludes': newexcludes,
293 'cgversion': '03',
323 'cgversion': '03',
294 'commonheads': common,
324 'commonheads': common,
295 'known': [],
325 'known': [],
296 'ellipses': False,
326 'ellipses': False,
297 }).result()
327 }).result()
298
328
299 with repo.transaction('widening') as tr:
329 with repo.transaction('widening') as tr:
300 with repo.ui.configoverride(overrides, 'widen'):
330 with repo.ui.configoverride(overrides, 'widen'):
301 tgetter = lambda: tr
331 tgetter = lambda: tr
302 bundle2.processbundle(repo, bundle,
332 bundle2.processbundle(repo, bundle,
303 transactiongetter=tgetter)
333 transactiongetter=tgetter)
304
334
305 with repo.transaction('widening'):
335 with repo.transaction('widening'):
306 repo.setnewnarrowpats()
336 repo.setnewnarrowpats()
307 narrowspec.updateworkingcopy(repo)
337 narrowspec.updateworkingcopy(repo)
308 narrowspec.copytoworkingcopy(repo)
338 narrowspec.copytoworkingcopy(repo)
309
339
310 # TODO(rdamazio): Make new matcher format and update description
340 # TODO(rdamazio): Make new matcher format and update description
311 @command('tracked',
341 @command('tracked',
312 [('', 'addinclude', [], _('new paths to include')),
342 [('', 'addinclude', [], _('new paths to include')),
313 ('', 'removeinclude', [], _('old paths to no longer include')),
343 ('', 'removeinclude', [], _('old paths to no longer include')),
314 ('', 'addexclude', [], _('new paths to exclude')),
344 ('', 'addexclude', [], _('new paths to exclude')),
315 ('', 'import-rules', '', _('import narrowspecs from a file')),
345 ('', 'import-rules', '', _('import narrowspecs from a file')),
316 ('', 'removeexclude', [], _('old paths to no longer exclude')),
346 ('', 'removeexclude', [], _('old paths to no longer exclude')),
317 ('', 'clear', False, _('whether to replace the existing narrowspec')),
347 ('', 'clear', False, _('whether to replace the existing narrowspec')),
318 ('', 'force-delete-local-changes', False,
348 ('', 'force-delete-local-changes', False,
319 _('forces deletion of local changes when narrowing')),
349 _('forces deletion of local changes when narrowing')),
320 ('', 'update-working-copy', False,
350 ('', 'update-working-copy', False,
321 _('update working copy when the store has changed')),
351 _('update working copy when the store has changed')),
322 ] + commands.remoteopts,
352 ] + commands.remoteopts,
323 _('[OPTIONS]... [REMOTE]'),
353 _('[OPTIONS]... [REMOTE]'),
324 inferrepo=True)
354 inferrepo=True)
325 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
355 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
326 """show or change the current narrowspec
356 """show or change the current narrowspec
327
357
328 With no argument, shows the current narrowspec entries, one per line. Each
358 With no argument, shows the current narrowspec entries, one per line. Each
329 line will be prefixed with 'I' or 'X' for included or excluded patterns,
359 line will be prefixed with 'I' or 'X' for included or excluded patterns,
330 respectively.
360 respectively.
331
361
332 The narrowspec is comprised of expressions to match remote files and/or
362 The narrowspec is comprised of expressions to match remote files and/or
333 directories that should be pulled into your client.
363 directories that should be pulled into your client.
334 The narrowspec has *include* and *exclude* expressions, with excludes always
364 The narrowspec has *include* and *exclude* expressions, with excludes always
335 trumping includes: that is, if a file matches an exclude expression, it will
365 trumping includes: that is, if a file matches an exclude expression, it will
336 be excluded even if it also matches an include expression.
366 be excluded even if it also matches an include expression.
337 Excluding files that were never included has no effect.
367 Excluding files that were never included has no effect.
338
368
339 Each included or excluded entry is in the format described by
369 Each included or excluded entry is in the format described by
340 'hg help patterns'.
370 'hg help patterns'.
341
371
342 The options allow you to add or remove included and excluded expressions.
372 The options allow you to add or remove included and excluded expressions.
343
373
344 If --clear is specified, then all previous includes and excludes are DROPPED
374 If --clear is specified, then all previous includes and excludes are DROPPED
345 and replaced by the new ones specified to --addinclude and --addexclude.
375 and replaced by the new ones specified to --addinclude and --addexclude.
346 If --clear is specified without any further options, the narrowspec will be
376 If --clear is specified without any further options, the narrowspec will be
347 empty and will not match any files.
377 empty and will not match any files.
348
378
349 --import-rules accepts a path to a file containing rules, allowing you to
379 --import-rules accepts a path to a file containing rules, allowing you to
350 add --addinclude, --addexclude rules in bulk. Like the other include and
380 add --addinclude, --addexclude rules in bulk. Like the other include and
351 exclude switches, the changes are applied immediately.
381 exclude switches, the changes are applied immediately.
352 """
382 """
353 opts = pycompat.byteskwargs(opts)
383 opts = pycompat.byteskwargs(opts)
354 if repository.NARROW_REQUIREMENT not in repo.requirements:
384 if repository.NARROW_REQUIREMENT not in repo.requirements:
355 raise error.Abort(_('the tracked command is only supported on '
385 raise error.Abort(_('the tracked command is only supported on '
356 'respositories cloned with --narrow'))
386 'respositories cloned with --narrow'))
357
387
358 # Before supporting, decide whether it "hg tracked --clear" should mean
388 # Before supporting, decide whether it "hg tracked --clear" should mean
359 # tracking no paths or all paths.
389 # tracking no paths or all paths.
360 if opts['clear']:
390 if opts['clear']:
361 raise error.Abort(_('the --clear option is not yet supported'))
391 raise error.Abort(_('the --clear option is not yet supported'))
362
392
363 # import rules from a file
393 # import rules from a file
364 newrules = opts.get('import_rules')
394 newrules = opts.get('import_rules')
365 if newrules:
395 if newrules:
366 try:
396 try:
367 filepath = os.path.join(encoding.getcwd(), newrules)
397 filepath = os.path.join(encoding.getcwd(), newrules)
368 fdata = util.readfile(filepath)
398 fdata = util.readfile(filepath)
369 except IOError as inst:
399 except IOError as inst:
370 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
400 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
371 (filepath, encoding.strtolocal(inst.strerror)))
401 (filepath, encoding.strtolocal(inst.strerror)))
372 includepats, excludepats, profiles = sparse.parseconfig(ui, fdata,
402 includepats, excludepats, profiles = sparse.parseconfig(ui, fdata,
373 'narrow')
403 'narrow')
374 if profiles:
404 if profiles:
375 raise error.Abort(_("including other spec files using '%include' "
405 raise error.Abort(_("including other spec files using '%include' "
376 "is not supported in narrowspec"))
406 "is not supported in narrowspec"))
377 opts['addinclude'].extend(includepats)
407 opts['addinclude'].extend(includepats)
378 opts['addexclude'].extend(excludepats)
408 opts['addexclude'].extend(excludepats)
379
409
380 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
410 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
381 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
411 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
382 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
412 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
383 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
413 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
384
414
385 update_working_copy = opts['update_working_copy']
415 update_working_copy = opts['update_working_copy']
386 only_show = not (addedincludes or removedincludes or addedexcludes or
416 only_show = not (addedincludes or removedincludes or addedexcludes or
387 removedexcludes or newrules or update_working_copy)
417 removedexcludes or newrules or update_working_copy)
388
418
389 oldincludes, oldexcludes = repo.narrowpats
419 oldincludes, oldexcludes = repo.narrowpats
390
420
391 # filter the user passed additions and deletions into actual additions and
421 # filter the user passed additions and deletions into actual additions and
392 # deletions of excludes and includes
422 # deletions of excludes and includes
393 addedincludes -= oldincludes
423 addedincludes -= oldincludes
394 removedincludes &= oldincludes
424 removedincludes &= oldincludes
395 addedexcludes -= oldexcludes
425 addedexcludes -= oldexcludes
396 removedexcludes &= oldexcludes
426 removedexcludes &= oldexcludes
397
427
398 widening = addedincludes or removedexcludes
428 widening = addedincludes or removedexcludes
399 narrowing = removedincludes or addedexcludes
429 narrowing = removedincludes or addedexcludes
400
430
401 # Only print the current narrowspec.
431 # Only print the current narrowspec.
402 if only_show:
432 if only_show:
403 ui.pager('tracked')
433 ui.pager('tracked')
404 fm = ui.formatter('narrow', opts)
434 fm = ui.formatter('narrow', opts)
405 for i in sorted(oldincludes):
435 for i in sorted(oldincludes):
406 fm.startitem()
436 fm.startitem()
407 fm.write('status', '%s ', 'I', label='narrow.included')
437 fm.write('status', '%s ', 'I', label='narrow.included')
408 fm.write('pat', '%s\n', i, label='narrow.included')
438 fm.write('pat', '%s\n', i, label='narrow.included')
409 for i in sorted(oldexcludes):
439 for i in sorted(oldexcludes):
410 fm.startitem()
440 fm.startitem()
411 fm.write('status', '%s ', 'X', label='narrow.excluded')
441 fm.write('status', '%s ', 'X', label='narrow.excluded')
412 fm.write('pat', '%s\n', i, label='narrow.excluded')
442 fm.write('pat', '%s\n', i, label='narrow.excluded')
413 fm.end()
443 fm.end()
414 return 0
444 return 0
415
445
416 if update_working_copy:
446 if update_working_copy:
417 with repo.wlock(), repo.lock(), repo.transaction('narrow-wc'):
447 with repo.wlock(), repo.lock(), repo.transaction('narrow-wc'):
418 narrowspec.updateworkingcopy(repo)
448 narrowspec.updateworkingcopy(repo)
419 narrowspec.copytoworkingcopy(repo)
449 narrowspec.copytoworkingcopy(repo)
420 return 0
450 return 0
421
451
422 if not widening and not narrowing:
452 if not widening and not narrowing:
423 ui.status(_("nothing to widen or narrow\n"))
453 ui.status(_("nothing to widen or narrow\n"))
424 return 0
454 return 0
425
455
426 with repo.wlock(), repo.lock():
456 with repo.wlock(), repo.lock():
427 cmdutil.bailifchanged(repo)
457 cmdutil.bailifchanged(repo)
428
458
429 # Find the revisions we have in common with the remote. These will
459 # Find the revisions we have in common with the remote. These will
430 # be used for finding local-only changes for narrowing. They will
460 # be used for finding local-only changes for narrowing. They will
431 # also define the set of revisions to update for widening.
461 # also define the set of revisions to update for widening.
432 remotepath = ui.expandpath(remotepath or 'default')
462 remotepath = ui.expandpath(remotepath or 'default')
433 url, branches = hg.parseurl(remotepath)
463 url, branches = hg.parseurl(remotepath)
434 ui.status(_('comparing with %s\n') % util.hidepassword(url))
464 ui.status(_('comparing with %s\n') % util.hidepassword(url))
435 remote = hg.peer(repo, opts, url)
465 remote = hg.peer(repo, opts, url)
436
466
437 # check narrow support before doing anything if widening needs to be
467 # check narrow support before doing anything if widening needs to be
438 # performed. In future we should also abort if client is ellipses and
468 # performed. In future we should also abort if client is ellipses and
439 # server does not support ellipses
469 # server does not support ellipses
440 if widening and wireprototypes.NARROWCAP not in remote.capabilities():
470 if widening and wireprototypes.NARROWCAP not in remote.capabilities():
441 raise error.Abort(_("server does not support narrow clones"))
471 raise error.Abort(_("server does not support narrow clones"))
442
472
443 commoninc = discovery.findcommonincoming(repo, remote)
473 commoninc = discovery.findcommonincoming(repo, remote)
444
474
445 if narrowing:
475 if narrowing:
446 newincludes = oldincludes - removedincludes
476 newincludes = oldincludes - removedincludes
447 newexcludes = oldexcludes | addedexcludes
477 newexcludes = oldexcludes | addedexcludes
448 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
478 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
449 newincludes, newexcludes,
479 newincludes, newexcludes,
450 opts['force_delete_local_changes'])
480 opts['force_delete_local_changes'])
451 # _narrow() updated the narrowspec and _widen() below needs to
481 # _narrow() updated the narrowspec and _widen() below needs to
452 # use the updated values as its base (otherwise removed includes
482 # use the updated values as its base (otherwise removed includes
453 # and addedexcludes will be lost in the resulting narrowspec)
483 # and addedexcludes will be lost in the resulting narrowspec)
454 oldincludes = newincludes
484 oldincludes = newincludes
455 oldexcludes = newexcludes
485 oldexcludes = newexcludes
456
486
457 if widening:
487 if widening:
458 newincludes = oldincludes | addedincludes
488 newincludes = oldincludes | addedincludes
459 newexcludes = oldexcludes - removedexcludes
489 newexcludes = oldexcludes - removedexcludes
460 _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
490 _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
461 newincludes, newexcludes)
491 newincludes, newexcludes)
462
492
463 return 0
493 return 0
@@ -1,107 +1,115 b''
1 # narrowwirepeer.py - passes narrow spec with unbundle command
1 # narrowwirepeer.py - passes narrow spec with unbundle command
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from mercurial import (
10 from mercurial import (
11 bundle2,
11 bundle2,
12 error,
12 error,
13 extensions,
13 extensions,
14 hg,
14 hg,
15 narrowspec,
15 narrowspec,
16 node as nodemod,
16 pycompat,
17 pycompat,
17 wireprototypes,
18 wireprototypes,
18 wireprotov1peer,
19 wireprotov1peer,
19 wireprotov1server,
20 wireprotov1server,
20 )
21 )
21
22
23 from . import narrowbundle2
24
22 def uisetup():
25 def uisetup():
23 wireprotov1peer.wirepeer.narrow_widen = peernarrowwiden
26 wireprotov1peer.wirepeer.narrow_widen = peernarrowwiden
24
27
25 def reposetup(repo):
28 def reposetup(repo):
26 def wirereposetup(ui, peer):
29 def wirereposetup(ui, peer):
27 def wrapped(orig, cmd, *args, **kwargs):
30 def wrapped(orig, cmd, *args, **kwargs):
28 if cmd == 'unbundle':
31 if cmd == 'unbundle':
29 # TODO: don't blindly add include/exclude wireproto
32 # TODO: don't blindly add include/exclude wireproto
30 # arguments to unbundle.
33 # arguments to unbundle.
31 include, exclude = repo.narrowpats
34 include, exclude = repo.narrowpats
32 kwargs[r"includepats"] = ','.join(include)
35 kwargs[r"includepats"] = ','.join(include)
33 kwargs[r"excludepats"] = ','.join(exclude)
36 kwargs[r"excludepats"] = ','.join(exclude)
34 return orig(cmd, *args, **kwargs)
37 return orig(cmd, *args, **kwargs)
35 extensions.wrapfunction(peer, '_calltwowaystream', wrapped)
38 extensions.wrapfunction(peer, '_calltwowaystream', wrapped)
36 hg.wirepeersetupfuncs.append(wirereposetup)
39 hg.wirepeersetupfuncs.append(wirereposetup)
37
40
38 @wireprotov1server.wireprotocommand('narrow_widen', 'oldincludes oldexcludes'
41 @wireprotov1server.wireprotocommand('narrow_widen', 'oldincludes oldexcludes'
39 ' newincludes newexcludes'
42 ' newincludes newexcludes'
40 ' commonheads cgversion'
43 ' commonheads cgversion'
41 ' known ellipses',
44 ' known ellipses',
42 permission='pull')
45 permission='pull')
43 def narrow_widen(repo, proto, oldincludes, oldexcludes, newincludes,
46 def narrow_widen(repo, proto, oldincludes, oldexcludes, newincludes,
44 newexcludes, commonheads, cgversion, known, ellipses):
47 newexcludes, commonheads, cgversion, known, ellipses):
45 """wireprotocol command to send data when a narrow clone is widen. We will
48 """wireprotocol command to send data when a narrow clone is widen. We will
46 be sending a changegroup here.
49 be sending a changegroup here.
47
50
48 The current set of arguments which are required:
51 The current set of arguments which are required:
49 oldincludes: the old includes of the narrow copy
52 oldincludes: the old includes of the narrow copy
50 oldexcludes: the old excludes of the narrow copy
53 oldexcludes: the old excludes of the narrow copy
51 newincludes: the new includes of the narrow copy
54 newincludes: the new includes of the narrow copy
52 newexcludes: the new excludes of the narrow copy
55 newexcludes: the new excludes of the narrow copy
53 commonheads: list of heads which are common between the server and client
56 commonheads: list of heads which are common between the server and client
54 cgversion(maybe): the changegroup version to produce
57 cgversion(maybe): the changegroup version to produce
55 known: list of nodes which are known on the client (used in ellipses cases)
58 known: list of nodes which are known on the client (used in ellipses cases)
56 ellipses: whether to send ellipses data or not
59 ellipses: whether to send ellipses data or not
57 """
60 """
58
61
59 preferuncompressed = False
62 preferuncompressed = False
60 try:
63 try:
61 oldincludes = wireprototypes.decodelist(oldincludes)
64 oldincludes = wireprototypes.decodelist(oldincludes)
62 newincludes = wireprototypes.decodelist(newincludes)
65 newincludes = wireprototypes.decodelist(newincludes)
63 oldexcludes = wireprototypes.decodelist(oldexcludes)
66 oldexcludes = wireprototypes.decodelist(oldexcludes)
64 newexcludes = wireprototypes.decodelist(newexcludes)
67 newexcludes = wireprototypes.decodelist(newexcludes)
65 # validate the patterns
68 # validate the patterns
66 narrowspec.validatepatterns(set(oldincludes))
69 narrowspec.validatepatterns(set(oldincludes))
67 narrowspec.validatepatterns(set(newincludes))
70 narrowspec.validatepatterns(set(newincludes))
68 narrowspec.validatepatterns(set(oldexcludes))
71 narrowspec.validatepatterns(set(oldexcludes))
69 narrowspec.validatepatterns(set(newexcludes))
72 narrowspec.validatepatterns(set(newexcludes))
70
73
71 common = wireprototypes.decodelist(commonheads)
74 common = wireprototypes.decodelist(commonheads)
72 known = None
75 known = wireprototypes.decodelist(known)
73 if known:
76 known = {nodemod.bin(n) for n in known}
74 known = wireprototypes.decodelist(known)
75 if ellipses == '0':
77 if ellipses == '0':
76 ellipses = False
78 ellipses = False
77 else:
79 else:
78 ellipses = bool(ellipses)
80 ellipses = bool(ellipses)
79 cgversion = cgversion
81 cgversion = cgversion
80 newmatch = narrowspec.match(repo.root, include=newincludes,
81 exclude=newexcludes)
82 oldmatch = narrowspec.match(repo.root, include=oldincludes,
83 exclude=oldexcludes)
84
82
85 bundler = bundle2.widen_bundle(repo, oldmatch, newmatch, common, known,
83 if not ellipses:
86 cgversion, ellipses)
84 newmatch = narrowspec.match(repo.root, include=newincludes,
85 exclude=newexcludes)
86 oldmatch = narrowspec.match(repo.root, include=oldincludes,
87 exclude=oldexcludes)
88 bundler = bundle2.widen_bundle(repo, oldmatch, newmatch, common,
89 known, cgversion, ellipses)
90 else:
91 bundler = bundle2.bundle20(repo.ui)
92 narrowbundle2.generateellipsesbundle2(bundler, repo, oldincludes,
93 oldexcludes, newincludes, newexcludes, cgversion, common,
94 list(common), known, None)
87 except error.Abort as exc:
95 except error.Abort as exc:
88 bundler = bundle2.bundle20(repo.ui)
96 bundler = bundle2.bundle20(repo.ui)
89 manargs = [('message', pycompat.bytestr(exc))]
97 manargs = [('message', pycompat.bytestr(exc))]
90 advargs = []
98 advargs = []
91 if exc.hint is not None:
99 if exc.hint is not None:
92 advargs.append(('hint', exc.hint))
100 advargs.append(('hint', exc.hint))
93 bundler.addpart(bundle2.bundlepart('error:abort', manargs, advargs))
101 bundler.addpart(bundle2.bundlepart('error:abort', manargs, advargs))
94 preferuncompressed = True
102 preferuncompressed = True
95
103
96 chunks = bundler.getchunks()
104 chunks = bundler.getchunks()
97 return wireprototypes.streamres(gen=chunks,
105 return wireprototypes.streamres(gen=chunks,
98 prefer_uncompressed=preferuncompressed)
106 prefer_uncompressed=preferuncompressed)
99
107
100 def peernarrowwiden(remote, **kwargs):
108 def peernarrowwiden(remote, **kwargs):
101 for ch in (r'oldincludes', r'newincludes', r'oldexcludes', r'newexcludes',
109 for ch in (r'oldincludes', r'newincludes', r'oldexcludes', r'newexcludes',
102 r'commonheads', r'known'):
110 r'commonheads', r'known'):
103 kwargs[ch] = wireprototypes.encodelist(kwargs[ch])
111 kwargs[ch] = wireprototypes.encodelist(kwargs[ch])
104
112
105 kwargs[r'ellipses'] = '%i' % bool(kwargs[r'ellipses'])
113 kwargs[r'ellipses'] = '%i' % bool(kwargs[r'ellipses'])
106 f = remote._callcompressable('narrow_widen', **kwargs)
114 f = remote._callcompressable('narrow_widen', **kwargs)
107 return bundle2.getunbundler(remote.ui, f)
115 return bundle2.getunbundler(remote.ui, f)
@@ -1,403 +1,405 b''
1 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
1 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 from .node import (
8 from .node import (
9 bin,
9 bin,
10 hex,
10 hex,
11 )
11 )
12 from .i18n import _
12 from .i18n import _
13 from .thirdparty import (
13 from .thirdparty import (
14 attr,
14 attr,
15 )
15 )
16 from . import (
16 from . import (
17 error,
17 error,
18 util,
18 util,
19 )
19 )
20 from .utils import (
20 from .utils import (
21 compression,
21 compression,
22 interfaceutil,
22 interfaceutil,
23 )
23 )
24
24
25 # Names of the SSH protocol implementations.
25 # Names of the SSH protocol implementations.
26 SSHV1 = 'ssh-v1'
26 SSHV1 = 'ssh-v1'
27 # These are advertised over the wire. Increment the counters at the end
27 # These are advertised over the wire. Increment the counters at the end
28 # to reflect BC breakages.
28 # to reflect BC breakages.
29 SSHV2 = 'exp-ssh-v2-0003'
29 SSHV2 = 'exp-ssh-v2-0003'
30 HTTP_WIREPROTO_V2 = 'exp-http-v2-0003'
30 HTTP_WIREPROTO_V2 = 'exp-http-v2-0003'
31
31
32 NARROWCAP = 'exp-narrow-1'
32 NARROWCAP = 'exp-narrow-1'
33 ELLIPSESCAP = 'exp-ellipses-1'
33 ELLIPSESCAP1 = 'exp-ellipses-1'
34 ELLIPSESCAP = 'exp-ellipses-2'
35 SUPPORTED_ELLIPSESCAP = (ELLIPSESCAP1, ELLIPSESCAP)
34
36
35 # All available wire protocol transports.
37 # All available wire protocol transports.
36 TRANSPORTS = {
38 TRANSPORTS = {
37 SSHV1: {
39 SSHV1: {
38 'transport': 'ssh',
40 'transport': 'ssh',
39 'version': 1,
41 'version': 1,
40 },
42 },
41 SSHV2: {
43 SSHV2: {
42 'transport': 'ssh',
44 'transport': 'ssh',
43 # TODO mark as version 2 once all commands are implemented.
45 # TODO mark as version 2 once all commands are implemented.
44 'version': 1,
46 'version': 1,
45 },
47 },
46 'http-v1': {
48 'http-v1': {
47 'transport': 'http',
49 'transport': 'http',
48 'version': 1,
50 'version': 1,
49 },
51 },
50 HTTP_WIREPROTO_V2: {
52 HTTP_WIREPROTO_V2: {
51 'transport': 'http',
53 'transport': 'http',
52 'version': 2,
54 'version': 2,
53 }
55 }
54 }
56 }
55
57
56 class bytesresponse(object):
58 class bytesresponse(object):
57 """A wire protocol response consisting of raw bytes."""
59 """A wire protocol response consisting of raw bytes."""
58 def __init__(self, data):
60 def __init__(self, data):
59 self.data = data
61 self.data = data
60
62
61 class ooberror(object):
63 class ooberror(object):
62 """wireproto reply: failure of a batch of operation
64 """wireproto reply: failure of a batch of operation
63
65
64 Something failed during a batch call. The error message is stored in
66 Something failed during a batch call. The error message is stored in
65 `self.message`.
67 `self.message`.
66 """
68 """
67 def __init__(self, message):
69 def __init__(self, message):
68 self.message = message
70 self.message = message
69
71
70 class pushres(object):
72 class pushres(object):
71 """wireproto reply: success with simple integer return
73 """wireproto reply: success with simple integer return
72
74
73 The call was successful and returned an integer contained in `self.res`.
75 The call was successful and returned an integer contained in `self.res`.
74 """
76 """
75 def __init__(self, res, output):
77 def __init__(self, res, output):
76 self.res = res
78 self.res = res
77 self.output = output
79 self.output = output
78
80
79 class pusherr(object):
81 class pusherr(object):
80 """wireproto reply: failure
82 """wireproto reply: failure
81
83
82 The call failed. The `self.res` attribute contains the error message.
84 The call failed. The `self.res` attribute contains the error message.
83 """
85 """
84 def __init__(self, res, output):
86 def __init__(self, res, output):
85 self.res = res
87 self.res = res
86 self.output = output
88 self.output = output
87
89
88 class streamres(object):
90 class streamres(object):
89 """wireproto reply: binary stream
91 """wireproto reply: binary stream
90
92
91 The call was successful and the result is a stream.
93 The call was successful and the result is a stream.
92
94
93 Accepts a generator containing chunks of data to be sent to the client.
95 Accepts a generator containing chunks of data to be sent to the client.
94
96
95 ``prefer_uncompressed`` indicates that the data is expected to be
97 ``prefer_uncompressed`` indicates that the data is expected to be
96 uncompressable and that the stream should therefore use the ``none``
98 uncompressable and that the stream should therefore use the ``none``
97 engine.
99 engine.
98 """
100 """
99 def __init__(self, gen=None, prefer_uncompressed=False):
101 def __init__(self, gen=None, prefer_uncompressed=False):
100 self.gen = gen
102 self.gen = gen
101 self.prefer_uncompressed = prefer_uncompressed
103 self.prefer_uncompressed = prefer_uncompressed
102
104
103 class streamreslegacy(object):
105 class streamreslegacy(object):
104 """wireproto reply: uncompressed binary stream
106 """wireproto reply: uncompressed binary stream
105
107
106 The call was successful and the result is a stream.
108 The call was successful and the result is a stream.
107
109
108 Accepts a generator containing chunks of data to be sent to the client.
110 Accepts a generator containing chunks of data to be sent to the client.
109
111
110 Like ``streamres``, but sends an uncompressed data for "version 1" clients
112 Like ``streamres``, but sends an uncompressed data for "version 1" clients
111 using the application/mercurial-0.1 media type.
113 using the application/mercurial-0.1 media type.
112 """
114 """
113 def __init__(self, gen=None):
115 def __init__(self, gen=None):
114 self.gen = gen
116 self.gen = gen
115
117
116 # list of nodes encoding / decoding
118 # list of nodes encoding / decoding
117 def decodelist(l, sep=' '):
119 def decodelist(l, sep=' '):
118 if l:
120 if l:
119 return [bin(v) for v in l.split(sep)]
121 return [bin(v) for v in l.split(sep)]
120 return []
122 return []
121
123
122 def encodelist(l, sep=' '):
124 def encodelist(l, sep=' '):
123 try:
125 try:
124 return sep.join(map(hex, l))
126 return sep.join(map(hex, l))
125 except TypeError:
127 except TypeError:
126 raise
128 raise
127
129
128 # batched call argument encoding
130 # batched call argument encoding
129
131
130 def escapebatcharg(plain):
132 def escapebatcharg(plain):
131 return (plain
133 return (plain
132 .replace(':', ':c')
134 .replace(':', ':c')
133 .replace(',', ':o')
135 .replace(',', ':o')
134 .replace(';', ':s')
136 .replace(';', ':s')
135 .replace('=', ':e'))
137 .replace('=', ':e'))
136
138
137 def unescapebatcharg(escaped):
139 def unescapebatcharg(escaped):
138 return (escaped
140 return (escaped
139 .replace(':e', '=')
141 .replace(':e', '=')
140 .replace(':s', ';')
142 .replace(':s', ';')
141 .replace(':o', ',')
143 .replace(':o', ',')
142 .replace(':c', ':'))
144 .replace(':c', ':'))
143
145
144 # mapping of options accepted by getbundle and their types
146 # mapping of options accepted by getbundle and their types
145 #
147 #
146 # Meant to be extended by extensions. It is extensions responsibility to ensure
148 # Meant to be extended by extensions. It is extensions responsibility to ensure
147 # such options are properly processed in exchange.getbundle.
149 # such options are properly processed in exchange.getbundle.
148 #
150 #
149 # supported types are:
151 # supported types are:
150 #
152 #
151 # :nodes: list of binary nodes
153 # :nodes: list of binary nodes
152 # :csv: list of comma-separated values
154 # :csv: list of comma-separated values
153 # :scsv: list of comma-separated values return as set
155 # :scsv: list of comma-separated values return as set
154 # :plain: string with no transformation needed.
156 # :plain: string with no transformation needed.
155 GETBUNDLE_ARGUMENTS = {
157 GETBUNDLE_ARGUMENTS = {
156 'heads': 'nodes',
158 'heads': 'nodes',
157 'bookmarks': 'boolean',
159 'bookmarks': 'boolean',
158 'common': 'nodes',
160 'common': 'nodes',
159 'obsmarkers': 'boolean',
161 'obsmarkers': 'boolean',
160 'phases': 'boolean',
162 'phases': 'boolean',
161 'bundlecaps': 'scsv',
163 'bundlecaps': 'scsv',
162 'listkeys': 'csv',
164 'listkeys': 'csv',
163 'cg': 'boolean',
165 'cg': 'boolean',
164 'cbattempted': 'boolean',
166 'cbattempted': 'boolean',
165 'stream': 'boolean',
167 'stream': 'boolean',
166 'includepats': 'csv',
168 'includepats': 'csv',
167 'excludepats': 'csv',
169 'excludepats': 'csv',
168 }
170 }
169
171
170 class baseprotocolhandler(interfaceutil.Interface):
172 class baseprotocolhandler(interfaceutil.Interface):
171 """Abstract base class for wire protocol handlers.
173 """Abstract base class for wire protocol handlers.
172
174
173 A wire protocol handler serves as an interface between protocol command
175 A wire protocol handler serves as an interface between protocol command
174 handlers and the wire protocol transport layer. Protocol handlers provide
176 handlers and the wire protocol transport layer. Protocol handlers provide
175 methods to read command arguments, redirect stdio for the duration of
177 methods to read command arguments, redirect stdio for the duration of
176 the request, handle response types, etc.
178 the request, handle response types, etc.
177 """
179 """
178
180
179 name = interfaceutil.Attribute(
181 name = interfaceutil.Attribute(
180 """The name of the protocol implementation.
182 """The name of the protocol implementation.
181
183
182 Used for uniquely identifying the transport type.
184 Used for uniquely identifying the transport type.
183 """)
185 """)
184
186
185 def getargs(args):
187 def getargs(args):
186 """return the value for arguments in <args>
188 """return the value for arguments in <args>
187
189
188 For version 1 transports, returns a list of values in the same
190 For version 1 transports, returns a list of values in the same
189 order they appear in ``args``. For version 2 transports, returns
191 order they appear in ``args``. For version 2 transports, returns
190 a dict mapping argument name to value.
192 a dict mapping argument name to value.
191 """
193 """
192
194
193 def getprotocaps():
195 def getprotocaps():
194 """Returns the list of protocol-level capabilities of client
196 """Returns the list of protocol-level capabilities of client
195
197
196 Returns a list of capabilities as declared by the client for
198 Returns a list of capabilities as declared by the client for
197 the current request (or connection for stateful protocol handlers)."""
199 the current request (or connection for stateful protocol handlers)."""
198
200
199 def getpayload():
201 def getpayload():
200 """Provide a generator for the raw payload.
202 """Provide a generator for the raw payload.
201
203
202 The caller is responsible for ensuring that the full payload is
204 The caller is responsible for ensuring that the full payload is
203 processed.
205 processed.
204 """
206 """
205
207
206 def mayberedirectstdio():
208 def mayberedirectstdio():
207 """Context manager to possibly redirect stdio.
209 """Context manager to possibly redirect stdio.
208
210
209 The context manager yields a file-object like object that receives
211 The context manager yields a file-object like object that receives
210 stdout and stderr output when the context manager is active. Or it
212 stdout and stderr output when the context manager is active. Or it
211 yields ``None`` if no I/O redirection occurs.
213 yields ``None`` if no I/O redirection occurs.
212
214
213 The intent of this context manager is to capture stdio output
215 The intent of this context manager is to capture stdio output
214 so it may be sent in the response. Some transports support streaming
216 so it may be sent in the response. Some transports support streaming
215 stdio to the client in real time. For these transports, stdio output
217 stdio to the client in real time. For these transports, stdio output
216 won't be captured.
218 won't be captured.
217 """
219 """
218
220
219 def client():
221 def client():
220 """Returns a string representation of this client (as bytes)."""
222 """Returns a string representation of this client (as bytes)."""
221
223
222 def addcapabilities(repo, caps):
224 def addcapabilities(repo, caps):
223 """Adds advertised capabilities specific to this protocol.
225 """Adds advertised capabilities specific to this protocol.
224
226
225 Receives the list of capabilities collected so far.
227 Receives the list of capabilities collected so far.
226
228
227 Returns a list of capabilities. The passed in argument can be returned.
229 Returns a list of capabilities. The passed in argument can be returned.
228 """
230 """
229
231
230 def checkperm(perm):
232 def checkperm(perm):
231 """Validate that the client has permissions to perform a request.
233 """Validate that the client has permissions to perform a request.
232
234
233 The argument is the permission required to proceed. If the client
235 The argument is the permission required to proceed. If the client
234 doesn't have that permission, the exception should raise or abort
236 doesn't have that permission, the exception should raise or abort
235 in a protocol specific manner.
237 in a protocol specific manner.
236 """
238 """
237
239
238 class commandentry(object):
240 class commandentry(object):
239 """Represents a declared wire protocol command."""
241 """Represents a declared wire protocol command."""
240 def __init__(self, func, args='', transports=None,
242 def __init__(self, func, args='', transports=None,
241 permission='push', cachekeyfn=None, extracapabilitiesfn=None):
243 permission='push', cachekeyfn=None, extracapabilitiesfn=None):
242 self.func = func
244 self.func = func
243 self.args = args
245 self.args = args
244 self.transports = transports or set()
246 self.transports = transports or set()
245 self.permission = permission
247 self.permission = permission
246 self.cachekeyfn = cachekeyfn
248 self.cachekeyfn = cachekeyfn
247 self.extracapabilitiesfn = extracapabilitiesfn
249 self.extracapabilitiesfn = extracapabilitiesfn
248
250
249 def _merge(self, func, args):
251 def _merge(self, func, args):
250 """Merge this instance with an incoming 2-tuple.
252 """Merge this instance with an incoming 2-tuple.
251
253
252 This is called when a caller using the old 2-tuple API attempts
254 This is called when a caller using the old 2-tuple API attempts
253 to replace an instance. The incoming values are merged with
255 to replace an instance. The incoming values are merged with
254 data not captured by the 2-tuple and a new instance containing
256 data not captured by the 2-tuple and a new instance containing
255 the union of the two objects is returned.
257 the union of the two objects is returned.
256 """
258 """
257 return commandentry(func, args=args, transports=set(self.transports),
259 return commandentry(func, args=args, transports=set(self.transports),
258 permission=self.permission)
260 permission=self.permission)
259
261
260 # Old code treats instances as 2-tuples. So expose that interface.
262 # Old code treats instances as 2-tuples. So expose that interface.
261 def __iter__(self):
263 def __iter__(self):
262 yield self.func
264 yield self.func
263 yield self.args
265 yield self.args
264
266
265 def __getitem__(self, i):
267 def __getitem__(self, i):
266 if i == 0:
268 if i == 0:
267 return self.func
269 return self.func
268 elif i == 1:
270 elif i == 1:
269 return self.args
271 return self.args
270 else:
272 else:
271 raise IndexError('can only access elements 0 and 1')
273 raise IndexError('can only access elements 0 and 1')
272
274
273 class commanddict(dict):
275 class commanddict(dict):
274 """Container for registered wire protocol commands.
276 """Container for registered wire protocol commands.
275
277
276 It behaves like a dict. But __setitem__ is overwritten to allow silent
278 It behaves like a dict. But __setitem__ is overwritten to allow silent
277 coercion of values from 2-tuples for API compatibility.
279 coercion of values from 2-tuples for API compatibility.
278 """
280 """
279 def __setitem__(self, k, v):
281 def __setitem__(self, k, v):
280 if isinstance(v, commandentry):
282 if isinstance(v, commandentry):
281 pass
283 pass
282 # Cast 2-tuples to commandentry instances.
284 # Cast 2-tuples to commandentry instances.
283 elif isinstance(v, tuple):
285 elif isinstance(v, tuple):
284 if len(v) != 2:
286 if len(v) != 2:
285 raise ValueError('command tuples must have exactly 2 elements')
287 raise ValueError('command tuples must have exactly 2 elements')
286
288
287 # It is common for extensions to wrap wire protocol commands via
289 # It is common for extensions to wrap wire protocol commands via
288 # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers
290 # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers
289 # doing this aren't aware of the new API that uses objects to store
291 # doing this aren't aware of the new API that uses objects to store
290 # command entries, we automatically merge old state with new.
292 # command entries, we automatically merge old state with new.
291 if k in self:
293 if k in self:
292 v = self[k]._merge(v[0], v[1])
294 v = self[k]._merge(v[0], v[1])
293 else:
295 else:
294 # Use default values from @wireprotocommand.
296 # Use default values from @wireprotocommand.
295 v = commandentry(v[0], args=v[1],
297 v = commandentry(v[0], args=v[1],
296 transports=set(TRANSPORTS),
298 transports=set(TRANSPORTS),
297 permission='push')
299 permission='push')
298 else:
300 else:
299 raise ValueError('command entries must be commandentry instances '
301 raise ValueError('command entries must be commandentry instances '
300 'or 2-tuples')
302 'or 2-tuples')
301
303
302 return super(commanddict, self).__setitem__(k, v)
304 return super(commanddict, self).__setitem__(k, v)
303
305
304 def commandavailable(self, command, proto):
306 def commandavailable(self, command, proto):
305 """Determine if a command is available for the requested protocol."""
307 """Determine if a command is available for the requested protocol."""
306 assert proto.name in TRANSPORTS
308 assert proto.name in TRANSPORTS
307
309
308 entry = self.get(command)
310 entry = self.get(command)
309
311
310 if not entry:
312 if not entry:
311 return False
313 return False
312
314
313 if proto.name not in entry.transports:
315 if proto.name not in entry.transports:
314 return False
316 return False
315
317
316 return True
318 return True
317
319
318 def supportedcompengines(ui, role):
320 def supportedcompengines(ui, role):
319 """Obtain the list of supported compression engines for a request."""
321 """Obtain the list of supported compression engines for a request."""
320 assert role in (compression.CLIENTROLE, compression.SERVERROLE)
322 assert role in (compression.CLIENTROLE, compression.SERVERROLE)
321
323
322 compengines = compression.compengines.supportedwireengines(role)
324 compengines = compression.compengines.supportedwireengines(role)
323
325
324 # Allow config to override default list and ordering.
326 # Allow config to override default list and ordering.
325 if role == compression.SERVERROLE:
327 if role == compression.SERVERROLE:
326 configengines = ui.configlist('server', 'compressionengines')
328 configengines = ui.configlist('server', 'compressionengines')
327 config = 'server.compressionengines'
329 config = 'server.compressionengines'
328 else:
330 else:
329 # This is currently implemented mainly to facilitate testing. In most
331 # This is currently implemented mainly to facilitate testing. In most
330 # cases, the server should be in charge of choosing a compression engine
332 # cases, the server should be in charge of choosing a compression engine
331 # because a server has the most to lose from a sub-optimal choice. (e.g.
333 # because a server has the most to lose from a sub-optimal choice. (e.g.
332 # CPU DoS due to an expensive engine or a network DoS due to poor
334 # CPU DoS due to an expensive engine or a network DoS due to poor
333 # compression ratio).
335 # compression ratio).
334 configengines = ui.configlist('experimental',
336 configengines = ui.configlist('experimental',
335 'clientcompressionengines')
337 'clientcompressionengines')
336 config = 'experimental.clientcompressionengines'
338 config = 'experimental.clientcompressionengines'
337
339
338 # No explicit config. Filter out the ones that aren't supposed to be
340 # No explicit config. Filter out the ones that aren't supposed to be
339 # advertised and return default ordering.
341 # advertised and return default ordering.
340 if not configengines:
342 if not configengines:
341 attr = 'serverpriority' if role == util.SERVERROLE else 'clientpriority'
343 attr = 'serverpriority' if role == util.SERVERROLE else 'clientpriority'
342 return [e for e in compengines
344 return [e for e in compengines
343 if getattr(e.wireprotosupport(), attr) > 0]
345 if getattr(e.wireprotosupport(), attr) > 0]
344
346
345 # If compression engines are listed in the config, assume there is a good
347 # If compression engines are listed in the config, assume there is a good
346 # reason for it (like server operators wanting to achieve specific
348 # reason for it (like server operators wanting to achieve specific
347 # performance characteristics). So fail fast if the config references
349 # performance characteristics). So fail fast if the config references
348 # unusable compression engines.
350 # unusable compression engines.
349 validnames = set(e.name() for e in compengines)
351 validnames = set(e.name() for e in compengines)
350 invalidnames = set(e for e in configengines if e not in validnames)
352 invalidnames = set(e for e in configengines if e not in validnames)
351 if invalidnames:
353 if invalidnames:
352 raise error.Abort(_('invalid compression engine defined in %s: %s') %
354 raise error.Abort(_('invalid compression engine defined in %s: %s') %
353 (config, ', '.join(sorted(invalidnames))))
355 (config, ', '.join(sorted(invalidnames))))
354
356
355 compengines = [e for e in compengines if e.name() in configengines]
357 compengines = [e for e in compengines if e.name() in configengines]
356 compengines = sorted(compengines,
358 compengines = sorted(compengines,
357 key=lambda e: configengines.index(e.name()))
359 key=lambda e: configengines.index(e.name()))
358
360
359 if not compengines:
361 if not compengines:
360 raise error.Abort(_('%s config option does not specify any known '
362 raise error.Abort(_('%s config option does not specify any known '
361 'compression engines') % config,
363 'compression engines') % config,
362 hint=_('usable compression engines: %s') %
364 hint=_('usable compression engines: %s') %
363 ', '.sorted(validnames))
365 ', '.sorted(validnames))
364
366
365 return compengines
367 return compengines
366
368
367 @attr.s
369 @attr.s
368 class encodedresponse(object):
370 class encodedresponse(object):
369 """Represents response data that is already content encoded.
371 """Represents response data that is already content encoded.
370
372
371 Wire protocol version 2 only.
373 Wire protocol version 2 only.
372
374
373 Commands typically emit Python objects that are encoded and sent over the
375 Commands typically emit Python objects that are encoded and sent over the
374 wire. If commands emit an object of this type, the encoding step is bypassed
376 wire. If commands emit an object of this type, the encoding step is bypassed
375 and the content from this object is used instead.
377 and the content from this object is used instead.
376 """
378 """
377 data = attr.ib()
379 data = attr.ib()
378
380
379 @attr.s
381 @attr.s
380 class alternatelocationresponse(object):
382 class alternatelocationresponse(object):
381 """Represents a response available at an alternate location.
383 """Represents a response available at an alternate location.
382
384
383 Instances are sent in place of actual response objects when the server
385 Instances are sent in place of actual response objects when the server
384 is sending a "content redirect" response.
386 is sending a "content redirect" response.
385
387
386 Only compatible with wire protocol version 2.
388 Only compatible with wire protocol version 2.
387 """
389 """
388 url = attr.ib()
390 url = attr.ib()
389 mediatype = attr.ib()
391 mediatype = attr.ib()
390 size = attr.ib(default=None)
392 size = attr.ib(default=None)
391 fullhashes = attr.ib(default=None)
393 fullhashes = attr.ib(default=None)
392 fullhashseed = attr.ib(default=None)
394 fullhashseed = attr.ib(default=None)
393 serverdercerts = attr.ib(default=None)
395 serverdercerts = attr.ib(default=None)
394 servercadercerts = attr.ib(default=None)
396 servercadercerts = attr.ib(default=None)
395
397
396 @attr.s
398 @attr.s
397 class indefinitebytestringresponse(object):
399 class indefinitebytestringresponse(object):
398 """Represents an object to be encoded to an indefinite length bytestring.
400 """Represents an object to be encoded to an indefinite length bytestring.
399
401
400 Instances are initialized from an iterable of chunks, with each chunk being
402 Instances are initialized from an iterable of chunks, with each chunk being
401 a bytes instance.
403 a bytes instance.
402 """
404 """
403 chunks = attr.ib()
405 chunks = attr.ib()
@@ -1,469 +1,459 b''
1 $ . "$TESTDIR/narrow-library.sh"
1 $ . "$TESTDIR/narrow-library.sh"
2
2
3 initialize nested directories to validate complex include/exclude patterns
3 initialize nested directories to validate complex include/exclude patterns
4
4
5 $ hg init master
5 $ hg init master
6 $ cd master
6 $ cd master
7 $ cat >> .hg/hgrc <<EOF
7 $ cat >> .hg/hgrc <<EOF
8 > [narrow]
8 > [narrow]
9 > serveellipses=True
9 > serveellipses=True
10 > EOF
10 > EOF
11
11
12 $ echo root > root
12 $ echo root > root
13 $ hg add root
13 $ hg add root
14 $ hg commit -m 'add root'
14 $ hg commit -m 'add root'
15
15
16 $ for d in dir1 dir2 dir1/dirA dir1/dirB dir2/dirA dir2/dirB
16 $ for d in dir1 dir2 dir1/dirA dir1/dirB dir2/dirA dir2/dirB
17 > do
17 > do
18 > mkdir -p $d
18 > mkdir -p $d
19 > echo $d/foo > $d/foo
19 > echo $d/foo > $d/foo
20 > hg add $d/foo
20 > hg add $d/foo
21 > hg commit -m "add $d/foo"
21 > hg commit -m "add $d/foo"
22 > echo $d/bar > $d/bar
22 > echo $d/bar > $d/bar
23 > hg add $d/bar
23 > hg add $d/bar
24 > hg commit -m "add $d/bar"
24 > hg commit -m "add $d/bar"
25 > done
25 > done
26 #if execbit
26 #if execbit
27 $ chmod +x dir1/dirA/foo
27 $ chmod +x dir1/dirA/foo
28 $ hg commit -m "make dir1/dirA/foo executable"
28 $ hg commit -m "make dir1/dirA/foo executable"
29 #else
29 #else
30 $ hg import --bypass - <<EOF
30 $ hg import --bypass - <<EOF
31 > # HG changeset patch
31 > # HG changeset patch
32 > make dir1/dirA/foo executable
32 > make dir1/dirA/foo executable
33 >
33 >
34 > diff --git a/dir1/dirA/foo b/dir1/dirA/foo
34 > diff --git a/dir1/dirA/foo b/dir1/dirA/foo
35 > old mode 100644
35 > old mode 100644
36 > new mode 100755
36 > new mode 100755
37 > EOF
37 > EOF
38 applying patch from stdin
38 applying patch from stdin
39 $ hg update -qr tip
39 $ hg update -qr tip
40 #endif
40 #endif
41 $ hg log -G -T '{rev} {node|short} {files}\n'
41 $ hg log -G -T '{rev} {node|short} {files}\n'
42 @ 13 c87ca422d521 dir1/dirA/foo
42 @ 13 c87ca422d521 dir1/dirA/foo
43 |
43 |
44 o 12 951b8a83924e dir2/dirB/bar
44 o 12 951b8a83924e dir2/dirB/bar
45 |
45 |
46 o 11 01ae5a51b563 dir2/dirB/foo
46 o 11 01ae5a51b563 dir2/dirB/foo
47 |
47 |
48 o 10 5eababdf0ac5 dir2/dirA/bar
48 o 10 5eababdf0ac5 dir2/dirA/bar
49 |
49 |
50 o 9 99d690663739 dir2/dirA/foo
50 o 9 99d690663739 dir2/dirA/foo
51 |
51 |
52 o 8 8e80155d5445 dir1/dirB/bar
52 o 8 8e80155d5445 dir1/dirB/bar
53 |
53 |
54 o 7 406760310428 dir1/dirB/foo
54 o 7 406760310428 dir1/dirB/foo
55 |
55 |
56 o 6 623466a5f475 dir1/dirA/bar
56 o 6 623466a5f475 dir1/dirA/bar
57 |
57 |
58 o 5 06ff3a5be997 dir1/dirA/foo
58 o 5 06ff3a5be997 dir1/dirA/foo
59 |
59 |
60 o 4 33227af02764 dir2/bar
60 o 4 33227af02764 dir2/bar
61 |
61 |
62 o 3 5e1f9d8d7c69 dir2/foo
62 o 3 5e1f9d8d7c69 dir2/foo
63 |
63 |
64 o 2 594bc4b13d4a dir1/bar
64 o 2 594bc4b13d4a dir1/bar
65 |
65 |
66 o 1 47f480a08324 dir1/foo
66 o 1 47f480a08324 dir1/foo
67 |
67 |
68 o 0 2a4f0c3b67da root
68 o 0 2a4f0c3b67da root
69
69
70 $ cd ..
70 $ cd ..
71
71
72 clone a narrow portion of the master, such that we can widen it later
72 clone a narrow portion of the master, such that we can widen it later
73
73
74 $ hg clone --narrow ssh://user@dummy/master narrow \
74 $ hg clone --narrow ssh://user@dummy/master narrow \
75 > --include dir1 \
75 > --include dir1 \
76 > --include dir2 \
76 > --include dir2 \
77 > --exclude dir1/dirA \
77 > --exclude dir1/dirA \
78 > --exclude dir1/dirB \
78 > --exclude dir1/dirB \
79 > --exclude dir2/dirA \
79 > --exclude dir2/dirA \
80 > --exclude dir2/dirB
80 > --exclude dir2/dirB
81 requesting all changes
81 requesting all changes
82 adding changesets
82 adding changesets
83 adding manifests
83 adding manifests
84 adding file changes
84 adding file changes
85 added 6 changesets with 4 changes to 4 files
85 added 6 changesets with 4 changes to 4 files
86 new changesets *:* (glob)
86 new changesets *:* (glob)
87 updating to branch default
87 updating to branch default
88 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
89
89
90 $ cd narrow
90 $ cd narrow
91 $ hg tracked
91 $ hg tracked
92 I path:dir1
92 I path:dir1
93 I path:dir2
93 I path:dir2
94 X path:dir1/dirA
94 X path:dir1/dirA
95 X path:dir1/dirB
95 X path:dir1/dirB
96 X path:dir2/dirA
96 X path:dir2/dirA
97 X path:dir2/dirB
97 X path:dir2/dirB
98 $ hg manifest -r tip
98 $ hg manifest -r tip
99 dir1/bar
99 dir1/bar
100 dir1/dirA/bar
100 dir1/dirA/bar
101 dir1/dirA/foo
101 dir1/dirA/foo
102 dir1/dirB/bar
102 dir1/dirB/bar
103 dir1/dirB/foo
103 dir1/dirB/foo
104 dir1/foo
104 dir1/foo
105 dir2/bar
105 dir2/bar
106 dir2/dirA/bar
106 dir2/dirA/bar
107 dir2/dirA/foo
107 dir2/dirA/foo
108 dir2/dirB/bar
108 dir2/dirB/bar
109 dir2/dirB/foo
109 dir2/dirB/foo
110 dir2/foo
110 dir2/foo
111 root
111 root
112 $ find * | sort
112 $ find * | sort
113 dir1
113 dir1
114 dir1/bar
114 dir1/bar
115 dir1/foo
115 dir1/foo
116 dir2
116 dir2
117 dir2/bar
117 dir2/bar
118 dir2/foo
118 dir2/foo
119 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
119 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
120 @ 5 c87ca422d521... dir1/dirA/foo
120 @ 5 c87ca422d521... dir1/dirA/foo
121 |
121 |
122 o 4 33227af02764 dir2/bar
122 o 4 33227af02764 dir2/bar
123 |
123 |
124 o 3 5e1f9d8d7c69 dir2/foo
124 o 3 5e1f9d8d7c69 dir2/foo
125 |
125 |
126 o 2 594bc4b13d4a dir1/bar
126 o 2 594bc4b13d4a dir1/bar
127 |
127 |
128 o 1 47f480a08324 dir1/foo
128 o 1 47f480a08324 dir1/foo
129 |
129 |
130 o 0 2a4f0c3b67da... root
130 o 0 2a4f0c3b67da... root
131
131
132
132
133 widen the narrow checkout
133 widen the narrow checkout
134
134
135 $ hg tracked --removeexclude dir1/dirA
135 $ hg tracked --removeexclude dir1/dirA
136 comparing with ssh://user@dummy/master
136 comparing with ssh://user@dummy/master
137 searching for changes
137 searching for changes
138 no changes found
139 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
138 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
140 adding changesets
139 adding changesets
141 adding manifests
140 adding manifests
142 adding file changes
141 adding file changes
143 added 9 changesets with 6 changes to 6 files
142 added 9 changesets with 6 changes to 6 files
144 new changesets *:* (glob)
145 $ hg tracked
143 $ hg tracked
146 I path:dir1
144 I path:dir1
147 I path:dir2
145 I path:dir2
148 X path:dir1/dirB
146 X path:dir1/dirB
149 X path:dir2/dirA
147 X path:dir2/dirA
150 X path:dir2/dirB
148 X path:dir2/dirB
151 $ find * | sort
149 $ find * | sort
152 dir1
150 dir1
153 dir1/bar
151 dir1/bar
154 dir1/dirA
152 dir1/dirA
155 dir1/dirA/bar
153 dir1/dirA/bar
156 dir1/dirA/foo
154 dir1/dirA/foo
157 dir1/foo
155 dir1/foo
158 dir2
156 dir2
159 dir2/bar
157 dir2/bar
160 dir2/foo
158 dir2/foo
161
159
162 #if execbit
160 #if execbit
163 $ test -x dir1/dirA/foo && echo executable
161 $ test -x dir1/dirA/foo && echo executable
164 executable
162 executable
165 $ test -x dir1/dirA/bar || echo not executable
163 $ test -x dir1/dirA/bar || echo not executable
166 not executable
164 not executable
167 #endif
165 #endif
168
166
169 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
167 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
170 @ 8 c87ca422d521 dir1/dirA/foo
168 @ 8 c87ca422d521 dir1/dirA/foo
171 |
169 |
172 o 7 951b8a83924e... dir2/dirB/bar
170 o 7 951b8a83924e... dir2/dirB/bar
173 |
171 |
174 o 6 623466a5f475 dir1/dirA/bar
172 o 6 623466a5f475 dir1/dirA/bar
175 |
173 |
176 o 5 06ff3a5be997 dir1/dirA/foo
174 o 5 06ff3a5be997 dir1/dirA/foo
177 |
175 |
178 o 4 33227af02764 dir2/bar
176 o 4 33227af02764 dir2/bar
179 |
177 |
180 o 3 5e1f9d8d7c69 dir2/foo
178 o 3 5e1f9d8d7c69 dir2/foo
181 |
179 |
182 o 2 594bc4b13d4a dir1/bar
180 o 2 594bc4b13d4a dir1/bar
183 |
181 |
184 o 1 47f480a08324 dir1/foo
182 o 1 47f480a08324 dir1/foo
185 |
183 |
186 o 0 2a4f0c3b67da... root
184 o 0 2a4f0c3b67da... root
187
185
188
186
189 widen narrow spec again, but exclude a file in previously included spec
187 widen narrow spec again, but exclude a file in previously included spec
190
188
191 $ hg tracked --removeexclude dir2/dirB --addexclude dir1/dirA/bar
189 $ hg tracked --removeexclude dir2/dirB --addexclude dir1/dirA/bar
192 comparing with ssh://user@dummy/master
190 comparing with ssh://user@dummy/master
193 searching for changes
191 searching for changes
194 looking for local changes to affected paths
192 looking for local changes to affected paths
195 deleting data/dir1/dirA/bar.i (reporevlogstore !)
193 deleting data/dir1/dirA/bar.i (reporevlogstore !)
196 deleting data/dir1/dirA/bar/0eca1d0cbdaea4651d1d04d71976a6d2d9bfaae5 (reposimplestore !)
194 deleting data/dir1/dirA/bar/0eca1d0cbdaea4651d1d04d71976a6d2d9bfaae5 (reposimplestore !)
197 deleting data/dir1/dirA/bar/index (reposimplestore !)
195 deleting data/dir1/dirA/bar/index (reposimplestore !)
198 no changes found
199 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
196 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
200 adding changesets
197 adding changesets
201 adding manifests
198 adding manifests
202 adding file changes
199 adding file changes
203 added 11 changesets with 7 changes to 7 files
200 added 11 changesets with 7 changes to 7 files
204 new changesets *:* (glob)
205 $ hg tracked
201 $ hg tracked
206 I path:dir1
202 I path:dir1
207 I path:dir2
203 I path:dir2
208 X path:dir1/dirA/bar
204 X path:dir1/dirA/bar
209 X path:dir1/dirB
205 X path:dir1/dirB
210 X path:dir2/dirA
206 X path:dir2/dirA
211 $ find * | sort
207 $ find * | sort
212 dir1
208 dir1
213 dir1/bar
209 dir1/bar
214 dir1/dirA
210 dir1/dirA
215 dir1/dirA/foo
211 dir1/dirA/foo
216 dir1/foo
212 dir1/foo
217 dir2
213 dir2
218 dir2/bar
214 dir2/bar
219 dir2/dirB
215 dir2/dirB
220 dir2/dirB/bar
216 dir2/dirB/bar
221 dir2/dirB/foo
217 dir2/dirB/foo
222 dir2/foo
218 dir2/foo
223 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
219 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
224 @ 10 c87ca422d521 dir1/dirA/foo
220 @ 10 c87ca422d521 dir1/dirA/foo
225 |
221 |
226 o 9 951b8a83924e dir2/dirB/bar
222 o 9 951b8a83924e dir2/dirB/bar
227 |
223 |
228 o 8 01ae5a51b563 dir2/dirB/foo
224 o 8 01ae5a51b563 dir2/dirB/foo
229 |
225 |
230 o 7 5eababdf0ac5... dir2/dirA/bar
226 o 7 5eababdf0ac5... dir2/dirA/bar
231 |
227 |
232 o 6 623466a5f475... dir1/dirA/bar
228 o 6 623466a5f475... dir1/dirA/bar
233 |
229 |
234 o 5 06ff3a5be997 dir1/dirA/foo
230 o 5 06ff3a5be997 dir1/dirA/foo
235 |
231 |
236 o 4 33227af02764 dir2/bar
232 o 4 33227af02764 dir2/bar
237 |
233 |
238 o 3 5e1f9d8d7c69 dir2/foo
234 o 3 5e1f9d8d7c69 dir2/foo
239 |
235 |
240 o 2 594bc4b13d4a dir1/bar
236 o 2 594bc4b13d4a dir1/bar
241 |
237 |
242 o 1 47f480a08324 dir1/foo
238 o 1 47f480a08324 dir1/foo
243 |
239 |
244 o 0 2a4f0c3b67da... root
240 o 0 2a4f0c3b67da... root
245
241
246
242
247 widen narrow spec yet again, excluding a directory in previous spec
243 widen narrow spec yet again, excluding a directory in previous spec
248
244
249 $ hg tracked --removeexclude dir2/dirA --addexclude dir1/dirA
245 $ hg tracked --removeexclude dir2/dirA --addexclude dir1/dirA
250 comparing with ssh://user@dummy/master
246 comparing with ssh://user@dummy/master
251 searching for changes
247 searching for changes
252 looking for local changes to affected paths
248 looking for local changes to affected paths
253 deleting data/dir1/dirA/foo.i (reporevlogstore !)
249 deleting data/dir1/dirA/foo.i (reporevlogstore !)
254 deleting data/dir1/dirA/foo/162caeb3d55dceb1fee793aa631ac8c73fcb8b5e (reposimplestore !)
250 deleting data/dir1/dirA/foo/162caeb3d55dceb1fee793aa631ac8c73fcb8b5e (reposimplestore !)
255 deleting data/dir1/dirA/foo/index (reposimplestore !)
251 deleting data/dir1/dirA/foo/index (reposimplestore !)
256 no changes found
257 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
252 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
258 adding changesets
253 adding changesets
259 adding manifests
254 adding manifests
260 adding file changes
255 adding file changes
261 added 13 changesets with 8 changes to 8 files
256 added 13 changesets with 8 changes to 8 files
262 new changesets *:* (glob)
263 $ hg tracked
257 $ hg tracked
264 I path:dir1
258 I path:dir1
265 I path:dir2
259 I path:dir2
266 X path:dir1/dirA
260 X path:dir1/dirA
267 X path:dir1/dirA/bar
261 X path:dir1/dirA/bar
268 X path:dir1/dirB
262 X path:dir1/dirB
269 $ find * | sort
263 $ find * | sort
270 dir1
264 dir1
271 dir1/bar
265 dir1/bar
272 dir1/foo
266 dir1/foo
273 dir2
267 dir2
274 dir2/bar
268 dir2/bar
275 dir2/dirA
269 dir2/dirA
276 dir2/dirA/bar
270 dir2/dirA/bar
277 dir2/dirA/foo
271 dir2/dirA/foo
278 dir2/dirB
272 dir2/dirB
279 dir2/dirB/bar
273 dir2/dirB/bar
280 dir2/dirB/foo
274 dir2/dirB/foo
281 dir2/foo
275 dir2/foo
282 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
276 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
283 @ 12 c87ca422d521... dir1/dirA/foo
277 @ 12 c87ca422d521... dir1/dirA/foo
284 |
278 |
285 o 11 951b8a83924e dir2/dirB/bar
279 o 11 951b8a83924e dir2/dirB/bar
286 |
280 |
287 o 10 01ae5a51b563 dir2/dirB/foo
281 o 10 01ae5a51b563 dir2/dirB/foo
288 |
282 |
289 o 9 5eababdf0ac5 dir2/dirA/bar
283 o 9 5eababdf0ac5 dir2/dirA/bar
290 |
284 |
291 o 8 99d690663739 dir2/dirA/foo
285 o 8 99d690663739 dir2/dirA/foo
292 |
286 |
293 o 7 8e80155d5445... dir1/dirB/bar
287 o 7 8e80155d5445... dir1/dirB/bar
294 |
288 |
295 o 6 623466a5f475... dir1/dirA/bar
289 o 6 623466a5f475... dir1/dirA/bar
296 |
290 |
297 o 5 06ff3a5be997... dir1/dirA/foo
291 o 5 06ff3a5be997... dir1/dirA/foo
298 |
292 |
299 o 4 33227af02764 dir2/bar
293 o 4 33227af02764 dir2/bar
300 |
294 |
301 o 3 5e1f9d8d7c69 dir2/foo
295 o 3 5e1f9d8d7c69 dir2/foo
302 |
296 |
303 o 2 594bc4b13d4a dir1/bar
297 o 2 594bc4b13d4a dir1/bar
304 |
298 |
305 o 1 47f480a08324 dir1/foo
299 o 1 47f480a08324 dir1/foo
306 |
300 |
307 o 0 2a4f0c3b67da... root
301 o 0 2a4f0c3b67da... root
308
302
309
303
310 include a directory that was previously explicitly excluded
304 include a directory that was previously explicitly excluded
311
305
312 $ hg tracked --removeexclude dir1/dirA
306 $ hg tracked --removeexclude dir1/dirA
313 comparing with ssh://user@dummy/master
307 comparing with ssh://user@dummy/master
314 searching for changes
308 searching for changes
315 no changes found
316 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
309 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
317 adding changesets
310 adding changesets
318 adding manifests
311 adding manifests
319 adding file changes
312 adding file changes
320 added 13 changesets with 9 changes to 9 files
313 added 13 changesets with 9 changes to 9 files
321 new changesets *:* (glob)
322 $ hg tracked
314 $ hg tracked
323 I path:dir1
315 I path:dir1
324 I path:dir2
316 I path:dir2
325 X path:dir1/dirA/bar
317 X path:dir1/dirA/bar
326 X path:dir1/dirB
318 X path:dir1/dirB
327 $ find * | sort
319 $ find * | sort
328 dir1
320 dir1
329 dir1/bar
321 dir1/bar
330 dir1/dirA
322 dir1/dirA
331 dir1/dirA/foo
323 dir1/dirA/foo
332 dir1/foo
324 dir1/foo
333 dir2
325 dir2
334 dir2/bar
326 dir2/bar
335 dir2/dirA
327 dir2/dirA
336 dir2/dirA/bar
328 dir2/dirA/bar
337 dir2/dirA/foo
329 dir2/dirA/foo
338 dir2/dirB
330 dir2/dirB
339 dir2/dirB/bar
331 dir2/dirB/bar
340 dir2/dirB/foo
332 dir2/dirB/foo
341 dir2/foo
333 dir2/foo
342 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
334 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
343 @ 12 c87ca422d521 dir1/dirA/foo
335 @ 12 c87ca422d521 dir1/dirA/foo
344 |
336 |
345 o 11 951b8a83924e dir2/dirB/bar
337 o 11 951b8a83924e dir2/dirB/bar
346 |
338 |
347 o 10 01ae5a51b563 dir2/dirB/foo
339 o 10 01ae5a51b563 dir2/dirB/foo
348 |
340 |
349 o 9 5eababdf0ac5 dir2/dirA/bar
341 o 9 5eababdf0ac5 dir2/dirA/bar
350 |
342 |
351 o 8 99d690663739 dir2/dirA/foo
343 o 8 99d690663739 dir2/dirA/foo
352 |
344 |
353 o 7 8e80155d5445... dir1/dirB/bar
345 o 7 8e80155d5445... dir1/dirB/bar
354 |
346 |
355 o 6 623466a5f475... dir1/dirA/bar
347 o 6 623466a5f475... dir1/dirA/bar
356 |
348 |
357 o 5 06ff3a5be997 dir1/dirA/foo
349 o 5 06ff3a5be997 dir1/dirA/foo
358 |
350 |
359 o 4 33227af02764 dir2/bar
351 o 4 33227af02764 dir2/bar
360 |
352 |
361 o 3 5e1f9d8d7c69 dir2/foo
353 o 3 5e1f9d8d7c69 dir2/foo
362 |
354 |
363 o 2 594bc4b13d4a dir1/bar
355 o 2 594bc4b13d4a dir1/bar
364 |
356 |
365 o 1 47f480a08324 dir1/foo
357 o 1 47f480a08324 dir1/foo
366 |
358 |
367 o 0 2a4f0c3b67da... root
359 o 0 2a4f0c3b67da... root
368
360
369
361
370 $ cd ..
362 $ cd ..
371
363
372 clone a narrow portion of the master, such that we can widen it later
364 clone a narrow portion of the master, such that we can widen it later
373
365
374 $ hg clone --narrow ssh://user@dummy/master narrow2 --include dir1/dirA
366 $ hg clone --narrow ssh://user@dummy/master narrow2 --include dir1/dirA
375 requesting all changes
367 requesting all changes
376 adding changesets
368 adding changesets
377 adding manifests
369 adding manifests
378 adding file changes
370 adding file changes
379 added 5 changesets with 2 changes to 2 files
371 added 5 changesets with 2 changes to 2 files
380 new changesets *:* (glob)
372 new changesets *:* (glob)
381 updating to branch default
373 updating to branch default
382 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 $ cd narrow2
375 $ cd narrow2
384 $ find * | sort
376 $ find * | sort
385 dir1
377 dir1
386 dir1/dirA
378 dir1/dirA
387 dir1/dirA/bar
379 dir1/dirA/bar
388 dir1/dirA/foo
380 dir1/dirA/foo
389 $ hg tracked --addinclude dir1
381 $ hg tracked --addinclude dir1
390 comparing with ssh://user@dummy/master
382 comparing with ssh://user@dummy/master
391 searching for changes
383 searching for changes
392 no changes found
393 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
384 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
394 adding changesets
385 adding changesets
395 adding manifests
386 adding manifests
396 adding file changes
387 adding file changes
397 added 10 changesets with 6 changes to 6 files
388 added 10 changesets with 6 changes to 6 files
398 new changesets *:* (glob)
399 $ find * | sort
389 $ find * | sort
400 dir1
390 dir1
401 dir1/bar
391 dir1/bar
402 dir1/dirA
392 dir1/dirA
403 dir1/dirA/bar
393 dir1/dirA/bar
404 dir1/dirA/foo
394 dir1/dirA/foo
405 dir1/dirB
395 dir1/dirB
406 dir1/dirB/bar
396 dir1/dirB/bar
407 dir1/dirB/foo
397 dir1/dirB/foo
408 dir1/foo
398 dir1/foo
409 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
399 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
410 @ 9 c87ca422d521 dir1/dirA/foo
400 @ 9 c87ca422d521 dir1/dirA/foo
411 |
401 |
412 o 8 951b8a83924e... dir2/dirB/bar
402 o 8 951b8a83924e... dir2/dirB/bar
413 |
403 |
414 o 7 8e80155d5445 dir1/dirB/bar
404 o 7 8e80155d5445 dir1/dirB/bar
415 |
405 |
416 o 6 406760310428 dir1/dirB/foo
406 o 6 406760310428 dir1/dirB/foo
417 |
407 |
418 o 5 623466a5f475 dir1/dirA/bar
408 o 5 623466a5f475 dir1/dirA/bar
419 |
409 |
420 o 4 06ff3a5be997 dir1/dirA/foo
410 o 4 06ff3a5be997 dir1/dirA/foo
421 |
411 |
422 o 3 33227af02764... dir2/bar
412 o 3 33227af02764... dir2/bar
423 |
413 |
424 o 2 594bc4b13d4a dir1/bar
414 o 2 594bc4b13d4a dir1/bar
425 |
415 |
426 o 1 47f480a08324 dir1/foo
416 o 1 47f480a08324 dir1/foo
427 |
417 |
428 o 0 2a4f0c3b67da... root
418 o 0 2a4f0c3b67da... root
429
419
430
420
431 Illegal patterns are rejected
421 Illegal patterns are rejected
432
422
433 $ hg tracked --addinclude glob:**
423 $ hg tracked --addinclude glob:**
434 abort: invalid prefix on narrow pattern: glob:**
424 abort: invalid prefix on narrow pattern: glob:**
435 (narrow patterns must begin with one of the following: path:, rootfilesin:)
425 (narrow patterns must begin with one of the following: path:, rootfilesin:)
436 [255]
426 [255]
437
427
438 $ hg tracked --addexclude set:ignored
428 $ hg tracked --addexclude set:ignored
439 abort: invalid prefix on narrow pattern: set:ignored
429 abort: invalid prefix on narrow pattern: set:ignored
440 (narrow patterns must begin with one of the following: path:, rootfilesin:)
430 (narrow patterns must begin with one of the following: path:, rootfilesin:)
441 [255]
431 [255]
442
432
443 $ cat .hg/store/narrowspec
433 $ cat .hg/store/narrowspec
444 [include]
434 [include]
445 path:dir1
435 path:dir1
446 path:dir1/dirA
436 path:dir1/dirA
447 [exclude]
437 [exclude]
448
438
449 $ cat > .hg/store/narrowspec << EOF
439 $ cat > .hg/store/narrowspec << EOF
450 > [include]
440 > [include]
451 > glob:**
441 > glob:**
452 > EOF
442 > EOF
453
443
454 $ hg tracked
444 $ hg tracked
455 abort: invalid prefix on narrow pattern: glob:**
445 abort: invalid prefix on narrow pattern: glob:**
456 (narrow patterns must begin with one of the following: path:, rootfilesin:)
446 (narrow patterns must begin with one of the following: path:, rootfilesin:)
457 [255]
447 [255]
458
448
459 $ cat > .hg/store/narrowspec << EOF
449 $ cat > .hg/store/narrowspec << EOF
460 > [include]
450 > [include]
461 > path:.
451 > path:.
462 > [exclude]
452 > [exclude]
463 > set:ignored
453 > set:ignored
464 > EOF
454 > EOF
465
455
466 $ hg tracked
456 $ hg tracked
467 abort: invalid prefix on narrow pattern: set:ignored
457 abort: invalid prefix on narrow pattern: set:ignored
468 (narrow patterns must begin with one of the following: path:, rootfilesin:)
458 (narrow patterns must begin with one of the following: path:, rootfilesin:)
469 [255]
459 [255]
@@ -1,230 +1,224 b''
1 #testcases flat tree
1 #testcases flat tree
2 $ . "$TESTDIR/narrow-library.sh"
2 $ . "$TESTDIR/narrow-library.sh"
3
3
4 #if tree
4 #if tree
5 $ cat << EOF >> $HGRCPATH
5 $ cat << EOF >> $HGRCPATH
6 > [experimental]
6 > [experimental]
7 > treemanifest = 1
7 > treemanifest = 1
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 $ hg init master
11 $ hg init master
12 $ cd master
12 $ cd master
13 $ cat >> .hg/hgrc <<EOF
13 $ cat >> .hg/hgrc <<EOF
14 > [narrow]
14 > [narrow]
15 > serveellipses=True
15 > serveellipses=True
16 > EOF
16 > EOF
17
17
18 $ mkdir inside
18 $ mkdir inside
19 $ echo 'inside' > inside/f
19 $ echo 'inside' > inside/f
20 $ hg add inside/f
20 $ hg add inside/f
21 $ hg commit -m 'add inside'
21 $ hg commit -m 'add inside'
22
22
23 $ mkdir widest
23 $ mkdir widest
24 $ echo 'widest' > widest/f
24 $ echo 'widest' > widest/f
25 $ hg add widest/f
25 $ hg add widest/f
26 $ hg commit -m 'add widest'
26 $ hg commit -m 'add widest'
27
27
28 $ mkdir outside
28 $ mkdir outside
29 $ echo 'outside' > outside/f
29 $ echo 'outside' > outside/f
30 $ hg add outside/f
30 $ hg add outside/f
31 $ hg commit -m 'add outside'
31 $ hg commit -m 'add outside'
32
32
33 $ cd ..
33 $ cd ..
34
34
35 narrow clone the inside file
35 narrow clone the inside file
36
36
37 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
37 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
38 requesting all changes
38 requesting all changes
39 adding changesets
39 adding changesets
40 adding manifests
40 adding manifests
41 adding file changes
41 adding file changes
42 added 2 changesets with 1 changes to 1 files
42 added 2 changesets with 1 changes to 1 files
43 new changesets *:* (glob)
43 new changesets *:* (glob)
44 updating to branch default
44 updating to branch default
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 $ cd narrow
46 $ cd narrow
47 $ hg tracked
47 $ hg tracked
48 I path:inside
48 I path:inside
49 $ ls
49 $ ls
50 inside
50 inside
51 $ cat inside/f
51 $ cat inside/f
52 inside
52 inside
53 $ cd ..
53 $ cd ..
54
54
55 add more upstream files which we will include in a wider narrow spec
55 add more upstream files which we will include in a wider narrow spec
56
56
57 $ cd master
57 $ cd master
58
58
59 $ mkdir wider
59 $ mkdir wider
60 $ echo 'wider' > wider/f
60 $ echo 'wider' > wider/f
61 $ hg add wider/f
61 $ hg add wider/f
62 $ echo 'widest v2' > widest/f
62 $ echo 'widest v2' > widest/f
63 $ hg commit -m 'add wider, update widest'
63 $ hg commit -m 'add wider, update widest'
64
64
65 $ echo 'widest v3' > widest/f
65 $ echo 'widest v3' > widest/f
66 $ hg commit -m 'update widest v3'
66 $ hg commit -m 'update widest v3'
67
67
68 $ echo 'inside v2' > inside/f
68 $ echo 'inside v2' > inside/f
69 $ hg commit -m 'update inside'
69 $ hg commit -m 'update inside'
70
70
71 $ mkdir outside2
71 $ mkdir outside2
72 $ echo 'outside2' > outside2/f
72 $ echo 'outside2' > outside2/f
73 $ hg add outside2/f
73 $ hg add outside2/f
74 $ hg commit -m 'add outside2'
74 $ hg commit -m 'add outside2'
75
75
76 $ echo 'widest v4' > widest/f
76 $ echo 'widest v4' > widest/f
77 $ hg commit -m 'update widest v4'
77 $ hg commit -m 'update widest v4'
78
78
79 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
79 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
80 7: update widest v4
80 7: update widest v4
81 6: add outside2
81 6: add outside2
82 5: update inside
82 5: update inside
83 4: update widest v3
83 4: update widest v3
84 3: add wider, update widest
84 3: add wider, update widest
85 2: add outside
85 2: add outside
86 1: add widest
86 1: add widest
87 0: add inside
87 0: add inside
88
88
89 $ cd ..
89 $ cd ..
90
90
91 Testing the --import-rules flag of `hg tracked` command
91 Testing the --import-rules flag of `hg tracked` command
92
92
93 $ cd narrow
93 $ cd narrow
94 $ hg tracked --import-rules
94 $ hg tracked --import-rules
95 hg tracked: option --import-rules requires argument
95 hg tracked: option --import-rules requires argument
96 hg tracked [OPTIONS]... [REMOTE]
96 hg tracked [OPTIONS]... [REMOTE]
97
97
98 show or change the current narrowspec
98 show or change the current narrowspec
99
99
100 options ([+] can be repeated):
100 options ([+] can be repeated):
101
101
102 --addinclude VALUE [+] new paths to include
102 --addinclude VALUE [+] new paths to include
103 --removeinclude VALUE [+] old paths to no longer include
103 --removeinclude VALUE [+] old paths to no longer include
104 --addexclude VALUE [+] new paths to exclude
104 --addexclude VALUE [+] new paths to exclude
105 --import-rules VALUE import narrowspecs from a file
105 --import-rules VALUE import narrowspecs from a file
106 --removeexclude VALUE [+] old paths to no longer exclude
106 --removeexclude VALUE [+] old paths to no longer exclude
107 --clear whether to replace the existing narrowspec
107 --clear whether to replace the existing narrowspec
108 --force-delete-local-changes forces deletion of local changes when
108 --force-delete-local-changes forces deletion of local changes when
109 narrowing
109 narrowing
110 --update-working-copy update working copy when the store has
110 --update-working-copy update working copy when the store has
111 changed
111 changed
112 -e --ssh CMD specify ssh command to use
112 -e --ssh CMD specify ssh command to use
113 --remotecmd CMD specify hg command to run on the remote side
113 --remotecmd CMD specify hg command to run on the remote side
114 --insecure do not verify server certificate (ignoring
114 --insecure do not verify server certificate (ignoring
115 web.cacerts config)
115 web.cacerts config)
116
116
117 (use 'hg tracked -h' to show more help)
117 (use 'hg tracked -h' to show more help)
118 [255]
118 [255]
119 $ hg tracked --import-rules doesnotexist
119 $ hg tracked --import-rules doesnotexist
120 abort: cannot read narrowspecs from '$TESTTMP/narrow/doesnotexist': $ENOENT$
120 abort: cannot read narrowspecs from '$TESTTMP/narrow/doesnotexist': $ENOENT$
121 [255]
121 [255]
122
122
123 $ cat > specs <<EOF
123 $ cat > specs <<EOF
124 > %include foo
124 > %include foo
125 > [include]
125 > [include]
126 > path:widest/
126 > path:widest/
127 > [exclude]
127 > [exclude]
128 > path:inside/
128 > path:inside/
129 > EOF
129 > EOF
130
130
131 $ hg tracked --import-rules specs
131 $ hg tracked --import-rules specs
132 abort: including other spec files using '%include' is not supported in narrowspec
132 abort: including other spec files using '%include' is not supported in narrowspec
133 [255]
133 [255]
134
134
135 $ cat > specs <<EOF
135 $ cat > specs <<EOF
136 > [include]
136 > [include]
137 > outisde
137 > outisde
138 > [exclude]
138 > [exclude]
139 > inside
139 > inside
140 > EOF
140 > EOF
141
141
142 $ hg tracked --import-rules specs
142 $ hg tracked --import-rules specs
143 comparing with ssh://user@dummy/master
143 comparing with ssh://user@dummy/master
144 searching for changes
144 searching for changes
145 looking for local changes to affected paths
145 looking for local changes to affected paths
146 deleting data/inside/f.i
146 deleting data/inside/f.i
147 deleting meta/inside/00manifest.i (tree !)
147 deleting meta/inside/00manifest.i (tree !)
148 no changes found
149 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
148 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
150 adding changesets
149 adding changesets
151 adding manifests
150 adding manifests
152 adding file changes
151 adding file changes
153 added 2 changesets with 0 changes to 0 files
152 added 2 changesets with 0 changes to 0 files
154 new changesets *:* (glob)
155 $ hg tracked
153 $ hg tracked
156 I path:outisde
154 I path:outisde
157 X path:inside
155 X path:inside
158
156
159 Testing the --import-rules flag with --addinclude and --addexclude
157 Testing the --import-rules flag with --addinclude and --addexclude
160
158
161 $ cat > specs <<EOF
159 $ cat > specs <<EOF
162 > [include]
160 > [include]
163 > widest
161 > widest
164 > EOF
162 > EOF
165
163
166 $ hg tracked --import-rules specs --addinclude 'wider/'
164 $ hg tracked --import-rules specs --addinclude 'wider/'
167 comparing with ssh://user@dummy/master
165 comparing with ssh://user@dummy/master
168 searching for changes
166 searching for changes
169 no changes found
170 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
167 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
171 adding changesets
168 adding changesets
172 adding manifests
169 adding manifests
173 adding file changes
170 adding file changes
174 added 3 changesets with 1 changes to 1 files
171 added 3 changesets with 1 changes to 1 files
175 new changesets *:* (glob)
176 $ hg tracked
172 $ hg tracked
177 I path:outisde
173 I path:outisde
178 I path:wider
174 I path:wider
179 I path:widest
175 I path:widest
180 X path:inside
176 X path:inside
181
177
182 $ cat > specs <<EOF
178 $ cat > specs <<EOF
183 > [exclude]
179 > [exclude]
184 > outside2
180 > outside2
185 > EOF
181 > EOF
186
182
187 $ hg tracked --import-rules specs --addexclude 'widest'
183 $ hg tracked --import-rules specs --addexclude 'widest'
188 comparing with ssh://user@dummy/master
184 comparing with ssh://user@dummy/master
189 searching for changes
185 searching for changes
190 looking for local changes to affected paths
186 looking for local changes to affected paths
191 deleting data/widest/f.i
187 deleting data/widest/f.i
192 deleting meta/widest/00manifest.i (tree !)
188 deleting meta/widest/00manifest.i (tree !)
193 $ hg tracked
189 $ hg tracked
194 I path:outisde
190 I path:outisde
195 I path:wider
191 I path:wider
196 X path:inside
192 X path:inside
197 X path:outside2
193 X path:outside2
198 X path:widest
194 X path:widest
199
195
200 $ hg tracked --import-rules specs --clear
196 $ hg tracked --import-rules specs --clear
201 abort: the --clear option is not yet supported
197 abort: the --clear option is not yet supported
202 [255]
198 [255]
203
199
204 Testing with passing a out of wdir file
200 Testing with passing a out of wdir file
205
201
206 $ cat > ../nspecs <<EOF
202 $ cat > ../nspecs <<EOF
207 > [include]
203 > [include]
208 > widest
204 > widest
209 > EOF
205 > EOF
210
206
211 $ hg tracked --import-rules ../nspecs
207 $ hg tracked --import-rules ../nspecs
212 comparing with ssh://user@dummy/master
208 comparing with ssh://user@dummy/master
213 searching for changes
209 searching for changes
214 no changes found
215 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
210 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
216 adding changesets
211 adding changesets
217 adding manifests
212 adding manifests
218 adding file changes
213 adding file changes
219 added 3 changesets with 0 changes to 0 files
214 added 3 changesets with 0 changes to 0 files
220 new changesets *:* (glob)
221
215
222 $ cd ..
216 $ cd ..
223
217
224 Testing tracked command on a non-narrow repo
218 Testing tracked command on a non-narrow repo
225
219
226 $ hg init non-narrow
220 $ hg init non-narrow
227 $ cd non-narrow
221 $ cd non-narrow
228 $ hg tracked --addinclude foobar
222 $ hg tracked --addinclude foobar
229 abort: the tracked command is only supported on respositories cloned with --narrow
223 abort: the tracked command is only supported on respositories cloned with --narrow
230 [255]
224 [255]
@@ -1,370 +1,363 b''
1 #testcases flat tree
1 #testcases flat tree
2 $ . "$TESTDIR/narrow-library.sh"
2 $ . "$TESTDIR/narrow-library.sh"
3
3
4 #if tree
4 #if tree
5 $ cat << EOF >> $HGRCPATH
5 $ cat << EOF >> $HGRCPATH
6 > [experimental]
6 > [experimental]
7 > treemanifest = 1
7 > treemanifest = 1
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 $ hg init master
11 $ hg init master
12 $ cd master
12 $ cd master
13 $ cat >> .hg/hgrc <<EOF
13 $ cat >> .hg/hgrc <<EOF
14 > [narrow]
14 > [narrow]
15 > serveellipses=True
15 > serveellipses=True
16 > EOF
16 > EOF
17
17
18 $ mkdir inside
18 $ mkdir inside
19 $ echo 'inside' > inside/f
19 $ echo 'inside' > inside/f
20 $ hg add inside/f
20 $ hg add inside/f
21 $ hg commit -m 'add inside'
21 $ hg commit -m 'add inside'
22
22
23 $ mkdir widest
23 $ mkdir widest
24 $ echo 'widest' > widest/f
24 $ echo 'widest' > widest/f
25 $ hg add widest/f
25 $ hg add widest/f
26 $ hg commit -m 'add widest'
26 $ hg commit -m 'add widest'
27
27
28 $ mkdir outside
28 $ mkdir outside
29 $ echo 'outside' > outside/f
29 $ echo 'outside' > outside/f
30 $ hg add outside/f
30 $ hg add outside/f
31 $ hg commit -m 'add outside'
31 $ hg commit -m 'add outside'
32
32
33 $ cd ..
33 $ cd ..
34
34
35 narrow clone the inside file
35 narrow clone the inside file
36
36
37 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
37 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
38 requesting all changes
38 requesting all changes
39 adding changesets
39 adding changesets
40 adding manifests
40 adding manifests
41 adding file changes
41 adding file changes
42 added 2 changesets with 1 changes to 1 files
42 added 2 changesets with 1 changes to 1 files
43 new changesets *:* (glob)
43 new changesets *:* (glob)
44 updating to branch default
44 updating to branch default
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 $ cd narrow
46 $ cd narrow
47 $ hg tracked
47 $ hg tracked
48 I path:inside
48 I path:inside
49 $ ls
49 $ ls
50 inside
50 inside
51 $ cat inside/f
51 $ cat inside/f
52 inside
52 inside
53 $ cd ..
53 $ cd ..
54
54
55 add more upstream files which we will include in a wider narrow spec
55 add more upstream files which we will include in a wider narrow spec
56
56
57 $ cd master
57 $ cd master
58
58
59 $ mkdir wider
59 $ mkdir wider
60 $ echo 'wider' > wider/f
60 $ echo 'wider' > wider/f
61 $ hg add wider/f
61 $ hg add wider/f
62 $ echo 'widest v2' > widest/f
62 $ echo 'widest v2' > widest/f
63 $ hg commit -m 'add wider, update widest'
63 $ hg commit -m 'add wider, update widest'
64
64
65 $ echo 'widest v3' > widest/f
65 $ echo 'widest v3' > widest/f
66 $ hg commit -m 'update widest v3'
66 $ hg commit -m 'update widest v3'
67
67
68 $ echo 'inside v2' > inside/f
68 $ echo 'inside v2' > inside/f
69 $ hg commit -m 'update inside'
69 $ hg commit -m 'update inside'
70
70
71 $ mkdir outside2
71 $ mkdir outside2
72 $ echo 'outside2' > outside2/f
72 $ echo 'outside2' > outside2/f
73 $ hg add outside2/f
73 $ hg add outside2/f
74 $ hg commit -m 'add outside2'
74 $ hg commit -m 'add outside2'
75
75
76 $ echo 'widest v4' > widest/f
76 $ echo 'widest v4' > widest/f
77 $ hg commit -m 'update widest v4'
77 $ hg commit -m 'update widest v4'
78
78
79 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
79 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
80 7: update widest v4
80 7: update widest v4
81 6: add outside2
81 6: add outside2
82 5: update inside
82 5: update inside
83 4: update widest v3
83 4: update widest v3
84 3: add wider, update widest
84 3: add wider, update widest
85 2: add outside
85 2: add outside
86 1: add widest
86 1: add widest
87 0: add inside
87 0: add inside
88
88
89 $ cd ..
89 $ cd ..
90
90
91 Widen the narrow spec to see the widest file. This should not get the newly
91 Widen the narrow spec to see the widest file. This should not get the newly
92 added upstream revisions.
92 added upstream revisions.
93
93
94 $ cd narrow
94 $ cd narrow
95 $ hg tracked --addinclude widest/f
95 $ hg tracked --addinclude widest/f
96 comparing with ssh://user@dummy/master
96 comparing with ssh://user@dummy/master
97 searching for changes
97 searching for changes
98 no changes found
99 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
98 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
100 adding changesets
99 adding changesets
101 adding manifests
100 adding manifests
102 adding file changes
101 adding file changes
103 added 3 changesets with 2 changes to 2 files
102 added 3 changesets with 2 changes to 2 files
104 new changesets *:* (glob)
105 $ hg tracked
103 $ hg tracked
106 I path:inside
104 I path:inside
107 I path:widest/f
105 I path:widest/f
108
106
109 $ cat widest/f
107 $ cat widest/f
110 widest
108 widest
111
109
112 Pull down the newly added upstream revision.
110 Pull down the newly added upstream revision.
113
111
114 $ hg pull
112 $ hg pull
115 pulling from ssh://user@dummy/master
113 pulling from ssh://user@dummy/master
116 searching for changes
114 searching for changes
117 adding changesets
115 adding changesets
118 adding manifests
116 adding manifests
119 adding file changes
117 adding file changes
120 added 5 changesets with 4 changes to 2 files
118 added 5 changesets with 4 changes to 2 files
121 new changesets *:* (glob)
119 new changesets *:* (glob)
122 (run 'hg update' to get a working copy)
120 (run 'hg update' to get a working copy)
123 $ hg update -r 'desc("add wider")'
121 $ hg update -r 'desc("add wider")'
124 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 $ cat widest/f
123 $ cat widest/f
126 widest v2
124 widest v2
127
125
128 $ hg update -r 'desc("update inside")'
126 $ hg update -r 'desc("update inside")'
129 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 $ cat widest/f
128 $ cat widest/f
131 widest v3
129 widest v3
132 $ cat inside/f
130 $ cat inside/f
133 inside v2
131 inside v2
134
132
135 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
133 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
136 7: update widest v4
134 7: update widest v4
137 ...6: add outside2
135 ...6: add outside2
138 5: update inside
136 5: update inside
139 4: update widest v3
137 4: update widest v3
140 3: add wider, update widest
138 3: add wider, update widest
141 ...2: add outside
139 ...2: add outside
142 1: add widest
140 1: add widest
143 0: add inside
141 0: add inside
144
142
145 Check that widening with a newline fails
143 Check that widening with a newline fails
146
144
147 $ hg tracked --addinclude 'widest
145 $ hg tracked --addinclude 'widest
148 > '
146 > '
149 abort: newlines are not allowed in narrowspec paths
147 abort: newlines are not allowed in narrowspec paths
150 [255]
148 [255]
151
149
152 widen the narrow spec to include the wider file
150 widen the narrow spec to include the wider file
153
151
154 $ hg tracked --addinclude wider
152 $ hg tracked --addinclude wider
155 comparing with ssh://user@dummy/master
153 comparing with ssh://user@dummy/master
156 searching for changes
154 searching for changes
157 no changes found
158 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
155 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
159 adding changesets
156 adding changesets
160 adding manifests
157 adding manifests
161 adding file changes
158 adding file changes
162 added 8 changesets with 7 changes to 3 files
159 added 8 changesets with 7 changes to 3 files
163 new changesets *:* (glob)
164 $ hg tracked
160 $ hg tracked
165 I path:inside
161 I path:inside
166 I path:wider
162 I path:wider
167 I path:widest/f
163 I path:widest/f
168 $ hg update 'desc("add widest")'
164 $ hg update 'desc("add widest")'
169 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
165 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
170 $ cat widest/f
166 $ cat widest/f
171 widest
167 widest
172 $ hg update 'desc("add wider, update widest")'
168 $ hg update 'desc("add wider, update widest")'
173 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 $ cat wider/f
170 $ cat wider/f
175 wider
171 wider
176 $ cat widest/f
172 $ cat widest/f
177 widest v2
173 widest v2
178 $ hg update 'desc("update widest v3")'
174 $ hg update 'desc("update widest v3")'
179 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
180 $ cat widest/f
176 $ cat widest/f
181 widest v3
177 widest v3
182 $ hg update 'desc("update widest v4")'
178 $ hg update 'desc("update widest v4")'
183 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 $ cat widest/f
180 $ cat widest/f
185 widest v4
181 widest v4
186
182
187 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
183 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
188 7: update widest v4
184 7: update widest v4
189 ...6: add outside2
185 ...6: add outside2
190 5: update inside
186 5: update inside
191 4: update widest v3
187 4: update widest v3
192 3: add wider, update widest
188 3: add wider, update widest
193 ...2: add outside
189 ...2: add outside
194 1: add widest
190 1: add widest
195 0: add inside
191 0: add inside
196
192
197 separate suite of tests: files from 0-10 modified in changes 0-10. This allows
193 separate suite of tests: files from 0-10 modified in changes 0-10. This allows
198 more obvious precise tests tickling particular corner cases.
194 more obvious precise tests tickling particular corner cases.
199
195
200 $ cd ..
196 $ cd ..
201 $ hg init upstream
197 $ hg init upstream
202 $ cd upstream
198 $ cd upstream
203 $ cat >> .hg/hgrc <<EOF
199 $ cat >> .hg/hgrc <<EOF
204 > [narrow]
200 > [narrow]
205 > serveellipses=True
201 > serveellipses=True
206 > EOF
202 > EOF
207 $ for x in `$TESTDIR/seq.py 0 10`
203 $ for x in `$TESTDIR/seq.py 0 10`
208 > do
204 > do
209 > mkdir d$x
205 > mkdir d$x
210 > echo $x > d$x/f
206 > echo $x > d$x/f
211 > hg add d$x/f
207 > hg add d$x/f
212 > hg commit -m "add d$x/f"
208 > hg commit -m "add d$x/f"
213 > done
209 > done
214 $ hg log -T "{rev}: {desc}\n"
210 $ hg log -T "{rev}: {desc}\n"
215 10: add d10/f
211 10: add d10/f
216 9: add d9/f
212 9: add d9/f
217 8: add d8/f
213 8: add d8/f
218 7: add d7/f
214 7: add d7/f
219 6: add d6/f
215 6: add d6/f
220 5: add d5/f
216 5: add d5/f
221 4: add d4/f
217 4: add d4/f
222 3: add d3/f
218 3: add d3/f
223 2: add d2/f
219 2: add d2/f
224 1: add d1/f
220 1: add d1/f
225 0: add d0/f
221 0: add d0/f
226
222
227 make narrow clone with every third node.
223 make narrow clone with every third node.
228
224
229 $ cd ..
225 $ cd ..
230 $ hg clone --narrow ssh://user@dummy/upstream narrow2 --include d0 --include d3 --include d6 --include d9
226 $ hg clone --narrow ssh://user@dummy/upstream narrow2 --include d0 --include d3 --include d6 --include d9
231 requesting all changes
227 requesting all changes
232 adding changesets
228 adding changesets
233 adding manifests
229 adding manifests
234 adding file changes
230 adding file changes
235 added 8 changesets with 4 changes to 4 files
231 added 8 changesets with 4 changes to 4 files
236 new changesets *:* (glob)
232 new changesets *:* (glob)
237 updating to branch default
233 updating to branch default
238 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 $ cd narrow2
235 $ cd narrow2
240 $ hg tracked
236 $ hg tracked
241 I path:d0
237 I path:d0
242 I path:d3
238 I path:d3
243 I path:d6
239 I path:d6
244 I path:d9
240 I path:d9
245 $ hg verify
241 $ hg verify
246 checking changesets
242 checking changesets
247 checking manifests
243 checking manifests
248 checking directory manifests (tree !)
244 checking directory manifests (tree !)
249 crosschecking files in changesets and manifests
245 crosschecking files in changesets and manifests
250 checking files
246 checking files
251 checked 8 changesets with 4 changes to 4 files
247 checked 8 changesets with 4 changes to 4 files
252 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
248 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
253 ...7: add d10/f
249 ...7: add d10/f
254 6: add d9/f
250 6: add d9/f
255 ...5: add d8/f
251 ...5: add d8/f
256 4: add d6/f
252 4: add d6/f
257 ...3: add d5/f
253 ...3: add d5/f
258 2: add d3/f
254 2: add d3/f
259 ...1: add d2/f
255 ...1: add d2/f
260 0: add d0/f
256 0: add d0/f
261 $ hg tracked --addinclude d1
257 $ hg tracked --addinclude d1
262 comparing with ssh://user@dummy/upstream
258 comparing with ssh://user@dummy/upstream
263 searching for changes
259 searching for changes
264 no changes found
265 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
260 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
266 adding changesets
261 adding changesets
267 adding manifests
262 adding manifests
268 adding file changes
263 adding file changes
269 added 9 changesets with 5 changes to 5 files
264 added 9 changesets with 5 changes to 5 files
270 new changesets *:* (glob)
271 $ hg tracked
265 $ hg tracked
272 I path:d0
266 I path:d0
273 I path:d1
267 I path:d1
274 I path:d3
268 I path:d3
275 I path:d6
269 I path:d6
276 I path:d9
270 I path:d9
277 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
271 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
278 ...8: add d10/f
272 ...8: add d10/f
279 7: add d9/f
273 7: add d9/f
280 ...6: add d8/f
274 ...6: add d8/f
281 5: add d6/f
275 5: add d6/f
282 ...4: add d5/f
276 ...4: add d5/f
283 3: add d3/f
277 3: add d3/f
284 ...2: add d2/f
278 ...2: add d2/f
285 1: add d1/f
279 1: add d1/f
286 0: add d0/f
280 0: add d0/f
287
281
288 Verify shouldn't claim the repo is corrupt after a widen.
282 Verify shouldn't claim the repo is corrupt after a widen.
289
283
290 $ hg verify
284 $ hg verify
291 checking changesets
285 checking changesets
292 checking manifests
286 checking manifests
293 checking directory manifests (tree !)
287 checking directory manifests (tree !)
294 crosschecking files in changesets and manifests
288 crosschecking files in changesets and manifests
295 checking files
289 checking files
296 checked 9 changesets with 5 changes to 5 files
290 checked 9 changesets with 5 changes to 5 files
297
291
298 Widening preserves parent of local commit
292 Widening preserves parent of local commit
299
293
300 $ cd ..
294 $ cd ..
301 $ hg clone -q --narrow ssh://user@dummy/upstream narrow3 --include d2 -r 2
295 $ hg clone -q --narrow ssh://user@dummy/upstream narrow3 --include d2 -r 2
302 $ cd narrow3
296 $ cd narrow3
303 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
297 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
304 1: add d2/f
298 1: add d2/f
305 ...0: add d1/f
299 ...0: add d1/f
306 $ hg pull -q -r 3
300 $ hg pull -q -r 3
307 $ hg co -q tip
301 $ hg co -q tip
308 $ hg pull -q -r 4
302 $ hg pull -q -r 4
309 $ echo local > d2/f
303 $ echo local > d2/f
310 $ hg ci -m local
304 $ hg ci -m local
311 created new head
305 created new head
312 $ hg tracked -q --addinclude d0 --addinclude d9
306 $ hg tracked -q --addinclude d0 --addinclude d9
313
307
314 Widening preserves bookmarks
308 Widening preserves bookmarks
315
309
316 $ cd ..
310 $ cd ..
317 $ hg clone -q --narrow ssh://user@dummy/upstream narrow-bookmarks --include d4
311 $ hg clone -q --narrow ssh://user@dummy/upstream narrow-bookmarks --include d4
318 $ cd narrow-bookmarks
312 $ cd narrow-bookmarks
319 $ echo local > d4/f
313 $ echo local > d4/f
320 $ hg ci -m local
314 $ hg ci -m local
321 $ hg bookmarks bookmark
315 $ hg bookmarks bookmark
322 $ hg bookmarks
316 $ hg bookmarks
323 * bookmark 3:* (glob)
317 * bookmark 3:* (glob)
324 $ hg -q tracked --addinclude d2
318 $ hg -q tracked --addinclude d2
325 $ hg bookmarks
319 $ hg bookmarks
326 * bookmark 5:* (glob)
320 * bookmark 5:* (glob)
327 $ hg log -r bookmark -T '{desc}\n'
321 $ hg log -r bookmark -T '{desc}\n'
328 local
322 local
329
323
330 Widening that fails can be recovered from
324 Widening that fails can be recovered from
331
325
332 $ cd ..
326 $ cd ..
333 $ hg clone -q --narrow ssh://user@dummy/upstream interrupted --include d0
327 $ hg clone -q --narrow ssh://user@dummy/upstream interrupted --include d0
334 $ cd interrupted
328 $ cd interrupted
335 $ echo local > d0/f
329 $ echo local > d0/f
336 $ hg ci -m local
330 $ hg ci -m local
337 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
331 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
338 2: local
332 2: local
339 ...1: add d10/f
333 ...1: add d10/f
340 0: add d0/f
334 0: add d0/f
341 $ hg bookmarks bookmark
335 $ hg bookmarks bookmark
342 $ hg --config hooks.pretxnchangegroup.bad=false tracked --addinclude d1
336 $ hg --config hooks.pretxnchangegroup.bad=false tracked --addinclude d1
343 comparing with ssh://user@dummy/upstream
337 comparing with ssh://user@dummy/upstream
344 searching for changes
338 searching for changes
345 no changes found
346 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/*-widen.hg (glob)
339 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/*-widen.hg (glob)
347 adding changesets
340 adding changesets
348 adding manifests
341 adding manifests
349 adding file changes
342 adding file changes
350 added 3 changesets with 2 changes to 2 files
343 added 3 changesets with 2 changes to 2 files
351 transaction abort!
344 transaction abort!
352 rollback completed
345 rollback completed
353 abort: pretxnchangegroup.bad hook exited with status 1
346 abort: pretxnchangegroup.bad hook exited with status 1
354 [255]
347 [255]
355 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
348 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
356 $ hg bookmarks
349 $ hg bookmarks
357 no bookmarks set
350 no bookmarks set
358 $ hg unbundle .hg/strip-backup/*-widen.hg
351 $ hg unbundle .hg/strip-backup/*-widen.hg
359 adding changesets
352 adding changesets
360 adding manifests
353 adding manifests
361 adding file changes
354 adding file changes
362 added 3 changesets with 2 changes to 1 files
355 added 3 changesets with 2 changes to 1 files
363 new changesets *:* (glob)
356 new changesets *:* (glob)
364 (run 'hg update' to get a working copy)
357 (run 'hg update' to get a working copy)
365 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
358 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
366 2: local
359 2: local
367 ...1: add d10/f
360 ...1: add d10/f
368 0: add d0/f
361 0: add d0/f
369 $ hg bookmarks
362 $ hg bookmarks
370 * bookmark 2:* (glob)
363 * bookmark 2:* (glob)
@@ -1,449 +1,447 b''
1 #testcases flat tree
1 #testcases flat tree
2 #testcases lfs-on lfs-off
2 #testcases lfs-on lfs-off
3
3
4 #if lfs-on
4 #if lfs-on
5 $ cat >> $HGRCPATH <<EOF
5 $ cat >> $HGRCPATH <<EOF
6 > [extensions]
6 > [extensions]
7 > lfs =
7 > lfs =
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 $ . "$TESTDIR/narrow-library.sh"
11 $ . "$TESTDIR/narrow-library.sh"
12
12
13 #if tree
13 #if tree
14 $ cat << EOF >> $HGRCPATH
14 $ cat << EOF >> $HGRCPATH
15 > [experimental]
15 > [experimental]
16 > treemanifest = 1
16 > treemanifest = 1
17 > EOF
17 > EOF
18 #endif
18 #endif
19
19
20 $ hg init master
20 $ hg init master
21 $ cd master
21 $ cd master
22 $ cat >> .hg/hgrc <<EOF
22 $ cat >> .hg/hgrc <<EOF
23 > [narrow]
23 > [narrow]
24 > serveellipses=True
24 > serveellipses=True
25 > EOF
25 > EOF
26 $ for x in `$TESTDIR/seq.py 0 10`
26 $ for x in `$TESTDIR/seq.py 0 10`
27 > do
27 > do
28 > mkdir d$x
28 > mkdir d$x
29 > echo $x > d$x/f
29 > echo $x > d$x/f
30 > hg add d$x/f
30 > hg add d$x/f
31 > hg commit -m "add d$x/f"
31 > hg commit -m "add d$x/f"
32 > done
32 > done
33 $ hg log -T "{rev}: {desc}\n"
33 $ hg log -T "{rev}: {desc}\n"
34 10: add d10/f
34 10: add d10/f
35 9: add d9/f
35 9: add d9/f
36 8: add d8/f
36 8: add d8/f
37 7: add d7/f
37 7: add d7/f
38 6: add d6/f
38 6: add d6/f
39 5: add d5/f
39 5: add d5/f
40 4: add d4/f
40 4: add d4/f
41 3: add d3/f
41 3: add d3/f
42 2: add d2/f
42 2: add d2/f
43 1: add d1/f
43 1: add d1/f
44 0: add d0/f
44 0: add d0/f
45 $ cd ..
45 $ cd ..
46
46
47 Error if '.' or '..' are in the directory to track.
47 Error if '.' or '..' are in the directory to track.
48 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
48 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
49 abort: "." and ".." are not allowed in narrowspec paths
49 abort: "." and ".." are not allowed in narrowspec paths
50 [255]
50 [255]
51 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
51 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
52 abort: "." and ".." are not allowed in narrowspec paths
52 abort: "." and ".." are not allowed in narrowspec paths
53 [255]
53 [255]
54 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
54 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
55 abort: "." and ".." are not allowed in narrowspec paths
55 abort: "." and ".." are not allowed in narrowspec paths
56 [255]
56 [255]
57
57
58 Names with '.' in them are OK.
58 Names with '.' in them are OK.
59 $ hg clone --narrow ssh://user@dummy/master should-work --include a/.b/c
59 $ hg clone --narrow ssh://user@dummy/master should-work --include a/.b/c
60 requesting all changes
60 requesting all changes
61 adding changesets
61 adding changesets
62 adding manifests
62 adding manifests
63 adding file changes
63 adding file changes
64 added 1 changesets with 0 changes to 0 files
64 added 1 changesets with 0 changes to 0 files
65 new changesets * (glob)
65 new changesets * (glob)
66 updating to branch default
66 updating to branch default
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
68
68
69 Test repo with local changes
69 Test repo with local changes
70 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
70 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
71 requesting all changes
71 requesting all changes
72 adding changesets
72 adding changesets
73 adding manifests
73 adding manifests
74 adding file changes
74 adding file changes
75 added 6 changesets with 3 changes to 3 files
75 added 6 changesets with 3 changes to 3 files
76 new changesets *:* (glob)
76 new changesets *:* (glob)
77 updating to branch default
77 updating to branch default
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 $ cd narrow-local-changes
79 $ cd narrow-local-changes
80 $ cat >> $HGRCPATH << EOF
80 $ cat >> $HGRCPATH << EOF
81 > [experimental]
81 > [experimental]
82 > evolution=createmarkers
82 > evolution=createmarkers
83 > EOF
83 > EOF
84 $ echo local change >> d0/f
84 $ echo local change >> d0/f
85 $ hg ci -m 'local change to d0'
85 $ hg ci -m 'local change to d0'
86 $ hg co '.^'
86 $ hg co '.^'
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 $ echo local change >> d3/f
88 $ echo local change >> d3/f
89 $ hg ci -m 'local hidden change to d3'
89 $ hg ci -m 'local hidden change to d3'
90 created new head
90 created new head
91 $ hg ci --amend -m 'local change to d3'
91 $ hg ci --amend -m 'local change to d3'
92 $ hg tracked --removeinclude d0
92 $ hg tracked --removeinclude d0
93 comparing with ssh://user@dummy/master
93 comparing with ssh://user@dummy/master
94 searching for changes
94 searching for changes
95 looking for local changes to affected paths
95 looking for local changes to affected paths
96 The following changeset(s) or their ancestors have local changes not on the remote:
96 The following changeset(s) or their ancestors have local changes not on the remote:
97 * (glob)
97 * (glob)
98 abort: local changes found
98 abort: local changes found
99 (use --force-delete-local-changes to ignore)
99 (use --force-delete-local-changes to ignore)
100 [255]
100 [255]
101 Check that nothing was removed by the failed attempts
101 Check that nothing was removed by the failed attempts
102 $ hg tracked
102 $ hg tracked
103 I path:d0
103 I path:d0
104 I path:d3
104 I path:d3
105 I path:d6
105 I path:d6
106 $ hg files
106 $ hg files
107 d0/f
107 d0/f
108 d3/f
108 d3/f
109 d6/f
109 d6/f
110 $ find *
110 $ find *
111 d0
111 d0
112 d0/f
112 d0/f
113 d3
113 d3
114 d3/f
114 d3/f
115 d6
115 d6
116 d6/f
116 d6/f
117 $ hg verify -q
117 $ hg verify -q
118 Force deletion of local changes
118 Force deletion of local changes
119 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
119 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
120 8: local change to d3
120 8: local change to d3
121 6: local change to d0
121 6: local change to d0
122 5: add d10/f outsidenarrow
122 5: add d10/f outsidenarrow
123 4: add d6/f
123 4: add d6/f
124 3: add d5/f outsidenarrow
124 3: add d5/f outsidenarrow
125 2: add d3/f
125 2: add d3/f
126 1: add d2/f outsidenarrow
126 1: add d2/f outsidenarrow
127 0: add d0/f
127 0: add d0/f
128 $ hg tracked --removeinclude d0 --force-delete-local-changes
128 $ hg tracked --removeinclude d0 --force-delete-local-changes
129 comparing with ssh://user@dummy/master
129 comparing with ssh://user@dummy/master
130 searching for changes
130 searching for changes
131 looking for local changes to affected paths
131 looking for local changes to affected paths
132 The following changeset(s) or their ancestors have local changes not on the remote:
132 The following changeset(s) or their ancestors have local changes not on the remote:
133 * (glob)
133 * (glob)
134 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
134 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
135 deleting data/d0/f.i (reporevlogstore !)
135 deleting data/d0/f.i (reporevlogstore !)
136 deleting meta/d0/00manifest.i (tree !)
136 deleting meta/d0/00manifest.i (tree !)
137 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
137 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
138 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
138 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
139 deleting data/d0/f/index (reposimplestore !)
139 deleting data/d0/f/index (reposimplestore !)
140
140
141 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
141 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
142 7: local change to d3
142 7: local change to d3
143 5: add d10/f outsidenarrow
143 5: add d10/f outsidenarrow
144 4: add d6/f
144 4: add d6/f
145 3: add d5/f outsidenarrow
145 3: add d5/f outsidenarrow
146 2: add d3/f
146 2: add d3/f
147 1: add d2/f outsidenarrow
147 1: add d2/f outsidenarrow
148 0: add d0/f outsidenarrow
148 0: add d0/f outsidenarrow
149 Can restore stripped local changes after widening
149 Can restore stripped local changes after widening
150 $ hg tracked --addinclude d0 -q
150 $ hg tracked --addinclude d0 -q
151 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
151 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
152 $ hg --hidden co -r 'desc("local change to d0")' -q
152 $ hg --hidden co -r 'desc("local change to d0")' -q
153 $ cat d0/f
153 $ cat d0/f
154 0
154 0
155 local change
155 local change
156 Pruned commits affecting removed paths should not prevent narrowing
156 Pruned commits affecting removed paths should not prevent narrowing
157 $ hg co '.^'
157 $ hg co '.^'
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
159 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
160 obsoleted 1 changesets
160 obsoleted 1 changesets
161 $ hg tracked --removeinclude d0
161 $ hg tracked --removeinclude d0
162 comparing with ssh://user@dummy/master
162 comparing with ssh://user@dummy/master
163 searching for changes
163 searching for changes
164 looking for local changes to affected paths
164 looking for local changes to affected paths
165 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
165 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
166 deleting data/d0/f.i (reporevlogstore !)
166 deleting data/d0/f.i (reporevlogstore !)
167 deleting meta/d0/00manifest.i (tree !)
167 deleting meta/d0/00manifest.i (tree !)
168 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
168 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
169 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
169 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
170 deleting data/d0/f/index (reposimplestore !)
170 deleting data/d0/f/index (reposimplestore !)
171
171
172 Updates off of stripped commit if necessary
172 Updates off of stripped commit if necessary
173 $ hg co -r 'desc("local change to d3")' -q
173 $ hg co -r 'desc("local change to d3")' -q
174 $ echo local change >> d6/f
174 $ echo local change >> d6/f
175 $ hg ci -m 'local change to d6'
175 $ hg ci -m 'local change to d6'
176 $ hg tracked --removeinclude d3 --force-delete-local-changes
176 $ hg tracked --removeinclude d3 --force-delete-local-changes
177 comparing with ssh://user@dummy/master
177 comparing with ssh://user@dummy/master
178 searching for changes
178 searching for changes
179 looking for local changes to affected paths
179 looking for local changes to affected paths
180 The following changeset(s) or their ancestors have local changes not on the remote:
180 The following changeset(s) or their ancestors have local changes not on the remote:
181 * (glob)
181 * (glob)
182 * (glob)
182 * (glob)
183 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
184 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
185 deleting data/d3/f.i (reporevlogstore !)
185 deleting data/d3/f.i (reporevlogstore !)
186 deleting meta/d3/00manifest.i (tree !)
186 deleting meta/d3/00manifest.i (tree !)
187 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
187 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
188 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
188 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
189 deleting data/d3/f/index (reposimplestore !)
189 deleting data/d3/f/index (reposimplestore !)
190 $ hg log -T '{desc}\n' -r .
190 $ hg log -T '{desc}\n' -r .
191 add d10/f
191 add d10/f
192 Updates to nullid if necessary
192 Updates to nullid if necessary
193 $ hg tracked --addinclude d3 -q
193 $ hg tracked --addinclude d3 -q
194 $ hg co null -q
194 $ hg co null -q
195 $ mkdir d3
195 $ mkdir d3
196 $ echo local change > d3/f
196 $ echo local change > d3/f
197 $ hg add d3/f
197 $ hg add d3/f
198 $ hg ci -m 'local change to d3'
198 $ hg ci -m 'local change to d3'
199 created new head
199 created new head
200 $ hg tracked --removeinclude d3 --force-delete-local-changes
200 $ hg tracked --removeinclude d3 --force-delete-local-changes
201 comparing with ssh://user@dummy/master
201 comparing with ssh://user@dummy/master
202 searching for changes
202 searching for changes
203 looking for local changes to affected paths
203 looking for local changes to affected paths
204 The following changeset(s) or their ancestors have local changes not on the remote:
204 The following changeset(s) or their ancestors have local changes not on the remote:
205 * (glob)
205 * (glob)
206 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
206 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
207 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
207 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
208 deleting data/d3/f.i (reporevlogstore !)
208 deleting data/d3/f.i (reporevlogstore !)
209 deleting meta/d3/00manifest.i (tree !)
209 deleting meta/d3/00manifest.i (tree !)
210 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
210 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
211 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
211 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
212 deleting data/d3/f/index (reposimplestore !)
212 deleting data/d3/f/index (reposimplestore !)
213 $ hg id
213 $ hg id
214 000000000000
214 000000000000
215 $ cd ..
215 $ cd ..
216
216
217 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
217 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
218 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
218 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
219 $ cd narrow-obsmarkers
219 $ cd narrow-obsmarkers
220 $ echo a >> d0/f2
220 $ echo a >> d0/f2
221 $ hg add d0/f2
221 $ hg add d0/f2
222 $ hg ci -m 'modify d0/'
222 $ hg ci -m 'modify d0/'
223 $ echo a >> d3/f2
223 $ echo a >> d3/f2
224 $ hg add d3/f2
224 $ hg add d3/f2
225 $ hg commit --amend -m 'modify d0/ and d3/'
225 $ hg commit --amend -m 'modify d0/ and d3/'
226 $ hg log -T "{rev}: {desc}\n"
226 $ hg log -T "{rev}: {desc}\n"
227 5: modify d0/ and d3/
227 5: modify d0/ and d3/
228 3: add d10/f
228 3: add d10/f
229 2: add d3/f
229 2: add d3/f
230 1: add d2/f
230 1: add d2/f
231 0: add d0/f
231 0: add d0/f
232 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
232 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
233 $ hg log -T "{rev}: {desc}\n"
233 $ hg log -T "{rev}: {desc}\n"
234 3: add d10/f
234 3: add d10/f
235 2: add d3/f
235 2: add d3/f
236 1: add d2/f
236 1: add d2/f
237 0: add d0/f
237 0: add d0/f
238 $ cd ..
238 $ cd ..
239
239
240 Widening doesn't lose bookmarks
240 Widening doesn't lose bookmarks
241 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
241 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
242 $ cd widen-bookmarks
242 $ cd widen-bookmarks
243 $ hg bookmark my-bookmark
243 $ hg bookmark my-bookmark
244 $ hg log -T "{rev}: {desc} {bookmarks}\n"
244 $ hg log -T "{rev}: {desc} {bookmarks}\n"
245 1: add d10/f my-bookmark
245 1: add d10/f my-bookmark
246 0: add d0/f
246 0: add d0/f
247 $ hg tracked --addinclude d3 -q
247 $ hg tracked --addinclude d3 -q
248 $ hg log -T "{rev}: {desc} {bookmarks}\n"
248 $ hg log -T "{rev}: {desc} {bookmarks}\n"
249 3: add d10/f my-bookmark
249 3: add d10/f my-bookmark
250 2: add d3/f
250 2: add d3/f
251 1: add d2/f
251 1: add d2/f
252 0: add d0/f
252 0: add d0/f
253 $ cd ..
253 $ cd ..
254
254
255 Can remove last include, making repo empty
255 Can remove last include, making repo empty
256 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
256 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
257 adding changesets
257 adding changesets
258 adding manifests
258 adding manifests
259 adding file changes
259 adding file changes
260 added 2 changesets with 1 changes to 1 files
260 added 2 changesets with 1 changes to 1 files
261 new changesets *:* (glob)
261 new changesets *:* (glob)
262 updating to branch default
262 updating to branch default
263 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 $ cd narrow-empty
264 $ cd narrow-empty
265 $ hg tracked --removeinclude d0
265 $ hg tracked --removeinclude d0
266 comparing with ssh://user@dummy/master
266 comparing with ssh://user@dummy/master
267 searching for changes
267 searching for changes
268 looking for local changes to affected paths
268 looking for local changes to affected paths
269 deleting data/d0/f.i (reporevlogstore !)
269 deleting data/d0/f.i (reporevlogstore !)
270 deleting meta/d0/00manifest.i (tree !)
270 deleting meta/d0/00manifest.i (tree !)
271 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
271 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
272 deleting data/d0/f/index (reposimplestore !)
272 deleting data/d0/f/index (reposimplestore !)
273 $ hg tracked
273 $ hg tracked
274 $ hg files
274 $ hg files
275 [1]
275 [1]
276 $ test -d d0
276 $ test -d d0
277 [1]
277 [1]
278 Do some work in the empty clone
278 Do some work in the empty clone
279 $ hg diff --change .
279 $ hg diff --change .
280 $ hg branch foo
280 $ hg branch foo
281 marked working directory as branch foo
281 marked working directory as branch foo
282 (branches are permanent and global, did you want a bookmark?)
282 (branches are permanent and global, did you want a bookmark?)
283 $ hg ci -m empty
283 $ hg ci -m empty
284 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
284 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
285 2: empty
285 2: empty
286 1: add d5/f outsidenarrow
286 1: add d5/f outsidenarrow
287 0: add d0/f outsidenarrow
287 0: add d0/f outsidenarrow
288 $ hg pull -q
288 $ hg pull -q
289 Can widen the empty clone
289 Can widen the empty clone
290 $ hg tracked --addinclude d0
290 $ hg tracked --addinclude d0
291 comparing with ssh://user@dummy/master
291 comparing with ssh://user@dummy/master
292 searching for changes
292 searching for changes
293 no changes found
294 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
293 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
295 adding changesets
294 adding changesets
296 adding manifests
295 adding manifests
297 adding file changes
296 adding file changes
298 added 3 changesets with 1 changes to 1 files
297 added 3 changesets with 1 changes to 1 files
299 new changesets *:* (glob)
300 $ hg tracked
298 $ hg tracked
301 I path:d0
299 I path:d0
302 $ hg files
300 $ hg files
303 d0/f
301 d0/f
304 $ find *
302 $ find *
305 d0
303 d0
306 d0/f
304 d0/f
307 $ cd ..
305 $ cd ..
308
306
309 TODO(martinvonz): test including e.g. d3/g and then removing it once
307 TODO(martinvonz): test including e.g. d3/g and then removing it once
310 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
308 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
311
309
312 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
310 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
313 requesting all changes
311 requesting all changes
314 adding changesets
312 adding changesets
315 adding manifests
313 adding manifests
316 adding file changes
314 adding file changes
317 added 8 changesets with 4 changes to 4 files
315 added 8 changesets with 4 changes to 4 files
318 new changesets *:* (glob)
316 new changesets *:* (glob)
319 updating to branch default
317 updating to branch default
320 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 $ cd narrow
319 $ cd narrow
322 $ hg tracked
320 $ hg tracked
323 I path:d0
321 I path:d0
324 I path:d3
322 I path:d3
325 I path:d6
323 I path:d6
326 I path:d9
324 I path:d9
327 $ hg tracked --removeinclude d6
325 $ hg tracked --removeinclude d6
328 comparing with ssh://user@dummy/master
326 comparing with ssh://user@dummy/master
329 searching for changes
327 searching for changes
330 looking for local changes to affected paths
328 looking for local changes to affected paths
331 deleting data/d6/f.i (reporevlogstore !)
329 deleting data/d6/f.i (reporevlogstore !)
332 deleting meta/d6/00manifest.i (tree !)
330 deleting meta/d6/00manifest.i (tree !)
333 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
331 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
334 deleting data/d6/f/index (reposimplestore !)
332 deleting data/d6/f/index (reposimplestore !)
335 $ hg tracked
333 $ hg tracked
336 I path:d0
334 I path:d0
337 I path:d3
335 I path:d3
338 I path:d9
336 I path:d9
339 #if repofncache
337 #if repofncache
340 $ hg debugrebuildfncache
338 $ hg debugrebuildfncache
341 fncache already up to date
339 fncache already up to date
342 #endif
340 #endif
343 $ find *
341 $ find *
344 d0
342 d0
345 d0/f
343 d0/f
346 d3
344 d3
347 d3/f
345 d3/f
348 d9
346 d9
349 d9/f
347 d9/f
350 $ hg verify -q
348 $ hg verify -q
351 $ hg tracked --addexclude d3/f
349 $ hg tracked --addexclude d3/f
352 comparing with ssh://user@dummy/master
350 comparing with ssh://user@dummy/master
353 searching for changes
351 searching for changes
354 looking for local changes to affected paths
352 looking for local changes to affected paths
355 deleting data/d3/f.i (reporevlogstore !)
353 deleting data/d3/f.i (reporevlogstore !)
356 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
354 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
357 deleting data/d3/f/index (reposimplestore !)
355 deleting data/d3/f/index (reposimplestore !)
358 $ hg tracked
356 $ hg tracked
359 I path:d0
357 I path:d0
360 I path:d3
358 I path:d3
361 I path:d9
359 I path:d9
362 X path:d3/f
360 X path:d3/f
363 #if repofncache
361 #if repofncache
364 $ hg debugrebuildfncache
362 $ hg debugrebuildfncache
365 fncache already up to date
363 fncache already up to date
366 #endif
364 #endif
367 $ find *
365 $ find *
368 d0
366 d0
369 d0/f
367 d0/f
370 d9
368 d9
371 d9/f
369 d9/f
372 $ hg verify -q
370 $ hg verify -q
373 $ hg tracked --addexclude d0
371 $ hg tracked --addexclude d0
374 comparing with ssh://user@dummy/master
372 comparing with ssh://user@dummy/master
375 searching for changes
373 searching for changes
376 looking for local changes to affected paths
374 looking for local changes to affected paths
377 deleting data/d0/f.i (reporevlogstore !)
375 deleting data/d0/f.i (reporevlogstore !)
378 deleting meta/d0/00manifest.i (tree !)
376 deleting meta/d0/00manifest.i (tree !)
379 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
377 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
380 deleting data/d0/f/index (reposimplestore !)
378 deleting data/d0/f/index (reposimplestore !)
381 $ hg tracked
379 $ hg tracked
382 I path:d3
380 I path:d3
383 I path:d9
381 I path:d9
384 X path:d0
382 X path:d0
385 X path:d3/f
383 X path:d3/f
386 #if repofncache
384 #if repofncache
387 $ hg debugrebuildfncache
385 $ hg debugrebuildfncache
388 fncache already up to date
386 fncache already up to date
389 #endif
387 #endif
390 $ find *
388 $ find *
391 d9
389 d9
392 d9/f
390 d9/f
393
391
394 Make a 15 of changes to d9 to test the path without --verbose
392 Make a 15 of changes to d9 to test the path without --verbose
395 (Note: using regexes instead of "* (glob)" because if the test fails, it
393 (Note: using regexes instead of "* (glob)" because if the test fails, it
396 produces more sensible diffs)
394 produces more sensible diffs)
397 $ hg tracked
395 $ hg tracked
398 I path:d3
396 I path:d3
399 I path:d9
397 I path:d9
400 X path:d0
398 X path:d0
401 X path:d3/f
399 X path:d3/f
402 $ for x in `$TESTDIR/seq.py 1 15`
400 $ for x in `$TESTDIR/seq.py 1 15`
403 > do
401 > do
404 > echo local change >> d9/f
402 > echo local change >> d9/f
405 > hg commit -m "change $x to d9/f"
403 > hg commit -m "change $x to d9/f"
406 > done
404 > done
407 $ hg tracked --removeinclude d9
405 $ hg tracked --removeinclude d9
408 comparing with ssh://user@dummy/master
406 comparing with ssh://user@dummy/master
409 searching for changes
407 searching for changes
410 looking for local changes to affected paths
408 looking for local changes to affected paths
411 The following changeset(s) or their ancestors have local changes not on the remote:
409 The following changeset(s) or their ancestors have local changes not on the remote:
412 ^[0-9a-f]{12}$ (re)
410 ^[0-9a-f]{12}$ (re)
413 ^[0-9a-f]{12}$ (re)
411 ^[0-9a-f]{12}$ (re)
414 ^[0-9a-f]{12}$ (re)
412 ^[0-9a-f]{12}$ (re)
415 ^[0-9a-f]{12}$ (re)
413 ^[0-9a-f]{12}$ (re)
416 ^[0-9a-f]{12}$ (re)
414 ^[0-9a-f]{12}$ (re)
417 ^[0-9a-f]{12}$ (re)
415 ^[0-9a-f]{12}$ (re)
418 ^[0-9a-f]{12}$ (re)
416 ^[0-9a-f]{12}$ (re)
419 ^[0-9a-f]{12}$ (re)
417 ^[0-9a-f]{12}$ (re)
420 ^[0-9a-f]{12}$ (re)
418 ^[0-9a-f]{12}$ (re)
421 ^[0-9a-f]{12}$ (re)
419 ^[0-9a-f]{12}$ (re)
422 ...and 5 more, use --verbose to list all
420 ...and 5 more, use --verbose to list all
423 abort: local changes found
421 abort: local changes found
424 (use --force-delete-local-changes to ignore)
422 (use --force-delete-local-changes to ignore)
425 [255]
423 [255]
426 Now test it *with* verbose.
424 Now test it *with* verbose.
427 $ hg tracked --removeinclude d9 --verbose
425 $ hg tracked --removeinclude d9 --verbose
428 comparing with ssh://user@dummy/master
426 comparing with ssh://user@dummy/master
429 searching for changes
427 searching for changes
430 looking for local changes to affected paths
428 looking for local changes to affected paths
431 The following changeset(s) or their ancestors have local changes not on the remote:
429 The following changeset(s) or their ancestors have local changes not on the remote:
432 ^[0-9a-f]{12}$ (re)
430 ^[0-9a-f]{12}$ (re)
433 ^[0-9a-f]{12}$ (re)
431 ^[0-9a-f]{12}$ (re)
434 ^[0-9a-f]{12}$ (re)
432 ^[0-9a-f]{12}$ (re)
435 ^[0-9a-f]{12}$ (re)
433 ^[0-9a-f]{12}$ (re)
436 ^[0-9a-f]{12}$ (re)
434 ^[0-9a-f]{12}$ (re)
437 ^[0-9a-f]{12}$ (re)
435 ^[0-9a-f]{12}$ (re)
438 ^[0-9a-f]{12}$ (re)
436 ^[0-9a-f]{12}$ (re)
439 ^[0-9a-f]{12}$ (re)
437 ^[0-9a-f]{12}$ (re)
440 ^[0-9a-f]{12}$ (re)
438 ^[0-9a-f]{12}$ (re)
441 ^[0-9a-f]{12}$ (re)
439 ^[0-9a-f]{12}$ (re)
442 ^[0-9a-f]{12}$ (re)
440 ^[0-9a-f]{12}$ (re)
443 ^[0-9a-f]{12}$ (re)
441 ^[0-9a-f]{12}$ (re)
444 ^[0-9a-f]{12}$ (re)
442 ^[0-9a-f]{12}$ (re)
445 ^[0-9a-f]{12}$ (re)
443 ^[0-9a-f]{12}$ (re)
446 ^[0-9a-f]{12}$ (re)
444 ^[0-9a-f]{12}$ (re)
447 abort: local changes found
445 abort: local changes found
448 (use --force-delete-local-changes to ignore)
446 (use --force-delete-local-changes to ignore)
449 [255]
447 [255]
General Comments 0
You need to be logged in to leave comments. Login now