##// END OF EJS Templates
largefiles: fix path handling for cp/mv (issue3516)...
Matt Harbison -
r17245:6e84171a stable
parent child Browse files
Show More
@@ -1,1080 +1,1082 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 15 node, archival, error, merge
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18 from hgext import rebase
19 19
20 20 import lfutil
21 21 import lfcommands
22 22
23 23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 24
25 25 def installnormalfilesmatchfn(manifest):
26 26 '''overrides scmutil.match so that the matcher it returns will ignore all
27 27 largefiles'''
28 28 oldmatch = None # for the closure
29 29 def overridematch(ctx, pats=[], opts={}, globbed=False,
30 30 default='relpath'):
31 31 match = oldmatch(ctx, pats, opts, globbed, default)
32 32 m = copy.copy(match)
33 33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
34 34 manifest)
35 35 m._files = filter(notlfile, m._files)
36 36 m._fmap = set(m._files)
37 37 origmatchfn = m.matchfn
38 38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
39 39 return m
40 40 oldmatch = installmatchfn(overridematch)
41 41
42 42 def installmatchfn(f):
43 43 oldmatch = scmutil.match
44 44 setattr(f, 'oldmatch', oldmatch)
45 45 scmutil.match = f
46 46 return oldmatch
47 47
48 48 def restorematchfn():
49 49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
50 50 was called. no-op if scmutil.match is its original function.
51 51
52 52 Note that n calls to installnormalfilesmatchfn will require n calls to
53 53 restore matchfn to reverse'''
54 54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
55 55
56 56 def addlargefiles(ui, repo, *pats, **opts):
57 57 large = opts.pop('large', None)
58 58 lfsize = lfutil.getminsize(
59 59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
60 60
61 61 lfmatcher = None
62 62 if lfutil.islfilesrepo(repo):
63 63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
64 64 if lfpats:
65 65 lfmatcher = match_.match(repo.root, '', list(lfpats))
66 66
67 67 lfnames = []
68 68 m = scmutil.match(repo[None], pats, opts)
69 69 m.bad = lambda x, y: None
70 70 wctx = repo[None]
71 71 for f in repo.walk(m):
72 72 exact = m.exact(f)
73 73 lfile = lfutil.standin(f) in wctx
74 74 nfile = f in wctx
75 75 exists = lfile or nfile
76 76
77 77 # Don't warn the user when they attempt to add a normal tracked file.
78 78 # The normal add code will do that for us.
79 79 if exact and exists:
80 80 if lfile:
81 81 ui.warn(_('%s already a largefile\n') % f)
82 82 continue
83 83
84 84 if (exact or not exists) and not lfutil.isstandin(f):
85 85 wfile = repo.wjoin(f)
86 86
87 87 # In case the file was removed previously, but not committed
88 88 # (issue3507)
89 89 if not os.path.exists(wfile):
90 90 continue
91 91
92 92 abovemin = (lfsize and
93 93 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
94 94 if large or abovemin or (lfmatcher and lfmatcher(f)):
95 95 lfnames.append(f)
96 96 if ui.verbose or not exact:
97 97 ui.status(_('adding %s as a largefile\n') % m.rel(f))
98 98
99 99 bad = []
100 100 standins = []
101 101
102 102 # Need to lock, otherwise there could be a race condition between
103 103 # when standins are created and added to the repo.
104 104 wlock = repo.wlock()
105 105 try:
106 106 if not opts.get('dry_run'):
107 107 lfdirstate = lfutil.openlfdirstate(ui, repo)
108 108 for f in lfnames:
109 109 standinname = lfutil.standin(f)
110 110 lfutil.writestandin(repo, standinname, hash='',
111 111 executable=lfutil.getexecutable(repo.wjoin(f)))
112 112 standins.append(standinname)
113 113 if lfdirstate[f] == 'r':
114 114 lfdirstate.normallookup(f)
115 115 else:
116 116 lfdirstate.add(f)
117 117 lfdirstate.write()
118 118 bad += [lfutil.splitstandin(f)
119 119 for f in lfutil.repoadd(repo, standins)
120 120 if f in m.files()]
121 121 finally:
122 122 wlock.release()
123 123 return bad
124 124
125 125 def removelargefiles(ui, repo, *pats, **opts):
126 126 after = opts.get('after')
127 127 if not pats and not after:
128 128 raise util.Abort(_('no files specified'))
129 129 m = scmutil.match(repo[None], pats, opts)
130 130 try:
131 131 repo.lfstatus = True
132 132 s = repo.status(match=m, clean=True)
133 133 finally:
134 134 repo.lfstatus = False
135 135 manifest = repo[None].manifest()
136 136 modified, added, deleted, clean = [[f for f in list
137 137 if lfutil.standin(f) in manifest]
138 138 for list in [s[0], s[1], s[3], s[6]]]
139 139
140 140 def warn(files, reason):
141 141 for f in files:
142 142 ui.warn(_('not removing %s: %s (use forget to undo)\n')
143 143 % (m.rel(f), reason))
144 144
145 145 if after:
146 146 remove, forget = deleted, []
147 147 warn(modified + added + clean, _('file still exists'))
148 148 else:
149 149 remove, forget = deleted + clean, []
150 150 warn(modified, _('file is modified'))
151 151 warn(added, _('file has been marked for add'))
152 152
153 153 for f in sorted(remove + forget):
154 154 if ui.verbose or not m.exact(f):
155 155 ui.status(_('removing %s\n') % m.rel(f))
156 156
157 157 # Need to lock because standin files are deleted then removed from the
158 158 # repository and we could race inbetween.
159 159 wlock = repo.wlock()
160 160 try:
161 161 lfdirstate = lfutil.openlfdirstate(ui, repo)
162 162 for f in remove:
163 163 if not after:
164 164 # If this is being called by addremove, notify the user that we
165 165 # are removing the file.
166 166 if getattr(repo, "_isaddremove", False):
167 167 ui.status(_('removing %s\n') % f)
168 168 if os.path.exists(repo.wjoin(f)):
169 169 util.unlinkpath(repo.wjoin(f))
170 170 lfdirstate.remove(f)
171 171 lfdirstate.write()
172 172 forget = [lfutil.standin(f) for f in forget]
173 173 remove = [lfutil.standin(f) for f in remove]
174 174 lfutil.repoforget(repo, forget)
175 175 # If this is being called by addremove, let the original addremove
176 176 # function handle this.
177 177 if not getattr(repo, "_isaddremove", False):
178 178 lfutil.reporemove(repo, remove, unlink=True)
179 179 else:
180 180 lfutil.reporemove(repo, remove, unlink=False)
181 181 finally:
182 182 wlock.release()
183 183
184 184 # For overriding mercurial.hgweb.webcommands so that largefiles will
185 185 # appear at their right place in the manifests.
186 186 def decodepath(orig, path):
187 187 return lfutil.splitstandin(path) or path
188 188
189 189 # -- Wrappers: modify existing commands --------------------------------
190 190
191 191 # Add works by going through the files that the user wanted to add and
192 192 # checking if they should be added as largefiles. Then it makes a new
193 193 # matcher which matches only the normal files and runs the original
194 194 # version of add.
195 195 def overrideadd(orig, ui, repo, *pats, **opts):
196 196 normal = opts.pop('normal')
197 197 if normal:
198 198 if opts.get('large'):
199 199 raise util.Abort(_('--normal cannot be used with --large'))
200 200 return orig(ui, repo, *pats, **opts)
201 201 bad = addlargefiles(ui, repo, *pats, **opts)
202 202 installnormalfilesmatchfn(repo[None].manifest())
203 203 result = orig(ui, repo, *pats, **opts)
204 204 restorematchfn()
205 205
206 206 return (result == 1 or bad) and 1 or 0
207 207
208 208 def overrideremove(orig, ui, repo, *pats, **opts):
209 209 installnormalfilesmatchfn(repo[None].manifest())
210 210 orig(ui, repo, *pats, **opts)
211 211 restorematchfn()
212 212 removelargefiles(ui, repo, *pats, **opts)
213 213
214 214 def overridestatusfn(orig, repo, rev2, **opts):
215 215 try:
216 216 repo._repo.lfstatus = True
217 217 return orig(repo, rev2, **opts)
218 218 finally:
219 219 repo._repo.lfstatus = False
220 220
221 221 def overridestatus(orig, ui, repo, *pats, **opts):
222 222 try:
223 223 repo.lfstatus = True
224 224 return orig(ui, repo, *pats, **opts)
225 225 finally:
226 226 repo.lfstatus = False
227 227
228 228 def overridedirty(orig, repo, ignoreupdate=False):
229 229 try:
230 230 repo._repo.lfstatus = True
231 231 return orig(repo, ignoreupdate)
232 232 finally:
233 233 repo._repo.lfstatus = False
234 234
235 235 def overridelog(orig, ui, repo, *pats, **opts):
236 236 try:
237 237 repo.lfstatus = True
238 238 orig(ui, repo, *pats, **opts)
239 239 finally:
240 240 repo.lfstatus = False
241 241
242 242 def overrideverify(orig, ui, repo, *pats, **opts):
243 243 large = opts.pop('large', False)
244 244 all = opts.pop('lfa', False)
245 245 contents = opts.pop('lfc', False)
246 246
247 247 result = orig(ui, repo, *pats, **opts)
248 248 if large:
249 249 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
250 250 return result
251 251
252 252 # Override needs to refresh standins so that update's normal merge
253 253 # will go through properly. Then the other update hook (overriding repo.update)
254 254 # will get the new files. Filemerge is also overriden so that the merge
255 255 # will merge standins correctly.
256 256 def overrideupdate(orig, ui, repo, *pats, **opts):
257 257 lfdirstate = lfutil.openlfdirstate(ui, repo)
258 258 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
259 259 False, False)
260 260 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
261 261
262 262 # Need to lock between the standins getting updated and their
263 263 # largefiles getting updated
264 264 wlock = repo.wlock()
265 265 try:
266 266 if opts['check']:
267 267 mod = len(modified) > 0
268 268 for lfile in unsure:
269 269 standin = lfutil.standin(lfile)
270 270 if repo['.'][standin].data().strip() != \
271 271 lfutil.hashfile(repo.wjoin(lfile)):
272 272 mod = True
273 273 else:
274 274 lfdirstate.normal(lfile)
275 275 lfdirstate.write()
276 276 if mod:
277 277 raise util.Abort(_('uncommitted local changes'))
278 278 # XXX handle removed differently
279 279 if not opts['clean']:
280 280 for lfile in unsure + modified + added:
281 281 lfutil.updatestandin(repo, lfutil.standin(lfile))
282 282 finally:
283 283 wlock.release()
284 284 return orig(ui, repo, *pats, **opts)
285 285
286 286 # Before starting the manifest merge, merge.updates will call
287 287 # _checkunknown to check if there are any files in the merged-in
288 288 # changeset that collide with unknown files in the working copy.
289 289 #
290 290 # The largefiles are seen as unknown, so this prevents us from merging
291 291 # in a file 'foo' if we already have a largefile with the same name.
292 292 #
293 293 # The overridden function filters the unknown files by removing any
294 294 # largefiles. This makes the merge proceed and we can then handle this
295 295 # case further in the overridden manifestmerge function below.
296 296 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
297 297 if lfutil.standin(f) in wctx:
298 298 return False
299 299 return origfn(repo, wctx, mctx, f)
300 300
301 301 # The manifest merge handles conflicts on the manifest level. We want
302 302 # to handle changes in largefile-ness of files at this level too.
303 303 #
304 304 # The strategy is to run the original manifestmerge and then process
305 305 # the action list it outputs. There are two cases we need to deal with:
306 306 #
307 307 # 1. Normal file in p1, largefile in p2. Here the largefile is
308 308 # detected via its standin file, which will enter the working copy
309 309 # with a "get" action. It is not "merge" since the standin is all
310 310 # Mercurial is concerned with at this level -- the link to the
311 311 # existing normal file is not relevant here.
312 312 #
313 313 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
314 314 # since the largefile will be present in the working copy and
315 315 # different from the normal file in p2. Mercurial therefore
316 316 # triggers a merge action.
317 317 #
318 318 # In both cases, we prompt the user and emit new actions to either
319 319 # remove the standin (if the normal file was kept) or to remove the
320 320 # normal file and get the standin (if the largefile was kept). The
321 321 # default prompt answer is to use the largefile version since it was
322 322 # presumably changed on purpose.
323 323 #
324 324 # Finally, the merge.applyupdates function will then take care of
325 325 # writing the files into the working copy and lfcommands.updatelfiles
326 326 # will update the largefiles.
327 327 def overridemanifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
328 328 actions = origfn(repo, p1, p2, pa, overwrite, partial)
329 329 processed = []
330 330
331 331 for action in actions:
332 332 if overwrite:
333 333 processed.append(action)
334 334 continue
335 335 f, m = action[:2]
336 336
337 337 choices = (_('&Largefile'), _('&Normal file'))
338 338 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
339 339 # Case 1: normal file in the working copy, largefile in
340 340 # the second parent
341 341 lfile = lfutil.splitstandin(f)
342 342 standin = f
343 343 msg = _('%s has been turned into a largefile\n'
344 344 'use (l)argefile or keep as (n)ormal file?') % lfile
345 345 if repo.ui.promptchoice(msg, choices, 0) == 0:
346 346 processed.append((lfile, "r"))
347 347 processed.append((standin, "g", p2.flags(standin)))
348 348 else:
349 349 processed.append((standin, "r"))
350 350 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
351 351 # Case 2: largefile in the working copy, normal file in
352 352 # the second parent
353 353 standin = lfutil.standin(f)
354 354 lfile = f
355 355 msg = _('%s has been turned into a normal file\n'
356 356 'keep as (l)argefile or use (n)ormal file?') % lfile
357 357 if repo.ui.promptchoice(msg, choices, 0) == 0:
358 358 processed.append((lfile, "r"))
359 359 else:
360 360 processed.append((standin, "r"))
361 361 processed.append((lfile, "g", p2.flags(lfile)))
362 362 else:
363 363 processed.append(action)
364 364
365 365 return processed
366 366
367 367 # Override filemerge to prompt the user about how they wish to merge
368 368 # largefiles. This will handle identical edits, and copy/rename +
369 369 # edit without prompting the user.
370 370 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
371 371 # Use better variable names here. Because this is a wrapper we cannot
372 372 # change the variable names in the function declaration.
373 373 fcdest, fcother, fcancestor = fcd, fco, fca
374 374 if not lfutil.isstandin(orig):
375 375 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
376 376 else:
377 377 if not fcother.cmp(fcdest): # files identical?
378 378 return None
379 379
380 380 # backwards, use working dir parent as ancestor
381 381 if fcancestor == fcother:
382 382 fcancestor = fcdest.parents()[0]
383 383
384 384 if orig != fcother.path():
385 385 repo.ui.status(_('merging %s and %s to %s\n')
386 386 % (lfutil.splitstandin(orig),
387 387 lfutil.splitstandin(fcother.path()),
388 388 lfutil.splitstandin(fcdest.path())))
389 389 else:
390 390 repo.ui.status(_('merging %s\n')
391 391 % lfutil.splitstandin(fcdest.path()))
392 392
393 393 if fcancestor.path() != fcother.path() and fcother.data() == \
394 394 fcancestor.data():
395 395 return 0
396 396 if fcancestor.path() != fcdest.path() and fcdest.data() == \
397 397 fcancestor.data():
398 398 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
399 399 return 0
400 400
401 401 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
402 402 'keep (l)ocal or take (o)ther?') %
403 403 lfutil.splitstandin(orig),
404 404 (_('&Local'), _('&Other')), 0) == 0:
405 405 return 0
406 406 else:
407 407 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
408 408 return 0
409 409
410 410 # Copy first changes the matchers to match standins instead of
411 411 # largefiles. Then it overrides util.copyfile in that function it
412 412 # checks if the destination largefile already exists. It also keeps a
413 413 # list of copied files so that the largefiles can be copied and the
414 414 # dirstate updated.
415 415 def overridecopy(orig, ui, repo, pats, opts, rename=False):
416 416 # doesn't remove largefile on rename
417 417 if len(pats) < 2:
418 418 # this isn't legal, let the original function deal with it
419 419 return orig(ui, repo, pats, opts, rename)
420 420
421 421 def makestandin(relpath):
422 422 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
423 423 return os.path.join(repo.wjoin(lfutil.standin(path)))
424 424
425 425 fullpats = scmutil.expandpats(pats)
426 426 dest = fullpats[-1]
427 427
428 428 if os.path.isdir(dest):
429 429 if not os.path.isdir(makestandin(dest)):
430 430 os.makedirs(makestandin(dest))
431 431 # This could copy both lfiles and normal files in one command,
432 432 # but we don't want to do that. First replace their matcher to
433 433 # only match normal files and run it, then replace it to just
434 434 # match largefiles and run it again.
435 435 nonormalfiles = False
436 436 nolfiles = False
437 437 try:
438 438 try:
439 439 installnormalfilesmatchfn(repo[None].manifest())
440 440 result = orig(ui, repo, pats, opts, rename)
441 441 except util.Abort, e:
442 442 if str(e) != 'no files to copy':
443 443 raise e
444 444 else:
445 445 nonormalfiles = True
446 446 result = 0
447 447 finally:
448 448 restorematchfn()
449 449
450 450 # The first rename can cause our current working directory to be removed.
451 451 # In that case there is nothing left to copy/rename so just quit.
452 452 try:
453 453 repo.getcwd()
454 454 except OSError:
455 455 return result
456 456
457 457 try:
458 458 try:
459 459 # When we call orig below it creates the standins but we don't add
460 460 # them to the dir state until later so lock during that time.
461 461 wlock = repo.wlock()
462 462
463 463 manifest = repo[None].manifest()
464 464 oldmatch = None # for the closure
465 465 def overridematch(ctx, pats=[], opts={}, globbed=False,
466 466 default='relpath'):
467 467 newpats = []
468 468 # The patterns were previously mangled to add the standin
469 469 # directory; we need to remove that now
470 470 for pat in pats:
471 471 if match_.patkind(pat) is None and lfutil.shortname in pat:
472 472 newpats.append(pat.replace(lfutil.shortname, ''))
473 473 else:
474 474 newpats.append(pat)
475 475 match = oldmatch(ctx, newpats, opts, globbed, default)
476 476 m = copy.copy(match)
477 477 lfile = lambda f: lfutil.standin(f) in manifest
478 478 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
479 479 m._fmap = set(m._files)
480 480 origmatchfn = m.matchfn
481 481 m.matchfn = lambda f: (lfutil.isstandin(f) and
482 482 (f in manifest) and
483 483 origmatchfn(lfutil.splitstandin(f)) or
484 484 None)
485 485 return m
486 486 oldmatch = installmatchfn(overridematch)
487 487 listpats = []
488 488 for pat in pats:
489 489 if match_.patkind(pat) is not None:
490 490 listpats.append(pat)
491 491 else:
492 492 listpats.append(makestandin(pat))
493 493
494 494 try:
495 495 origcopyfile = util.copyfile
496 496 copiedfiles = []
497 497 def overridecopyfile(src, dest):
498 498 if (lfutil.shortname in src and
499 499 dest.startswith(repo.wjoin(lfutil.shortname))):
500 500 destlfile = dest.replace(lfutil.shortname, '')
501 501 if not opts['force'] and os.path.exists(destlfile):
502 502 raise IOError('',
503 503 _('destination largefile already exists'))
504 504 copiedfiles.append((src, dest))
505 505 origcopyfile(src, dest)
506 506
507 507 util.copyfile = overridecopyfile
508 508 result += orig(ui, repo, listpats, opts, rename)
509 509 finally:
510 510 util.copyfile = origcopyfile
511 511
512 512 lfdirstate = lfutil.openlfdirstate(ui, repo)
513 513 for (src, dest) in copiedfiles:
514 514 if (lfutil.shortname in src and
515 515 dest.startswith(repo.wjoin(lfutil.shortname))):
516 516 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
517 517 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
518 destlfiledir = os.path.dirname(destlfile) or '.'
518 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
519 519 if not os.path.isdir(destlfiledir):
520 520 os.makedirs(destlfiledir)
521 521 if rename:
522 522 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
523 523 lfdirstate.remove(srclfile)
524 524 else:
525 util.copyfile(srclfile, destlfile)
525 util.copyfile(repo.wjoin(srclfile),
526 repo.wjoin(destlfile))
527
526 528 lfdirstate.add(destlfile)
527 529 lfdirstate.write()
528 530 except util.Abort, e:
529 531 if str(e) != 'no files to copy':
530 532 raise e
531 533 else:
532 534 nolfiles = True
533 535 finally:
534 536 restorematchfn()
535 537 wlock.release()
536 538
537 539 if nolfiles and nonormalfiles:
538 540 raise util.Abort(_('no files to copy'))
539 541
540 542 return result
541 543
542 544 # When the user calls revert, we have to be careful to not revert any
543 545 # changes to other largefiles accidentally. This means we have to keep
544 546 # track of the largefiles that are being reverted so we only pull down
545 547 # the necessary largefiles.
546 548 #
547 549 # Standins are only updated (to match the hash of largefiles) before
548 550 # commits. Update the standins then run the original revert, changing
549 551 # the matcher to hit standins instead of largefiles. Based on the
550 552 # resulting standins update the largefiles. Then return the standins
551 553 # to their proper state
552 554 def overriderevert(orig, ui, repo, *pats, **opts):
553 555 # Because we put the standins in a bad state (by updating them)
554 556 # and then return them to a correct state we need to lock to
555 557 # prevent others from changing them in their incorrect state.
556 558 wlock = repo.wlock()
557 559 try:
558 560 lfdirstate = lfutil.openlfdirstate(ui, repo)
559 561 (modified, added, removed, missing, unknown, ignored, clean) = \
560 562 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
561 563 for lfile in modified:
562 564 lfutil.updatestandin(repo, lfutil.standin(lfile))
563 565 for lfile in missing:
564 566 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
565 567 os.unlink(repo.wjoin(lfutil.standin(lfile)))
566 568
567 569 try:
568 570 ctx = repo[opts.get('rev')]
569 571 oldmatch = None # for the closure
570 572 def overridematch(ctx, pats=[], opts={}, globbed=False,
571 573 default='relpath'):
572 574 match = oldmatch(ctx, pats, opts, globbed, default)
573 575 m = copy.copy(match)
574 576 def tostandin(f):
575 577 if lfutil.standin(f) in ctx:
576 578 return lfutil.standin(f)
577 579 elif lfutil.standin(f) in repo[None]:
578 580 return None
579 581 return f
580 582 m._files = [tostandin(f) for f in m._files]
581 583 m._files = [f for f in m._files if f is not None]
582 584 m._fmap = set(m._files)
583 585 origmatchfn = m.matchfn
584 586 def matchfn(f):
585 587 if lfutil.isstandin(f):
586 588 # We need to keep track of what largefiles are being
587 589 # matched so we know which ones to update later --
588 590 # otherwise we accidentally revert changes to other
589 591 # largefiles. This is repo-specific, so duckpunch the
590 592 # repo object to keep the list of largefiles for us
591 593 # later.
592 594 if origmatchfn(lfutil.splitstandin(f)) and \
593 595 (f in repo[None] or f in ctx):
594 596 lfileslist = getattr(repo, '_lfilestoupdate', [])
595 597 lfileslist.append(lfutil.splitstandin(f))
596 598 repo._lfilestoupdate = lfileslist
597 599 return True
598 600 else:
599 601 return False
600 602 return origmatchfn(f)
601 603 m.matchfn = matchfn
602 604 return m
603 605 oldmatch = installmatchfn(overridematch)
604 606 scmutil.match
605 607 matches = overridematch(repo[None], pats, opts)
606 608 orig(ui, repo, *pats, **opts)
607 609 finally:
608 610 restorematchfn()
609 611 lfileslist = getattr(repo, '_lfilestoupdate', [])
610 612 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
611 613 printmessage=False)
612 614
613 615 # empty out the largefiles list so we start fresh next time
614 616 repo._lfilestoupdate = []
615 617 for lfile in modified:
616 618 if lfile in lfileslist:
617 619 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
618 620 in repo['.']:
619 621 lfutil.writestandin(repo, lfutil.standin(lfile),
620 622 repo['.'][lfile].data().strip(),
621 623 'x' in repo['.'][lfile].flags())
622 624 lfdirstate = lfutil.openlfdirstate(ui, repo)
623 625 for lfile in added:
624 626 standin = lfutil.standin(lfile)
625 627 if standin not in ctx and (standin in matches or opts.get('all')):
626 628 if lfile in lfdirstate:
627 629 lfdirstate.drop(lfile)
628 630 util.unlinkpath(repo.wjoin(standin))
629 631 lfdirstate.write()
630 632 finally:
631 633 wlock.release()
632 634
633 635 def hgupdate(orig, repo, node):
634 636 # Only call updatelfiles the standins that have changed to save time
635 637 oldstandins = lfutil.getstandinsstate(repo)
636 638 result = orig(repo, node)
637 639 newstandins = lfutil.getstandinsstate(repo)
638 640 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
639 641 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
640 642 return result
641 643
642 644 def hgclean(orig, repo, node, show_stats=True):
643 645 result = orig(repo, node, show_stats)
644 646 lfcommands.updatelfiles(repo.ui, repo)
645 647 return result
646 648
647 649 def hgmerge(orig, repo, node, force=None, remind=True):
648 650 # Mark the repo as being in the middle of a merge, so that
649 651 # updatelfiles() will know that it needs to trust the standins in
650 652 # the working copy, not in the standins in the current node
651 653 repo._ismerging = True
652 654 try:
653 655 result = orig(repo, node, force, remind)
654 656 lfcommands.updatelfiles(repo.ui, repo)
655 657 finally:
656 658 repo._ismerging = False
657 659 return result
658 660
659 661 # When we rebase a repository with remotely changed largefiles, we need to
660 662 # take some extra care so that the largefiles are correctly updated in the
661 663 # working copy
662 664 def overridepull(orig, ui, repo, source=None, **opts):
663 665 revsprepull = len(repo)
664 666 if opts.get('rebase', False):
665 667 repo._isrebasing = True
666 668 try:
667 669 if opts.get('update'):
668 670 del opts['update']
669 671 ui.debug('--update and --rebase are not compatible, ignoring '
670 672 'the update flag\n')
671 673 del opts['rebase']
672 674 cmdutil.bailifchanged(repo)
673 675 origpostincoming = commands.postincoming
674 676 def _dummy(*args, **kwargs):
675 677 pass
676 678 commands.postincoming = _dummy
677 679 repo.lfpullsource = source
678 680 if not source:
679 681 source = 'default'
680 682 try:
681 683 result = commands.pull(ui, repo, source, **opts)
682 684 finally:
683 685 commands.postincoming = origpostincoming
684 686 revspostpull = len(repo)
685 687 if revspostpull > revsprepull:
686 688 result = result or rebase.rebase(ui, repo)
687 689 finally:
688 690 repo._isrebasing = False
689 691 else:
690 692 repo.lfpullsource = source
691 693 if not source:
692 694 source = 'default'
693 695 oldheads = lfutil.getcurrentheads(repo)
694 696 result = orig(ui, repo, source, **opts)
695 697 # If we do not have the new largefiles for any new heads we pulled, we
696 698 # will run into a problem later if we try to merge or rebase with one of
697 699 # these heads, so cache the largefiles now direclty into the system
698 700 # cache.
699 701 ui.status(_("caching new largefiles\n"))
700 702 numcached = 0
701 703 heads = lfutil.getcurrentheads(repo)
702 704 newheads = set(heads).difference(set(oldheads))
703 705 for head in newheads:
704 706 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
705 707 numcached += len(cached)
706 708 ui.status(_("%d largefiles cached\n") % numcached)
707 709 if opts.get('all_largefiles'):
708 710 revspostpull = len(repo)
709 711 revs = []
710 712 for rev in xrange(revsprepull + 1, revspostpull):
711 713 revs.append(repo[rev].rev())
712 714 lfcommands.downloadlfiles(ui, repo, revs)
713 715 return result
714 716
715 717 def overrideclone(orig, ui, source, dest=None, **opts):
716 718 if dest is None:
717 719 dest = hg.defaultdest(source)
718 720 if opts.get('all_largefiles') and not hg.islocal(dest):
719 721 raise util.Abort(_(
720 722 '--all-largefiles is incompatible with non-local destination %s' %
721 723 dest))
722 724 result = hg.clone(ui, opts, source, dest,
723 725 pull=opts.get('pull'),
724 726 stream=opts.get('uncompressed'),
725 727 rev=opts.get('rev'),
726 728 update=True, # required for successful walkchangerevs
727 729 branch=opts.get('branch'))
728 730 if result is None:
729 731 return True
730 732 if opts.get('all_largefiles'):
731 733 sourcerepo, destrepo = result
732 734 success, missing = lfcommands.downloadlfiles(ui, destrepo.local(), None)
733 735 return missing != 0
734 736 return result is None
735 737
736 738 def overriderebase(orig, ui, repo, **opts):
737 739 repo._isrebasing = True
738 740 try:
739 741 orig(ui, repo, **opts)
740 742 finally:
741 743 repo._isrebasing = False
742 744
743 745 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
744 746 prefix=None, mtime=None, subrepos=None):
745 747 # No need to lock because we are only reading history and
746 748 # largefile caches, neither of which are modified.
747 749 lfcommands.cachelfiles(repo.ui, repo, node)
748 750
749 751 if kind not in archival.archivers:
750 752 raise util.Abort(_("unknown archive type '%s'") % kind)
751 753
752 754 ctx = repo[node]
753 755
754 756 if kind == 'files':
755 757 if prefix:
756 758 raise util.Abort(
757 759 _('cannot give prefix when archiving to files'))
758 760 else:
759 761 prefix = archival.tidyprefix(dest, kind, prefix)
760 762
761 763 def write(name, mode, islink, getdata):
762 764 if matchfn and not matchfn(name):
763 765 return
764 766 data = getdata()
765 767 if decode:
766 768 data = repo.wwritedata(name, data)
767 769 archiver.addfile(prefix + name, mode, islink, data)
768 770
769 771 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
770 772
771 773 if repo.ui.configbool("ui", "archivemeta", True):
772 774 def metadata():
773 775 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
774 776 hex(repo.changelog.node(0)), hex(node), ctx.branch())
775 777
776 778 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
777 779 if repo.tagtype(t) == 'global')
778 780 if not tags:
779 781 repo.ui.pushbuffer()
780 782 opts = {'template': '{latesttag}\n{latesttagdistance}',
781 783 'style': '', 'patch': None, 'git': None}
782 784 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
783 785 ltags, dist = repo.ui.popbuffer().split('\n')
784 786 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
785 787 tags += 'latesttagdistance: %s\n' % dist
786 788
787 789 return base + tags
788 790
789 791 write('.hg_archival.txt', 0644, False, metadata)
790 792
791 793 for f in ctx:
792 794 ff = ctx.flags(f)
793 795 getdata = ctx[f].data
794 796 if lfutil.isstandin(f):
795 797 path = lfutil.findfile(repo, getdata().strip())
796 798 if path is None:
797 799 raise util.Abort(
798 800 _('largefile %s not found in repo store or system cache')
799 801 % lfutil.splitstandin(f))
800 802 f = lfutil.splitstandin(f)
801 803
802 804 def getdatafn():
803 805 fd = None
804 806 try:
805 807 fd = open(path, 'rb')
806 808 return fd.read()
807 809 finally:
808 810 if fd:
809 811 fd.close()
810 812
811 813 getdata = getdatafn
812 814 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
813 815
814 816 if subrepos:
815 817 for subpath in ctx.substate:
816 818 sub = ctx.sub(subpath)
817 819 submatch = match_.narrowmatcher(subpath, matchfn)
818 820 sub.archive(repo.ui, archiver, prefix, submatch)
819 821
820 822 archiver.done()
821 823
822 824 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
823 825 rev = repo._state[1]
824 826 ctx = repo._repo[rev]
825 827
826 828 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
827 829
828 830 def write(name, mode, islink, getdata):
829 831 # At this point, the standin has been replaced with the largefile name,
830 832 # so the normal matcher works here without the lfutil variants.
831 833 if match and not match(f):
832 834 return
833 835 data = getdata()
834 836
835 837 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
836 838
837 839 for f in ctx:
838 840 ff = ctx.flags(f)
839 841 getdata = ctx[f].data
840 842 if lfutil.isstandin(f):
841 843 path = lfutil.findfile(repo._repo, getdata().strip())
842 844 if path is None:
843 845 raise util.Abort(
844 846 _('largefile %s not found in repo store or system cache')
845 847 % lfutil.splitstandin(f))
846 848 f = lfutil.splitstandin(f)
847 849
848 850 def getdatafn():
849 851 fd = None
850 852 try:
851 853 fd = open(os.path.join(prefix, path), 'rb')
852 854 return fd.read()
853 855 finally:
854 856 if fd:
855 857 fd.close()
856 858
857 859 getdata = getdatafn
858 860
859 861 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
860 862
861 863 for subpath in ctx.substate:
862 864 sub = ctx.sub(subpath)
863 865 submatch = match_.narrowmatcher(subpath, match)
864 866 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
865 867 submatch)
866 868
867 869 # If a largefile is modified, the change is not reflected in its
868 870 # standin until a commit. cmdutil.bailifchanged() raises an exception
869 871 # if the repo has uncommitted changes. Wrap it to also check if
870 872 # largefiles were changed. This is used by bisect and backout.
871 873 def overridebailifchanged(orig, repo):
872 874 orig(repo)
873 875 repo.lfstatus = True
874 876 modified, added, removed, deleted = repo.status()[:4]
875 877 repo.lfstatus = False
876 878 if modified or added or removed or deleted:
877 879 raise util.Abort(_('outstanding uncommitted changes'))
878 880
879 881 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
880 882 def overridefetch(orig, ui, repo, *pats, **opts):
881 883 repo.lfstatus = True
882 884 modified, added, removed, deleted = repo.status()[:4]
883 885 repo.lfstatus = False
884 886 if modified or added or removed or deleted:
885 887 raise util.Abort(_('outstanding uncommitted changes'))
886 888 return orig(ui, repo, *pats, **opts)
887 889
888 890 def overrideforget(orig, ui, repo, *pats, **opts):
889 891 installnormalfilesmatchfn(repo[None].manifest())
890 892 orig(ui, repo, *pats, **opts)
891 893 restorematchfn()
892 894 m = scmutil.match(repo[None], pats, opts)
893 895
894 896 try:
895 897 repo.lfstatus = True
896 898 s = repo.status(match=m, clean=True)
897 899 finally:
898 900 repo.lfstatus = False
899 901 forget = sorted(s[0] + s[1] + s[3] + s[6])
900 902 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
901 903
902 904 for f in forget:
903 905 if lfutil.standin(f) not in repo.dirstate and not \
904 906 os.path.isdir(m.rel(lfutil.standin(f))):
905 907 ui.warn(_('not removing %s: file is already untracked\n')
906 908 % m.rel(f))
907 909
908 910 for f in forget:
909 911 if ui.verbose or not m.exact(f):
910 912 ui.status(_('removing %s\n') % m.rel(f))
911 913
912 914 # Need to lock because standin files are deleted then removed from the
913 915 # repository and we could race inbetween.
914 916 wlock = repo.wlock()
915 917 try:
916 918 lfdirstate = lfutil.openlfdirstate(ui, repo)
917 919 for f in forget:
918 920 if lfdirstate[f] == 'a':
919 921 lfdirstate.drop(f)
920 922 else:
921 923 lfdirstate.remove(f)
922 924 lfdirstate.write()
923 925 lfutil.reporemove(repo, [lfutil.standin(f) for f in forget],
924 926 unlink=True)
925 927 finally:
926 928 wlock.release()
927 929
928 930 def getoutgoinglfiles(ui, repo, dest=None, **opts):
929 931 dest = ui.expandpath(dest or 'default-push', dest or 'default')
930 932 dest, branches = hg.parseurl(dest, opts.get('branch'))
931 933 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
932 934 if revs:
933 935 revs = [repo.lookup(rev) for rev in revs]
934 936
935 937 remoteui = hg.remoteui
936 938
937 939 try:
938 940 remote = hg.repository(remoteui(repo, opts), dest)
939 941 except error.RepoError:
940 942 return None
941 943 o = lfutil.findoutgoing(repo, remote, False)
942 944 if not o:
943 945 return None
944 946 o = repo.changelog.nodesbetween(o, revs)[0]
945 947 if opts.get('newest_first'):
946 948 o.reverse()
947 949
948 950 toupload = set()
949 951 for n in o:
950 952 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
951 953 ctx = repo[n]
952 954 files = set(ctx.files())
953 955 if len(parents) == 2:
954 956 mc = ctx.manifest()
955 957 mp1 = ctx.parents()[0].manifest()
956 958 mp2 = ctx.parents()[1].manifest()
957 959 for f in mp1:
958 960 if f not in mc:
959 961 files.add(f)
960 962 for f in mp2:
961 963 if f not in mc:
962 964 files.add(f)
963 965 for f in mc:
964 966 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
965 967 files.add(f)
966 968 toupload = toupload.union(
967 969 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
968 970 return toupload
969 971
970 972 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
971 973 orig(ui, repo, dest, **opts)
972 974
973 975 if opts.pop('large', None):
974 976 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
975 977 if toupload is None:
976 978 ui.status(_('largefiles: No remote repo\n'))
977 979 else:
978 980 ui.status(_('largefiles to upload:\n'))
979 981 for file in toupload:
980 982 ui.status(lfutil.splitstandin(file) + '\n')
981 983 ui.status('\n')
982 984
983 985 def overridesummary(orig, ui, repo, *pats, **opts):
984 986 try:
985 987 repo.lfstatus = True
986 988 orig(ui, repo, *pats, **opts)
987 989 finally:
988 990 repo.lfstatus = False
989 991
990 992 if opts.pop('large', None):
991 993 toupload = getoutgoinglfiles(ui, repo, None, **opts)
992 994 if toupload is None:
993 995 ui.status(_('largefiles: No remote repo\n'))
994 996 else:
995 997 ui.status(_('largefiles: %d to upload\n') % len(toupload))
996 998
997 999 def overrideaddremove(orig, ui, repo, *pats, **opts):
998 1000 if not lfutil.islfilesrepo(repo):
999 1001 return orig(ui, repo, *pats, **opts)
1000 1002 # Get the list of missing largefiles so we can remove them
1001 1003 lfdirstate = lfutil.openlfdirstate(ui, repo)
1002 1004 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1003 1005 False, False)
1004 1006 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1005 1007
1006 1008 # Call into the normal remove code, but the removing of the standin, we want
1007 1009 # to have handled by original addremove. Monkey patching here makes sure
1008 1010 # we don't remove the standin in the largefiles code, preventing a very
1009 1011 # confused state later.
1010 1012 if missing:
1011 1013 m = [repo.wjoin(f) for f in missing]
1012 1014 repo._isaddremove = True
1013 1015 removelargefiles(ui, repo, *m, **opts)
1014 1016 repo._isaddremove = False
1015 1017 # Call into the normal add code, and any files that *should* be added as
1016 1018 # largefiles will be
1017 1019 addlargefiles(ui, repo, *pats, **opts)
1018 1020 # Now that we've handled largefiles, hand off to the original addremove
1019 1021 # function to take care of the rest. Make sure it doesn't do anything with
1020 1022 # largefiles by installing a matcher that will ignore them.
1021 1023 installnormalfilesmatchfn(repo[None].manifest())
1022 1024 result = orig(ui, repo, *pats, **opts)
1023 1025 restorematchfn()
1024 1026 return result
1025 1027
1026 1028 # Calling purge with --all will cause the largefiles to be deleted.
1027 1029 # Override repo.status to prevent this from happening.
1028 1030 def overridepurge(orig, ui, repo, *dirs, **opts):
1029 1031 oldstatus = repo.status
1030 1032 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1031 1033 clean=False, unknown=False, listsubrepos=False):
1032 1034 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1033 1035 listsubrepos)
1034 1036 lfdirstate = lfutil.openlfdirstate(ui, repo)
1035 1037 modified, added, removed, deleted, unknown, ignored, clean = r
1036 1038 unknown = [f for f in unknown if lfdirstate[f] == '?']
1037 1039 ignored = [f for f in ignored if lfdirstate[f] == '?']
1038 1040 return modified, added, removed, deleted, unknown, ignored, clean
1039 1041 repo.status = overridestatus
1040 1042 orig(ui, repo, *dirs, **opts)
1041 1043 repo.status = oldstatus
1042 1044
1043 1045 def overriderollback(orig, ui, repo, **opts):
1044 1046 result = orig(ui, repo, **opts)
1045 1047 merge.update(repo, node=None, branchmerge=False, force=True,
1046 1048 partial=lfutil.isstandin)
1047 1049 wlock = repo.wlock()
1048 1050 try:
1049 1051 lfdirstate = lfutil.openlfdirstate(ui, repo)
1050 1052 lfiles = lfutil.listlfiles(repo)
1051 1053 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1052 1054 for file in lfiles:
1053 1055 if file in oldlfiles:
1054 1056 lfdirstate.normallookup(file)
1055 1057 else:
1056 1058 lfdirstate.add(file)
1057 1059 lfdirstate.write()
1058 1060 finally:
1059 1061 wlock.release()
1060 1062 return result
1061 1063
1062 1064 def overridetransplant(orig, ui, repo, *revs, **opts):
1063 1065 try:
1064 1066 oldstandins = lfutil.getstandinsstate(repo)
1065 1067 repo._istransplanting = True
1066 1068 result = orig(ui, repo, *revs, **opts)
1067 1069 newstandins = lfutil.getstandinsstate(repo)
1068 1070 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1069 1071 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1070 1072 printmessage=True)
1071 1073 finally:
1072 1074 repo._istransplanting = False
1073 1075 return result
1074 1076
1075 1077 def overridecat(orig, ui, repo, file1, *pats, **opts):
1076 1078 rev = opts.get('rev')
1077 1079 if not lfutil.standin(file1) in repo[rev]:
1078 1080 result = orig(ui, repo, file1, *pats, **opts)
1079 1081 return result
1080 1082 return lfcommands.catlfile(repo, file1, opts.get('rev'), opts.get('output'))
@@ -1,1374 +1,1411 b''
1 1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 2 $ mkdir "${USERCACHE}"
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles=
6 6 > purge=
7 7 > rebase=
8 8 > transplant=
9 9 > [phases]
10 10 > publish=False
11 11 > [largefiles]
12 12 > minsize=2
13 13 > patterns=glob:**.dat
14 14 > usercache=${USERCACHE}
15 15 > [hooks]
16 16 > precommit=sh -c "echo \"Invoking status precommit hook\"; hg status"
17 17 > EOF
18 18
19 19 Create the repo with a couple of revisions of both large and normal
20 20 files, testing that status correctly shows largefiles and that summary output
21 21 is correct.
22 22
23 23 $ hg init a
24 24 $ cd a
25 25 $ mkdir sub
26 26 $ echo normal1 > normal1
27 27 $ echo normal2 > sub/normal2
28 28 $ echo large1 > large1
29 29 $ echo large2 > sub/large2
30 30 $ hg add normal1 sub/normal2
31 31 $ hg add --large large1 sub/large2
32 32 $ hg commit -m "add files"
33 33 Invoking status precommit hook
34 34 A large1
35 35 A normal1
36 36 A sub/large2
37 37 A sub/normal2
38 38 $ echo normal11 > normal1
39 39 $ echo normal22 > sub/normal2
40 40 $ echo large11 > large1
41 41 $ echo large22 > sub/large2
42 42 $ hg commit -m "edit files"
43 43 Invoking status precommit hook
44 44 M large1
45 45 M normal1
46 46 M sub/large2
47 47 M sub/normal2
48 48 $ hg sum --large
49 49 parent: 1:ce8896473775 tip
50 50 edit files
51 51 branch: default
52 52 commit: (clean)
53 53 update: (current)
54 54 largefiles: No remote repo
55 55
56 56 Commit preserved largefile contents.
57 57
58 58 $ cat normal1
59 59 normal11
60 60 $ cat large1
61 61 large11
62 62 $ cat sub/normal2
63 63 normal22
64 64 $ cat sub/large2
65 65 large22
66 66
67 67 Test status, subdir and unknown files
68 68
69 69 $ echo unknown > sub/unknown
70 70 $ hg st --all
71 71 ? sub/unknown
72 72 C large1
73 73 C normal1
74 74 C sub/large2
75 75 C sub/normal2
76 76 $ hg st --all sub
77 77 ? sub/unknown
78 78 C sub/large2
79 79 C sub/normal2
80 80 $ rm sub/unknown
81 81
82 82 Remove both largefiles and normal files.
83 83
84 84 $ hg remove normal1 large1
85 85 $ hg status large1
86 86 R large1
87 87 $ hg commit -m "remove files"
88 88 Invoking status precommit hook
89 89 R large1
90 90 R normal1
91 91 $ ls
92 92 sub
93 93 $ echo "testlargefile" > large1-test
94 94 $ hg add --large large1-test
95 95 $ hg st
96 96 A large1-test
97 97 $ hg rm large1-test
98 98 not removing large1-test: file has been marked for add (use forget to undo)
99 99 $ hg st
100 100 A large1-test
101 101 $ hg forget large1-test
102 102 $ hg st
103 103 ? large1-test
104 104 $ rm large1-test
105 105
106 106 Copy both largefiles and normal files (testing that status output is correct).
107 107
108 108 $ hg cp sub/normal2 normal1
109 109 $ hg cp sub/large2 large1
110 110 $ hg commit -m "copy files"
111 111 Invoking status precommit hook
112 112 A large1
113 113 A normal1
114 114 $ cat normal1
115 115 normal22
116 116 $ cat large1
117 117 large22
118 118
119 119 Test moving largefiles and verify that normal files are also unaffected.
120 120
121 121 $ hg mv normal1 normal3
122 122 $ hg mv large1 large3
123 123 $ hg mv sub/normal2 sub/normal4
124 124 $ hg mv sub/large2 sub/large4
125 125 $ hg commit -m "move files"
126 126 Invoking status precommit hook
127 127 A large3
128 128 A normal3
129 129 A sub/large4
130 130 A sub/normal4
131 131 R large1
132 132 R normal1
133 133 R sub/large2
134 134 R sub/normal2
135 135 $ cat normal3
136 136 normal22
137 137 $ cat large3
138 138 large22
139 139 $ cat sub/normal4
140 140 normal22
141 141 $ cat sub/large4
142 142 large22
143 143
144 Test copies and moves from a directory other than root (issue3516)
145
146 $ cd ..
147 $ hg init lf_cpmv
148 $ cd lf_cpmv
149 $ mkdir dira
150 $ mkdir dira/dirb
151 $ touch dira/dirb/largefile
152 $ hg add --large dira/dirb/largefile
153 $ hg commit -m "added"
154 Invoking status precommit hook
155 A dira/dirb/largefile
156 $ cd dira
157 $ hg cp dirb/largefile foo/largefile
158 $ hg ci -m "deep copy"
159 Invoking status precommit hook
160 A dira/foo/largefile
161 $ find . | sort
162 .
163 ./dirb
164 ./dirb/largefile
165 ./foo
166 ./foo/largefile
167 $ hg mv foo/largefile baz/largefile
168 $ hg ci -m "moved"
169 Invoking status precommit hook
170 A dira/baz/largefile
171 R dira/foo/largefile
172 $ find . | sort
173 .
174 ./baz
175 ./baz/largefile
176 ./dirb
177 ./dirb/largefile
178 ./foo
179 $ cd ../../a
180
144 181 #if hgweb
145 182 Test display of largefiles in hgweb
146 183
147 184 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
148 185 $ cat ../hg.pid >> $DAEMON_PIDS
149 186 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
150 187 200 Script output follows
151 188
152 189
153 190 drwxr-xr-x sub
154 191 -rw-r--r-- 41 large3
155 192 -rw-r--r-- 9 normal3
156 193
157 194
158 195 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
159 196 200 Script output follows
160 197
161 198
162 199 -rw-r--r-- 41 large4
163 200 -rw-r--r-- 9 normal4
164 201
165 202
166 203 $ "$TESTDIR/killdaemons.py"
167 204 #endif
168 205
169 206 Test archiving the various revisions. These hit corner cases known with
170 207 archiving.
171 208
172 209 $ hg archive -r 0 ../archive0
173 210 $ hg archive -r 1 ../archive1
174 211 $ hg archive -r 2 ../archive2
175 212 $ hg archive -r 3 ../archive3
176 213 $ hg archive -r 4 ../archive4
177 214 $ cd ../archive0
178 215 $ cat normal1
179 216 normal1
180 217 $ cat large1
181 218 large1
182 219 $ cat sub/normal2
183 220 normal2
184 221 $ cat sub/large2
185 222 large2
186 223 $ cd ../archive1
187 224 $ cat normal1
188 225 normal11
189 226 $ cat large1
190 227 large11
191 228 $ cat sub/normal2
192 229 normal22
193 230 $ cat sub/large2
194 231 large22
195 232 $ cd ../archive2
196 233 $ ls
197 234 sub
198 235 $ cat sub/normal2
199 236 normal22
200 237 $ cat sub/large2
201 238 large22
202 239 $ cd ../archive3
203 240 $ cat normal1
204 241 normal22
205 242 $ cat large1
206 243 large22
207 244 $ cat sub/normal2
208 245 normal22
209 246 $ cat sub/large2
210 247 large22
211 248 $ cd ../archive4
212 249 $ cat normal3
213 250 normal22
214 251 $ cat large3
215 252 large22
216 253 $ cat sub/normal4
217 254 normal22
218 255 $ cat sub/large4
219 256 large22
220 257
221 258 Commit corner case: specify files to commit.
222 259
223 260 $ cd ../a
224 261 $ echo normal3 > normal3
225 262 $ echo large3 > large3
226 263 $ echo normal4 > sub/normal4
227 264 $ echo large4 > sub/large4
228 265 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
229 266 Invoking status precommit hook
230 267 M large3
231 268 M normal3
232 269 M sub/large4
233 270 M sub/normal4
234 271 $ cat normal3
235 272 normal3
236 273 $ cat large3
237 274 large3
238 275 $ cat sub/normal4
239 276 normal4
240 277 $ cat sub/large4
241 278 large4
242 279
243 280 One more commit corner case: commit from a subdirectory.
244 281
245 282 $ cd ../a
246 283 $ echo normal33 > normal3
247 284 $ echo large33 > large3
248 285 $ echo normal44 > sub/normal4
249 286 $ echo large44 > sub/large4
250 287 $ cd sub
251 288 $ hg commit -m "edit files yet again"
252 289 Invoking status precommit hook
253 290 M large3
254 291 M normal3
255 292 M sub/large4
256 293 M sub/normal4
257 294 $ cat ../normal3
258 295 normal33
259 296 $ cat ../large3
260 297 large33
261 298 $ cat normal4
262 299 normal44
263 300 $ cat large4
264 301 large44
265 302
266 303 Committing standins is not allowed.
267 304
268 305 $ cd ..
269 306 $ echo large3 > large3
270 307 $ hg commit .hglf/large3 -m "try to commit standin"
271 308 abort: file ".hglf/large3" is a largefile standin
272 309 (commit the largefile itself instead)
273 310 [255]
274 311
275 312 Corner cases for adding largefiles.
276 313
277 314 $ echo large5 > large5
278 315 $ hg add --large large5
279 316 $ hg add --large large5
280 317 large5 already a largefile
281 318 $ mkdir sub2
282 319 $ echo large6 > sub2/large6
283 320 $ echo large7 > sub2/large7
284 321 $ hg add --large sub2
285 322 adding sub2/large6 as a largefile (glob)
286 323 adding sub2/large7 as a largefile (glob)
287 324 $ hg st
288 325 M large3
289 326 A large5
290 327 A sub2/large6
291 328 A sub2/large7
292 329
293 330 Test "hg status" with combination of 'file pattern' and 'directory
294 331 pattern' for largefiles:
295 332
296 333 $ hg status sub2/large6 sub2
297 334 A sub2/large6
298 335 A sub2/large7
299 336
300 337 Config settings (pattern **.dat, minsize 2 MB) are respected.
301 338
302 339 $ echo testdata > test.dat
303 340 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
304 341 $ hg add
305 342 adding reallylarge as a largefile
306 343 adding test.dat as a largefile
307 344
308 345 Test that minsize and --lfsize handle float values;
309 346 also tests that --lfsize overrides largefiles.minsize.
310 347 (0.250 MB = 256 kB = 262144 B)
311 348
312 349 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
313 350 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
314 351 $ hg --config largefiles.minsize=.25 add
315 352 adding ratherlarge as a largefile
316 353 adding medium
317 354 $ hg forget medium
318 355 $ hg --config largefiles.minsize=.25 add --lfsize=.125
319 356 adding medium as a largefile
320 357 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
321 358 $ hg --config largefiles.minsize=.25 add --lfsize=.125
322 359 adding notlarge
323 360 $ hg forget notlarge
324 361
325 362 Test forget on largefiles.
326 363
327 364 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
328 365 $ hg commit -m "add/edit more largefiles"
329 366 Invoking status precommit hook
330 367 A sub2/large6
331 368 A sub2/large7
332 369 R large3
333 370 ? large5
334 371 ? medium
335 372 ? notlarge
336 373 ? ratherlarge
337 374 ? reallylarge
338 375 ? test.dat
339 376 $ hg st
340 377 ? large3
341 378 ? large5
342 379 ? medium
343 380 ? notlarge
344 381 ? ratherlarge
345 382 ? reallylarge
346 383 ? test.dat
347 384
348 385 Purge with largefiles: verify that largefiles are still in the working
349 386 dir after a purge.
350 387
351 388 $ hg purge --all
352 389 $ cat sub/large4
353 390 large44
354 391 $ cat sub2/large6
355 392 large6
356 393 $ cat sub2/large7
357 394 large7
358 395
359 396 Test addremove: verify that files that should be added as largfiles are added as
360 397 such and that already-existing largfiles are not added as normal files by
361 398 accident.
362 399
363 400 $ rm normal3
364 401 $ rm sub/large4
365 402 $ echo "testing addremove with patterns" > testaddremove.dat
366 403 $ echo "normaladdremove" > normaladdremove
367 404 $ hg addremove
368 405 removing sub/large4
369 406 adding testaddremove.dat as a largefile
370 407 removing normal3
371 408 adding normaladdremove
372 409
373 410 Test addremove with -R
374 411
375 412 $ hg up -C
376 413 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 414 getting changed largefiles
378 415 1 largefiles updated, 0 removed
379 416 $ rm normal3
380 417 $ rm sub/large4
381 418 $ echo "testing addremove with patterns" > testaddremove.dat
382 419 $ echo "normaladdremove" > normaladdremove
383 420 $ cd ..
384 421 $ hg -R a addremove
385 422 removing sub/large4
386 423 adding a/testaddremove.dat as a largefile (glob)
387 424 removing normal3
388 425 adding normaladdremove
389 426 $ cd a
390 427
391 428 Test 3364
392 429 $ hg clone . ../addrm
393 430 updating to branch default
394 431 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 432 getting changed largefiles
396 433 3 largefiles updated, 0 removed
397 434 $ cd ../addrm
398 435 $ cat >> .hg/hgrc <<EOF
399 436 > [hooks]
400 437 > post-commit.stat=sh -c "echo \"Invoking status postcommit hook\"; hg status -A"
401 438 > EOF
402 439 $ touch foo
403 440 $ hg add --large foo
404 441 $ hg ci -m "add foo"
405 442 Invoking status precommit hook
406 443 A foo
407 444 Invoking status postcommit hook
408 445 C foo
409 446 C normal3
410 447 C sub/large4
411 448 C sub/normal4
412 449 C sub2/large6
413 450 C sub2/large7
414 451 $ rm foo
415 452 $ hg st
416 453 ! foo
417 454 hmm.. no precommit invoked, but there is a postcommit??
418 455 $ hg ci -m "will not checkin"
419 456 nothing changed
420 457 Invoking status postcommit hook
421 458 ! foo
422 459 C normal3
423 460 C sub/large4
424 461 C sub/normal4
425 462 C sub2/large6
426 463 C sub2/large7
427 464 [1]
428 465 $ hg addremove
429 466 removing foo
430 467 $ hg st
431 468 R foo
432 469 $ hg ci -m "used to say nothing changed"
433 470 Invoking status precommit hook
434 471 R foo
435 472 Invoking status postcommit hook
436 473 C normal3
437 474 C sub/large4
438 475 C sub/normal4
439 476 C sub2/large6
440 477 C sub2/large7
441 478 $ hg st
442 479
443 480 Test 3507 (both normal files and largefiles were a problem)
444 481
445 482 $ touch normal
446 483 $ touch large
447 484 $ hg add normal
448 485 $ hg add --large large
449 486 $ hg ci -m "added"
450 487 Invoking status precommit hook
451 488 A large
452 489 A normal
453 490 Invoking status postcommit hook
454 491 C large
455 492 C normal
456 493 C normal3
457 494 C sub/large4
458 495 C sub/normal4
459 496 C sub2/large6
460 497 C sub2/large7
461 498 $ hg remove normal
462 499 $ hg addremove --traceback
463 500 $ hg ci -m "addremoved normal"
464 501 Invoking status precommit hook
465 502 R normal
466 503 Invoking status postcommit hook
467 504 C large
468 505 C normal3
469 506 C sub/large4
470 507 C sub/normal4
471 508 C sub2/large6
472 509 C sub2/large7
473 510 $ hg up -C '.^'
474 511 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 512 getting changed largefiles
476 513 0 largefiles updated, 0 removed
477 514 $ hg remove large
478 515 $ hg addremove --traceback
479 516 $ hg ci -m "removed large"
480 517 Invoking status precommit hook
481 518 R large
482 519 created new head
483 520 Invoking status postcommit hook
484 521 C normal
485 522 C normal3
486 523 C sub/large4
487 524 C sub/normal4
488 525 C sub2/large6
489 526 C sub2/large7
490 527
491 528 Test that a standin can't be added as a large file
492 529
493 530 $ touch large
494 531 $ hg add --large large
495 532 $ hg ci -m "add"
496 533 Invoking status precommit hook
497 534 A large
498 535 Invoking status postcommit hook
499 536 C large
500 537 C normal
501 538 C normal3
502 539 C sub/large4
503 540 C sub/normal4
504 541 C sub2/large6
505 542 C sub2/large7
506 543 $ hg remove large
507 544 $ touch large
508 545 $ hg addremove --config largefiles.patterns=**large --traceback
509 546 adding large as a largefile
510 547
511 548 $ cd ../a
512 549
513 550 Clone a largefiles repo.
514 551
515 552 $ hg clone . ../b
516 553 updating to branch default
517 554 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 555 getting changed largefiles
519 556 3 largefiles updated, 0 removed
520 557 $ cd ../b
521 558 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
522 559 7:daea875e9014 add/edit more largefiles
523 560 6:4355d653f84f edit files yet again
524 561 5:9d5af5072dbd edit files again
525 562 4:74c02385b94c move files
526 563 3:9e8fbc4bce62 copy files
527 564 2:51a0ae4d5864 remove files
528 565 1:ce8896473775 edit files
529 566 0:30d30fe6a5be add files
530 567 $ cat normal3
531 568 normal33
532 569 $ cat sub/normal4
533 570 normal44
534 571 $ cat sub/large4
535 572 large44
536 573 $ cat sub2/large6
537 574 large6
538 575 $ cat sub2/large7
539 576 large7
540 577 $ cd ..
541 578 $ hg clone a -r 3 c
542 579 adding changesets
543 580 adding manifests
544 581 adding file changes
545 582 added 4 changesets with 10 changes to 4 files
546 583 updating to branch default
547 584 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
548 585 getting changed largefiles
549 586 2 largefiles updated, 0 removed
550 587 $ cd c
551 588 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
552 589 3:9e8fbc4bce62 copy files
553 590 2:51a0ae4d5864 remove files
554 591 1:ce8896473775 edit files
555 592 0:30d30fe6a5be add files
556 593 $ cat normal1
557 594 normal22
558 595 $ cat large1
559 596 large22
560 597 $ cat sub/normal2
561 598 normal22
562 599 $ cat sub/large2
563 600 large22
564 601
565 602 Old revisions of a clone have correct largefiles content (this also
566 603 tests update).
567 604
568 605 $ hg update -r 1
569 606 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
570 607 getting changed largefiles
571 608 1 largefiles updated, 0 removed
572 609 $ cat large1
573 610 large11
574 611 $ cat sub/large2
575 612 large22
576 613 $ cd ..
577 614
578 615 Test cloning with --all-largefiles flag
579 616
580 617 $ rm "${USERCACHE}"/*
581 618 $ hg clone --all-largefiles a a-backup
582 619 updating to branch default
583 620 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 621 getting changed largefiles
585 622 3 largefiles updated, 0 removed
586 623 8 additional largefiles cached
587 624
588 625 $ hg clone --all-largefiles a ssh://localhost/a
589 626 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
590 627 [255]
591 628
592 629 Test pulling with --all-largefiles flag
593 630
594 631 $ rm -Rf a-backup
595 632 $ hg clone -r 1 a a-backup
596 633 adding changesets
597 634 adding manifests
598 635 adding file changes
599 636 added 2 changesets with 8 changes to 4 files
600 637 updating to branch default
601 638 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
602 639 getting changed largefiles
603 640 2 largefiles updated, 0 removed
604 641 $ rm "${USERCACHE}"/*
605 642 $ cd a-backup
606 643 $ hg pull --all-largefiles
607 644 pulling from $TESTTMP/a (glob)
608 645 searching for changes
609 646 adding changesets
610 647 adding manifests
611 648 adding file changes
612 649 added 6 changesets with 16 changes to 8 files
613 650 (run 'hg update' to get a working copy)
614 651 caching new largefiles
615 652 3 largefiles cached
616 653 3 additional largefiles cached
617 654 $ cd ..
618 655
619 656 Rebasing between two repositories does not revert largefiles to old
620 657 revisions (this was a very bad bug that took a lot of work to fix).
621 658
622 659 $ hg clone a d
623 660 updating to branch default
624 661 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 662 getting changed largefiles
626 663 3 largefiles updated, 0 removed
627 664 $ cd b
628 665 $ echo large4-modified > sub/large4
629 666 $ echo normal3-modified > normal3
630 667 $ hg commit -m "modify normal file and largefile in repo b"
631 668 Invoking status precommit hook
632 669 M normal3
633 670 M sub/large4
634 671 $ cd ../d
635 672 $ echo large6-modified > sub2/large6
636 673 $ echo normal4-modified > sub/normal4
637 674 $ hg commit -m "modify normal file largefile in repo d"
638 675 Invoking status precommit hook
639 676 M sub/normal4
640 677 M sub2/large6
641 678 $ cd ..
642 679 $ hg clone d e
643 680 updating to branch default
644 681 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 682 getting changed largefiles
646 683 3 largefiles updated, 0 removed
647 684 $ cd d
648 685 $ hg pull --rebase ../b
649 686 pulling from ../b
650 687 searching for changes
651 688 adding changesets
652 689 adding manifests
653 690 adding file changes
654 691 added 1 changesets with 2 changes to 2 files (+1 heads)
655 692 Invoking status precommit hook
656 693 M sub/normal4
657 694 M sub2/large6
658 695 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
659 696 nothing to rebase
660 697 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
661 698 9:598410d3eb9a modify normal file largefile in repo d
662 699 8:a381d2c8c80e modify normal file and largefile in repo b
663 700 7:daea875e9014 add/edit more largefiles
664 701 6:4355d653f84f edit files yet again
665 702 5:9d5af5072dbd edit files again
666 703 4:74c02385b94c move files
667 704 3:9e8fbc4bce62 copy files
668 705 2:51a0ae4d5864 remove files
669 706 1:ce8896473775 edit files
670 707 0:30d30fe6a5be add files
671 708 $ cat normal3
672 709 normal3-modified
673 710 $ cat sub/normal4
674 711 normal4-modified
675 712 $ cat sub/large4
676 713 large4-modified
677 714 $ cat sub2/large6
678 715 large6-modified
679 716 $ cat sub2/large7
680 717 large7
681 718 $ cd ../e
682 719 $ hg pull ../b
683 720 pulling from ../b
684 721 searching for changes
685 722 adding changesets
686 723 adding manifests
687 724 adding file changes
688 725 added 1 changesets with 2 changes to 2 files (+1 heads)
689 726 (run 'hg heads' to see heads, 'hg merge' to merge)
690 727 caching new largefiles
691 728 0 largefiles cached
692 729 $ hg rebase
693 730 Invoking status precommit hook
694 731 M sub/normal4
695 732 M sub2/large6
696 733 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
697 734 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
698 735 9:598410d3eb9a modify normal file largefile in repo d
699 736 8:a381d2c8c80e modify normal file and largefile in repo b
700 737 7:daea875e9014 add/edit more largefiles
701 738 6:4355d653f84f edit files yet again
702 739 5:9d5af5072dbd edit files again
703 740 4:74c02385b94c move files
704 741 3:9e8fbc4bce62 copy files
705 742 2:51a0ae4d5864 remove files
706 743 1:ce8896473775 edit files
707 744 0:30d30fe6a5be add files
708 745 $ cat normal3
709 746 normal3-modified
710 747 $ cat sub/normal4
711 748 normal4-modified
712 749 $ cat sub/large4
713 750 large4-modified
714 751 $ cat sub2/large6
715 752 large6-modified
716 753 $ cat sub2/large7
717 754 large7
718 755
719 756 Rollback on largefiles.
720 757
721 758 $ echo large4-modified-again > sub/large4
722 759 $ hg commit -m "Modify large4 again"
723 760 Invoking status precommit hook
724 761 M sub/large4
725 762 $ hg rollback
726 763 repository tip rolled back to revision 9 (undo commit)
727 764 working directory now based on revision 9
728 765 $ hg st
729 766 M sub/large4
730 767 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
731 768 9:598410d3eb9a modify normal file largefile in repo d
732 769 8:a381d2c8c80e modify normal file and largefile in repo b
733 770 7:daea875e9014 add/edit more largefiles
734 771 6:4355d653f84f edit files yet again
735 772 5:9d5af5072dbd edit files again
736 773 4:74c02385b94c move files
737 774 3:9e8fbc4bce62 copy files
738 775 2:51a0ae4d5864 remove files
739 776 1:ce8896473775 edit files
740 777 0:30d30fe6a5be add files
741 778 $ cat sub/large4
742 779 large4-modified-again
743 780
744 781 "update --check" refuses to update with uncommitted changes.
745 782 $ hg update --check 8
746 783 abort: uncommitted local changes
747 784 [255]
748 785
749 786 "update --clean" leaves correct largefiles in working copy.
750 787
751 788 $ hg update --clean
752 789 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
753 790 getting changed largefiles
754 791 1 largefiles updated, 0 removed
755 792 $ cat normal3
756 793 normal3-modified
757 794 $ cat sub/normal4
758 795 normal4-modified
759 796 $ cat sub/large4
760 797 large4-modified
761 798 $ cat sub2/large6
762 799 large6-modified
763 800 $ cat sub2/large7
764 801 large7
765 802
766 803 Now "update check" is happy.
767 804 $ hg update --check 8
768 805 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
769 806 getting changed largefiles
770 807 1 largefiles updated, 0 removed
771 808 $ hg update --check
772 809 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
773 810 getting changed largefiles
774 811 1 largefiles updated, 0 removed
775 812
776 813 Test removing empty largefiles directories on update
777 814 $ test -d sub2 && echo "sub2 exists"
778 815 sub2 exists
779 816 $ hg update -q null
780 817 $ test -d sub2 && echo "error: sub2 should not exist anymore"
781 818 [1]
782 819 $ hg update -q
783 820
784 821 Test hg remove removes empty largefiles directories
785 822 $ test -d sub2 && echo "sub2 exists"
786 823 sub2 exists
787 824 $ hg remove sub2/*
788 825 $ test -d sub2 && echo "error: sub2 should not exist anymore"
789 826 [1]
790 827 $ hg revert sub2/large6 sub2/large7
791 828
792 829 "revert" works on largefiles (and normal files too).
793 830 $ echo hack3 >> normal3
794 831 $ echo hack4 >> sub/normal4
795 832 $ echo hack4 >> sub/large4
796 833 $ rm sub2/large6
797 834 $ hg revert sub2/large6
798 835 $ hg rm sub2/large6
799 836 $ echo new >> sub2/large8
800 837 $ hg add --large sub2/large8
801 838 # XXX we don't really want to report that we're reverting the standin;
802 839 # that's just an implementation detail. But I don't see an obvious fix. ;-(
803 840 $ hg revert sub
804 841 reverting .hglf/sub/large4 (glob)
805 842 reverting sub/normal4 (glob)
806 843 $ hg status
807 844 M normal3
808 845 A sub2/large8
809 846 R sub2/large6
810 847 ? sub/large4.orig
811 848 ? sub/normal4.orig
812 849 $ cat sub/normal4
813 850 normal4-modified
814 851 $ cat sub/large4
815 852 large4-modified
816 853 $ hg revert -a --no-backup
817 854 undeleting .hglf/sub2/large6 (glob)
818 855 forgetting .hglf/sub2/large8 (glob)
819 856 reverting normal3
820 857 $ hg status
821 858 ? sub/large4.orig
822 859 ? sub/normal4.orig
823 860 ? sub2/large8
824 861 $ cat normal3
825 862 normal3-modified
826 863 $ cat sub2/large6
827 864 large6-modified
828 865 $ rm sub/*.orig sub2/large8
829 866
830 867 revert some files to an older revision
831 868 $ hg revert --no-backup -r 8 sub2
832 869 reverting .hglf/sub2/large6 (glob)
833 870 $ cat sub2/large6
834 871 large6
835 872 $ hg revert --no-backup sub2
836 873 reverting .hglf/sub2/large6 (glob)
837 874 $ hg status
838 875
839 876 "verify --large" actually verifies largefiles
840 877
841 878 $ hg verify --large
842 879 checking changesets
843 880 checking manifests
844 881 crosschecking files in changesets and manifests
845 882 checking files
846 883 10 files, 10 changesets, 28 total revisions
847 884 searching 1 changesets for largefiles
848 885 verified existence of 3 revisions of 3 largefiles
849 886
850 887 Merging does not revert to old versions of largefiles and also check
851 888 that merging after having pulled from a non-default remote works
852 889 correctly.
853 890
854 891 $ cd ..
855 892 $ hg clone -r 7 e temp
856 893 adding changesets
857 894 adding manifests
858 895 adding file changes
859 896 added 8 changesets with 24 changes to 10 files
860 897 updating to branch default
861 898 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
862 899 getting changed largefiles
863 900 3 largefiles updated, 0 removed
864 901 $ hg clone temp f
865 902 updating to branch default
866 903 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
867 904 getting changed largefiles
868 905 3 largefiles updated, 0 removed
869 906 # Delete the largefiles in the largefiles system cache so that we have an
870 907 # opportunity to test that caching after a pull works.
871 908 $ rm "${USERCACHE}"/*
872 909 $ cd f
873 910 $ echo "large4-merge-test" > sub/large4
874 911 $ hg commit -m "Modify large4 to test merge"
875 912 Invoking status precommit hook
876 913 M sub/large4
877 914 $ hg pull ../e
878 915 pulling from ../e
879 916 searching for changes
880 917 adding changesets
881 918 adding manifests
882 919 adding file changes
883 920 added 2 changesets with 4 changes to 4 files (+1 heads)
884 921 (run 'hg heads' to see heads, 'hg merge' to merge)
885 922 caching new largefiles
886 923 2 largefiles cached
887 924 $ hg merge
888 925 merging sub/large4
889 926 largefile sub/large4 has a merge conflict
890 927 keep (l)ocal or take (o)ther? l
891 928 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
892 929 (branch merge, don't forget to commit)
893 930 getting changed largefiles
894 931 1 largefiles updated, 0 removed
895 932 $ hg commit -m "Merge repos e and f"
896 933 Invoking status precommit hook
897 934 M normal3
898 935 M sub/normal4
899 936 M sub2/large6
900 937 $ cat normal3
901 938 normal3-modified
902 939 $ cat sub/normal4
903 940 normal4-modified
904 941 $ cat sub/large4
905 942 large4-merge-test
906 943 $ cat sub2/large6
907 944 large6-modified
908 945 $ cat sub2/large7
909 946 large7
910 947
911 948 Test status after merging with a branch that introduces a new largefile:
912 949
913 950 $ echo large > large
914 951 $ hg add --large large
915 952 $ hg commit -m 'add largefile'
916 953 Invoking status precommit hook
917 954 A large
918 955 $ hg update -q ".^"
919 956 $ echo change >> normal3
920 957 $ hg commit -m 'some change'
921 958 Invoking status precommit hook
922 959 M normal3
923 960 created new head
924 961 $ hg merge
925 962 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
926 963 (branch merge, don't forget to commit)
927 964 getting changed largefiles
928 965 1 largefiles updated, 0 removed
929 966 $ hg status
930 967 M large
931 968
932 969 Test that a normal file and a largefile with the same name and path cannot
933 970 coexist.
934 971
935 972 $ rm sub2/large7
936 973 $ echo "largeasnormal" > sub2/large7
937 974 $ hg add sub2/large7
938 975 sub2/large7 already a largefile
939 976
940 977 Test that transplanting a largefile change works correctly.
941 978
942 979 $ cd ..
943 980 $ hg clone -r 8 d g
944 981 adding changesets
945 982 adding manifests
946 983 adding file changes
947 984 added 9 changesets with 26 changes to 10 files
948 985 updating to branch default
949 986 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
950 987 getting changed largefiles
951 988 3 largefiles updated, 0 removed
952 989 $ cd g
953 990 $ hg transplant -s ../d 598410d3eb9a
954 991 searching for changes
955 992 searching for changes
956 993 adding changesets
957 994 adding manifests
958 995 adding file changes
959 996 added 1 changesets with 2 changes to 2 files
960 997 getting changed largefiles
961 998 1 largefiles updated, 0 removed
962 999 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
963 1000 9:598410d3eb9a modify normal file largefile in repo d
964 1001 8:a381d2c8c80e modify normal file and largefile in repo b
965 1002 7:daea875e9014 add/edit more largefiles
966 1003 6:4355d653f84f edit files yet again
967 1004 5:9d5af5072dbd edit files again
968 1005 4:74c02385b94c move files
969 1006 3:9e8fbc4bce62 copy files
970 1007 2:51a0ae4d5864 remove files
971 1008 1:ce8896473775 edit files
972 1009 0:30d30fe6a5be add files
973 1010 $ cat normal3
974 1011 normal3-modified
975 1012 $ cat sub/normal4
976 1013 normal4-modified
977 1014 $ cat sub/large4
978 1015 large4-modified
979 1016 $ cat sub2/large6
980 1017 large6-modified
981 1018 $ cat sub2/large7
982 1019 large7
983 1020
984 1021 Cat a largefile
985 1022 $ hg cat normal3
986 1023 normal3-modified
987 1024 $ hg cat sub/large4
988 1025 large4-modified
989 1026 $ rm "${USERCACHE}"/*
990 1027 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
991 1028 $ cat cat.out
992 1029 large4-modified
993 1030 $ rm cat.out
994 1031 $ hg cat -r a381d2c8c80e normal3
995 1032 normal3-modified
996 1033
997 1034 Test that renaming a largefile results in correct output for status
998 1035
999 1036 $ hg rename sub/large4 large4-renamed
1000 1037 $ hg commit -m "test rename output"
1001 1038 Invoking status precommit hook
1002 1039 A large4-renamed
1003 1040 R sub/large4
1004 1041 $ cat large4-renamed
1005 1042 large4-modified
1006 1043 $ cd sub2
1007 1044 $ hg rename large6 large6-renamed
1008 1045 $ hg st
1009 1046 A sub2/large6-renamed
1010 1047 R sub2/large6
1011 1048 $ cd ..
1012 1049
1013 1050 Test --normal flag
1014 1051
1015 1052 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1016 1053 $ hg add --normal --large new-largefile
1017 1054 abort: --normal cannot be used with --large
1018 1055 [255]
1019 1056 $ hg add --normal new-largefile
1020 1057 new-largefile: up to 69 MB of RAM may be required to manage this file
1021 1058 (use 'hg revert new-largefile' to cancel the pending addition)
1022 1059 $ cd ..
1023 1060
1024 1061 #if serve
1025 1062 vanilla clients not locked out from largefiles servers on vanilla repos
1026 1063 $ mkdir r1
1027 1064 $ cd r1
1028 1065 $ hg init
1029 1066 $ echo c1 > f1
1030 1067 $ hg add f1
1031 1068 $ hg commit -m "m1"
1032 1069 Invoking status precommit hook
1033 1070 A f1
1034 1071 $ cd ..
1035 1072 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1036 1073 $ cat hg.pid >> $DAEMON_PIDS
1037 1074 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1038 1075 requesting all changes
1039 1076 adding changesets
1040 1077 adding manifests
1041 1078 adding file changes
1042 1079 added 1 changesets with 1 changes to 1 files
1043 1080 updating to branch default
1044 1081 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1045 1082
1046 1083 largefiles clients still work with vanilla servers
1047 1084 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1048 1085 $ cat hg.pid >> $DAEMON_PIDS
1049 1086 $ hg clone http://localhost:$HGPORT1 r3
1050 1087 requesting all changes
1051 1088 adding changesets
1052 1089 adding manifests
1053 1090 adding file changes
1054 1091 added 1 changesets with 1 changes to 1 files
1055 1092 updating to branch default
1056 1093 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1057 1094 #endif
1058 1095
1059 1096
1060 1097 vanilla clients locked out from largefiles http repos
1061 1098 $ mkdir r4
1062 1099 $ cd r4
1063 1100 $ hg init
1064 1101 $ echo c1 > f1
1065 1102 $ hg add --large f1
1066 1103 $ hg commit -m "m1"
1067 1104 Invoking status precommit hook
1068 1105 A f1
1069 1106 $ cd ..
1070 1107
1071 1108 #if serve
1072 1109 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1073 1110 $ cat hg.pid >> $DAEMON_PIDS
1074 1111 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1075 1112 abort: remote error:
1076 1113
1077 1114 This repository uses the largefiles extension.
1078 1115
1079 1116 Please enable it in your Mercurial config file.
1080 1117 [255]
1081 1118
1082 1119 used all HGPORTs, kill all daemons
1083 1120 $ "$TESTDIR/killdaemons.py"
1084 1121 #endif
1085 1122
1086 1123 vanilla clients locked out from largefiles ssh repos
1087 1124 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1088 1125 abort: remote error:
1089 1126
1090 1127 This repository uses the largefiles extension.
1091 1128
1092 1129 Please enable it in your Mercurial config file.
1093 1130 [255]
1094 1131
1095 1132 #if serve
1096 1133
1097 1134 largefiles clients refuse to push largefiles repos to vanilla servers
1098 1135 $ mkdir r6
1099 1136 $ cd r6
1100 1137 $ hg init
1101 1138 $ echo c1 > f1
1102 1139 $ hg add f1
1103 1140 $ hg commit -m "m1"
1104 1141 Invoking status precommit hook
1105 1142 A f1
1106 1143 $ cat >> .hg/hgrc <<!
1107 1144 > [web]
1108 1145 > push_ssl = false
1109 1146 > allow_push = *
1110 1147 > !
1111 1148 $ cd ..
1112 1149 $ hg clone r6 r7
1113 1150 updating to branch default
1114 1151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1115 1152 $ cd r7
1116 1153 $ echo c2 > f2
1117 1154 $ hg add --large f2
1118 1155 $ hg commit -m "m2"
1119 1156 Invoking status precommit hook
1120 1157 A f2
1121 1158 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1122 1159 $ cat ../hg.pid >> $DAEMON_PIDS
1123 1160 $ hg push http://localhost:$HGPORT
1124 1161 pushing to http://localhost:$HGPORT/
1125 1162 searching for changes
1126 1163 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1127 1164 [255]
1128 1165 $ cd ..
1129 1166
1130 1167 putlfile errors are shown (issue3123)
1131 1168 Corrupt the cached largefile in r7 and in the usercache (required for testing on vfat)
1132 1169 $ echo corruption > "$TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8"
1133 1170 $ echo corruption > "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1134 1171 $ hg init empty
1135 1172 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1136 1173 > --config 'web.allow_push=*' --config web.push_ssl=False
1137 1174 $ cat hg.pid >> $DAEMON_PIDS
1138 1175 $ hg push -R r7 http://localhost:$HGPORT1
1139 1176 pushing to http://localhost:$HGPORT1/
1140 1177 searching for changes
1141 1178 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1142 1179 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1143 1180 [255]
1144 1181 $ rm -rf empty
1145 1182
1146 1183 Push a largefiles repository to a served empty repository
1147 1184 $ hg init r8
1148 1185 $ echo c3 > r8/f1
1149 1186 $ hg add --large r8/f1 -R r8
1150 1187 $ hg commit -m "m1" -R r8
1151 1188 Invoking status precommit hook
1152 1189 A f1
1153 1190 $ hg init empty
1154 1191 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1155 1192 > --config 'web.allow_push=*' --config web.push_ssl=False
1156 1193 $ cat hg.pid >> $DAEMON_PIDS
1157 1194 $ rm "${USERCACHE}"/*
1158 1195 $ hg push -R r8 http://localhost:$HGPORT2
1159 1196 pushing to http://localhost:$HGPORT2/
1160 1197 searching for changes
1161 1198 searching for changes
1162 1199 remote: adding changesets
1163 1200 remote: adding manifests
1164 1201 remote: adding file changes
1165 1202 remote: added 1 changesets with 1 changes to 1 files
1166 1203 $ rm -rf empty
1167 1204
1168 1205 used all HGPORTs, kill all daemons
1169 1206 $ "$TESTDIR/killdaemons.py"
1170 1207
1171 1208 #endif
1172 1209
1173 1210
1174 1211 #if unix-permissions
1175 1212
1176 1213 Clone a local repository owned by another user
1177 1214 We have to simulate that here by setting $HOME and removing write permissions
1178 1215 $ ORIGHOME="$HOME"
1179 1216 $ mkdir alice
1180 1217 $ HOME="`pwd`/alice"
1181 1218 $ cd alice
1182 1219 $ hg init pubrepo
1183 1220 $ cd pubrepo
1184 1221 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1185 1222 $ hg add --large a-large-file
1186 1223 $ hg commit -m "Add a large file"
1187 1224 Invoking status precommit hook
1188 1225 A a-large-file
1189 1226 $ cd ..
1190 1227 $ chmod -R a-w pubrepo
1191 1228 $ cd ..
1192 1229 $ mkdir bob
1193 1230 $ HOME="`pwd`/bob"
1194 1231 $ cd bob
1195 1232 $ hg clone --pull ../alice/pubrepo pubrepo
1196 1233 requesting all changes
1197 1234 adding changesets
1198 1235 adding manifests
1199 1236 adding file changes
1200 1237 added 1 changesets with 1 changes to 1 files
1201 1238 updating to branch default
1202 1239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1203 1240 getting changed largefiles
1204 1241 1 largefiles updated, 0 removed
1205 1242 $ cd ..
1206 1243 $ chmod -R u+w alice/pubrepo
1207 1244 $ HOME="$ORIGHOME"
1208 1245
1209 1246 #endif
1210 1247
1211 1248 #if symlink
1212 1249
1213 1250 Symlink to a large largefile should behave the same as a symlink to a normal file
1214 1251 $ hg init largesymlink
1215 1252 $ cd largesymlink
1216 1253 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1217 1254 $ hg add --large largefile
1218 1255 $ hg commit -m "commit a large file"
1219 1256 Invoking status precommit hook
1220 1257 A largefile
1221 1258 $ ln -s largefile largelink
1222 1259 $ hg add largelink
1223 1260 $ hg commit -m "commit a large symlink"
1224 1261 Invoking status precommit hook
1225 1262 A largelink
1226 1263 $ rm -f largelink
1227 1264 $ hg up >/dev/null
1228 1265 $ test -f largelink
1229 1266 [1]
1230 1267 $ test -L largelink
1231 1268 [1]
1232 1269 $ rm -f largelink # make next part of the test independent of the previous
1233 1270 $ hg up -C >/dev/null
1234 1271 $ test -f largelink
1235 1272 $ test -L largelink
1236 1273 $ cd ..
1237 1274
1238 1275 #endif
1239 1276
1240 1277 test for pattern matching on 'hg status':
1241 1278 to boost performance, largefiles checks whether specified patterns are
1242 1279 related to largefiles in working directory (NOT to STANDIN) or not.
1243 1280
1244 1281 $ hg init statusmatch
1245 1282 $ cd statusmatch
1246 1283
1247 1284 $ mkdir -p a/b/c/d
1248 1285 $ echo normal > a/b/c/d/e.normal.txt
1249 1286 $ hg add a/b/c/d/e.normal.txt
1250 1287 $ echo large > a/b/c/d/e.large.txt
1251 1288 $ hg add --large a/b/c/d/e.large.txt
1252 1289 $ mkdir -p a/b/c/x
1253 1290 $ echo normal > a/b/c/x/y.normal.txt
1254 1291 $ hg add a/b/c/x/y.normal.txt
1255 1292 $ hg commit -m 'add files'
1256 1293 Invoking status precommit hook
1257 1294 A a/b/c/d/e.large.txt
1258 1295 A a/b/c/d/e.normal.txt
1259 1296 A a/b/c/x/y.normal.txt
1260 1297
1261 1298 (1) no pattern: no performance boost
1262 1299 $ hg status -A
1263 1300 C a/b/c/d/e.large.txt
1264 1301 C a/b/c/d/e.normal.txt
1265 1302 C a/b/c/x/y.normal.txt
1266 1303
1267 1304 (2) pattern not related to largefiles: performance boost
1268 1305 $ hg status -A a/b/c/x
1269 1306 C a/b/c/x/y.normal.txt
1270 1307
1271 1308 (3) pattern related to largefiles: no performance boost
1272 1309 $ hg status -A a/b/c/d
1273 1310 C a/b/c/d/e.large.txt
1274 1311 C a/b/c/d/e.normal.txt
1275 1312
1276 1313 (4) pattern related to STANDIN (not to largefiles): performance boost
1277 1314 $ hg status -A .hglf/a
1278 1315 C .hglf/a/b/c/d/e.large.txt
1279 1316
1280 1317 (5) mixed case: no performance boost
1281 1318 $ hg status -A a/b/c/x a/b/c/d
1282 1319 C a/b/c/d/e.large.txt
1283 1320 C a/b/c/d/e.normal.txt
1284 1321 C a/b/c/x/y.normal.txt
1285 1322
1286 1323 verify that largefiles doesn't break filesets
1287 1324
1288 1325 $ hg log --rev . --exclude "set:binary()"
1289 1326 changeset: 0:41bd42f10efa
1290 1327 tag: tip
1291 1328 user: test
1292 1329 date: Thu Jan 01 00:00:00 1970 +0000
1293 1330 summary: add files
1294 1331
1295 1332 verify that large files in subrepos handled properly
1296 1333 $ hg init subrepo
1297 1334 $ echo "subrepo = subrepo" > .hgsub
1298 1335 $ hg add .hgsub
1299 1336 $ hg ci -m "add subrepo"
1300 1337 Invoking status precommit hook
1301 1338 A .hgsub
1302 1339 ? .hgsubstate
1303 1340 $ echo "rev 1" > subrepo/large.txt
1304 1341 $ hg -R subrepo add --large subrepo/large.txt
1305 1342 $ hg sum
1306 1343 parent: 1:8ee150ea2e9c tip
1307 1344 add subrepo
1308 1345 branch: default
1309 1346 commit: 1 subrepos
1310 1347 update: (current)
1311 1348 $ hg st
1312 1349 $ hg st -S
1313 1350 A subrepo/large.txt
1314 1351 $ hg ci -S -m "commit top repo"
1315 1352 committing subrepository subrepo
1316 1353 Invoking status precommit hook
1317 1354 A large.txt
1318 1355 Invoking status precommit hook
1319 1356 M .hgsubstate
1320 1357 # No differences
1321 1358 $ hg st -S
1322 1359 $ hg sum
1323 1360 parent: 2:ce4cd0c527a6 tip
1324 1361 commit top repo
1325 1362 branch: default
1326 1363 commit: (clean)
1327 1364 update: (current)
1328 1365 $ echo "rev 2" > subrepo/large.txt
1329 1366 $ hg st -S
1330 1367 M subrepo/large.txt
1331 1368 $ hg sum
1332 1369 parent: 2:ce4cd0c527a6 tip
1333 1370 commit top repo
1334 1371 branch: default
1335 1372 commit: 1 subrepos
1336 1373 update: (current)
1337 1374 $ hg ci -m "this commit should fail without -S"
1338 1375 abort: uncommitted changes in subrepo subrepo
1339 1376 (use --subrepos for recursive commit)
1340 1377 [255]
1341 1378
1342 1379 Add a normal file to the subrepo, then test archiving
1343 1380
1344 1381 $ echo 'normal file' > subrepo/normal.txt
1345 1382 $ hg -R subrepo add subrepo/normal.txt
1346 1383
1347 1384 Lock in subrepo, otherwise the change isn't archived
1348 1385
1349 1386 $ hg ci -S -m "add normal file to top level"
1350 1387 committing subrepository subrepo
1351 1388 Invoking status precommit hook
1352 1389 M large.txt
1353 1390 A normal.txt
1354 1391 Invoking status precommit hook
1355 1392 M .hgsubstate
1356 1393 $ hg archive -S lf_subrepo_archive
1357 1394 $ find lf_subrepo_archive | sort
1358 1395 lf_subrepo_archive
1359 1396 lf_subrepo_archive/.hg_archival.txt
1360 1397 lf_subrepo_archive/.hgsub
1361 1398 lf_subrepo_archive/.hgsubstate
1362 1399 lf_subrepo_archive/a
1363 1400 lf_subrepo_archive/a/b
1364 1401 lf_subrepo_archive/a/b/c
1365 1402 lf_subrepo_archive/a/b/c/d
1366 1403 lf_subrepo_archive/a/b/c/d/e.large.txt
1367 1404 lf_subrepo_archive/a/b/c/d/e.normal.txt
1368 1405 lf_subrepo_archive/a/b/c/x
1369 1406 lf_subrepo_archive/a/b/c/x/y.normal.txt
1370 1407 lf_subrepo_archive/subrepo
1371 1408 lf_subrepo_archive/subrepo/large.txt
1372 1409 lf_subrepo_archive/subrepo/normal.txt
1373 1410
1374 1411 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now