##// END OF EJS Templates
narrow: don't resurrect old commits when narrowing (don't strip obsmarkers)...
Martin von Zweigbergk -
r40864:77173267 default
parent child Browse files
Show More
@@ -1,469 +1,471 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 merge,
23 merge,
24 narrowspec,
24 narrowspec,
25 node,
25 node,
26 pycompat,
26 pycompat,
27 registrar,
27 registrar,
28 repair,
28 repair,
29 repository,
29 repository,
30 repoview,
30 repoview,
31 sparse,
31 sparse,
32 util,
32 util,
33 wireprototypes,
33 wireprototypes,
34 )
34 )
35
35
36 table = {}
36 table = {}
37 command = registrar.command(table)
37 command = registrar.command(table)
38
38
39 def setup():
39 def setup():
40 """Wraps user-facing mercurial commands with narrow-aware versions."""
40 """Wraps user-facing mercurial commands with narrow-aware versions."""
41
41
42 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
42 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
43 entry[1].append(('', 'narrow', None,
43 entry[1].append(('', 'narrow', None,
44 _("create a narrow clone of select files")))
44 _("create a narrow clone of select files")))
45 entry[1].append(('', 'depth', '',
45 entry[1].append(('', 'depth', '',
46 _("limit the history fetched by distance from heads")))
46 _("limit the history fetched by distance from heads")))
47 entry[1].append(('', 'narrowspec', '',
47 entry[1].append(('', 'narrowspec', '',
48 _("read narrowspecs from file")))
48 _("read narrowspecs from file")))
49 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
49 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
50 if 'sparse' not in extensions.enabled():
50 if 'sparse' not in extensions.enabled():
51 entry[1].append(('', 'include', [],
51 entry[1].append(('', 'include', [],
52 _("specifically fetch this file/directory")))
52 _("specifically fetch this file/directory")))
53 entry[1].append(
53 entry[1].append(
54 ('', 'exclude', [],
54 ('', 'exclude', [],
55 _("do not fetch this file/directory, even if included")))
55 _("do not fetch this file/directory, even if included")))
56
56
57 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
57 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
58 entry[1].append(('', 'depth', '',
58 entry[1].append(('', 'depth', '',
59 _("limit the history fetched by distance from heads")))
59 _("limit the history fetched by distance from heads")))
60
60
61 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
61 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
62
62
63 def clonenarrowcmd(orig, ui, repo, *args, **opts):
63 def clonenarrowcmd(orig, ui, repo, *args, **opts):
64 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
64 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
65 opts = pycompat.byteskwargs(opts)
65 opts = pycompat.byteskwargs(opts)
66 wrappedextraprepare = util.nullcontextmanager()
66 wrappedextraprepare = util.nullcontextmanager()
67 narrowspecfile = opts['narrowspec']
67 narrowspecfile = opts['narrowspec']
68
68
69 if narrowspecfile:
69 if narrowspecfile:
70 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
70 filepath = os.path.join(encoding.getcwd(), narrowspecfile)
71 ui.status(_("reading narrowspec from '%s'\n") % filepath)
71 ui.status(_("reading narrowspec from '%s'\n") % filepath)
72 try:
72 try:
73 fdata = util.readfile(filepath)
73 fdata = util.readfile(filepath)
74 except IOError as inst:
74 except IOError as inst:
75 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
75 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
76 (filepath, encoding.strtolocal(inst.strerror)))
76 (filepath, encoding.strtolocal(inst.strerror)))
77
77
78 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow')
78 includes, excludes, profiles = sparse.parseconfig(ui, fdata, 'narrow')
79 if profiles:
79 if profiles:
80 raise error.Abort(_("cannot specify other files using '%include' in"
80 raise error.Abort(_("cannot specify other files using '%include' in"
81 " narrowspec"))
81 " narrowspec"))
82
82
83 narrowspec.validatepatterns(includes)
83 narrowspec.validatepatterns(includes)
84 narrowspec.validatepatterns(excludes)
84 narrowspec.validatepatterns(excludes)
85
85
86 # narrowspec is passed so we should assume that user wants narrow clone
86 # narrowspec is passed so we should assume that user wants narrow clone
87 opts['narrow'] = True
87 opts['narrow'] = True
88 opts['include'].extend(includes)
88 opts['include'].extend(includes)
89 opts['exclude'].extend(excludes)
89 opts['exclude'].extend(excludes)
90
90
91 if opts['narrow']:
91 if opts['narrow']:
92 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
92 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
93 orig(pullop, kwargs)
93 orig(pullop, kwargs)
94
94
95 if opts.get('depth'):
95 if opts.get('depth'):
96 kwargs['depth'] = opts['depth']
96 kwargs['depth'] = opts['depth']
97 wrappedextraprepare = extensions.wrappedfunction(exchange,
97 wrappedextraprepare = extensions.wrappedfunction(exchange,
98 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
98 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
99
99
100 with wrappedextraprepare:
100 with wrappedextraprepare:
101 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
101 return orig(ui, repo, *args, **pycompat.strkwargs(opts))
102
102
103 def pullnarrowcmd(orig, ui, repo, *args, **opts):
103 def pullnarrowcmd(orig, ui, repo, *args, **opts):
104 """Wraps pull command to allow modifying narrow spec."""
104 """Wraps pull command to allow modifying narrow spec."""
105 wrappedextraprepare = util.nullcontextmanager()
105 wrappedextraprepare = util.nullcontextmanager()
106 if repository.NARROW_REQUIREMENT in repo.requirements:
106 if repository.NARROW_REQUIREMENT in repo.requirements:
107
107
108 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
108 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
109 orig(pullop, kwargs)
109 orig(pullop, kwargs)
110 if opts.get(r'depth'):
110 if opts.get(r'depth'):
111 kwargs['depth'] = opts[r'depth']
111 kwargs['depth'] = opts[r'depth']
112 wrappedextraprepare = extensions.wrappedfunction(exchange,
112 wrappedextraprepare = extensions.wrappedfunction(exchange,
113 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
113 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
114
114
115 with wrappedextraprepare:
115 with wrappedextraprepare:
116 return orig(ui, repo, *args, **opts)
116 return orig(ui, repo, *args, **opts)
117
117
118 def archivenarrowcmd(orig, ui, repo, *args, **opts):
118 def archivenarrowcmd(orig, ui, repo, *args, **opts):
119 """Wraps archive command to narrow the default includes."""
119 """Wraps archive command to narrow the default includes."""
120 if repository.NARROW_REQUIREMENT in repo.requirements:
120 if repository.NARROW_REQUIREMENT in repo.requirements:
121 repo_includes, repo_excludes = repo.narrowpats
121 repo_includes, repo_excludes = repo.narrowpats
122 includes = set(opts.get(r'include', []))
122 includes = set(opts.get(r'include', []))
123 excludes = set(opts.get(r'exclude', []))
123 excludes = set(opts.get(r'exclude', []))
124 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
124 includes, excludes, unused_invalid = narrowspec.restrictpatterns(
125 includes, excludes, repo_includes, repo_excludes)
125 includes, excludes, repo_includes, repo_excludes)
126 if includes:
126 if includes:
127 opts[r'include'] = includes
127 opts[r'include'] = includes
128 if excludes:
128 if excludes:
129 opts[r'exclude'] = excludes
129 opts[r'exclude'] = excludes
130 return orig(ui, repo, *args, **opts)
130 return orig(ui, repo, *args, **opts)
131
131
132 def pullbundle2extraprepare(orig, pullop, kwargs):
132 def pullbundle2extraprepare(orig, pullop, kwargs):
133 repo = pullop.repo
133 repo = pullop.repo
134 if repository.NARROW_REQUIREMENT not in repo.requirements:
134 if repository.NARROW_REQUIREMENT not in repo.requirements:
135 return orig(pullop, kwargs)
135 return orig(pullop, kwargs)
136
136
137 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
137 if wireprototypes.NARROWCAP not in pullop.remote.capabilities():
138 raise error.Abort(_("server does not support narrow clones"))
138 raise error.Abort(_("server does not support narrow clones"))
139 orig(pullop, kwargs)
139 orig(pullop, kwargs)
140 kwargs['narrow'] = True
140 kwargs['narrow'] = True
141 include, exclude = repo.narrowpats
141 include, exclude = repo.narrowpats
142 kwargs['oldincludepats'] = include
142 kwargs['oldincludepats'] = include
143 kwargs['oldexcludepats'] = exclude
143 kwargs['oldexcludepats'] = exclude
144 if include:
144 if include:
145 kwargs['includepats'] = include
145 kwargs['includepats'] = include
146 if exclude:
146 if exclude:
147 kwargs['excludepats'] = exclude
147 kwargs['excludepats'] = exclude
148 # calculate known nodes only in ellipses cases because in non-ellipses cases
148 # calculate known nodes only in ellipses cases because in non-ellipses cases
149 # we have all the nodes
149 # we have all the nodes
150 if wireprototypes.ELLIPSESCAP in pullop.remote.capabilities():
150 if wireprototypes.ELLIPSESCAP in pullop.remote.capabilities():
151 kwargs['known'] = [node.hex(ctx.node()) for ctx in
151 kwargs['known'] = [node.hex(ctx.node()) for ctx in
152 repo.set('::%ln', pullop.common)
152 repo.set('::%ln', pullop.common)
153 if ctx.node() != node.nullid]
153 if ctx.node() != node.nullid]
154 if not kwargs['known']:
154 if not kwargs['known']:
155 # Mercurial serializes an empty list as '' and deserializes it as
155 # Mercurial serializes an empty list as '' and deserializes it as
156 # [''], so delete it instead to avoid handling the empty string on
156 # [''], so delete it instead to avoid handling the empty string on
157 # the server.
157 # the server.
158 del kwargs['known']
158 del kwargs['known']
159
159
160 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
160 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
161 pullbundle2extraprepare)
161 pullbundle2extraprepare)
162
162
163 # This is an extension point for filesystems that need to do something other
163 # This is an extension point for filesystems that need to do something other
164 # than just blindly unlink the files. It's not clear what arguments would be
164 # than just blindly unlink the files. It's not clear what arguments would be
165 # useful, so we're passing in a fair number of them, some of them redundant.
165 # useful, so we're passing in a fair number of them, some of them redundant.
166 def _narrowcleanupwdir(repo, oldincludes, oldexcludes, newincludes, newexcludes,
166 def _narrowcleanupwdir(repo, oldincludes, oldexcludes, newincludes, newexcludes,
167 oldmatch, newmatch):
167 oldmatch, newmatch):
168 for f in repo.dirstate:
168 for f in repo.dirstate:
169 if not newmatch(f):
169 if not newmatch(f):
170 repo.dirstate.drop(f)
170 repo.dirstate.drop(f)
171 repo.wvfs.unlinkpath(f)
171 repo.wvfs.unlinkpath(f)
172
172
173 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
173 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
174 newincludes, newexcludes, force):
174 newincludes, newexcludes, force):
175 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
175 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
176 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
176 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
177
177
178 # This is essentially doing "hg outgoing" to find all local-only
178 # This is essentially doing "hg outgoing" to find all local-only
179 # commits. We will then check that the local-only commits don't
179 # commits. We will then check that the local-only commits don't
180 # have any changes to files that will be untracked.
180 # have any changes to files that will be untracked.
181 unfi = repo.unfiltered()
181 unfi = repo.unfiltered()
182 outgoing = discovery.findcommonoutgoing(unfi, remote,
182 outgoing = discovery.findcommonoutgoing(unfi, remote,
183 commoninc=commoninc)
183 commoninc=commoninc)
184 ui.status(_('looking for local changes to affected paths\n'))
184 ui.status(_('looking for local changes to affected paths\n'))
185 localnodes = []
185 localnodes = []
186 for n in itertools.chain(outgoing.missing, outgoing.excluded):
186 for n in itertools.chain(outgoing.missing, outgoing.excluded):
187 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
187 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
188 localnodes.append(n)
188 localnodes.append(n)
189 revstostrip = unfi.revs('descendants(%ln)', localnodes)
189 revstostrip = unfi.revs('descendants(%ln)', localnodes)
190 hiddenrevs = repoview.filterrevs(repo, 'visible')
190 hiddenrevs = repoview.filterrevs(repo, 'visible')
191 visibletostrip = list(repo.changelog.node(r)
191 visibletostrip = list(repo.changelog.node(r)
192 for r in (revstostrip - hiddenrevs))
192 for r in (revstostrip - hiddenrevs))
193 if visibletostrip:
193 if visibletostrip:
194 ui.status(_('The following changeset(s) or their ancestors have '
194 ui.status(_('The following changeset(s) or their ancestors have '
195 'local changes not on the remote:\n'))
195 'local changes not on the remote:\n'))
196 maxnodes = 10
196 maxnodes = 10
197 if ui.verbose or len(visibletostrip) <= maxnodes:
197 if ui.verbose or len(visibletostrip) <= maxnodes:
198 for n in visibletostrip:
198 for n in visibletostrip:
199 ui.status('%s\n' % node.short(n))
199 ui.status('%s\n' % node.short(n))
200 else:
200 else:
201 for n in visibletostrip[:maxnodes]:
201 for n in visibletostrip[:maxnodes]:
202 ui.status('%s\n' % node.short(n))
202 ui.status('%s\n' % node.short(n))
203 ui.status(_('...and %d more, use --verbose to list all\n') %
203 ui.status(_('...and %d more, use --verbose to list all\n') %
204 (len(visibletostrip) - maxnodes))
204 (len(visibletostrip) - maxnodes))
205 if not force:
205 if not force:
206 raise error.Abort(_('local changes found'),
206 raise error.Abort(_('local changes found'),
207 hint=_('use --force-delete-local-changes to '
207 hint=_('use --force-delete-local-changes to '
208 'ignore'))
208 'ignore'))
209
209
210 with ui.uninterruptable():
210 with ui.uninterruptable():
211 if revstostrip:
211 if revstostrip:
212 tostrip = [unfi.changelog.node(r) for r in revstostrip]
212 tostrip = [unfi.changelog.node(r) for r in revstostrip]
213 if repo['.'].node() in tostrip:
213 if repo['.'].node() in tostrip:
214 # stripping working copy, so move to a different commit first
214 # stripping working copy, so move to a different commit first
215 urev = max(repo.revs('(::%n) - %ln + null',
215 urev = max(repo.revs('(::%n) - %ln + null',
216 repo['.'].node(), visibletostrip))
216 repo['.'].node(), visibletostrip))
217 hg.clean(repo, urev)
217 hg.clean(repo, urev)
218 repair.strip(ui, unfi, tostrip, topic='narrow')
218 overrides = {('devel', 'strip-obsmarkers'): False}
219 with ui.configoverride(overrides, 'narrow'):
220 repair.strip(ui, unfi, tostrip, topic='narrow')
219
221
220 todelete = []
222 todelete = []
221 for f, f2, size in repo.store.datafiles():
223 for f, f2, size in repo.store.datafiles():
222 if f.startswith('data/'):
224 if f.startswith('data/'):
223 file = f[5:-2]
225 file = f[5:-2]
224 if not newmatch(file):
226 if not newmatch(file):
225 todelete.append(f)
227 todelete.append(f)
226 elif f.startswith('meta/'):
228 elif f.startswith('meta/'):
227 dir = f[5:-13]
229 dir = f[5:-13]
228 dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
230 dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
229 include = True
231 include = True
230 for d in dirs:
232 for d in dirs:
231 visit = newmatch.visitdir(d)
233 visit = newmatch.visitdir(d)
232 if not visit:
234 if not visit:
233 include = False
235 include = False
234 break
236 break
235 if visit == 'all':
237 if visit == 'all':
236 break
238 break
237 if not include:
239 if not include:
238 todelete.append(f)
240 todelete.append(f)
239
241
240 repo.destroying()
242 repo.destroying()
241
243
242 with repo.transaction("narrowing"):
244 with repo.transaction("narrowing"):
243 for f in todelete:
245 for f in todelete:
244 ui.status(_('deleting %s\n') % f)
246 ui.status(_('deleting %s\n') % f)
245 util.unlinkpath(repo.svfs.join(f))
247 util.unlinkpath(repo.svfs.join(f))
246 repo.store.markremoved(f)
248 repo.store.markremoved(f)
247
249
248 _narrowcleanupwdir(repo, oldincludes, oldexcludes, newincludes,
250 _narrowcleanupwdir(repo, oldincludes, oldexcludes, newincludes,
249 newexcludes, oldmatch, newmatch)
251 newexcludes, oldmatch, newmatch)
250 repo.setnarrowpats(newincludes, newexcludes)
252 repo.setnarrowpats(newincludes, newexcludes)
251
253
252 repo.destroyed()
254 repo.destroyed()
253
255
254 def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
256 def _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
255 newincludes, newexcludes):
257 newincludes, newexcludes):
256 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
258 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
257
259
258 # for now we assume that if a server has ellipses enabled, we will be
260 # for now we assume that if a server has ellipses enabled, we will be
259 # exchanging ellipses nodes. In future we should add ellipses as a client
261 # exchanging ellipses nodes. In future we should add ellipses as a client
260 # side requirement (maybe) to distinguish a client is shallow or not and
262 # side requirement (maybe) to distinguish a client is shallow or not and
261 # then send that information to server whether we want ellipses or not.
263 # then send that information to server whether we want ellipses or not.
262 # Theoretically a non-ellipses repo should be able to use narrow
264 # Theoretically a non-ellipses repo should be able to use narrow
263 # functionality from an ellipses enabled server
265 # functionality from an ellipses enabled server
264 ellipsesremote = wireprototypes.ELLIPSESCAP in remote.capabilities()
266 ellipsesremote = wireprototypes.ELLIPSESCAP in remote.capabilities()
265
267
266 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
268 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
267 orig(pullop, kwargs)
269 orig(pullop, kwargs)
268 # The old{in,ex}cludepats have already been set by orig()
270 # The old{in,ex}cludepats have already been set by orig()
269 kwargs['includepats'] = newincludes
271 kwargs['includepats'] = newincludes
270 kwargs['excludepats'] = newexcludes
272 kwargs['excludepats'] = newexcludes
271 wrappedextraprepare = extensions.wrappedfunction(exchange,
273 wrappedextraprepare = extensions.wrappedfunction(exchange,
272 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
274 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
273
275
274 # define a function that narrowbundle2 can call after creating the
276 # define a function that narrowbundle2 can call after creating the
275 # backup bundle, but before applying the bundle from the server
277 # backup bundle, but before applying the bundle from the server
276 def setnewnarrowpats():
278 def setnewnarrowpats():
277 repo.setnarrowpats(newincludes, newexcludes)
279 repo.setnarrowpats(newincludes, newexcludes)
278 repo.setnewnarrowpats = setnewnarrowpats
280 repo.setnewnarrowpats = setnewnarrowpats
279 # silence the devel-warning of applying an empty changegroup
281 # silence the devel-warning of applying an empty changegroup
280 overrides = {('devel', 'all-warnings'): False}
282 overrides = {('devel', 'all-warnings'): False}
281
283
282 with ui.uninterruptable():
284 with ui.uninterruptable():
283 common = commoninc[0]
285 common = commoninc[0]
284 if ellipsesremote:
286 if ellipsesremote:
285 ds = repo.dirstate
287 ds = repo.dirstate
286 p1, p2 = ds.p1(), ds.p2()
288 p1, p2 = ds.p1(), ds.p2()
287 with ds.parentchange():
289 with ds.parentchange():
288 ds.setparents(node.nullid, node.nullid)
290 ds.setparents(node.nullid, node.nullid)
289 with wrappedextraprepare,\
291 with wrappedextraprepare,\
290 repo.ui.configoverride(overrides, 'widen'):
292 repo.ui.configoverride(overrides, 'widen'):
291 exchange.pull(repo, remote, heads=common)
293 exchange.pull(repo, remote, heads=common)
292 with ds.parentchange():
294 with ds.parentchange():
293 ds.setparents(p1, p2)
295 ds.setparents(p1, p2)
294 else:
296 else:
295 with remote.commandexecutor() as e:
297 with remote.commandexecutor() as e:
296 bundle = e.callcommand('narrow_widen', {
298 bundle = e.callcommand('narrow_widen', {
297 'oldincludes': oldincludes,
299 'oldincludes': oldincludes,
298 'oldexcludes': oldexcludes,
300 'oldexcludes': oldexcludes,
299 'newincludes': newincludes,
301 'newincludes': newincludes,
300 'newexcludes': newexcludes,
302 'newexcludes': newexcludes,
301 'cgversion': '03',
303 'cgversion': '03',
302 'commonheads': common,
304 'commonheads': common,
303 'known': [],
305 'known': [],
304 'ellipses': False,
306 'ellipses': False,
305 }).result()
307 }).result()
306
308
307 with repo.transaction('widening') as tr,\
309 with repo.transaction('widening') as tr,\
308 repo.ui.configoverride(overrides, 'widen'):
310 repo.ui.configoverride(overrides, 'widen'):
309 tgetter = lambda: tr
311 tgetter = lambda: tr
310 bundle2.processbundle(repo, bundle,
312 bundle2.processbundle(repo, bundle,
311 transactiongetter=tgetter)
313 transactiongetter=tgetter)
312
314
313 repo.setnewnarrowpats()
315 repo.setnewnarrowpats()
314 actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
316 actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
315 addgaction = actions['g'].append
317 addgaction = actions['g'].append
316
318
317 mf = repo['.'].manifest().matches(newmatch)
319 mf = repo['.'].manifest().matches(newmatch)
318 for f, fn in mf.iteritems():
320 for f, fn in mf.iteritems():
319 if f not in repo.dirstate:
321 if f not in repo.dirstate:
320 addgaction((f, (mf.flags(f), False),
322 addgaction((f, (mf.flags(f), False),
321 "add from widened narrow clone"))
323 "add from widened narrow clone"))
322
324
323 merge.applyupdates(repo, actions, wctx=repo[None],
325 merge.applyupdates(repo, actions, wctx=repo[None],
324 mctx=repo['.'], overwrite=False)
326 mctx=repo['.'], overwrite=False)
325 merge.recordupdates(repo, actions, branchmerge=False)
327 merge.recordupdates(repo, actions, branchmerge=False)
326
328
327 # TODO(rdamazio): Make new matcher format and update description
329 # TODO(rdamazio): Make new matcher format and update description
328 @command('tracked',
330 @command('tracked',
329 [('', 'addinclude', [], _('new paths to include')),
331 [('', 'addinclude', [], _('new paths to include')),
330 ('', 'removeinclude', [], _('old paths to no longer include')),
332 ('', 'removeinclude', [], _('old paths to no longer include')),
331 ('', 'addexclude', [], _('new paths to exclude')),
333 ('', 'addexclude', [], _('new paths to exclude')),
332 ('', 'import-rules', '', _('import narrowspecs from a file')),
334 ('', 'import-rules', '', _('import narrowspecs from a file')),
333 ('', 'removeexclude', [], _('old paths to no longer exclude')),
335 ('', 'removeexclude', [], _('old paths to no longer exclude')),
334 ('', 'clear', False, _('whether to replace the existing narrowspec')),
336 ('', 'clear', False, _('whether to replace the existing narrowspec')),
335 ('', 'force-delete-local-changes', False,
337 ('', 'force-delete-local-changes', False,
336 _('forces deletion of local changes when narrowing')),
338 _('forces deletion of local changes when narrowing')),
337 ] + commands.remoteopts,
339 ] + commands.remoteopts,
338 _('[OPTIONS]... [REMOTE]'),
340 _('[OPTIONS]... [REMOTE]'),
339 inferrepo=True)
341 inferrepo=True)
340 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
342 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
341 """show or change the current narrowspec
343 """show or change the current narrowspec
342
344
343 With no argument, shows the current narrowspec entries, one per line. Each
345 With no argument, shows the current narrowspec entries, one per line. Each
344 line will be prefixed with 'I' or 'X' for included or excluded patterns,
346 line will be prefixed with 'I' or 'X' for included or excluded patterns,
345 respectively.
347 respectively.
346
348
347 The narrowspec is comprised of expressions to match remote files and/or
349 The narrowspec is comprised of expressions to match remote files and/or
348 directories that should be pulled into your client.
350 directories that should be pulled into your client.
349 The narrowspec has *include* and *exclude* expressions, with excludes always
351 The narrowspec has *include* and *exclude* expressions, with excludes always
350 trumping includes: that is, if a file matches an exclude expression, it will
352 trumping includes: that is, if a file matches an exclude expression, it will
351 be excluded even if it also matches an include expression.
353 be excluded even if it also matches an include expression.
352 Excluding files that were never included has no effect.
354 Excluding files that were never included has no effect.
353
355
354 Each included or excluded entry is in the format described by
356 Each included or excluded entry is in the format described by
355 'hg help patterns'.
357 'hg help patterns'.
356
358
357 The options allow you to add or remove included and excluded expressions.
359 The options allow you to add or remove included and excluded expressions.
358
360
359 If --clear is specified, then all previous includes and excludes are DROPPED
361 If --clear is specified, then all previous includes and excludes are DROPPED
360 and replaced by the new ones specified to --addinclude and --addexclude.
362 and replaced by the new ones specified to --addinclude and --addexclude.
361 If --clear is specified without any further options, the narrowspec will be
363 If --clear is specified without any further options, the narrowspec will be
362 empty and will not match any files.
364 empty and will not match any files.
363 """
365 """
364 opts = pycompat.byteskwargs(opts)
366 opts = pycompat.byteskwargs(opts)
365 if repository.NARROW_REQUIREMENT not in repo.requirements:
367 if repository.NARROW_REQUIREMENT not in repo.requirements:
366 ui.warn(_('The narrow command is only supported on respositories cloned'
368 ui.warn(_('The narrow command is only supported on respositories cloned'
367 ' with --narrow.\n'))
369 ' with --narrow.\n'))
368 return 1
370 return 1
369
371
370 # Before supporting, decide whether it "hg tracked --clear" should mean
372 # Before supporting, decide whether it "hg tracked --clear" should mean
371 # tracking no paths or all paths.
373 # tracking no paths or all paths.
372 if opts['clear']:
374 if opts['clear']:
373 ui.warn(_('The --clear option is not yet supported.\n'))
375 ui.warn(_('The --clear option is not yet supported.\n'))
374 return 1
376 return 1
375
377
376 # import rules from a file
378 # import rules from a file
377 newrules = opts.get('import_rules')
379 newrules = opts.get('import_rules')
378 if newrules:
380 if newrules:
379 try:
381 try:
380 filepath = os.path.join(encoding.getcwd(), newrules)
382 filepath = os.path.join(encoding.getcwd(), newrules)
381 fdata = util.readfile(filepath)
383 fdata = util.readfile(filepath)
382 except IOError as inst:
384 except IOError as inst:
383 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
385 raise error.Abort(_("cannot read narrowspecs from '%s': %s") %
384 (filepath, encoding.strtolocal(inst.strerror)))
386 (filepath, encoding.strtolocal(inst.strerror)))
385 includepats, excludepats, profiles = sparse.parseconfig(ui, fdata,
387 includepats, excludepats, profiles = sparse.parseconfig(ui, fdata,
386 'narrow')
388 'narrow')
387 if profiles:
389 if profiles:
388 raise error.Abort(_("including other spec files using '%include' "
390 raise error.Abort(_("including other spec files using '%include' "
389 "is not supported in narrowspec"))
391 "is not supported in narrowspec"))
390 opts['addinclude'].extend(includepats)
392 opts['addinclude'].extend(includepats)
391 opts['addexclude'].extend(excludepats)
393 opts['addexclude'].extend(excludepats)
392
394
393 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
395 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
394 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
396 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
395 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
397 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
396 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
398 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
397
399
398 only_show = not (addedincludes or removedincludes or addedexcludes or
400 only_show = not (addedincludes or removedincludes or addedexcludes or
399 removedexcludes or newrules)
401 removedexcludes or newrules)
400
402
401 oldincludes, oldexcludes = repo.narrowpats
403 oldincludes, oldexcludes = repo.narrowpats
402
404
403 # filter the user passed additions and deletions into actual additions and
405 # filter the user passed additions and deletions into actual additions and
404 # deletions of excludes and includes
406 # deletions of excludes and includes
405 addedincludes -= oldincludes
407 addedincludes -= oldincludes
406 removedincludes &= oldincludes
408 removedincludes &= oldincludes
407 addedexcludes -= oldexcludes
409 addedexcludes -= oldexcludes
408 removedexcludes &= oldexcludes
410 removedexcludes &= oldexcludes
409
411
410 widening = addedincludes or removedexcludes
412 widening = addedincludes or removedexcludes
411 narrowing = removedincludes or addedexcludes
413 narrowing = removedincludes or addedexcludes
412
414
413 # Only print the current narrowspec.
415 # Only print the current narrowspec.
414 if only_show:
416 if only_show:
415 ui.pager('tracked')
417 ui.pager('tracked')
416 fm = ui.formatter('narrow', opts)
418 fm = ui.formatter('narrow', opts)
417 for i in sorted(oldincludes):
419 for i in sorted(oldincludes):
418 fm.startitem()
420 fm.startitem()
419 fm.write('status', '%s ', 'I', label='narrow.included')
421 fm.write('status', '%s ', 'I', label='narrow.included')
420 fm.write('pat', '%s\n', i, label='narrow.included')
422 fm.write('pat', '%s\n', i, label='narrow.included')
421 for i in sorted(oldexcludes):
423 for i in sorted(oldexcludes):
422 fm.startitem()
424 fm.startitem()
423 fm.write('status', '%s ', 'X', label='narrow.excluded')
425 fm.write('status', '%s ', 'X', label='narrow.excluded')
424 fm.write('pat', '%s\n', i, label='narrow.excluded')
426 fm.write('pat', '%s\n', i, label='narrow.excluded')
425 fm.end()
427 fm.end()
426 return 0
428 return 0
427
429
428 if not widening and not narrowing:
430 if not widening and not narrowing:
429 ui.status(_("nothing to widen or narrow\n"))
431 ui.status(_("nothing to widen or narrow\n"))
430 return 0
432 return 0
431
433
432 with repo.wlock(), repo.lock():
434 with repo.wlock(), repo.lock():
433 cmdutil.bailifchanged(repo)
435 cmdutil.bailifchanged(repo)
434
436
435 # Find the revisions we have in common with the remote. These will
437 # Find the revisions we have in common with the remote. These will
436 # be used for finding local-only changes for narrowing. They will
438 # be used for finding local-only changes for narrowing. They will
437 # also define the set of revisions to update for widening.
439 # also define the set of revisions to update for widening.
438 remotepath = ui.expandpath(remotepath or 'default')
440 remotepath = ui.expandpath(remotepath or 'default')
439 url, branches = hg.parseurl(remotepath)
441 url, branches = hg.parseurl(remotepath)
440 ui.status(_('comparing with %s\n') % util.hidepassword(url))
442 ui.status(_('comparing with %s\n') % util.hidepassword(url))
441 remote = hg.peer(repo, opts, url)
443 remote = hg.peer(repo, opts, url)
442
444
443 # check narrow support before doing anything if widening needs to be
445 # check narrow support before doing anything if widening needs to be
444 # performed. In future we should also abort if client is ellipses and
446 # performed. In future we should also abort if client is ellipses and
445 # server does not support ellipses
447 # server does not support ellipses
446 if widening and wireprototypes.NARROWCAP not in remote.capabilities():
448 if widening and wireprototypes.NARROWCAP not in remote.capabilities():
447 raise error.Abort(_("server does not support narrow clones"))
449 raise error.Abort(_("server does not support narrow clones"))
448
450
449 commoninc = discovery.findcommonincoming(repo, remote)
451 commoninc = discovery.findcommonincoming(repo, remote)
450
452
451 if narrowing:
453 if narrowing:
452 newincludes = oldincludes - removedincludes
454 newincludes = oldincludes - removedincludes
453 newexcludes = oldexcludes | addedexcludes
455 newexcludes = oldexcludes | addedexcludes
454 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
456 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
455 newincludes, newexcludes,
457 newincludes, newexcludes,
456 opts['force_delete_local_changes'])
458 opts['force_delete_local_changes'])
457 # _narrow() updated the narrowspec and _widen() below needs to
459 # _narrow() updated the narrowspec and _widen() below needs to
458 # use the updated values as its base (otherwise removed includes
460 # use the updated values as its base (otherwise removed includes
459 # and addedexcludes will be lost in the resulting narrowspec)
461 # and addedexcludes will be lost in the resulting narrowspec)
460 oldincludes = newincludes
462 oldincludes = newincludes
461 oldexcludes = newexcludes
463 oldexcludes = newexcludes
462
464
463 if widening:
465 if widening:
464 newincludes = oldincludes | addedincludes
466 newincludes = oldincludes | addedincludes
465 newexcludes = oldexcludes - removedexcludes
467 newexcludes = oldexcludes - removedexcludes
466 _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
468 _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes,
467 newincludes, newexcludes)
469 newincludes, newexcludes)
468
470
469 return 0
471 return 0
@@ -1,407 +1,430 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)
218 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
219 $ cd narrow-obsmarkers
220 $ echo a >> d0/f2
221 $ hg add d0/f2
222 $ hg ci -m 'modify d0/'
223 $ echo a >> d3/f2
224 $ hg add d3/f2
225 $ hg commit --amend -m 'modify d0/ and d3/'
226 $ hg log -T "{rev}: {desc}\n"
227 5: modify d0/ and d3/
228 3: add d10/f
229 2: add d3/f
230 1: add d2/f
231 0: add d0/f
232 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
233 $ hg log -T "{rev}: {desc}\n"
234 3: add d10/f
235 2: add d3/f
236 1: add d2/f
237 0: add d0/f
238 $ cd ..
239
217 Can remove last include, making repo empty
240 Can remove last include, making repo empty
218 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
241 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
219 adding changesets
242 adding changesets
220 adding manifests
243 adding manifests
221 adding file changes
244 adding file changes
222 added 2 changesets with 1 changes to 1 files
245 added 2 changesets with 1 changes to 1 files
223 new changesets *:* (glob)
246 new changesets *:* (glob)
224 updating to branch default
247 updating to branch default
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 $ cd narrow-empty
249 $ cd narrow-empty
227 $ hg tracked --removeinclude d0
250 $ hg tracked --removeinclude d0
228 comparing with ssh://user@dummy/master
251 comparing with ssh://user@dummy/master
229 searching for changes
252 searching for changes
230 looking for local changes to affected paths
253 looking for local changes to affected paths
231 deleting data/d0/f.i (reporevlogstore !)
254 deleting data/d0/f.i (reporevlogstore !)
232 deleting meta/d0/00manifest.i (tree !)
255 deleting meta/d0/00manifest.i (tree !)
233 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
256 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
234 deleting data/d0/f/index (reposimplestore !)
257 deleting data/d0/f/index (reposimplestore !)
235 $ hg tracked
258 $ hg tracked
236 $ hg files
259 $ hg files
237 [1]
260 [1]
238 $ test -d d0
261 $ test -d d0
239 [1]
262 [1]
240 Do some work in the empty clone
263 Do some work in the empty clone
241 $ hg diff --change .
264 $ hg diff --change .
242 $ hg branch foo
265 $ hg branch foo
243 marked working directory as branch foo
266 marked working directory as branch foo
244 (branches are permanent and global, did you want a bookmark?)
267 (branches are permanent and global, did you want a bookmark?)
245 $ hg ci -m empty
268 $ hg ci -m empty
246 $ hg pull -q
269 $ hg pull -q
247 Can widen the empty clone
270 Can widen the empty clone
248 $ hg tracked --addinclude d0
271 $ hg tracked --addinclude d0
249 comparing with ssh://user@dummy/master
272 comparing with ssh://user@dummy/master
250 searching for changes
273 searching for changes
251 no changes found
274 no changes found
252 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
275 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
253 adding changesets
276 adding changesets
254 adding manifests
277 adding manifests
255 adding file changes
278 adding file changes
256 added 3 changesets with 1 changes to 1 files
279 added 3 changesets with 1 changes to 1 files
257 new changesets *:* (glob)
280 new changesets *:* (glob)
258 $ hg tracked
281 $ hg tracked
259 I path:d0
282 I path:d0
260 $ hg files
283 $ hg files
261 d0/f
284 d0/f
262 $ find *
285 $ find *
263 d0
286 d0
264 d0/f
287 d0/f
265 $ cd ..
288 $ cd ..
266
289
267 TODO(martinvonz): test including e.g. d3/g and then removing it once
290 TODO(martinvonz): test including e.g. d3/g and then removing it once
268 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
291 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
269
292
270 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
293 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
271 requesting all changes
294 requesting all changes
272 adding changesets
295 adding changesets
273 adding manifests
296 adding manifests
274 adding file changes
297 adding file changes
275 added 8 changesets with 4 changes to 4 files
298 added 8 changesets with 4 changes to 4 files
276 new changesets *:* (glob)
299 new changesets *:* (glob)
277 updating to branch default
300 updating to branch default
278 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 $ cd narrow
302 $ cd narrow
280 $ hg tracked
303 $ hg tracked
281 I path:d0
304 I path:d0
282 I path:d3
305 I path:d3
283 I path:d6
306 I path:d6
284 I path:d9
307 I path:d9
285 $ hg tracked --removeinclude d6
308 $ hg tracked --removeinclude d6
286 comparing with ssh://user@dummy/master
309 comparing with ssh://user@dummy/master
287 searching for changes
310 searching for changes
288 looking for local changes to affected paths
311 looking for local changes to affected paths
289 deleting data/d6/f.i (reporevlogstore !)
312 deleting data/d6/f.i (reporevlogstore !)
290 deleting meta/d6/00manifest.i (tree !)
313 deleting meta/d6/00manifest.i (tree !)
291 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
314 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
292 deleting data/d6/f/index (reposimplestore !)
315 deleting data/d6/f/index (reposimplestore !)
293 $ hg tracked
316 $ hg tracked
294 I path:d0
317 I path:d0
295 I path:d3
318 I path:d3
296 I path:d9
319 I path:d9
297 #if repofncache
320 #if repofncache
298 $ hg debugrebuildfncache
321 $ hg debugrebuildfncache
299 fncache already up to date
322 fncache already up to date
300 #endif
323 #endif
301 $ find *
324 $ find *
302 d0
325 d0
303 d0/f
326 d0/f
304 d3
327 d3
305 d3/f
328 d3/f
306 d9
329 d9
307 d9/f
330 d9/f
308 $ hg verify -q
331 $ hg verify -q
309 $ hg tracked --addexclude d3/f
332 $ hg tracked --addexclude d3/f
310 comparing with ssh://user@dummy/master
333 comparing with ssh://user@dummy/master
311 searching for changes
334 searching for changes
312 looking for local changes to affected paths
335 looking for local changes to affected paths
313 deleting data/d3/f.i (reporevlogstore !)
336 deleting data/d3/f.i (reporevlogstore !)
314 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
337 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
315 deleting data/d3/f/index (reposimplestore !)
338 deleting data/d3/f/index (reposimplestore !)
316 $ hg tracked
339 $ hg tracked
317 I path:d0
340 I path:d0
318 I path:d3
341 I path:d3
319 I path:d9
342 I path:d9
320 X path:d3/f
343 X path:d3/f
321 #if repofncache
344 #if repofncache
322 $ hg debugrebuildfncache
345 $ hg debugrebuildfncache
323 fncache already up to date
346 fncache already up to date
324 #endif
347 #endif
325 $ find *
348 $ find *
326 d0
349 d0
327 d0/f
350 d0/f
328 d9
351 d9
329 d9/f
352 d9/f
330 $ hg verify -q
353 $ hg verify -q
331 $ hg tracked --addexclude d0
354 $ hg tracked --addexclude d0
332 comparing with ssh://user@dummy/master
355 comparing with ssh://user@dummy/master
333 searching for changes
356 searching for changes
334 looking for local changes to affected paths
357 looking for local changes to affected paths
335 deleting data/d0/f.i (reporevlogstore !)
358 deleting data/d0/f.i (reporevlogstore !)
336 deleting meta/d0/00manifest.i (tree !)
359 deleting meta/d0/00manifest.i (tree !)
337 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
360 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
338 deleting data/d0/f/index (reposimplestore !)
361 deleting data/d0/f/index (reposimplestore !)
339 $ hg tracked
362 $ hg tracked
340 I path:d3
363 I path:d3
341 I path:d9
364 I path:d9
342 X path:d0
365 X path:d0
343 X path:d3/f
366 X path:d3/f
344 #if repofncache
367 #if repofncache
345 $ hg debugrebuildfncache
368 $ hg debugrebuildfncache
346 fncache already up to date
369 fncache already up to date
347 #endif
370 #endif
348 $ find *
371 $ find *
349 d9
372 d9
350 d9/f
373 d9/f
351
374
352 Make a 15 of changes to d9 to test the path without --verbose
375 Make a 15 of changes to d9 to test the path without --verbose
353 (Note: using regexes instead of "* (glob)" because if the test fails, it
376 (Note: using regexes instead of "* (glob)" because if the test fails, it
354 produces more sensible diffs)
377 produces more sensible diffs)
355 $ hg tracked
378 $ hg tracked
356 I path:d3
379 I path:d3
357 I path:d9
380 I path:d9
358 X path:d0
381 X path:d0
359 X path:d3/f
382 X path:d3/f
360 $ for x in `$TESTDIR/seq.py 1 15`
383 $ for x in `$TESTDIR/seq.py 1 15`
361 > do
384 > do
362 > echo local change >> d9/f
385 > echo local change >> d9/f
363 > hg commit -m "change $x to d9/f"
386 > hg commit -m "change $x to d9/f"
364 > done
387 > done
365 $ hg tracked --removeinclude d9
388 $ hg tracked --removeinclude d9
366 comparing with ssh://user@dummy/master
389 comparing with ssh://user@dummy/master
367 searching for changes
390 searching for changes
368 looking for local changes to affected paths
391 looking for local changes to affected paths
369 The following changeset(s) or their ancestors have local changes not on the remote:
392 The following changeset(s) or their ancestors have local changes not on the remote:
370 ^[0-9a-f]{12}$ (re)
393 ^[0-9a-f]{12}$ (re)
371 ^[0-9a-f]{12}$ (re)
394 ^[0-9a-f]{12}$ (re)
372 ^[0-9a-f]{12}$ (re)
395 ^[0-9a-f]{12}$ (re)
373 ^[0-9a-f]{12}$ (re)
396 ^[0-9a-f]{12}$ (re)
374 ^[0-9a-f]{12}$ (re)
397 ^[0-9a-f]{12}$ (re)
375 ^[0-9a-f]{12}$ (re)
398 ^[0-9a-f]{12}$ (re)
376 ^[0-9a-f]{12}$ (re)
399 ^[0-9a-f]{12}$ (re)
377 ^[0-9a-f]{12}$ (re)
400 ^[0-9a-f]{12}$ (re)
378 ^[0-9a-f]{12}$ (re)
401 ^[0-9a-f]{12}$ (re)
379 ^[0-9a-f]{12}$ (re)
402 ^[0-9a-f]{12}$ (re)
380 ...and 5 more, use --verbose to list all
403 ...and 5 more, use --verbose to list all
381 abort: local changes found
404 abort: local changes found
382 (use --force-delete-local-changes to ignore)
405 (use --force-delete-local-changes to ignore)
383 [255]
406 [255]
384 Now test it *with* verbose.
407 Now test it *with* verbose.
385 $ hg tracked --removeinclude d9 --verbose
408 $ hg tracked --removeinclude d9 --verbose
386 comparing with ssh://user@dummy/master
409 comparing with ssh://user@dummy/master
387 searching for changes
410 searching for changes
388 looking for local changes to affected paths
411 looking for local changes to affected paths
389 The following changeset(s) or their ancestors have local changes not on the remote:
412 The following changeset(s) or their ancestors have local changes not on the remote:
390 ^[0-9a-f]{12}$ (re)
413 ^[0-9a-f]{12}$ (re)
391 ^[0-9a-f]{12}$ (re)
414 ^[0-9a-f]{12}$ (re)
392 ^[0-9a-f]{12}$ (re)
415 ^[0-9a-f]{12}$ (re)
393 ^[0-9a-f]{12}$ (re)
416 ^[0-9a-f]{12}$ (re)
394 ^[0-9a-f]{12}$ (re)
417 ^[0-9a-f]{12}$ (re)
395 ^[0-9a-f]{12}$ (re)
418 ^[0-9a-f]{12}$ (re)
396 ^[0-9a-f]{12}$ (re)
419 ^[0-9a-f]{12}$ (re)
397 ^[0-9a-f]{12}$ (re)
420 ^[0-9a-f]{12}$ (re)
398 ^[0-9a-f]{12}$ (re)
421 ^[0-9a-f]{12}$ (re)
399 ^[0-9a-f]{12}$ (re)
422 ^[0-9a-f]{12}$ (re)
400 ^[0-9a-f]{12}$ (re)
423 ^[0-9a-f]{12}$ (re)
401 ^[0-9a-f]{12}$ (re)
424 ^[0-9a-f]{12}$ (re)
402 ^[0-9a-f]{12}$ (re)
425 ^[0-9a-f]{12}$ (re)
403 ^[0-9a-f]{12}$ (re)
426 ^[0-9a-f]{12}$ (re)
404 ^[0-9a-f]{12}$ (re)
427 ^[0-9a-f]{12}$ (re)
405 abort: local changes found
428 abort: local changes found
406 (use --force-delete-local-changes to ignore)
429 (use --force-delete-local-changes to ignore)
407 [255]
430 [255]
General Comments 0
You need to be logged in to leave comments. Login now