##// END OF EJS Templates
narrow: strip trailing `/` from manifest dir before matching it...
Martin von Zweigbergk -
r52169:03665fd8 default
parent child Browse files
Show More
@@ -1,697 +1,697 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
7
8 import itertools
8 import itertools
9 import os
9 import os
10
10
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial.node import (
12 from mercurial.node import (
13 hex,
13 hex,
14 short,
14 short,
15 )
15 )
16 from mercurial import (
16 from mercurial import (
17 bundle2,
17 bundle2,
18 cmdutil,
18 cmdutil,
19 commands,
19 commands,
20 discovery,
20 discovery,
21 encoding,
21 encoding,
22 error,
22 error,
23 exchange,
23 exchange,
24 extensions,
24 extensions,
25 hg,
25 hg,
26 narrowspec,
26 narrowspec,
27 pathutil,
27 pathutil,
28 pycompat,
28 pycompat,
29 registrar,
29 registrar,
30 repair,
30 repair,
31 repoview,
31 repoview,
32 requirements,
32 requirements,
33 sparse,
33 sparse,
34 util,
34 util,
35 wireprototypes,
35 wireprototypes,
36 )
36 )
37 from mercurial.utils import (
37 from mercurial.utils import (
38 urlutil,
38 urlutil,
39 )
39 )
40
40
41 table = {}
41 table = {}
42 command = registrar.command(table)
42 command = registrar.command(table)
43
43
44
44
45 def setup():
45 def setup():
46 """Wraps user-facing mercurial commands with narrow-aware versions."""
46 """Wraps user-facing mercurial commands with narrow-aware versions."""
47
47
48 entry = extensions.wrapcommand(commands.table, b'clone', clonenarrowcmd)
48 entry = extensions.wrapcommand(commands.table, b'clone', clonenarrowcmd)
49 entry[1].append(
49 entry[1].append(
50 (b'', b'narrow', None, _(b"create a narrow clone of select files"))
50 (b'', b'narrow', None, _(b"create a narrow clone of select files"))
51 )
51 )
52 entry[1].append(
52 entry[1].append(
53 (
53 (
54 b'',
54 b'',
55 b'depth',
55 b'depth',
56 b'',
56 b'',
57 _(b"limit the history fetched by distance from heads"),
57 _(b"limit the history fetched by distance from heads"),
58 )
58 )
59 )
59 )
60 entry[1].append((b'', b'narrowspec', b'', _(b"read narrowspecs from file")))
60 entry[1].append((b'', b'narrowspec', b'', _(b"read narrowspecs from file")))
61 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
61 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
62 if b'sparse' not in extensions.enabled():
62 if b'sparse' not in extensions.enabled():
63 entry[1].append(
63 entry[1].append(
64 (b'', b'include', [], _(b"specifically fetch this file/directory"))
64 (b'', b'include', [], _(b"specifically fetch this file/directory"))
65 )
65 )
66 entry[1].append(
66 entry[1].append(
67 (
67 (
68 b'',
68 b'',
69 b'exclude',
69 b'exclude',
70 [],
70 [],
71 _(b"do not fetch this file/directory, even if included"),
71 _(b"do not fetch this file/directory, even if included"),
72 )
72 )
73 )
73 )
74
74
75 entry = extensions.wrapcommand(commands.table, b'pull', pullnarrowcmd)
75 entry = extensions.wrapcommand(commands.table, b'pull', pullnarrowcmd)
76 entry[1].append(
76 entry[1].append(
77 (
77 (
78 b'',
78 b'',
79 b'depth',
79 b'depth',
80 b'',
80 b'',
81 _(b"limit the history fetched by distance from heads"),
81 _(b"limit the history fetched by distance from heads"),
82 )
82 )
83 )
83 )
84
84
85 extensions.wrapcommand(commands.table, b'archive', archivenarrowcmd)
85 extensions.wrapcommand(commands.table, b'archive', archivenarrowcmd)
86
86
87
87
88 def clonenarrowcmd(orig, ui, repo, *args, **opts):
88 def clonenarrowcmd(orig, ui, repo, *args, **opts):
89 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
89 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
90 wrappedextraprepare = util.nullcontextmanager()
90 wrappedextraprepare = util.nullcontextmanager()
91 narrowspecfile = opts['narrowspec']
91 narrowspecfile = opts['narrowspec']
92
92
93 if narrowspecfile:
93 if narrowspecfile:
94 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
94 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
95 ui.status(_(b"reading narrowspec from '%s'\n") % filepath)
95 ui.status(_(b"reading narrowspec from '%s'\n") % filepath)
96 try:
96 try:
97 fdata = util.readfile(filepath)
97 fdata = util.readfile(filepath)
98 except IOError as inst:
98 except IOError as inst:
99 raise error.Abort(
99 raise error.Abort(
100 _(b"cannot read narrowspecs from '%s': %s")
100 _(b"cannot read narrowspecs from '%s': %s")
101 % (filepath, encoding.strtolocal(inst.strerror))
101 % (filepath, encoding.strtolocal(inst.strerror))
102 )
102 )
103
103
104 includes, excludes, profiles = sparse.parseconfig(ui, fdata, b'narrow')
104 includes, excludes, profiles = sparse.parseconfig(ui, fdata, b'narrow')
105 if profiles:
105 if profiles:
106 raise error.ConfigError(
106 raise error.ConfigError(
107 _(
107 _(
108 b"cannot specify other files using '%include' in"
108 b"cannot specify other files using '%include' in"
109 b" narrowspec"
109 b" narrowspec"
110 )
110 )
111 )
111 )
112
112
113 narrowspec.validatepatterns(includes)
113 narrowspec.validatepatterns(includes)
114 narrowspec.validatepatterns(excludes)
114 narrowspec.validatepatterns(excludes)
115
115
116 # narrowspec is passed so we should assume that user wants narrow clone
116 # narrowspec is passed so we should assume that user wants narrow clone
117 opts['narrow'] = True
117 opts['narrow'] = True
118 opts['include'].extend(includes)
118 opts['include'].extend(includes)
119 opts['exclude'].extend(excludes)
119 opts['exclude'].extend(excludes)
120
120
121 if opts['narrow']:
121 if opts['narrow']:
122
122
123 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
123 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
124 orig(pullop, kwargs)
124 orig(pullop, kwargs)
125
125
126 if opts.get('depth'):
126 if opts.get('depth'):
127 # TODO: fix exchange._pullbundle2extraprepare()
127 # TODO: fix exchange._pullbundle2extraprepare()
128 kwargs[b'depth'] = opts['depth']
128 kwargs[b'depth'] = opts['depth']
129
129
130 wrappedextraprepare = extensions.wrappedfunction(
130 wrappedextraprepare = extensions.wrappedfunction(
131 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
131 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
132 )
132 )
133
133
134 with wrappedextraprepare:
134 with wrappedextraprepare:
135 return orig(ui, repo, *args, **opts)
135 return orig(ui, repo, *args, **opts)
136
136
137
137
138 def pullnarrowcmd(orig, ui, repo, *args, **opts):
138 def pullnarrowcmd(orig, ui, repo, *args, **opts):
139 """Wraps pull command to allow modifying narrow spec."""
139 """Wraps pull command to allow modifying narrow spec."""
140 wrappedextraprepare = util.nullcontextmanager()
140 wrappedextraprepare = util.nullcontextmanager()
141 if requirements.NARROW_REQUIREMENT in repo.requirements:
141 if requirements.NARROW_REQUIREMENT in repo.requirements:
142
142
143 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
143 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
144 orig(pullop, kwargs)
144 orig(pullop, kwargs)
145 if opts.get('depth'):
145 if opts.get('depth'):
146 kwargs[b'depth'] = opts['depth']
146 kwargs[b'depth'] = opts['depth']
147
147
148 wrappedextraprepare = extensions.wrappedfunction(
148 wrappedextraprepare = extensions.wrappedfunction(
149 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
149 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
150 )
150 )
151
151
152 with wrappedextraprepare:
152 with wrappedextraprepare:
153 return orig(ui, repo, *args, **opts)
153 return orig(ui, repo, *args, **opts)
154
154
155
155
156 def archivenarrowcmd(orig, ui, repo, *args, **opts):
156 def archivenarrowcmd(orig, ui, repo, *args, **opts):
157 """Wraps archive command to narrow the default includes."""
157 """Wraps archive command to narrow the default includes."""
158 if requirements.NARROW_REQUIREMENT in repo.requirements:
158 if requirements.NARROW_REQUIREMENT in repo.requirements:
159 repo_includes, repo_excludes = repo.narrowpats
159 repo_includes, repo_excludes = repo.narrowpats
160 includes = set(opts.get('include', []))
160 includes = set(opts.get('include', []))
161 excludes = set(opts.get('exclude', []))
161 excludes = set(opts.get('exclude', []))
162 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
162 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
163 includes, excludes, repo_includes, repo_excludes
163 includes, excludes, repo_includes, repo_excludes
164 )
164 )
165 if includes:
165 if includes:
166 opts['include'] = includes
166 opts['include'] = includes
167 if excludes:
167 if excludes:
168 opts['exclude'] = excludes
168 opts['exclude'] = excludes
169 return orig(ui, repo, *args, **opts)
169 return orig(ui, repo, *args, **opts)
170
170
171
171
172 def pullbundle2extraprepare(orig, pullop, kwargs):
172 def pullbundle2extraprepare(orig, pullop, kwargs):
173 repo = pullop.repo
173 repo = pullop.repo
174 if requirements.NARROW_REQUIREMENT not in repo.requirements:
174 if requirements.NARROW_REQUIREMENT not in repo.requirements:
175 return orig(pullop, kwargs)
175 return orig(pullop, kwargs)
176
176
177 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
177 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
178 raise error.Abort(_(b"server does not support narrow clones"))
178 raise error.Abort(_(b"server does not support narrow clones"))
179 orig(pullop, kwargs)
179 orig(pullop, kwargs)
180 kwargs[b'narrow'] = True
180 kwargs[b'narrow'] = True
181 include, exclude = repo.narrowpats
181 include, exclude = repo.narrowpats
182 kwargs[b'oldincludepats'] = include
182 kwargs[b'oldincludepats'] = include
183 kwargs[b'oldexcludepats'] = exclude
183 kwargs[b'oldexcludepats'] = exclude
184 if include:
184 if include:
185 kwargs[b'includepats'] = include
185 kwargs[b'includepats'] = include
186 if exclude:
186 if exclude:
187 kwargs[b'excludepats'] = exclude
187 kwargs[b'excludepats'] = exclude
188 # calculate known nodes only in ellipses cases because in non-ellipses cases
188 # calculate known nodes only in ellipses cases because in non-ellipses cases
189 # we have all the nodes
189 # we have all the nodes
190 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities():
190 if wireprototypes.ELLIPSESCAP1 in pullop.remote.capabilities():
191 kwargs[b'known'] = [
191 kwargs[b'known'] = [
192 hex(ctx.node())
192 hex(ctx.node())
193 for ctx in repo.set(b'::%ln', pullop.common)
193 for ctx in repo.set(b'::%ln', pullop.common)
194 if ctx.node() != repo.nullid
194 if ctx.node() != repo.nullid
195 ]
195 ]
196 if not kwargs[b'known']:
196 if not kwargs[b'known']:
197 # Mercurial serializes an empty list as '' and deserializes it as
197 # Mercurial serializes an empty list as '' and deserializes it as
198 # [''], so delete it instead to avoid handling the empty string on
198 # [''], so delete it instead to avoid handling the empty string on
199 # the server.
199 # the server.
200 del kwargs[b'known']
200 del kwargs[b'known']
201
201
202
202
203 extensions.wrapfunction(
203 extensions.wrapfunction(
204 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare
204 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare
205 )
205 )
206
206
207
207
208 def _narrow(
208 def _narrow(
209 ui,
209 ui,
210 repo,
210 repo,
211 remote,
211 remote,
212 commoninc,
212 commoninc,
213 oldincludes,
213 oldincludes,
214 oldexcludes,
214 oldexcludes,
215 newincludes,
215 newincludes,
216 newexcludes,
216 newexcludes,
217 force,
217 force,
218 backup,
218 backup,
219 ):
219 ):
220 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
220 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
221 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
221 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
222
222
223 # This is essentially doing "hg outgoing" to find all local-only
223 # This is essentially doing "hg outgoing" to find all local-only
224 # commits. We will then check that the local-only commits don't
224 # commits. We will then check that the local-only commits don't
225 # have any changes to files that will be untracked.
225 # have any changes to files that will be untracked.
226 unfi = repo.unfiltered()
226 unfi = repo.unfiltered()
227 outgoing = discovery.findcommonoutgoing(unfi, remote, commoninc=commoninc)
227 outgoing = discovery.findcommonoutgoing(unfi, remote, commoninc=commoninc)
228 ui.status(_(b'looking for local changes to affected paths\n'))
228 ui.status(_(b'looking for local changes to affected paths\n'))
229 progress = ui.makeprogress(
229 progress = ui.makeprogress(
230 topic=_(b'changesets'),
230 topic=_(b'changesets'),
231 unit=_(b'changesets'),
231 unit=_(b'changesets'),
232 total=len(outgoing.missing) + len(outgoing.excluded),
232 total=len(outgoing.missing) + len(outgoing.excluded),
233 )
233 )
234 localnodes = []
234 localnodes = []
235 with progress:
235 with progress:
236 for n in itertools.chain(outgoing.missing, outgoing.excluded):
236 for n in itertools.chain(outgoing.missing, outgoing.excluded):
237 progress.increment()
237 progress.increment()
238 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
238 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
239 localnodes.append(n)
239 localnodes.append(n)
240 revstostrip = unfi.revs(b'descendants(%ln)', localnodes)
240 revstostrip = unfi.revs(b'descendants(%ln)', localnodes)
241 hiddenrevs = repoview.filterrevs(repo, b'visible')
241 hiddenrevs = repoview.filterrevs(repo, b'visible')
242 visibletostrip = list(
242 visibletostrip = list(
243 repo.changelog.node(r) for r in (revstostrip - hiddenrevs)
243 repo.changelog.node(r) for r in (revstostrip - hiddenrevs)
244 )
244 )
245 if visibletostrip:
245 if visibletostrip:
246 ui.status(
246 ui.status(
247 _(
247 _(
248 b'The following changeset(s) or their ancestors have '
248 b'The following changeset(s) or their ancestors have '
249 b'local changes not on the remote:\n'
249 b'local changes not on the remote:\n'
250 )
250 )
251 )
251 )
252 maxnodes = 10
252 maxnodes = 10
253 if ui.verbose or len(visibletostrip) <= maxnodes:
253 if ui.verbose or len(visibletostrip) <= maxnodes:
254 for n in visibletostrip:
254 for n in visibletostrip:
255 ui.status(b'%s\n' % short(n))
255 ui.status(b'%s\n' % short(n))
256 else:
256 else:
257 for n in visibletostrip[:maxnodes]:
257 for n in visibletostrip[:maxnodes]:
258 ui.status(b'%s\n' % short(n))
258 ui.status(b'%s\n' % short(n))
259 ui.status(
259 ui.status(
260 _(b'...and %d more, use --verbose to list all\n')
260 _(b'...and %d more, use --verbose to list all\n')
261 % (len(visibletostrip) - maxnodes)
261 % (len(visibletostrip) - maxnodes)
262 )
262 )
263 if not force:
263 if not force:
264 raise error.StateError(
264 raise error.StateError(
265 _(b'local changes found'),
265 _(b'local changes found'),
266 hint=_(b'use --force-delete-local-changes to ignore'),
266 hint=_(b'use --force-delete-local-changes to ignore'),
267 )
267 )
268
268
269 with ui.uninterruptible():
269 with ui.uninterruptible():
270 if revstostrip:
270 if revstostrip:
271 tostrip = [unfi.changelog.node(r) for r in revstostrip]
271 tostrip = [unfi.changelog.node(r) for r in revstostrip]
272 if repo[b'.'].node() in tostrip:
272 if repo[b'.'].node() in tostrip:
273 # stripping working copy, so move to a different commit first
273 # stripping working copy, so move to a different commit first
274 urev = max(
274 urev = max(
275 repo.revs(
275 repo.revs(
276 b'(::%n) - %ln + null',
276 b'(::%n) - %ln + null',
277 repo[b'.'].node(),
277 repo[b'.'].node(),
278 visibletostrip,
278 visibletostrip,
279 )
279 )
280 )
280 )
281 hg.clean(repo, urev)
281 hg.clean(repo, urev)
282 overrides = {(b'devel', b'strip-obsmarkers'): False}
282 overrides = {(b'devel', b'strip-obsmarkers'): False}
283 if backup:
283 if backup:
284 ui.status(_(b'moving unwanted changesets to backup\n'))
284 ui.status(_(b'moving unwanted changesets to backup\n'))
285 else:
285 else:
286 ui.status(_(b'deleting unwanted changesets\n'))
286 ui.status(_(b'deleting unwanted changesets\n'))
287 with ui.configoverride(overrides, b'narrow'):
287 with ui.configoverride(overrides, b'narrow'):
288 repair.strip(ui, unfi, tostrip, topic=b'narrow', backup=backup)
288 repair.strip(ui, unfi, tostrip, topic=b'narrow', backup=backup)
289
289
290 todelete = []
290 todelete = []
291 for entry in repo.store.data_entries():
291 for entry in repo.store.data_entries():
292 if not entry.is_revlog:
292 if not entry.is_revlog:
293 continue
293 continue
294 if entry.is_filelog:
294 if entry.is_filelog:
295 if not newmatch(entry.target_id):
295 if not newmatch(entry.target_id):
296 for file_ in entry.files():
296 for file_ in entry.files():
297 todelete.append(file_.unencoded_path)
297 todelete.append(file_.unencoded_path)
298 elif entry.is_manifestlog:
298 elif entry.is_manifestlog:
299 dir = entry.target_id
299 dir = entry.target_id[:-1]
300 dirs = sorted(pathutil.dirs({dir})) + [dir]
300 dirs = sorted(pathutil.dirs({dir})) + [dir]
301 include = True
301 include = True
302 for d in dirs:
302 for d in dirs:
303 visit = newmatch.visitdir(d)
303 visit = newmatch.visitdir(d)
304 if not visit:
304 if not visit:
305 include = False
305 include = False
306 break
306 break
307 if visit == b'all':
307 if visit == b'all':
308 break
308 break
309 if not include:
309 if not include:
310 for file_ in entry.files():
310 for file_ in entry.files():
311 todelete.append(file_.unencoded_path)
311 todelete.append(file_.unencoded_path)
312
312
313 repo.destroying()
313 repo.destroying()
314
314
315 with repo.transaction(b'narrowing'):
315 with repo.transaction(b'narrowing'):
316 # Update narrowspec before removing revlogs, so repo won't be
316 # Update narrowspec before removing revlogs, so repo won't be
317 # corrupt in case of crash
317 # corrupt in case of crash
318 repo.setnarrowpats(newincludes, newexcludes)
318 repo.setnarrowpats(newincludes, newexcludes)
319
319
320 for f in todelete:
320 for f in todelete:
321 ui.status(_(b'deleting %s\n') % f)
321 ui.status(_(b'deleting %s\n') % f)
322 util.unlinkpath(repo.svfs.join(f))
322 util.unlinkpath(repo.svfs.join(f))
323 repo.store.markremoved(f)
323 repo.store.markremoved(f)
324
324
325 ui.status(_(b'deleting unwanted files from working copy\n'))
325 ui.status(_(b'deleting unwanted files from working copy\n'))
326 with repo.dirstate.changing_parents(repo):
326 with repo.dirstate.changing_parents(repo):
327 narrowspec.updateworkingcopy(repo, assumeclean=True)
327 narrowspec.updateworkingcopy(repo, assumeclean=True)
328 narrowspec.copytoworkingcopy(repo)
328 narrowspec.copytoworkingcopy(repo)
329
329
330 repo.destroyed()
330 repo.destroyed()
331
331
332
332
333 def _widen(
333 def _widen(
334 ui,
334 ui,
335 repo,
335 repo,
336 remote,
336 remote,
337 commoninc,
337 commoninc,
338 oldincludes,
338 oldincludes,
339 oldexcludes,
339 oldexcludes,
340 newincludes,
340 newincludes,
341 newexcludes,
341 newexcludes,
342 ):
342 ):
343 # for now we assume that if a server has ellipses enabled, we will be
343 # for now we assume that if a server has ellipses enabled, we will be
344 # exchanging ellipses nodes. In future we should add ellipses as a client
344 # exchanging ellipses nodes. In future we should add ellipses as a client
345 # side requirement (maybe) to distinguish a client is shallow or not and
345 # side requirement (maybe) to distinguish a client is shallow or not and
346 # then send that information to server whether we want ellipses or not.
346 # then send that information to server whether we want ellipses or not.
347 # Theoretically a non-ellipses repo should be able to use narrow
347 # Theoretically a non-ellipses repo should be able to use narrow
348 # functionality from an ellipses enabled server
348 # functionality from an ellipses enabled server
349 remotecap = remote.capabilities()
349 remotecap = remote.capabilities()
350 ellipsesremote = any(
350 ellipsesremote = any(
351 cap in remotecap for cap in wireprototypes.SUPPORTED_ELLIPSESCAP
351 cap in remotecap for cap in wireprototypes.SUPPORTED_ELLIPSESCAP
352 )
352 )
353
353
354 # check whether we are talking to a server which supports old version of
354 # check whether we are talking to a server which supports old version of
355 # ellipses capabilities
355 # ellipses capabilities
356 isoldellipses = (
356 isoldellipses = (
357 ellipsesremote
357 ellipsesremote
358 and wireprototypes.ELLIPSESCAP1 in remotecap
358 and wireprototypes.ELLIPSESCAP1 in remotecap
359 and wireprototypes.ELLIPSESCAP not in remotecap
359 and wireprototypes.ELLIPSESCAP not in remotecap
360 )
360 )
361
361
362 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
362 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
363 orig(pullop, kwargs)
363 orig(pullop, kwargs)
364 # The old{in,ex}cludepats have already been set by orig()
364 # The old{in,ex}cludepats have already been set by orig()
365 kwargs[b'includepats'] = newincludes
365 kwargs[b'includepats'] = newincludes
366 kwargs[b'excludepats'] = newexcludes
366 kwargs[b'excludepats'] = newexcludes
367
367
368 wrappedextraprepare = extensions.wrappedfunction(
368 wrappedextraprepare = extensions.wrappedfunction(
369 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
369 exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen
370 )
370 )
371
371
372 # define a function that narrowbundle2 can call after creating the
372 # define a function that narrowbundle2 can call after creating the
373 # backup bundle, but before applying the bundle from the server
373 # backup bundle, but before applying the bundle from the server
374 def setnewnarrowpats():
374 def setnewnarrowpats():
375 repo.setnarrowpats(newincludes, newexcludes)
375 repo.setnarrowpats(newincludes, newexcludes)
376
376
377 repo.setnewnarrowpats = setnewnarrowpats
377 repo.setnewnarrowpats = setnewnarrowpats
378 # silence the devel-warning of applying an empty changegroup
378 # silence the devel-warning of applying an empty changegroup
379 overrides = {(b'devel', b'all-warnings'): False}
379 overrides = {(b'devel', b'all-warnings'): False}
380
380
381 common = commoninc[0]
381 common = commoninc[0]
382 with ui.uninterruptible():
382 with ui.uninterruptible():
383 if ellipsesremote:
383 if ellipsesremote:
384 ds = repo.dirstate
384 ds = repo.dirstate
385 p1, p2 = ds.p1(), ds.p2()
385 p1, p2 = ds.p1(), ds.p2()
386 with ds.changing_parents(repo):
386 with ds.changing_parents(repo):
387 ds.setparents(repo.nullid, repo.nullid)
387 ds.setparents(repo.nullid, repo.nullid)
388 if isoldellipses:
388 if isoldellipses:
389 with wrappedextraprepare:
389 with wrappedextraprepare:
390 exchange.pull(repo, remote, heads=common)
390 exchange.pull(repo, remote, heads=common)
391 else:
391 else:
392 known = []
392 known = []
393 if ellipsesremote:
393 if ellipsesremote:
394 known = [
394 known = [
395 ctx.node()
395 ctx.node()
396 for ctx in repo.set(b'::%ln', common)
396 for ctx in repo.set(b'::%ln', common)
397 if ctx.node() != repo.nullid
397 if ctx.node() != repo.nullid
398 ]
398 ]
399 with remote.commandexecutor() as e:
399 with remote.commandexecutor() as e:
400 bundle = e.callcommand(
400 bundle = e.callcommand(
401 b'narrow_widen',
401 b'narrow_widen',
402 {
402 {
403 b'oldincludes': oldincludes,
403 b'oldincludes': oldincludes,
404 b'oldexcludes': oldexcludes,
404 b'oldexcludes': oldexcludes,
405 b'newincludes': newincludes,
405 b'newincludes': newincludes,
406 b'newexcludes': newexcludes,
406 b'newexcludes': newexcludes,
407 b'cgversion': b'03',
407 b'cgversion': b'03',
408 b'commonheads': common,
408 b'commonheads': common,
409 b'known': known,
409 b'known': known,
410 b'ellipses': ellipsesremote,
410 b'ellipses': ellipsesremote,
411 },
411 },
412 ).result()
412 ).result()
413
413
414 trmanager = exchange.transactionmanager(
414 trmanager = exchange.transactionmanager(
415 repo, b'widen', remote.url()
415 repo, b'widen', remote.url()
416 )
416 )
417 with trmanager, repo.ui.configoverride(overrides, b'widen'):
417 with trmanager, repo.ui.configoverride(overrides, b'widen'):
418 op = bundle2.bundleoperation(
418 op = bundle2.bundleoperation(
419 repo, trmanager.transaction, source=b'widen'
419 repo, trmanager.transaction, source=b'widen'
420 )
420 )
421 # TODO: we should catch error.Abort here
421 # TODO: we should catch error.Abort here
422 bundle2.processbundle(repo, bundle, op=op, remote=remote)
422 bundle2.processbundle(repo, bundle, op=op, remote=remote)
423
423
424 if ellipsesremote:
424 if ellipsesremote:
425 with ds.changing_parents(repo):
425 with ds.changing_parents(repo):
426 ds.setparents(p1, p2)
426 ds.setparents(p1, p2)
427
427
428 with repo.transaction(b'widening'), repo.dirstate.changing_parents(
428 with repo.transaction(b'widening'), repo.dirstate.changing_parents(
429 repo
429 repo
430 ):
430 ):
431 repo.setnewnarrowpats()
431 repo.setnewnarrowpats()
432 narrowspec.updateworkingcopy(repo)
432 narrowspec.updateworkingcopy(repo)
433 narrowspec.copytoworkingcopy(repo)
433 narrowspec.copytoworkingcopy(repo)
434
434
435
435
436 # TODO(rdamazio): Make new matcher format and update description
436 # TODO(rdamazio): Make new matcher format and update description
437 @command(
437 @command(
438 b'tracked',
438 b'tracked',
439 [
439 [
440 (b'', b'addinclude', [], _(b'new paths to include')),
440 (b'', b'addinclude', [], _(b'new paths to include')),
441 (b'', b'removeinclude', [], _(b'old paths to no longer include')),
441 (b'', b'removeinclude', [], _(b'old paths to no longer include')),
442 (
442 (
443 b'',
443 b'',
444 b'auto-remove-includes',
444 b'auto-remove-includes',
445 False,
445 False,
446 _(b'automatically choose unused includes to remove'),
446 _(b'automatically choose unused includes to remove'),
447 ),
447 ),
448 (b'', b'addexclude', [], _(b'new paths to exclude')),
448 (b'', b'addexclude', [], _(b'new paths to exclude')),
449 (b'', b'import-rules', b'', _(b'import narrowspecs from a file')),
449 (b'', b'import-rules', b'', _(b'import narrowspecs from a file')),
450 (b'', b'removeexclude', [], _(b'old paths to no longer exclude')),
450 (b'', b'removeexclude', [], _(b'old paths to no longer exclude')),
451 (
451 (
452 b'',
452 b'',
453 b'clear',
453 b'clear',
454 False,
454 False,
455 _(b'whether to replace the existing narrowspec'),
455 _(b'whether to replace the existing narrowspec'),
456 ),
456 ),
457 (
457 (
458 b'',
458 b'',
459 b'force-delete-local-changes',
459 b'force-delete-local-changes',
460 False,
460 False,
461 _(b'forces deletion of local changes when narrowing'),
461 _(b'forces deletion of local changes when narrowing'),
462 ),
462 ),
463 (
463 (
464 b'',
464 b'',
465 b'backup',
465 b'backup',
466 True,
466 True,
467 _(b'back up local changes when narrowing'),
467 _(b'back up local changes when narrowing'),
468 ),
468 ),
469 (
469 (
470 b'',
470 b'',
471 b'update-working-copy',
471 b'update-working-copy',
472 False,
472 False,
473 _(b'update working copy when the store has changed'),
473 _(b'update working copy when the store has changed'),
474 ),
474 ),
475 ]
475 ]
476 + commands.remoteopts,
476 + commands.remoteopts,
477 _(b'[OPTIONS]... [REMOTE]'),
477 _(b'[OPTIONS]... [REMOTE]'),
478 inferrepo=True,
478 inferrepo=True,
479 helpcategory=command.CATEGORY_MAINTENANCE,
479 helpcategory=command.CATEGORY_MAINTENANCE,
480 )
480 )
481 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
481 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
482 """show or change the current narrowspec
482 """show or change the current narrowspec
483
483
484 With no argument, shows the current narrowspec entries, one per line. Each
484 With no argument, shows the current narrowspec entries, one per line. Each
485 line will be prefixed with 'I' or 'X' for included or excluded patterns,
485 line will be prefixed with 'I' or 'X' for included or excluded patterns,
486 respectively.
486 respectively.
487
487
488 The narrowspec is comprised of expressions to match remote files and/or
488 The narrowspec is comprised of expressions to match remote files and/or
489 directories that should be pulled into your client.
489 directories that should be pulled into your client.
490 The narrowspec has *include* and *exclude* expressions, with excludes always
490 The narrowspec has *include* and *exclude* expressions, with excludes always
491 trumping includes: that is, if a file matches an exclude expression, it will
491 trumping includes: that is, if a file matches an exclude expression, it will
492 be excluded even if it also matches an include expression.
492 be excluded even if it also matches an include expression.
493 Excluding files that were never included has no effect.
493 Excluding files that were never included has no effect.
494
494
495 Each included or excluded entry is in the format described by
495 Each included or excluded entry is in the format described by
496 'hg help patterns'.
496 'hg help patterns'.
497
497
498 The options allow you to add or remove included and excluded expressions.
498 The options allow you to add or remove included and excluded expressions.
499
499
500 If --clear is specified, then all previous includes and excludes are DROPPED
500 If --clear is specified, then all previous includes and excludes are DROPPED
501 and replaced by the new ones specified to --addinclude and --addexclude.
501 and replaced by the new ones specified to --addinclude and --addexclude.
502 If --clear is specified without any further options, the narrowspec will be
502 If --clear is specified without any further options, the narrowspec will be
503 empty and will not match any files.
503 empty and will not match any files.
504
504
505 If --auto-remove-includes is specified, then those includes that don't match
505 If --auto-remove-includes is specified, then those includes that don't match
506 any files modified by currently visible local commits (those not shared by
506 any files modified by currently visible local commits (those not shared by
507 the remote) will be added to the set of explicitly specified includes to
507 the remote) will be added to the set of explicitly specified includes to
508 remove.
508 remove.
509
509
510 --import-rules accepts a path to a file containing rules, allowing you to
510 --import-rules accepts a path to a file containing rules, allowing you to
511 add --addinclude, --addexclude rules in bulk. Like the other include and
511 add --addinclude, --addexclude rules in bulk. Like the other include and
512 exclude switches, the changes are applied immediately.
512 exclude switches, the changes are applied immediately.
513 """
513 """
514 if requirements.NARROW_REQUIREMENT not in repo.requirements:
514 if requirements.NARROW_REQUIREMENT not in repo.requirements:
515 raise error.InputError(
515 raise error.InputError(
516 _(
516 _(
517 b'the tracked command is only supported on '
517 b'the tracked command is only supported on '
518 b'repositories cloned with --narrow'
518 b'repositories cloned with --narrow'
519 )
519 )
520 )
520 )
521
521
522 # Before supporting, decide whether it "hg tracked --clear" should mean
522 # Before supporting, decide whether it "hg tracked --clear" should mean
523 # tracking no paths or all paths.
523 # tracking no paths or all paths.
524 if opts['clear']:
524 if opts['clear']:
525 raise error.InputError(_(b'the --clear option is not yet supported'))
525 raise error.InputError(_(b'the --clear option is not yet supported'))
526
526
527 # import rules from a file
527 # import rules from a file
528 newrules = opts.get('import_rules')
528 newrules = opts.get('import_rules')
529 if newrules:
529 if newrules:
530 filepath = os.path.join(encoding.getcwd(), newrules)
530 filepath = os.path.join(encoding.getcwd(), newrules)
531 try:
531 try:
532 fdata = util.readfile(filepath)
532 fdata = util.readfile(filepath)
533 except IOError as inst:
533 except IOError as inst:
534 raise error.StorageError(
534 raise error.StorageError(
535 _(b"cannot read narrowspecs from '%s': %s")
535 _(b"cannot read narrowspecs from '%s': %s")
536 % (filepath, encoding.strtolocal(inst.strerror))
536 % (filepath, encoding.strtolocal(inst.strerror))
537 )
537 )
538 includepats, excludepats, profiles = sparse.parseconfig(
538 includepats, excludepats, profiles = sparse.parseconfig(
539 ui, fdata, b'narrow'
539 ui, fdata, b'narrow'
540 )
540 )
541 if profiles:
541 if profiles:
542 raise error.InputError(
542 raise error.InputError(
543 _(
543 _(
544 b"including other spec files using '%include' "
544 b"including other spec files using '%include' "
545 b"is not supported in narrowspec"
545 b"is not supported in narrowspec"
546 )
546 )
547 )
547 )
548 opts['addinclude'].extend(includepats)
548 opts['addinclude'].extend(includepats)
549 opts['addexclude'].extend(excludepats)
549 opts['addexclude'].extend(excludepats)
550
550
551 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
551 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
552 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
552 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
553 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
553 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
554 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
554 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
555 autoremoveincludes = opts['auto_remove_includes']
555 autoremoveincludes = opts['auto_remove_includes']
556
556
557 update_working_copy = opts['update_working_copy']
557 update_working_copy = opts['update_working_copy']
558 only_show = not (
558 only_show = not (
559 addedincludes
559 addedincludes
560 or removedincludes
560 or removedincludes
561 or addedexcludes
561 or addedexcludes
562 or removedexcludes
562 or removedexcludes
563 or newrules
563 or newrules
564 or autoremoveincludes
564 or autoremoveincludes
565 or update_working_copy
565 or update_working_copy
566 )
566 )
567
567
568 # Only print the current narrowspec.
568 # Only print the current narrowspec.
569 if only_show:
569 if only_show:
570 oldincludes, oldexcludes = repo.narrowpats
570 oldincludes, oldexcludes = repo.narrowpats
571 ui.pager(b'tracked')
571 ui.pager(b'tracked')
572 fm = ui.formatter(b'narrow', pycompat.byteskwargs(opts))
572 fm = ui.formatter(b'narrow', pycompat.byteskwargs(opts))
573 for i in sorted(oldincludes):
573 for i in sorted(oldincludes):
574 fm.startitem()
574 fm.startitem()
575 fm.write(b'status', b'%s ', b'I', label=b'narrow.included')
575 fm.write(b'status', b'%s ', b'I', label=b'narrow.included')
576 fm.write(b'pat', b'%s\n', i, label=b'narrow.included')
576 fm.write(b'pat', b'%s\n', i, label=b'narrow.included')
577 for i in sorted(oldexcludes):
577 for i in sorted(oldexcludes):
578 fm.startitem()
578 fm.startitem()
579 fm.write(b'status', b'%s ', b'X', label=b'narrow.excluded')
579 fm.write(b'status', b'%s ', b'X', label=b'narrow.excluded')
580 fm.write(b'pat', b'%s\n', i, label=b'narrow.excluded')
580 fm.write(b'pat', b'%s\n', i, label=b'narrow.excluded')
581 fm.end()
581 fm.end()
582 return 0
582 return 0
583
583
584 with repo.wlock(), repo.lock():
584 with repo.wlock(), repo.lock():
585 oldincludes, oldexcludes = repo.narrowpats
585 oldincludes, oldexcludes = repo.narrowpats
586
586
587 # filter the user passed additions and deletions into actual additions and
587 # filter the user passed additions and deletions into actual additions and
588 # deletions of excludes and includes
588 # deletions of excludes and includes
589 addedincludes -= oldincludes
589 addedincludes -= oldincludes
590 removedincludes &= oldincludes
590 removedincludes &= oldincludes
591 addedexcludes -= oldexcludes
591 addedexcludes -= oldexcludes
592 removedexcludes &= oldexcludes
592 removedexcludes &= oldexcludes
593
593
594 widening = addedincludes or removedexcludes
594 widening = addedincludes or removedexcludes
595 narrowing = removedincludes or addedexcludes
595 narrowing = removedincludes or addedexcludes
596
596
597 if update_working_copy:
597 if update_working_copy:
598 with repo.transaction(b'narrow-wc'), repo.dirstate.changing_parents(
598 with repo.transaction(b'narrow-wc'), repo.dirstate.changing_parents(
599 repo
599 repo
600 ):
600 ):
601 narrowspec.updateworkingcopy(repo)
601 narrowspec.updateworkingcopy(repo)
602 narrowspec.copytoworkingcopy(repo)
602 narrowspec.copytoworkingcopy(repo)
603 return 0
603 return 0
604
604
605 if not (widening or narrowing or autoremoveincludes):
605 if not (widening or narrowing or autoremoveincludes):
606 ui.status(_(b"nothing to widen or narrow\n"))
606 ui.status(_(b"nothing to widen or narrow\n"))
607 return 0
607 return 0
608
608
609 cmdutil.bailifchanged(repo)
609 cmdutil.bailifchanged(repo)
610
610
611 # Find the revisions we have in common with the remote. These will
611 # Find the revisions we have in common with the remote. These will
612 # be used for finding local-only changes for narrowing. They will
612 # be used for finding local-only changes for narrowing. They will
613 # also define the set of revisions to update for widening.
613 # also define the set of revisions to update for widening.
614 path = urlutil.get_unique_pull_path_obj(b'tracked', ui, remotepath)
614 path = urlutil.get_unique_pull_path_obj(b'tracked', ui, remotepath)
615 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
615 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
616 remote = hg.peer(repo, pycompat.byteskwargs(opts), path)
616 remote = hg.peer(repo, pycompat.byteskwargs(opts), path)
617
617
618 try:
618 try:
619 # check narrow support before doing anything if widening needs to be
619 # check narrow support before doing anything if widening needs to be
620 # performed. In future we should also abort if client is ellipses and
620 # performed. In future we should also abort if client is ellipses and
621 # server does not support ellipses
621 # server does not support ellipses
622 if (
622 if (
623 widening
623 widening
624 and wireprototypes.NARROWCAP not in remote.capabilities()
624 and wireprototypes.NARROWCAP not in remote.capabilities()
625 ):
625 ):
626 raise error.Abort(_(b"server does not support narrow clones"))
626 raise error.Abort(_(b"server does not support narrow clones"))
627
627
628 commoninc = discovery.findcommonincoming(repo, remote)
628 commoninc = discovery.findcommonincoming(repo, remote)
629
629
630 if autoremoveincludes:
630 if autoremoveincludes:
631 outgoing = discovery.findcommonoutgoing(
631 outgoing = discovery.findcommonoutgoing(
632 repo, remote, commoninc=commoninc
632 repo, remote, commoninc=commoninc
633 )
633 )
634 ui.status(_(b'looking for unused includes to remove\n'))
634 ui.status(_(b'looking for unused includes to remove\n'))
635 localfiles = set()
635 localfiles = set()
636 for n in itertools.chain(outgoing.missing, outgoing.excluded):
636 for n in itertools.chain(outgoing.missing, outgoing.excluded):
637 localfiles.update(repo[n].files())
637 localfiles.update(repo[n].files())
638 suggestedremovals = []
638 suggestedremovals = []
639 for include in sorted(oldincludes):
639 for include in sorted(oldincludes):
640 match = narrowspec.match(repo.root, [include], oldexcludes)
640 match = narrowspec.match(repo.root, [include], oldexcludes)
641 if not any(match(f) for f in localfiles):
641 if not any(match(f) for f in localfiles):
642 suggestedremovals.append(include)
642 suggestedremovals.append(include)
643 if suggestedremovals:
643 if suggestedremovals:
644 for s in suggestedremovals:
644 for s in suggestedremovals:
645 ui.status(b'%s\n' % s)
645 ui.status(b'%s\n' % s)
646 if (
646 if (
647 ui.promptchoice(
647 ui.promptchoice(
648 _(
648 _(
649 b'remove these unused includes (Yn)?'
649 b'remove these unused includes (Yn)?'
650 b'$$ &Yes $$ &No'
650 b'$$ &Yes $$ &No'
651 )
651 )
652 )
652 )
653 == 0
653 == 0
654 ):
654 ):
655 removedincludes.update(suggestedremovals)
655 removedincludes.update(suggestedremovals)
656 narrowing = True
656 narrowing = True
657 else:
657 else:
658 ui.status(_(b'found no unused includes\n'))
658 ui.status(_(b'found no unused includes\n'))
659
659
660 if narrowing:
660 if narrowing:
661 newincludes = oldincludes - removedincludes
661 newincludes = oldincludes - removedincludes
662 newexcludes = oldexcludes | addedexcludes
662 newexcludes = oldexcludes | addedexcludes
663 _narrow(
663 _narrow(
664 ui,
664 ui,
665 repo,
665 repo,
666 remote,
666 remote,
667 commoninc,
667 commoninc,
668 oldincludes,
668 oldincludes,
669 oldexcludes,
669 oldexcludes,
670 newincludes,
670 newincludes,
671 newexcludes,
671 newexcludes,
672 opts['force_delete_local_changes'],
672 opts['force_delete_local_changes'],
673 opts['backup'],
673 opts['backup'],
674 )
674 )
675 # _narrow() updated the narrowspec and _widen() below needs to
675 # _narrow() updated the narrowspec and _widen() below needs to
676 # use the updated values as its base (otherwise removed includes
676 # use the updated values as its base (otherwise removed includes
677 # and addedexcludes will be lost in the resulting narrowspec)
677 # and addedexcludes will be lost in the resulting narrowspec)
678 oldincludes = newincludes
678 oldincludes = newincludes
679 oldexcludes = newexcludes
679 oldexcludes = newexcludes
680
680
681 if widening:
681 if widening:
682 newincludes = oldincludes | addedincludes
682 newincludes = oldincludes | addedincludes
683 newexcludes = oldexcludes - removedexcludes
683 newexcludes = oldexcludes - removedexcludes
684 _widen(
684 _widen(
685 ui,
685 ui,
686 repo,
686 repo,
687 remote,
687 remote,
688 commoninc,
688 commoninc,
689 oldincludes,
689 oldincludes,
690 oldexcludes,
690 oldexcludes,
691 newincludes,
691 newincludes,
692 newexcludes,
692 newexcludes,
693 )
693 )
694 finally:
694 finally:
695 remote.close()
695 remote.close()
696
696
697 return 0
697 return 0
@@ -1,574 +1,560 b''
1 #testcases flat tree
1 #testcases flat tree
2 #testcases lfs-on lfs-off
2 #testcases lfs-on lfs-off
3
3
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [experimental]
5 > [experimental]
6 > evolution=createmarkers
6 > evolution=createmarkers
7 > EOF
7 > EOF
8
8
9 #if lfs-on
9 #if lfs-on
10 $ cat >> $HGRCPATH <<EOF
10 $ cat >> $HGRCPATH <<EOF
11 > [extensions]
11 > [extensions]
12 > lfs =
12 > lfs =
13 > EOF
13 > EOF
14 #endif
14 #endif
15
15
16 $ . "$TESTDIR/narrow-library.sh"
16 $ . "$TESTDIR/narrow-library.sh"
17
17
18 #if tree
18 #if tree
19 $ cat << EOF >> $HGRCPATH
19 $ cat << EOF >> $HGRCPATH
20 > [experimental]
20 > [experimental]
21 > treemanifest = 1
21 > treemanifest = 1
22 > EOF
22 > EOF
23 #endif
23 #endif
24
24
25 $ hg init master
25 $ hg init master
26 $ cd master
26 $ cd master
27 $ cat >> .hg/hgrc <<EOF
27 $ cat >> .hg/hgrc <<EOF
28 > [narrow]
28 > [narrow]
29 > serveellipses=True
29 > serveellipses=True
30 > EOF
30 > EOF
31 $ for x in `$TESTDIR/seq.py 0 10`
31 $ for x in `$TESTDIR/seq.py 0 10`
32 > do
32 > do
33 > mkdir d$x
33 > mkdir d$x
34 > echo $x > d$x/f
34 > echo $x > d$x/f
35 > hg add d$x/f
35 > hg add d$x/f
36 > hg commit -m "add d$x/f"
36 > hg commit -m "add d$x/f"
37 > done
37 > done
38 $ hg log -T "{rev}: {desc}\n"
38 $ hg log -T "{rev}: {desc}\n"
39 10: add d10/f
39 10: add d10/f
40 9: add d9/f
40 9: add d9/f
41 8: add d8/f
41 8: add d8/f
42 7: add d7/f
42 7: add d7/f
43 6: add d6/f
43 6: add d6/f
44 5: add d5/f
44 5: add d5/f
45 4: add d4/f
45 4: add d4/f
46 3: add d3/f
46 3: add d3/f
47 2: add d2/f
47 2: add d2/f
48 1: add d1/f
48 1: add d1/f
49 0: add d0/f
49 0: add d0/f
50 $ cd ..
50 $ cd ..
51
51
52 Error if '.' or '..' are in the directory to track.
52 Error if '.' or '..' are in the directory to track.
53 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
53 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
54 abort: "." and ".." are not allowed in narrowspec paths
54 abort: "." and ".." are not allowed in narrowspec paths
55 [255]
55 [255]
56 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
56 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
57 abort: "." and ".." are not allowed in narrowspec paths
57 abort: "." and ".." are not allowed in narrowspec paths
58 [255]
58 [255]
59 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
59 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
60 abort: "." and ".." are not allowed in narrowspec paths
60 abort: "." and ".." are not allowed in narrowspec paths
61 [255]
61 [255]
62
62
63 Names with '.' in them are OK.
63 Names with '.' in them are OK.
64 $ hg clone --narrow ./master should-work --include a/.b/c
64 $ hg clone --narrow ./master should-work --include a/.b/c
65 requesting all changes
65 requesting all changes
66 adding changesets
66 adding changesets
67 adding manifests
67 adding manifests
68 adding file changes
68 adding file changes
69 added 1 changesets with 0 changes to 0 files
69 added 1 changesets with 0 changes to 0 files
70 new changesets * (glob)
70 new changesets * (glob)
71 updating to branch default
71 updating to branch default
72 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
73
73
74 The "narrow" repo requirement is ignored by [debugupgraderepo]
74 The "narrow" repo requirement is ignored by [debugupgraderepo]
75
75
76 $ (cd should-work; hg debugupgraderepo | grep 'no format upgrades found in existing repository')
76 $ (cd should-work; hg debugupgraderepo | grep 'no format upgrades found in existing repository')
77 (no format upgrades found in existing repository)
77 (no format upgrades found in existing repository)
78
78
79 Test repo with local changes
79 Test repo with local changes
80 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
80 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
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 3 changes to 3 files
85 added 6 changesets with 3 changes to 3 files
86 new changesets *:* (glob)
86 new changesets *:* (glob)
87 updating to branch default
87 updating to branch default
88 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ cd narrow-local-changes
89 $ cd narrow-local-changes
90 $ echo local change >> d0/f
90 $ echo local change >> d0/f
91 $ hg ci -m 'local change to d0'
91 $ hg ci -m 'local change to d0'
92 $ hg co '.^'
92 $ hg co '.^'
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 $ echo local change >> d3/f
94 $ echo local change >> d3/f
95 $ hg ci -m 'local hidden change to d3'
95 $ hg ci -m 'local hidden change to d3'
96 created new head
96 created new head
97 $ hg ci --amend -m 'local change to d3'
97 $ hg ci --amend -m 'local change to d3'
98 $ hg tracked --removeinclude d0
98 $ hg tracked --removeinclude d0
99 comparing with ssh://user@dummy/master
99 comparing with ssh://user@dummy/master
100 searching for changes
100 searching for changes
101 looking for local changes to affected paths
101 looking for local changes to affected paths
102 The following changeset(s) or their ancestors have local changes not on the remote:
102 The following changeset(s) or their ancestors have local changes not on the remote:
103 * (glob)
103 * (glob)
104 abort: local changes found
104 abort: local changes found
105 (use --force-delete-local-changes to ignore)
105 (use --force-delete-local-changes to ignore)
106 [20]
106 [20]
107 Check that nothing was removed by the failed attempts
107 Check that nothing was removed by the failed attempts
108 $ hg tracked
108 $ hg tracked
109 I path:d0
109 I path:d0
110 I path:d3
110 I path:d3
111 I path:d6
111 I path:d6
112 $ hg files
112 $ hg files
113 d0/f
113 d0/f
114 d3/f
114 d3/f
115 d6/f
115 d6/f
116 $ find *
116 $ find *
117 d0
117 d0
118 d0/f
118 d0/f
119 d3
119 d3
120 d3/f
120 d3/f
121 d6
121 d6
122 d6/f
122 d6/f
123 $ hg verify -q
123 $ hg verify -q
124 Force deletion of local changes
124 Force deletion of local changes
125 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
125 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
126 8: local change to d3
126 8: local change to d3
127 6: local change to d0
127 6: local change to d0
128 5: add d10/f outsidenarrow
128 5: add d10/f outsidenarrow
129 4: add d6/f
129 4: add d6/f
130 3: add d5/f outsidenarrow
130 3: add d5/f outsidenarrow
131 2: add d3/f
131 2: add d3/f
132 1: add d2/f outsidenarrow
132 1: add d2/f outsidenarrow
133 0: add d0/f
133 0: add d0/f
134 $ hg tracked --removeinclude d0 --force-delete-local-changes
134 $ hg tracked --removeinclude d0 --force-delete-local-changes
135 comparing with ssh://user@dummy/master
135 comparing with ssh://user@dummy/master
136 searching for changes
136 searching for changes
137 looking for local changes to affected paths
137 looking for local changes to affected paths
138 The following changeset(s) or their ancestors have local changes not on the remote:
138 The following changeset(s) or their ancestors have local changes not on the remote:
139 * (glob)
139 * (glob)
140 moving unwanted changesets to backup
140 moving unwanted changesets to backup
141 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
141 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
142 deleting data/d0/f.i (reporevlogstore !)
142 deleting data/d0/f.i (reporevlogstore !)
143 deleting meta/d0/00manifest.i (tree !)
143 deleting meta/d0/00manifest.i (tree !)
144 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
144 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
145 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
145 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
146 deleting data/d0/f/index (reposimplestore !)
146 deleting data/d0/f/index (reposimplestore !)
147 deleting unwanted files from working copy
147 deleting unwanted files from working copy
148
148
149 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
149 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
150 7: local change to d3
150 7: local change to d3
151 5: add d10/f outsidenarrow
151 5: add d10/f outsidenarrow
152 4: add d6/f
152 4: add d6/f
153 3: add d5/f outsidenarrow
153 3: add d5/f outsidenarrow
154 2: add d3/f
154 2: add d3/f
155 1: add d2/f outsidenarrow
155 1: add d2/f outsidenarrow
156 0: add d0/f outsidenarrow
156 0: add d0/f outsidenarrow
157 Can restore stripped local changes after widening
157 Can restore stripped local changes after widening
158 $ hg tracked --addinclude d0 -q
158 $ hg tracked --addinclude d0 -q
159 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
159 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
160 $ hg --hidden co -r 'desc("local change to d0")' -q
160 $ hg --hidden co -r 'desc("local change to d0")' -q
161 $ cat d0/f
161 $ cat d0/f
162 0
162 0
163 local change
163 local change
164 Pruned commits affecting removed paths should not prevent narrowing
164 Pruned commits affecting removed paths should not prevent narrowing
165 $ hg co '.^'
165 $ hg co '.^'
166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
167 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
168 1 new obsolescence markers
168 1 new obsolescence markers
169 obsoleted 1 changesets
169 obsoleted 1 changesets
170 $ hg tracked --removeinclude d0
170 $ hg tracked --removeinclude d0
171 comparing with ssh://user@dummy/master
171 comparing with ssh://user@dummy/master
172 searching for changes
172 searching for changes
173 looking for local changes to affected paths
173 looking for local changes to affected paths
174 moving unwanted changesets to backup
174 moving unwanted changesets to backup
175 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
175 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
176 deleting data/d0/f.i (reporevlogstore !)
176 deleting data/d0/f.i (reporevlogstore !)
177 deleting meta/d0/00manifest.i (tree !)
177 deleting meta/d0/00manifest.i (tree !)
178 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
178 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
179 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
179 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
180 deleting data/d0/f/index (reposimplestore !)
180 deleting data/d0/f/index (reposimplestore !)
181 deleting unwanted files from working copy
181 deleting unwanted files from working copy
182
182
183 Updates off of stripped commit if necessary
183 Updates off of stripped commit if necessary
184 $ hg co -r 'desc("local change to d3")' -q
184 $ hg co -r 'desc("local change to d3")' -q
185 $ echo local change >> d6/f
185 $ echo local change >> d6/f
186 $ hg ci -m 'local change to d6'
186 $ hg ci -m 'local change to d6'
187 $ hg tracked --removeinclude d3 --force-delete-local-changes
187 $ hg tracked --removeinclude d3 --force-delete-local-changes
188 comparing with ssh://user@dummy/master
188 comparing with ssh://user@dummy/master
189 searching for changes
189 searching for changes
190 looking for local changes to affected paths
190 looking for local changes to affected paths
191 The following changeset(s) or their ancestors have local changes not on the remote:
191 The following changeset(s) or their ancestors have local changes not on the remote:
192 * (glob)
192 * (glob)
193 * (glob)
193 * (glob)
194 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
195 moving unwanted changesets to backup
195 moving unwanted changesets to backup
196 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
196 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
197 deleting data/d3/f.i (reporevlogstore !)
197 deleting data/d3/f.i (reporevlogstore !)
198 deleting meta/d3/00manifest.i (tree !)
198 deleting meta/d3/00manifest.i (tree !)
199 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
199 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
200 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
200 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
201 deleting data/d3/f/index (reposimplestore !)
201 deleting data/d3/f/index (reposimplestore !)
202 deleting unwanted files from working copy
202 deleting unwanted files from working copy
203 $ hg log -T '{desc}\n' -r .
203 $ hg log -T '{desc}\n' -r .
204 add d10/f
204 add d10/f
205 Updates to nullid if necessary
205 Updates to nullid if necessary
206 $ hg tracked --addinclude d3 -q
206 $ hg tracked --addinclude d3 -q
207 $ hg co null -q
207 $ hg co null -q
208 $ mkdir d3
208 $ mkdir d3
209 $ echo local change > d3/f
209 $ echo local change > d3/f
210 $ hg add d3/f
210 $ hg add d3/f
211 $ hg ci -m 'local change to d3'
211 $ hg ci -m 'local change to d3'
212 created new head
212 created new head
213 $ hg tracked --removeinclude d3 --force-delete-local-changes
213 $ hg tracked --removeinclude d3 --force-delete-local-changes
214 comparing with ssh://user@dummy/master
214 comparing with ssh://user@dummy/master
215 searching for changes
215 searching for changes
216 looking for local changes to affected paths
216 looking for local changes to affected paths
217 The following changeset(s) or their ancestors have local changes not on the remote:
217 The following changeset(s) or their ancestors have local changes not on the remote:
218 * (glob)
218 * (glob)
219 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
219 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
220 moving unwanted changesets to backup
220 moving unwanted changesets to backup
221 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
221 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
222 deleting data/d3/f.i (reporevlogstore !)
222 deleting data/d3/f.i (reporevlogstore !)
223 deleting meta/d3/00manifest.i (tree !)
223 deleting meta/d3/00manifest.i (tree !)
224 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
224 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
225 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
225 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
226 deleting data/d3/f/index (reposimplestore !)
226 deleting data/d3/f/index (reposimplestore !)
227 deleting unwanted files from working copy
227 deleting unwanted files from working copy
228 $ hg id
228 $ hg id
229 000000000000
229 000000000000
230 $ cd ..
230 $ cd ..
231
231
232 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
232 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
233 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
233 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
234 $ cd narrow-obsmarkers
234 $ cd narrow-obsmarkers
235 $ echo a >> d0/f2
235 $ echo a >> d0/f2
236 $ hg add d0/f2
236 $ hg add d0/f2
237 $ hg ci -m 'modify d0/'
237 $ hg ci -m 'modify d0/'
238 $ echo a >> d3/f2
238 $ echo a >> d3/f2
239 $ hg add d3/f2
239 $ hg add d3/f2
240 $ hg commit --amend -m 'modify d0/ and d3/'
240 $ hg commit --amend -m 'modify d0/ and d3/'
241 $ hg log -T "{rev}: {desc}\n"
241 $ hg log -T "{rev}: {desc}\n"
242 5: modify d0/ and d3/
242 5: modify d0/ and d3/
243 3: add d10/f
243 3: add d10/f
244 2: add d3/f
244 2: add d3/f
245 1: add d2/f
245 1: add d2/f
246 0: add d0/f
246 0: add d0/f
247 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
247 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
248 $ hg log -T "{rev}: {desc}\n"
248 $ hg log -T "{rev}: {desc}\n"
249 3: add d10/f
249 3: add d10/f
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 Widening doesn't lose bookmarks
255 Widening doesn't lose bookmarks
256 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
256 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
257 $ cd widen-bookmarks
257 $ cd widen-bookmarks
258 $ hg bookmark my-bookmark
258 $ hg bookmark my-bookmark
259 $ hg log -T "{rev}: {desc} {bookmarks}\n"
259 $ hg log -T "{rev}: {desc} {bookmarks}\n"
260 1: add d10/f my-bookmark
260 1: add d10/f my-bookmark
261 0: add d0/f
261 0: add d0/f
262 $ hg tracked --addinclude d3 -q
262 $ hg tracked --addinclude d3 -q
263 $ hg log -T "{rev}: {desc} {bookmarks}\n"
263 $ hg log -T "{rev}: {desc} {bookmarks}\n"
264 3: add d10/f my-bookmark
264 3: add d10/f my-bookmark
265 2: add d3/f
265 2: add d3/f
266 1: add d2/f
266 1: add d2/f
267 0: add d0/f
267 0: add d0/f
268 $ cd ..
268 $ cd ..
269
269
270 Can remove last include, making repo empty
270 Can remove last include, making repo empty
271 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
271 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
272 adding changesets
272 adding changesets
273 adding manifests
273 adding manifests
274 adding file changes
274 adding file changes
275 added 2 changesets with 1 changes to 1 files
275 added 2 changesets with 1 changes to 1 files
276 new changesets *:* (glob)
276 new changesets *:* (glob)
277 updating to branch default
277 updating to branch default
278 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 $ cd narrow-empty
279 $ cd narrow-empty
280 $ hg tracked --removeinclude d0
280 $ hg tracked --removeinclude d0
281 comparing with ssh://user@dummy/master
281 comparing with ssh://user@dummy/master
282 searching for changes
282 searching for changes
283 looking for local changes to affected paths
283 looking for local changes to affected paths
284 deleting data/d0/f.i (reporevlogstore !)
284 deleting data/d0/f.i (reporevlogstore !)
285 deleting meta/d0/00manifest.i (tree !)
285 deleting meta/d0/00manifest.i (tree !)
286 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
286 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
287 deleting data/d0/f/index (reposimplestore !)
287 deleting data/d0/f/index (reposimplestore !)
288 deleting unwanted files from working copy
288 deleting unwanted files from working copy
289 $ hg tracked
289 $ hg tracked
290 $ hg files
290 $ hg files
291 [1]
291 [1]
292 $ test -d d0
292 $ test -d d0
293 [1]
293 [1]
294 Do some work in the empty clone
294 Do some work in the empty clone
295 $ hg diff --change .
295 $ hg diff --change .
296 $ hg branch foo
296 $ hg branch foo
297 marked working directory as branch foo
297 marked working directory as branch foo
298 (branches are permanent and global, did you want a bookmark?)
298 (branches are permanent and global, did you want a bookmark?)
299 $ hg ci -m empty
299 $ hg ci -m empty
300 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
300 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
301 2: empty
301 2: empty
302 1: add d5/f outsidenarrow
302 1: add d5/f outsidenarrow
303 0: add d0/f outsidenarrow
303 0: add d0/f outsidenarrow
304 $ hg pull -q
304 $ hg pull -q
305 Can widen the empty clone
305 Can widen the empty clone
306 $ hg tracked --addinclude d0
306 $ hg tracked --addinclude d0
307 comparing with ssh://user@dummy/master
307 comparing with ssh://user@dummy/master
308 searching for changes
308 searching for changes
309 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
309 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
310 adding changesets
310 adding changesets
311 adding manifests
311 adding manifests
312 adding file changes
312 adding file changes
313 added 4 changesets with 1 changes to 1 files (+1 heads)
313 added 4 changesets with 1 changes to 1 files (+1 heads)
314 $ hg tracked
314 $ hg tracked
315 I path:d0
315 I path:d0
316 $ hg files
316 $ hg files
317 d0/f
317 d0/f
318 $ find *
318 $ find *
319 d0
319 d0
320 d0/f
320 d0/f
321 $ cd ..
321 $ cd ..
322
322
323 TODO(martinvonz): test including e.g. d3/g and then removing it once
323 TODO(martinvonz): test including e.g. d3/g and then removing it once
324 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
324 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
325
325
326 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
326 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
327 requesting all changes
327 requesting all changes
328 adding changesets
328 adding changesets
329 adding manifests
329 adding manifests
330 adding file changes
330 adding file changes
331 added 8 changesets with 4 changes to 4 files
331 added 8 changesets with 4 changes to 4 files
332 new changesets *:* (glob)
332 new changesets *:* (glob)
333 updating to branch default
333 updating to branch default
334 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ cd narrow
335 $ cd narrow
336 $ hg tracked
336 $ hg tracked
337 I path:d0
337 I path:d0
338 I path:d3
338 I path:d3
339 I path:d6
339 I path:d6
340 I path:d9
340 I path:d9
341 $ hg tracked --removeinclude d6
341 $ hg tracked --removeinclude d6
342 comparing with ssh://user@dummy/master
342 comparing with ssh://user@dummy/master
343 searching for changes
343 searching for changes
344 looking for local changes to affected paths
344 looking for local changes to affected paths
345 deleting data/d6/f.i (reporevlogstore !)
345 deleting data/d6/f.i (reporevlogstore !)
346 deleting meta/d6/00manifest.i (tree !)
346 deleting meta/d6/00manifest.i (tree !)
347 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
347 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
348 deleting data/d6/f/index (reposimplestore !)
348 deleting data/d6/f/index (reposimplestore !)
349 deleting unwanted files from working copy
349 deleting unwanted files from working copy
350 $ hg tracked
350 $ hg tracked
351 I path:d0
351 I path:d0
352 I path:d3
352 I path:d3
353 I path:d9
353 I path:d9
354 #if repofncache
354 #if repofncache
355 $ hg debugrebuildfncache
355 $ hg debugrebuildfncache
356 fncache already up to date
356 fncache already up to date
357 #endif
357 #endif
358 $ find *
358 $ find *
359 d0
359 d0
360 d0/f
360 d0/f
361 d3
361 d3
362 d3/f
362 d3/f
363 d9
363 d9
364 d9/f
364 d9/f
365 $ hg verify -q
365 $ hg verify -q
366 $ hg tracked --addexclude d3/f
366 $ hg tracked --addexclude d3/f
367 comparing with ssh://user@dummy/master
367 comparing with ssh://user@dummy/master
368 searching for changes
368 searching for changes
369 looking for local changes to affected paths
369 looking for local changes to affected paths
370 deleting data/d3/f.i (reporevlogstore !)
370 deleting data/d3/f.i (reporevlogstore !)
371 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
371 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
372 deleting data/d3/f/index (reposimplestore !)
372 deleting data/d3/f/index (reposimplestore !)
373 deleting unwanted files from working copy
373 deleting unwanted files from working copy
374 $ hg tracked
374 $ hg tracked
375 I path:d0
375 I path:d0
376 I path:d3
376 I path:d3
377 I path:d9
377 I path:d9
378 X path:d3/f
378 X path:d3/f
379 #if repofncache
379 #if repofncache
380 $ hg debugrebuildfncache
380 $ hg debugrebuildfncache
381 fncache already up to date
381 fncache already up to date
382 #endif
382 #endif
383 $ find *
383 $ find *
384 d0
384 d0
385 d0/f
385 d0/f
386 d9
386 d9
387 d9/f
387 d9/f
388 $ hg verify -q
388 $ hg verify -q
389 $ hg tracked --addexclude d0
389 $ hg tracked --addexclude d0
390 comparing with ssh://user@dummy/master
390 comparing with ssh://user@dummy/master
391 searching for changes
391 searching for changes
392 looking for local changes to affected paths
392 looking for local changes to affected paths
393 deleting data/d0/f.i (reporevlogstore !)
393 deleting data/d0/f.i (reporevlogstore !)
394 deleting meta/d0/00manifest.i (tree !)
394 deleting meta/d0/00manifest.i (tree !)
395 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
395 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
396 deleting data/d0/f/index (reposimplestore !)
396 deleting data/d0/f/index (reposimplestore !)
397 deleting unwanted files from working copy
397 deleting unwanted files from working copy
398 $ hg tracked
398 $ hg tracked
399 I path:d3
399 I path:d3
400 I path:d9
400 I path:d9
401 X path:d0
401 X path:d0
402 X path:d3/f
402 X path:d3/f
403 #if repofncache
403 #if repofncache
404 $ hg debugrebuildfncache
404 $ hg debugrebuildfncache
405 fncache already up to date
405 fncache already up to date
406 #endif
406 #endif
407 $ find *
407 $ find *
408 d9
408 d9
409 d9/f
409 d9/f
410
410
411 Make a 15 of changes to d9 to test the path without --verbose
411 Make a 15 of changes to d9 to test the path without --verbose
412 (Note: using regexes instead of "* (glob)" because if the test fails, it
412 (Note: using regexes instead of "* (glob)" because if the test fails, it
413 produces more sensible diffs)
413 produces more sensible diffs)
414 $ hg tracked
414 $ hg tracked
415 I path:d3
415 I path:d3
416 I path:d9
416 I path:d9
417 X path:d0
417 X path:d0
418 X path:d3/f
418 X path:d3/f
419 $ for x in `$TESTDIR/seq.py 1 15`
419 $ for x in `$TESTDIR/seq.py 1 15`
420 > do
420 > do
421 > echo local change >> d9/f
421 > echo local change >> d9/f
422 > hg commit -m "change $x to d9/f"
422 > hg commit -m "change $x to d9/f"
423 > done
423 > done
424 $ hg tracked --removeinclude d9
424 $ hg tracked --removeinclude d9
425 comparing with ssh://user@dummy/master
425 comparing with ssh://user@dummy/master
426 searching for changes
426 searching for changes
427 looking for local changes to affected paths
427 looking for local changes to affected paths
428 The following changeset(s) or their ancestors have local changes not on the remote:
428 The following changeset(s) or their ancestors have local changes not on the remote:
429 ^[0-9a-f]{12}$ (re)
429 ^[0-9a-f]{12}$ (re)
430 ^[0-9a-f]{12}$ (re)
430 ^[0-9a-f]{12}$ (re)
431 ^[0-9a-f]{12}$ (re)
431 ^[0-9a-f]{12}$ (re)
432 ^[0-9a-f]{12}$ (re)
432 ^[0-9a-f]{12}$ (re)
433 ^[0-9a-f]{12}$ (re)
433 ^[0-9a-f]{12}$ (re)
434 ^[0-9a-f]{12}$ (re)
434 ^[0-9a-f]{12}$ (re)
435 ^[0-9a-f]{12}$ (re)
435 ^[0-9a-f]{12}$ (re)
436 ^[0-9a-f]{12}$ (re)
436 ^[0-9a-f]{12}$ (re)
437 ^[0-9a-f]{12}$ (re)
437 ^[0-9a-f]{12}$ (re)
438 ^[0-9a-f]{12}$ (re)
438 ^[0-9a-f]{12}$ (re)
439 ...and 5 more, use --verbose to list all
439 ...and 5 more, use --verbose to list all
440 abort: local changes found
440 abort: local changes found
441 (use --force-delete-local-changes to ignore)
441 (use --force-delete-local-changes to ignore)
442 [20]
442 [20]
443 Now test it *with* verbose.
443 Now test it *with* verbose.
444 $ hg tracked --removeinclude d9 --verbose
444 $ hg tracked --removeinclude d9 --verbose
445 comparing with ssh://user@dummy/master
445 comparing with ssh://user@dummy/master
446 searching for changes
446 searching for changes
447 looking for local changes to affected paths
447 looking for local changes to affected paths
448 The following changeset(s) or their ancestors have local changes not on the remote:
448 The following changeset(s) or their ancestors have local changes not on the remote:
449 ^[0-9a-f]{12}$ (re)
449 ^[0-9a-f]{12}$ (re)
450 ^[0-9a-f]{12}$ (re)
450 ^[0-9a-f]{12}$ (re)
451 ^[0-9a-f]{12}$ (re)
451 ^[0-9a-f]{12}$ (re)
452 ^[0-9a-f]{12}$ (re)
452 ^[0-9a-f]{12}$ (re)
453 ^[0-9a-f]{12}$ (re)
453 ^[0-9a-f]{12}$ (re)
454 ^[0-9a-f]{12}$ (re)
454 ^[0-9a-f]{12}$ (re)
455 ^[0-9a-f]{12}$ (re)
455 ^[0-9a-f]{12}$ (re)
456 ^[0-9a-f]{12}$ (re)
456 ^[0-9a-f]{12}$ (re)
457 ^[0-9a-f]{12}$ (re)
457 ^[0-9a-f]{12}$ (re)
458 ^[0-9a-f]{12}$ (re)
458 ^[0-9a-f]{12}$ (re)
459 ^[0-9a-f]{12}$ (re)
459 ^[0-9a-f]{12}$ (re)
460 ^[0-9a-f]{12}$ (re)
460 ^[0-9a-f]{12}$ (re)
461 ^[0-9a-f]{12}$ (re)
461 ^[0-9a-f]{12}$ (re)
462 ^[0-9a-f]{12}$ (re)
462 ^[0-9a-f]{12}$ (re)
463 ^[0-9a-f]{12}$ (re)
463 ^[0-9a-f]{12}$ (re)
464 abort: local changes found
464 abort: local changes found
465 (use --force-delete-local-changes to ignore)
465 (use --force-delete-local-changes to ignore)
466 [20]
466 [20]
467 $ cd ..
467 $ cd ..
468
468
469 Test --auto-remove-includes
469 Test --auto-remove-includes
470 $ hg clone --narrow ssh://user@dummy/master narrow-auto-remove -q \
470 $ hg clone --narrow ssh://user@dummy/master narrow-auto-remove -q \
471 > --include d0 --include d1 --include d2
471 > --include d0 --include d1 --include d2
472 $ cd narrow-auto-remove
472 $ cd narrow-auto-remove
473 $ echo a >> d0/f
473 $ echo a >> d0/f
474 $ hg ci -m 'local change to d0'
474 $ hg ci -m 'local change to d0'
475 $ hg co '.^'
475 $ hg co '.^'
476 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
477 $ echo a >> d1/f
477 $ echo a >> d1/f
478 $ hg ci -m 'local change to d1'
478 $ hg ci -m 'local change to d1'
479 created new head
479 created new head
480 $ hg debugobsolete $(hg log -T '{node}' -r 'desc("local change to d0")')
480 $ hg debugobsolete $(hg log -T '{node}' -r 'desc("local change to d0")')
481 1 new obsolescence markers
481 1 new obsolescence markers
482 obsoleted 1 changesets
482 obsoleted 1 changesets
483 $ echo n | hg tracked --auto-remove-includes --config ui.interactive=yes
483 $ echo n | hg tracked --auto-remove-includes --config ui.interactive=yes
484 comparing with ssh://user@dummy/master
484 comparing with ssh://user@dummy/master
485 searching for changes
485 searching for changes
486 looking for unused includes to remove
486 looking for unused includes to remove
487 path:d0
487 path:d0
488 path:d2
488 path:d2
489 remove these unused includes (Yn)? n
489 remove these unused includes (Yn)? n
490 $ hg tracked --auto-remove-includes
490 $ hg tracked --auto-remove-includes
491 comparing with ssh://user@dummy/master
491 comparing with ssh://user@dummy/master
492 searching for changes
492 searching for changes
493 looking for unused includes to remove
493 looking for unused includes to remove
494 path:d0
494 path:d0
495 path:d2
495 path:d2
496 remove these unused includes (Yn)? y
496 remove these unused includes (Yn)? y
497 looking for local changes to affected paths
497 looking for local changes to affected paths
498 moving unwanted changesets to backup
498 moving unwanted changesets to backup
499 saved backup bundle to $TESTTMP/narrow-auto-remove/.hg/strip-backup/*-narrow.hg (glob)
499 saved backup bundle to $TESTTMP/narrow-auto-remove/.hg/strip-backup/*-narrow.hg (glob)
500 deleting data/d0/f.i
500 deleting data/d0/f.i
501 deleting data/d2/f.i
501 deleting data/d2/f.i
502 deleting meta/d0/00manifest.i (tree !)
502 deleting meta/d0/00manifest.i (tree !)
503 deleting meta/d2/00manifest.i (tree !)
503 deleting meta/d2/00manifest.i (tree !)
504 deleting unwanted files from working copy
504 deleting unwanted files from working copy
505 $ hg tracked
505 $ hg tracked
506 I path:d1
506 I path:d1
507 $ hg files
507 $ hg files
508 d1/f
508 d1/f
509 $ hg tracked --auto-remove-includes
509 $ hg tracked --auto-remove-includes
510 comparing with ssh://user@dummy/master
510 comparing with ssh://user@dummy/master
511 searching for changes
511 searching for changes
512 looking for unused includes to remove
512 looking for unused includes to remove
513 found no unused includes
513 found no unused includes
514 Test --no-backup
514 Test --no-backup
515 $ hg tracked --addinclude d0 --addinclude d2 -q
515 $ hg tracked --addinclude d0 --addinclude d2 -q
516 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
516 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
517 $ rm .hg/strip-backup/*
517 $ rm .hg/strip-backup/*
518 $ hg tracked --auto-remove-includes --no-backup
518 $ hg tracked --auto-remove-includes --no-backup
519 comparing with ssh://user@dummy/master
519 comparing with ssh://user@dummy/master
520 searching for changes
520 searching for changes
521 looking for unused includes to remove
521 looking for unused includes to remove
522 path:d0
522 path:d0
523 path:d2
523 path:d2
524 remove these unused includes (Yn)? y
524 remove these unused includes (Yn)? y
525 looking for local changes to affected paths
525 looking for local changes to affected paths
526 deleting unwanted changesets
526 deleting unwanted changesets
527 deleting data/d0/f.i
527 deleting data/d0/f.i
528 deleting data/d2/f.i
528 deleting data/d2/f.i
529 deleting meta/d0/00manifest.i (tree !)
529 deleting meta/d0/00manifest.i (tree !)
530 deleting meta/d2/00manifest.i (tree !)
530 deleting meta/d2/00manifest.i (tree !)
531 deleting unwanted files from working copy
531 deleting unwanted files from working copy
532 $ ls .hg/strip-backup/
532 $ ls .hg/strip-backup/
533
533
534
534
535 Test removing include while concurrently modifying file in that path
535 Test removing include while concurrently modifying file in that path
536 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
536 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
537 > --include d0 --include d1
537 > --include d0 --include d1
538 $ cd narrow-concurrent-modify
538 $ cd narrow-concurrent-modify
539 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude d0
539 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude d0
540 comparing with ssh://user@dummy/master
540 comparing with ssh://user@dummy/master
541 searching for changes
541 searching for changes
542 looking for local changes to affected paths
542 looking for local changes to affected paths
543 deleting data/d0/f.i
543 deleting data/d0/f.i
544 deleting meta/d0/00manifest.i (tree !)
544 deleting meta/d0/00manifest.i (tree !)
545 deleting unwanted files from working copy
545 deleting unwanted files from working copy
546 not deleting possibly dirty file d0/f
546 not deleting possibly dirty file d0/f
547
547
548
548
549 Test removing `rootfilesin:` include
549 Test removing `rootfilesin:` include
550 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
550 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
551 > --include rootfilesin:d0 --include rootfilesin:d1
551 > --include rootfilesin:d0 --include rootfilesin:d1
552 $ cd narrow-concurrent-modify
552 $ cd narrow-concurrent-modify
553 #if flat
554 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude rootfilesin:d0
553 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude rootfilesin:d0
555 comparing with ssh://user@dummy/master
554 comparing with ssh://user@dummy/master
556 searching for changes
555 searching for changes
557 looking for local changes to affected paths
556 looking for local changes to affected paths
558 deleting data/d0/f.i
557 deleting data/d0/f.i
558 deleting meta/d0/00manifest.i (tree !)
559 deleting unwanted files from working copy
559 deleting unwanted files from working copy
560 not deleting possibly dirty file d0/f
560 not deleting possibly dirty file d0/f
561 #endif
562 #if tree
563 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude rootfilesin:d0
564 comparing with ssh://user@dummy/master
565 searching for changes
566 looking for local changes to affected paths
567 deleting data/d0/f.i
568 deleting meta/d0/00manifest.i
569 deleting meta/d1/00manifest.i (known-bad-output !)
570 deleting unwanted files from working copy
571 not deleting possibly dirty file d0/f
572 abort: meta/d1/00manifest@77a3e194be076ae47ba9282271028916012d815c: no node (known-bad-output !)
573 [50]
574 #endif
General Comments 0
You need to be logged in to leave comments. Login now