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