##// END OF EJS Templates
largefiles: better handling of merge of largefiles that not are available...
Mads Kiilerich -
r26627:832c98d7 default
parent child Browse files
Show More
@@ -1,612 +1,613 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 '''largefiles utility code: must not import other modules in this package.'''
10 10
11 11 import os
12 12 import platform
13 13 import shutil
14 14 import stat
15 15 import copy
16 16
17 17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 18 from mercurial.i18n import _
19 19 from mercurial import node, error
20 20
21 21 shortname = '.hglf'
22 22 shortnameslash = shortname + '/'
23 23 longname = 'largefiles'
24 24
25 25
26 26 # -- Private worker functions ------------------------------------------
27 27
28 28 def getminsize(ui, assumelfiles, opt, default=10):
29 29 lfsize = opt
30 30 if not lfsize and assumelfiles:
31 31 lfsize = ui.config(longname, 'minsize', default=default)
32 32 if lfsize:
33 33 try:
34 34 lfsize = float(lfsize)
35 35 except ValueError:
36 36 raise error.Abort(_('largefiles: size must be number (not %s)\n')
37 37 % lfsize)
38 38 if lfsize is None:
39 39 raise error.Abort(_('minimum size for largefiles must be specified'))
40 40 return lfsize
41 41
42 42 def link(src, dest):
43 43 util.makedirs(os.path.dirname(dest))
44 44 try:
45 45 util.oslink(src, dest)
46 46 except OSError:
47 47 # if hardlinks fail, fallback on atomic copy
48 48 dst = util.atomictempfile(dest)
49 49 for chunk in util.filechunkiter(open(src, 'rb')):
50 50 dst.write(chunk)
51 51 dst.close()
52 52 os.chmod(dest, os.stat(src).st_mode)
53 53
54 54 def usercachepath(ui, hash):
55 55 path = ui.configpath(longname, 'usercache', None)
56 56 if path:
57 57 path = os.path.join(path, hash)
58 58 else:
59 59 if os.name == 'nt':
60 60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
61 61 if appdata:
62 62 path = os.path.join(appdata, longname, hash)
63 63 elif platform.system() == 'Darwin':
64 64 home = os.getenv('HOME')
65 65 if home:
66 66 path = os.path.join(home, 'Library', 'Caches',
67 67 longname, hash)
68 68 elif os.name == 'posix':
69 69 path = os.getenv('XDG_CACHE_HOME')
70 70 if path:
71 71 path = os.path.join(path, longname, hash)
72 72 else:
73 73 home = os.getenv('HOME')
74 74 if home:
75 75 path = os.path.join(home, '.cache', longname, hash)
76 76 else:
77 77 raise error.Abort(_('unknown operating system: %s\n') % os.name)
78 78 return path
79 79
80 80 def inusercache(ui, hash):
81 81 path = usercachepath(ui, hash)
82 82 return path and os.path.exists(path)
83 83
84 84 def findfile(repo, hash):
85 85 path, exists = findstorepath(repo, hash)
86 86 if exists:
87 87 repo.ui.note(_('found %s in store\n') % hash)
88 88 return path
89 89 elif inusercache(repo.ui, hash):
90 90 repo.ui.note(_('found %s in system cache\n') % hash)
91 91 path = storepath(repo, hash)
92 92 link(usercachepath(repo.ui, hash), path)
93 93 return path
94 94 return None
95 95
96 96 class largefilesdirstate(dirstate.dirstate):
97 97 def __getitem__(self, key):
98 98 return super(largefilesdirstate, self).__getitem__(unixpath(key))
99 99 def normal(self, f):
100 100 return super(largefilesdirstate, self).normal(unixpath(f))
101 101 def remove(self, f):
102 102 return super(largefilesdirstate, self).remove(unixpath(f))
103 103 def add(self, f):
104 104 return super(largefilesdirstate, self).add(unixpath(f))
105 105 def drop(self, f):
106 106 return super(largefilesdirstate, self).drop(unixpath(f))
107 107 def forget(self, f):
108 108 return super(largefilesdirstate, self).forget(unixpath(f))
109 109 def normallookup(self, f):
110 110 return super(largefilesdirstate, self).normallookup(unixpath(f))
111 111 def _ignore(self, f):
112 112 return False
113 113
114 114 def openlfdirstate(ui, repo, create=True):
115 115 '''
116 116 Return a dirstate object that tracks largefiles: i.e. its root is
117 117 the repo root, but it is saved in .hg/largefiles/dirstate.
118 118 '''
119 119 lfstoredir = repo.join(longname)
120 120 opener = scmutil.opener(lfstoredir)
121 121 lfdirstate = largefilesdirstate(opener, ui, repo.root,
122 122 repo.dirstate._validate)
123 123
124 124 # If the largefiles dirstate does not exist, populate and create
125 125 # it. This ensures that we create it on the first meaningful
126 126 # largefiles operation in a new clone.
127 127 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
128 128 matcher = getstandinmatcher(repo)
129 129 standins = repo.dirstate.walk(matcher, [], False, False)
130 130
131 131 if len(standins) > 0:
132 132 util.makedirs(lfstoredir)
133 133
134 134 for standin in standins:
135 135 lfile = splitstandin(standin)
136 136 lfdirstate.normallookup(lfile)
137 137 return lfdirstate
138 138
139 139 def lfdirstatestatus(lfdirstate, repo):
140 140 wctx = repo['.']
141 141 match = match_.always(repo.root, repo.getcwd())
142 142 unsure, s = lfdirstate.status(match, [], False, False, False)
143 143 modified, clean = s.modified, s.clean
144 144 for lfile in unsure:
145 145 try:
146 146 fctx = wctx[standin(lfile)]
147 147 except LookupError:
148 148 fctx = None
149 149 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
150 150 modified.append(lfile)
151 151 else:
152 152 clean.append(lfile)
153 153 lfdirstate.normal(lfile)
154 154 return s
155 155
156 156 def listlfiles(repo, rev=None, matcher=None):
157 157 '''return a list of largefiles in the working copy or the
158 158 specified changeset'''
159 159
160 160 if matcher is None:
161 161 matcher = getstandinmatcher(repo)
162 162
163 163 # ignore unknown files in working directory
164 164 return [splitstandin(f)
165 165 for f in repo[rev].walk(matcher)
166 166 if rev is not None or repo.dirstate[f] != '?']
167 167
168 168 def instore(repo, hash, forcelocal=False):
169 169 return os.path.exists(storepath(repo, hash, forcelocal))
170 170
171 171 def storepath(repo, hash, forcelocal=False):
172 172 if not forcelocal and repo.shared():
173 173 return repo.vfs.reljoin(repo.sharedpath, longname, hash)
174 174 return repo.join(longname, hash)
175 175
176 176 def findstorepath(repo, hash):
177 177 '''Search through the local store path(s) to find the file for the given
178 178 hash. If the file is not found, its path in the primary store is returned.
179 179 The return value is a tuple of (path, exists(path)).
180 180 '''
181 181 # For shared repos, the primary store is in the share source. But for
182 182 # backward compatibility, force a lookup in the local store if it wasn't
183 183 # found in the share source.
184 184 path = storepath(repo, hash, False)
185 185
186 186 if instore(repo, hash):
187 187 return (path, True)
188 188 elif repo.shared() and instore(repo, hash, True):
189 189 return storepath(repo, hash, True)
190 190
191 191 return (path, False)
192 192
193 193 def copyfromcache(repo, hash, filename):
194 194 '''Copy the specified largefile from the repo or system cache to
195 195 filename in the repository. Return true on success or false if the
196 196 file was not found in either cache (which should not happened:
197 197 this is meant to be called only after ensuring that the needed
198 198 largefile exists in the cache).'''
199 199 path = findfile(repo, hash)
200 200 if path is None:
201 201 return False
202 202 util.makedirs(os.path.dirname(repo.wjoin(filename)))
203 203 # The write may fail before the file is fully written, but we
204 204 # don't use atomic writes in the working copy.
205 205 shutil.copy(path, repo.wjoin(filename))
206 206 return True
207 207
208 208 def copytostore(repo, rev, file, uploaded=False):
209 209 hash = readstandin(repo, file, rev)
210 210 if instore(repo, hash):
211 211 return
212 212 copytostoreabsolute(repo, repo.wjoin(file), hash)
213 213
214 214 def copyalltostore(repo, node):
215 215 '''Copy all largefiles in a given revision to the store'''
216 216
217 217 ctx = repo[node]
218 218 for filename in ctx.files():
219 219 if isstandin(filename) and filename in ctx.manifest():
220 220 realfile = splitstandin(filename)
221 221 copytostore(repo, ctx.node(), realfile)
222 222
223 223
224 224 def copytostoreabsolute(repo, file, hash):
225 225 if inusercache(repo.ui, hash):
226 226 link(usercachepath(repo.ui, hash), storepath(repo, hash))
227 227 else:
228 228 util.makedirs(os.path.dirname(storepath(repo, hash)))
229 229 dst = util.atomictempfile(storepath(repo, hash),
230 230 createmode=repo.store.createmode)
231 231 for chunk in util.filechunkiter(open(file, 'rb')):
232 232 dst.write(chunk)
233 233 dst.close()
234 234 linktousercache(repo, hash)
235 235
236 236 def linktousercache(repo, hash):
237 237 path = usercachepath(repo.ui, hash)
238 238 if path:
239 239 link(storepath(repo, hash), path)
240 240
241 241 def getstandinmatcher(repo, rmatcher=None):
242 242 '''Return a match object that applies rmatcher to the standin directory'''
243 243 standindir = repo.wjoin(shortname)
244 244
245 245 # no warnings about missing files or directories
246 246 badfn = lambda f, msg: None
247 247
248 248 if rmatcher and not rmatcher.always():
249 249 pats = [os.path.join(standindir, pat) for pat in rmatcher.files()]
250 250 if not pats:
251 251 pats = [standindir]
252 252 match = scmutil.match(repo[None], pats, badfn=badfn)
253 253 # if pats is empty, it would incorrectly always match, so clear _always
254 254 match._always = False
255 255 else:
256 256 # no patterns: relative to repo root
257 257 match = scmutil.match(repo[None], [standindir], badfn=badfn)
258 258 return match
259 259
260 260 def composestandinmatcher(repo, rmatcher):
261 261 '''Return a matcher that accepts standins corresponding to the
262 262 files accepted by rmatcher. Pass the list of files in the matcher
263 263 as the paths specified by the user.'''
264 264 smatcher = getstandinmatcher(repo, rmatcher)
265 265 isstandin = smatcher.matchfn
266 266 def composedmatchfn(f):
267 267 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
268 268 smatcher.matchfn = composedmatchfn
269 269
270 270 return smatcher
271 271
272 272 def standin(filename):
273 273 '''Return the repo-relative path to the standin for the specified big
274 274 file.'''
275 275 # Notes:
276 276 # 1) Some callers want an absolute path, but for instance addlargefiles
277 277 # needs it repo-relative so it can be passed to repo[None].add(). So
278 278 # leave it up to the caller to use repo.wjoin() to get an absolute path.
279 279 # 2) Join with '/' because that's what dirstate always uses, even on
280 280 # Windows. Change existing separator to '/' first in case we are
281 281 # passed filenames from an external source (like the command line).
282 282 return shortnameslash + util.pconvert(filename)
283 283
284 284 def isstandin(filename):
285 285 '''Return true if filename is a big file standin. filename must be
286 286 in Mercurial's internal form (slash-separated).'''
287 287 return filename.startswith(shortnameslash)
288 288
289 289 def splitstandin(filename):
290 290 # Split on / because that's what dirstate always uses, even on Windows.
291 291 # Change local separator to / first just in case we are passed filenames
292 292 # from an external source (like the command line).
293 293 bits = util.pconvert(filename).split('/', 1)
294 294 if len(bits) == 2 and bits[0] == shortname:
295 295 return bits[1]
296 296 else:
297 297 return None
298 298
299 299 def updatestandin(repo, standin):
300 300 file = repo.wjoin(splitstandin(standin))
301 301 if os.path.exists(file):
302 302 hash = hashfile(file)
303 303 executable = getexecutable(file)
304 304 writestandin(repo, standin, hash, executable)
305 305
306 306 def readstandin(repo, filename, node=None):
307 307 '''read hex hash from standin for filename at given node, or working
308 308 directory if no node is given'''
309 309 return repo[node][standin(filename)].data().strip()
310 310
311 311 def writestandin(repo, standin, hash, executable):
312 312 '''write hash to <repo.root>/<standin>'''
313 313 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
314 314
315 315 def copyandhash(instream, outfile):
316 316 '''Read bytes from instream (iterable) and write them to outfile,
317 317 computing the SHA-1 hash of the data along the way. Return the hash.'''
318 318 hasher = util.sha1('')
319 319 for data in instream:
320 320 hasher.update(data)
321 321 outfile.write(data)
322 322 return hasher.hexdigest()
323 323
324 324 def hashrepofile(repo, file):
325 325 return hashfile(repo.wjoin(file))
326 326
327 327 def hashfile(file):
328 328 if not os.path.exists(file):
329 329 return ''
330 330 hasher = util.sha1('')
331 331 fd = open(file, 'rb')
332 332 for data in util.filechunkiter(fd, 128 * 1024):
333 333 hasher.update(data)
334 334 fd.close()
335 335 return hasher.hexdigest()
336 336
337 337 def getexecutable(filename):
338 338 mode = os.stat(filename).st_mode
339 339 return ((mode & stat.S_IXUSR) and
340 340 (mode & stat.S_IXGRP) and
341 341 (mode & stat.S_IXOTH))
342 342
343 343 def urljoin(first, second, *arg):
344 344 def join(left, right):
345 345 if not left.endswith('/'):
346 346 left += '/'
347 347 if right.startswith('/'):
348 348 right = right[1:]
349 349 return left + right
350 350
351 351 url = join(first, second)
352 352 for a in arg:
353 353 url = join(url, a)
354 354 return url
355 355
356 356 def hexsha1(data):
357 357 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
358 358 object data"""
359 359 h = util.sha1()
360 360 for chunk in util.filechunkiter(data):
361 361 h.update(chunk)
362 362 return h.hexdigest()
363 363
364 364 def httpsendfile(ui, filename):
365 365 return httpconnection.httpsendfile(ui, filename, 'rb')
366 366
367 367 def unixpath(path):
368 368 '''Return a version of path normalized for use with the lfdirstate.'''
369 369 return util.pconvert(os.path.normpath(path))
370 370
371 371 def islfilesrepo(repo):
372 372 if ('largefiles' in repo.requirements and
373 373 any(shortnameslash in f[0] for f in repo.store.datafiles())):
374 374 return True
375 375
376 376 return any(openlfdirstate(repo.ui, repo, False))
377 377
378 378 class storeprotonotcapable(Exception):
379 379 def __init__(self, storetypes):
380 380 self.storetypes = storetypes
381 381
382 382 def getstandinsstate(repo):
383 383 standins = []
384 384 matcher = getstandinmatcher(repo)
385 385 for standin in repo.dirstate.walk(matcher, [], False, False):
386 386 lfile = splitstandin(standin)
387 387 try:
388 388 hash = readstandin(repo, lfile)
389 389 except IOError:
390 390 hash = None
391 391 standins.append((lfile, hash))
392 392 return standins
393 393
394 394 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
395 395 lfstandin = standin(lfile)
396 396 if lfstandin in repo.dirstate:
397 397 stat = repo.dirstate._map[lfstandin]
398 398 state, mtime = stat[0], stat[3]
399 399 else:
400 400 state, mtime = '?', -1
401 401 if state == 'n':
402 if normallookup or mtime < 0:
402 if (normallookup or mtime < 0 or
403 not os.path.exists(repo.wjoin(lfile))):
403 404 # state 'n' doesn't ensure 'clean' in this case
404 405 lfdirstate.normallookup(lfile)
405 406 else:
406 407 lfdirstate.normal(lfile)
407 408 elif state == 'm':
408 409 lfdirstate.normallookup(lfile)
409 410 elif state == 'r':
410 411 lfdirstate.remove(lfile)
411 412 elif state == 'a':
412 413 lfdirstate.add(lfile)
413 414 elif state == '?':
414 415 lfdirstate.drop(lfile)
415 416
416 417 def markcommitted(orig, ctx, node):
417 418 repo = ctx.repo()
418 419
419 420 orig(node)
420 421
421 422 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
422 423 # because files coming from the 2nd parent are omitted in the latter.
423 424 #
424 425 # The former should be used to get targets of "synclfdirstate",
425 426 # because such files:
426 427 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
427 428 # - have to be marked as "n" after commit, but
428 429 # - aren't listed in "repo[node].files()"
429 430
430 431 lfdirstate = openlfdirstate(repo.ui, repo)
431 432 for f in ctx.files():
432 433 if isstandin(f):
433 434 lfile = splitstandin(f)
434 435 synclfdirstate(repo, lfdirstate, lfile, False)
435 436 lfdirstate.write()
436 437
437 438 # As part of committing, copy all of the largefiles into the cache.
438 439 copyalltostore(repo, node)
439 440
440 441 def getlfilestoupdate(oldstandins, newstandins):
441 442 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
442 443 filelist = []
443 444 for f in changedstandins:
444 445 if f[0] not in filelist:
445 446 filelist.append(f[0])
446 447 return filelist
447 448
448 449 def getlfilestoupload(repo, missing, addfunc):
449 450 for i, n in enumerate(missing):
450 451 repo.ui.progress(_('finding outgoing largefiles'), i,
451 452 unit=_('revision'), total=len(missing))
452 453 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
453 454
454 455 oldlfstatus = repo.lfstatus
455 456 repo.lfstatus = False
456 457 try:
457 458 ctx = repo[n]
458 459 finally:
459 460 repo.lfstatus = oldlfstatus
460 461
461 462 files = set(ctx.files())
462 463 if len(parents) == 2:
463 464 mc = ctx.manifest()
464 465 mp1 = ctx.parents()[0].manifest()
465 466 mp2 = ctx.parents()[1].manifest()
466 467 for f in mp1:
467 468 if f not in mc:
468 469 files.add(f)
469 470 for f in mp2:
470 471 if f not in mc:
471 472 files.add(f)
472 473 for f in mc:
473 474 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
474 475 files.add(f)
475 476 for fn in files:
476 477 if isstandin(fn) and fn in ctx:
477 478 addfunc(fn, ctx[fn].data().strip())
478 479 repo.ui.progress(_('finding outgoing largefiles'), None)
479 480
480 481 def updatestandinsbymatch(repo, match):
481 482 '''Update standins in the working directory according to specified match
482 483
483 484 This returns (possibly modified) ``match`` object to be used for
484 485 subsequent commit process.
485 486 '''
486 487
487 488 ui = repo.ui
488 489
489 490 # Case 1: user calls commit with no specific files or
490 491 # include/exclude patterns: refresh and commit all files that
491 492 # are "dirty".
492 493 if match is None or match.always():
493 494 # Spend a bit of time here to get a list of files we know
494 495 # are modified so we can compare only against those.
495 496 # It can cost a lot of time (several seconds)
496 497 # otherwise to update all standins if the largefiles are
497 498 # large.
498 499 lfdirstate = openlfdirstate(ui, repo)
499 500 dirtymatch = match_.always(repo.root, repo.getcwd())
500 501 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
501 502 False)
502 503 modifiedfiles = unsure + s.modified + s.added + s.removed
503 504 lfiles = listlfiles(repo)
504 505 # this only loops through largefiles that exist (not
505 506 # removed/renamed)
506 507 for lfile in lfiles:
507 508 if lfile in modifiedfiles:
508 509 if os.path.exists(
509 510 repo.wjoin(standin(lfile))):
510 511 # this handles the case where a rebase is being
511 512 # performed and the working copy is not updated
512 513 # yet.
513 514 if os.path.exists(repo.wjoin(lfile)):
514 515 updatestandin(repo,
515 516 standin(lfile))
516 517
517 518 return match
518 519
519 520 lfiles = listlfiles(repo)
520 521 match._files = repo._subdirlfs(match.files(), lfiles)
521 522
522 523 # Case 2: user calls commit with specified patterns: refresh
523 524 # any matching big files.
524 525 smatcher = composestandinmatcher(repo, match)
525 526 standins = repo.dirstate.walk(smatcher, [], False, False)
526 527
527 528 # No matching big files: get out of the way and pass control to
528 529 # the usual commit() method.
529 530 if not standins:
530 531 return match
531 532
532 533 # Refresh all matching big files. It's possible that the
533 534 # commit will end up failing, in which case the big files will
534 535 # stay refreshed. No harm done: the user modified them and
535 536 # asked to commit them, so sooner or later we're going to
536 537 # refresh the standins. Might as well leave them refreshed.
537 538 lfdirstate = openlfdirstate(ui, repo)
538 539 for fstandin in standins:
539 540 lfile = splitstandin(fstandin)
540 541 if lfdirstate[lfile] != 'r':
541 542 updatestandin(repo, fstandin)
542 543
543 544 # Cook up a new matcher that only matches regular files or
544 545 # standins corresponding to the big files requested by the
545 546 # user. Have to modify _files to prevent commit() from
546 547 # complaining "not tracked" for big files.
547 548 match = copy.copy(match)
548 549 origmatchfn = match.matchfn
549 550
550 551 # Check both the list of largefiles and the list of
551 552 # standins because if a largefile was removed, it
552 553 # won't be in the list of largefiles at this point
553 554 match._files += sorted(standins)
554 555
555 556 actualfiles = []
556 557 for f in match._files:
557 558 fstandin = standin(f)
558 559
559 560 # ignore known largefiles and standins
560 561 if f in lfiles or fstandin in standins:
561 562 continue
562 563
563 564 actualfiles.append(f)
564 565 match._files = actualfiles
565 566
566 567 def matchfn(f):
567 568 if origmatchfn(f):
568 569 return f not in lfiles
569 570 else:
570 571 return f in standins
571 572
572 573 match.matchfn = matchfn
573 574
574 575 return match
575 576
576 577 class automatedcommithook(object):
577 578 '''Stateful hook to update standins at the 1st commit of resuming
578 579
579 580 For efficiency, updating standins in the working directory should
580 581 be avoided while automated committing (like rebase, transplant and
581 582 so on), because they should be updated before committing.
582 583
583 584 But the 1st commit of resuming automated committing (e.g. ``rebase
584 585 --continue``) should update them, because largefiles may be
585 586 modified manually.
586 587 '''
587 588 def __init__(self, resuming):
588 589 self.resuming = resuming
589 590
590 591 def __call__(self, repo, match):
591 592 if self.resuming:
592 593 self.resuming = False # avoids updating at subsequent commits
593 594 return updatestandinsbymatch(repo, match)
594 595 else:
595 596 return match
596 597
597 598 def getstatuswriter(ui, repo, forcibly=None):
598 599 '''Return the function to write largefiles specific status out
599 600
600 601 If ``forcibly`` is ``None``, this returns the last element of
601 602 ``repo._lfstatuswriters`` as "default" writer function.
602 603
603 604 Otherwise, this returns the function to always write out (or
604 605 ignore if ``not forcibly``) status.
605 606 '''
606 607 if forcibly is None and util.safehasattr(repo, '_largefilesenabled'):
607 608 return repo._lfstatuswriters[-1]
608 609 else:
609 610 if forcibly:
610 611 return ui.status # forcibly WRITE OUT
611 612 else:
612 613 return lambda *msg, **opts: None # forcibly IGNORE
@@ -1,706 +1,728 b''
1 1 This file focuses mainly on updating largefiles in the working
2 2 directory (and ".hg/largefiles/dirstate")
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [ui]
6 6 > merge = internal:fail
7 7 > [extensions]
8 8 > largefiles =
9 9 > EOF
10 10
11 11 $ hg init repo
12 12 $ cd repo
13 13
14 14 $ echo large1 > large1
15 15 $ echo large2 > large2
16 16 $ hg add --large large1 large2
17 17 $ echo normal1 > normal1
18 18 $ hg add normal1
19 19 $ hg commit -m '#0'
20 20 $ echo 'large1 in #1' > large1
21 21 $ echo 'normal1 in #1' > normal1
22 22 $ hg commit -m '#1'
23 23 $ hg extdiff -r '.^' --config extensions.extdiff=
24 24 diff -Npru repo.0d9d9b8dc9a3/.hglf/large1 repo/.hglf/large1
25 25 --- repo.0d9d9b8dc9a3/.hglf/large1 * (glob)
26 26 +++ repo/.hglf/large1 * (glob)
27 27 @@ -1 +1 @@
28 28 -4669e532d5b2c093a78eca010077e708a071bb64
29 29 +58e24f733a964da346e2407a2bee99d9001184f5
30 30 diff -Npru repo.0d9d9b8dc9a3/normal1 repo/normal1
31 31 --- repo.0d9d9b8dc9a3/normal1 * (glob)
32 32 +++ repo/normal1 * (glob)
33 33 @@ -1 +1 @@
34 34 -normal1
35 35 +normal1 in #1
36 36 [1]
37 37 $ hg update -q -C 0
38 38 $ echo 'large2 in #2' > large2
39 39 $ hg commit -m '#2'
40 40 created new head
41 41
42 42 Test that update also updates the lfdirstate of 'unsure' largefiles after
43 43 hashing them:
44 44
45 45 The previous operations will usually have left us with largefiles with a mtime
46 46 within the same second as the dirstate was written.
47 47 The lfdirstate entries will thus have been written with an invalidated/unset
48 48 mtime to make sure further changes within the same second is detected.
49 49 We will however occasionally be "lucky" and get a tick between writing
50 50 largefiles and writing dirstate so we get valid lfdirstate timestamps. The
51 51 following verification is thus disabled but can be verified manually.
52 52
53 53 #if false
54 54 $ hg debugdirstate --large --nodate
55 55 n 644 7 unset large1
56 56 n 644 13 unset large2
57 57 #endif
58 58
59 59 Wait to make sure we get a tick so the mtime of the largefiles become valid.
60 60
61 61 $ sleep 1
62 62
63 63 A linear merge will update standins before performing the actual merge. It will
64 64 do a lfdirstate status walk and find 'unset'/'unsure' files, hash them, and
65 65 update the corresponding standins.
66 66 Verify that it actually marks the clean files as clean in lfdirstate so
67 67 we don't have to hash them again next time we update.
68 68
69 69 $ hg up
70 70 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 71 $ hg debugdirstate --large --nodate
72 72 n 644 7 set large1
73 73 n 644 13 set large2
74 74
75 75 Test that lfdirstate keeps track of last modification of largefiles and
76 76 prevents unnecessary hashing of content - also after linear/noop update
77 77
78 78 $ sleep 1
79 79 $ hg st
80 80 $ hg debugdirstate --large --nodate
81 81 n 644 7 set large1
82 82 n 644 13 set large2
83 83 $ hg up
84 84 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 85 $ hg debugdirstate --large --nodate
86 86 n 644 7 set large1
87 87 n 644 13 set large2
88 88
89 89 Test that "hg merge" updates largefiles from "other" correctly
90 90
91 91 (getting largefiles from "other" normally)
92 92
93 93 $ hg status -A large1
94 94 C large1
95 95 $ cat large1
96 96 large1
97 97 $ cat .hglf/large1
98 98 4669e532d5b2c093a78eca010077e708a071bb64
99 99 $ hg merge --config debug.dirstate.delaywrite=2
100 100 getting changed largefiles
101 101 1 largefiles updated, 0 removed
102 102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 103 (branch merge, don't forget to commit)
104 104 $ hg status -A large1
105 105 M large1
106 106 $ cat large1
107 107 large1 in #1
108 108 $ cat .hglf/large1
109 109 58e24f733a964da346e2407a2bee99d9001184f5
110 110 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
111 111 -4669e532d5b2c093a78eca010077e708a071bb64
112 112 +58e24f733a964da346e2407a2bee99d9001184f5
113 113
114 114 (getting largefiles from "other" via conflict prompt)
115 115
116 116 $ hg update -q -C 2
117 117 $ echo 'large1 in #3' > large1
118 118 $ echo 'normal1 in #3' > normal1
119 119 $ hg commit -m '#3'
120 120 $ cat .hglf/large1
121 121 e5bb990443d6a92aaf7223813720f7566c9dd05b
122 122 $ hg merge --config debug.dirstate.delaywrite=2 --config ui.interactive=True <<EOF
123 123 > o
124 124 > EOF
125 125 largefile large1 has a merge conflict
126 126 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
127 127 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
128 128 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
129 129 merging normal1
130 130 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
131 131 getting changed largefiles
132 132 1 largefiles updated, 0 removed
133 133 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
134 134 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
135 135 [1]
136 136 $ hg status -A large1
137 137 M large1
138 138 $ cat large1
139 139 large1 in #1
140 140 $ cat .hglf/large1
141 141 58e24f733a964da346e2407a2bee99d9001184f5
142 142
143 (merge non-existing largefiles from "other" via conflict prompt -
144 make sure the following commit doesn't abort in a confusing way when trying to
145 mark the non-existing file as normal in lfdirstate)
146
147 $ mv .hg/largefiles/58e24f733a964da346e2407a2bee99d9001184f5 .
148 $ hg update -q -C 3
149 $ hg merge --config largefiles.usercache=not --config debug.dirstate.delaywrite=2 --tool :local --config ui.interactive=True <<EOF
150 > o
151 > EOF
152 largefile large1 has a merge conflict
153 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
154 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
155 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
156 getting changed largefiles
157 large1: largefile 58e24f733a964da346e2407a2bee99d9001184f5 not available from file:/*/$TESTTMP/repo (glob)
158 0 largefiles updated, 0 removed
159 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
160 (branch merge, don't forget to commit)
161 $ hg commit -m '1-2-3 testing'
162 $ hg rollback -q
163 $ mv 58e24f733a964da346e2407a2bee99d9001184f5 .hg/largefiles/
164
143 165 Test that "hg revert -r REV" updates largefiles from "REV" correctly
144 166
145 167 $ hg update -q -C 3
146 168 $ hg status -A large1
147 169 C large1
148 170 $ cat large1
149 171 large1 in #3
150 172 $ cat .hglf/large1
151 173 e5bb990443d6a92aaf7223813720f7566c9dd05b
152 174 $ hg diff -c 1 --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
153 175 -4669e532d5b2c093a78eca010077e708a071bb64
154 176 +58e24f733a964da346e2407a2bee99d9001184f5
155 177 $ hg revert --no-backup -r 1 --config debug.dirstate.delaywrite=2 large1
156 178 $ hg status -A large1
157 179 M large1
158 180 $ cat large1
159 181 large1 in #1
160 182 $ cat .hglf/large1
161 183 58e24f733a964da346e2407a2bee99d9001184f5
162 184
163 185 Test that "hg rollback" restores status of largefiles correctly
164 186
165 187 $ hg update -C -q
166 188 $ hg remove large1
167 189 $ test -f .hglf/large1
168 190 [1]
169 191 $ hg forget large2
170 192 $ test -f .hglf/large2
171 193 [1]
172 194 $ echo largeX > largeX
173 195 $ hg add --large largeX
174 196 $ cat .hglf/largeX
175 197
176 198 $ hg commit -m 'will be rollback-ed soon'
177 199 $ echo largeY > largeY
178 200 $ hg add --large largeY
179 201 #if windows
180 202 $ hg status -A large1
181 203 large1: * (glob)
182 204 #else
183 205 $ hg status -A large1
184 206 large1: No such file or directory
185 207 #endif
186 208 $ hg status -A large2
187 209 ? large2
188 210 $ hg status -A largeX
189 211 C largeX
190 212 $ hg status -A largeY
191 213 A largeY
192 214 $ hg rollback
193 215 repository tip rolled back to revision 3 (undo commit)
194 216 working directory now based on revision 3
195 217 $ hg status -A large1
196 218 R large1
197 219 $ test -f .hglf/large1
198 220 [1]
199 221 $ hg status -A large2
200 222 R large2
201 223 $ test -f .hglf/large2
202 224 [1]
203 225 $ hg status -A largeX
204 226 A largeX
205 227 $ cat .hglf/largeX
206 228
207 229 $ hg status -A largeY
208 230 ? largeY
209 231 $ test -f .hglf/largeY
210 232 [1]
211 233
212 234 Test that "hg rollback" restores standins correctly
213 235
214 236 $ hg commit -m 'will be rollback-ed soon'
215 237 $ hg update -q -C 2
216 238 $ cat large1
217 239 large1
218 240 $ cat .hglf/large1
219 241 4669e532d5b2c093a78eca010077e708a071bb64
220 242 $ cat large2
221 243 large2 in #2
222 244 $ cat .hglf/large2
223 245 3cfce6277e7668985707b6887ce56f9f62f6ccd9
224 246
225 247 $ hg rollback -q -f
226 248 $ cat large1
227 249 large1
228 250 $ cat .hglf/large1
229 251 4669e532d5b2c093a78eca010077e708a071bb64
230 252 $ cat large2
231 253 large2 in #2
232 254 $ cat .hglf/large2
233 255 3cfce6277e7668985707b6887ce56f9f62f6ccd9
234 256
235 257 (rollback the parent of the working directory, when the parent of it
236 258 is not branch-tip)
237 259
238 260 $ hg update -q -C 1
239 261 $ cat .hglf/large1
240 262 58e24f733a964da346e2407a2bee99d9001184f5
241 263 $ cat .hglf/large2
242 264 1deebade43c8c498a3c8daddac0244dc55d1331d
243 265
244 266 $ echo normalX > normalX
245 267 $ hg add normalX
246 268 $ hg commit -m 'will be rollback-ed soon'
247 269 $ hg rollback -q
248 270
249 271 $ cat .hglf/large1
250 272 58e24f733a964da346e2407a2bee99d9001184f5
251 273 $ cat .hglf/large2
252 274 1deebade43c8c498a3c8daddac0244dc55d1331d
253 275
254 276 Test that "hg status" shows status of largefiles correctly just after
255 277 automated commit like rebase/transplant
256 278
257 279 $ cat >> .hg/hgrc <<EOF
258 280 > [extensions]
259 281 > rebase =
260 282 > strip =
261 283 > transplant =
262 284 > EOF
263 285 $ hg update -q -C 1
264 286 $ hg remove large1
265 287 $ echo largeX > largeX
266 288 $ hg add --large largeX
267 289 $ hg commit -m '#4'
268 290
269 291 $ hg rebase -s 1 -d 2 --keep
270 292 rebasing 1:72518492caa6 "#1"
271 293 rebasing 4:07d6153b5c04 "#4" (tip)
272 294 #if windows
273 295 $ hg status -A large1
274 296 large1: * (glob)
275 297 #else
276 298 $ hg status -A large1
277 299 large1: No such file or directory
278 300 #endif
279 301 $ hg status -A largeX
280 302 C largeX
281 303 $ hg strip -q 5
282 304
283 305 $ hg update -q -C 2
284 306 $ hg transplant -q 1 4
285 307 #if windows
286 308 $ hg status -A large1
287 309 large1: * (glob)
288 310 #else
289 311 $ hg status -A large1
290 312 large1: No such file or directory
291 313 #endif
292 314 $ hg status -A largeX
293 315 C largeX
294 316 $ hg strip -q 5
295 317
296 318 $ hg update -q -C 2
297 319 $ hg transplant -q --merge 1 --merge 4
298 320 #if windows
299 321 $ hg status -A large1
300 322 large1: * (glob)
301 323 #else
302 324 $ hg status -A large1
303 325 large1: No such file or directory
304 326 #endif
305 327 $ hg status -A largeX
306 328 C largeX
307 329 $ hg strip -q 5
308 330
309 331 Test that linear merge can detect modification (and conflict) correctly
310 332
311 333 (linear merge without conflict)
312 334
313 335 $ echo 'large2 for linear merge (no conflict)' > large2
314 336 $ hg update 3 --config debug.dirstate.delaywrite=2
315 337 getting changed largefiles
316 338 1 largefiles updated, 0 removed
317 339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 340 $ hg status -A large2
319 341 M large2
320 342 $ cat large2
321 343 large2 for linear merge (no conflict)
322 344 $ cat .hglf/large2
323 345 9c4bf8f1b33536d6e5f89447e10620cfe52ea710
324 346
325 347 (linear merge with conflict, choosing "other")
326 348
327 349 $ hg update -q -C 2
328 350 $ echo 'large1 for linear merge (conflict)' > large1
329 351 $ hg update 3 --config ui.interactive=True <<EOF
330 352 > o
331 353 > EOF
332 354 largefile large1 has a merge conflict
333 355 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
334 356 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
335 357 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? o
336 358 getting changed largefiles
337 359 1 largefiles updated, 0 removed
338 360 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
339 361 $ hg status -A large1
340 362 C large1
341 363 $ cat large1
342 364 large1 in #3
343 365 $ cat .hglf/large1
344 366 e5bb990443d6a92aaf7223813720f7566c9dd05b
345 367
346 368 (linear merge with conflict, choosing "local")
347 369
348 370 $ hg update -q -C 2
349 371 $ echo 'large1 for linear merge (conflict)' > large1
350 372 $ hg update 3 --config debug.dirstate.delaywrite=2
351 373 largefile large1 has a merge conflict
352 374 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
353 375 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
354 376 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
355 377 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
356 378 $ hg status -A large1
357 379 M large1
358 380 $ cat large1
359 381 large1 for linear merge (conflict)
360 382 $ cat .hglf/large1
361 383 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
362 384
363 385 Test a linear merge to a revision containing same-name normal file
364 386
365 387 $ hg update -q -C 3
366 388 $ hg remove large2
367 389 $ echo 'large2 as normal file' > large2
368 390 $ hg add large2
369 391 $ echo 'large3 as normal file' > large3
370 392 $ hg add large3
371 393 $ hg commit -m '#5'
372 394 $ hg manifest
373 395 .hglf/large1
374 396 large2
375 397 large3
376 398 normal1
377 399
378 400 (modified largefile is already switched to normal)
379 401
380 402 $ hg update -q -C 2
381 403 $ echo 'modified large2 for linear merge' > large2
382 404 $ hg update -q 5
383 405 remote turned local largefile large2 into a normal file
384 406 keep (l)argefile or use (n)ormal file? l
385 407 $ hg debugdirstate --nodates | grep large2
386 408 a 0 -1 unset .hglf/large2
387 409 r 0 0 set large2
388 410 $ hg status -A large2
389 411 A large2
390 412 $ cat large2
391 413 modified large2 for linear merge
392 414
393 415 (added largefile is already committed as normal)
394 416
395 417 $ hg update -q -C 2
396 418 $ echo 'large3 as large file for linear merge' > large3
397 419 $ hg add --large large3
398 420 $ hg update -q 5
399 421 remote turned local largefile large3 into a normal file
400 422 keep (l)argefile or use (n)ormal file? l
401 423 $ hg debugdirstate --nodates | grep large3
402 424 a 0 -1 unset .hglf/large3
403 425 r 0 0 set large3
404 426 $ hg status -A large3
405 427 A large3
406 428 $ cat large3
407 429 large3 as large file for linear merge
408 430 $ rm -f large3 .hglf/large3
409 431
410 432 Test that the internal linear merging works correctly
411 433 (both heads are stripped to keep pairing of revision number and commit log)
412 434
413 435 $ hg update -q -C 2
414 436 $ hg strip 3 4
415 437 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-2e7b195d-backup.hg (glob)
416 438 $ mv .hg/strip-backup/9530e27857f7-2e7b195d-backup.hg $TESTTMP
417 439
418 440 (internal linear merging at "hg pull --update")
419 441
420 442 $ echo 'large1 for linear merge (conflict)' > large1
421 443 $ echo 'large2 for linear merge (conflict with normal file)' > large2
422 444 $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
423 445 pulling from $TESTTMP/9530e27857f7-2e7b195d-backup.hg (glob)
424 446 searching for changes
425 447 adding changesets
426 448 adding manifests
427 449 adding file changes
428 450 added 3 changesets with 5 changes to 5 files
429 451 remote turned local largefile large2 into a normal file
430 452 keep (l)argefile or use (n)ormal file? l
431 453 largefile large1 has a merge conflict
432 454 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
433 455 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
434 456 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
435 457 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
436 458
437 459 $ hg status -A large1
438 460 M large1
439 461 $ cat large1
440 462 large1 for linear merge (conflict)
441 463 $ cat .hglf/large1
442 464 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
443 465 $ hg status -A large2
444 466 A large2
445 467 $ cat large2
446 468 large2 for linear merge (conflict with normal file)
447 469 $ cat .hglf/large2
448 470 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
449 471
450 472 (internal linear merging at "hg unbundle --update")
451 473
452 474 $ hg update -q -C 2
453 475 $ hg rollback -q
454 476
455 477 $ echo 'large1 for linear merge (conflict)' > large1
456 478 $ echo 'large2 for linear merge (conflict with normal file)' > large2
457 479 $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-2e7b195d-backup.hg
458 480 adding changesets
459 481 adding manifests
460 482 adding file changes
461 483 added 3 changesets with 5 changes to 5 files
462 484 remote turned local largefile large2 into a normal file
463 485 keep (l)argefile or use (n)ormal file? l
464 486 largefile large1 has a merge conflict
465 487 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
466 488 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
467 489 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
468 490 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
469 491
470 492 $ hg status -A large1
471 493 M large1
472 494 $ cat large1
473 495 large1 for linear merge (conflict)
474 496 $ cat .hglf/large1
475 497 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
476 498 $ hg status -A large2
477 499 A large2
478 500 $ cat large2
479 501 large2 for linear merge (conflict with normal file)
480 502 $ cat .hglf/large2
481 503 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
482 504
483 505 (internal linear merging in subrepo at "hg update")
484 506
485 507 $ cd ..
486 508 $ hg init subparent
487 509 $ cd subparent
488 510
489 511 $ hg clone -q -u 2 ../repo sub
490 512 $ cat > .hgsub <<EOF
491 513 > sub = sub
492 514 > EOF
493 515 $ hg add .hgsub
494 516 $ hg commit -m '#0@parent'
495 517 $ cat .hgsubstate
496 518 f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub
497 519 $ hg -R sub update -q
498 520 $ hg commit -m '#1@parent'
499 521 $ cat .hgsubstate
500 522 d65e59e952a9638e2ce863b41a420ca723dd3e8d sub
501 523 $ hg update -q 0
502 524
503 525 $ echo 'large1 for linear merge (conflict)' > sub/large1
504 526 $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2
505 527 $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF
506 528 > m
507 529 > r
508 530 > l
509 531 > l
510 532 > EOF
511 533 subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9)
512 534 (M)erge, keep (l)ocal or keep (r)emote? m
513 535 subrepository sources for sub differ (in checked out version)
514 536 use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? r
515 537 remote turned local largefile large2 into a normal file
516 538 keep (l)argefile or use (n)ormal file? l
517 539 largefile large1 has a merge conflict
518 540 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
519 541 keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or
520 542 take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l
521 543 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
522 544 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
523 545
524 546 $ hg -R sub status -A sub/large1
525 547 M sub/large1
526 548 $ cat sub/large1
527 549 large1 for linear merge (conflict)
528 550 $ cat sub/.hglf/large1
529 551 ba94c2efe5b7c5e0af8d189295ce00553b0612b7
530 552 $ hg -R sub status -A sub/large2
531 553 A sub/large2
532 554 $ cat sub/large2
533 555 large2 for linear merge (conflict with normal file)
534 556 $ cat sub/.hglf/large2
535 557 d7591fe9be0f6227d90bddf3e4f52ff41fc1f544
536 558
537 559 $ cd ..
538 560 $ cd repo
539 561
540 562 Test that rebase updates largefiles in the working directory even if
541 563 it is aborted by conflict.
542 564
543 565 $ hg update -q -C 3
544 566 $ cat .hglf/large1
545 567 e5bb990443d6a92aaf7223813720f7566c9dd05b
546 568 $ cat large1
547 569 large1 in #3
548 570 $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF
549 571 > o
550 572 > EOF
551 573 rebasing 1:72518492caa6 "#1"
552 574 largefile large1 has a merge conflict
553 575 ancestor was 4669e532d5b2c093a78eca010077e708a071bb64
554 576 keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or
555 577 take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? o
556 578 merging normal1
557 579 warning: conflicts while merging normal1! (edit, then use 'hg resolve --mark')
558 580 unresolved conflicts (see hg resolve, then hg rebase --continue)
559 581 [1]
560 582 $ cat .hglf/large1
561 583 58e24f733a964da346e2407a2bee99d9001184f5
562 584 $ cat large1
563 585 large1 in #1
564 586
565 587 Test that rebase updates standins for manually modified largefiles at
566 588 the 1st commit of resuming.
567 589
568 590 $ echo "manually modified before 'hg rebase --continue'" > large1
569 591 $ hg resolve -m normal1
570 592 (no more unresolved files)
571 593 $ hg rebase --continue --config ui.interactive=True <<EOF
572 594 > c
573 595 > EOF
574 596 rebasing 1:72518492caa6 "#1"
575 597 rebasing 4:07d6153b5c04 "#4"
576 598 local changed .hglf/large1 which remote deleted
577 599 use (c)hanged version or (d)elete? c
578 600
579 601 $ hg diff -c "tip~1" --nodates .hglf/large1 | grep '^[+-][0-9a-z]'
580 602 -e5bb990443d6a92aaf7223813720f7566c9dd05b
581 603 +8a4f783556e7dea21139ca0466eafce954c75c13
582 604 $ rm -f large1
583 605 $ hg update -q -C tip
584 606 $ cat large1
585 607 manually modified before 'hg rebase --continue'
586 608
587 609 Test that transplant updates largefiles, of which standins are safely
588 610 changed, even if it is aborted by conflict of other.
589 611
590 612 $ hg update -q -C 5
591 613 $ cat .hglf/large1
592 614 e5bb990443d6a92aaf7223813720f7566c9dd05b
593 615 $ cat large1
594 616 large1 in #3
595 617 $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]'
596 618 +fa44618ea25181aff4f48b70428294790cec9f61
597 619 $ hg transplant 4
598 620 applying 07d6153b5c04
599 621 patching file .hglf/large1
600 622 Hunk #1 FAILED at 0
601 623 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej
602 624 patch failed to apply
603 625 abort: fix up the merge and run hg transplant --continue
604 626 [255]
605 627 $ hg status -A large1
606 628 C large1
607 629 $ cat .hglf/large1
608 630 e5bb990443d6a92aaf7223813720f7566c9dd05b
609 631 $ cat large1
610 632 large1 in #3
611 633 $ hg status -A largeX
612 634 A largeX
613 635 $ cat .hglf/largeX
614 636 fa44618ea25181aff4f48b70428294790cec9f61
615 637 $ cat largeX
616 638 largeX
617 639
618 640 Test that transplant updates standins for manually modified largefiles
619 641 at the 1st commit of resuming.
620 642
621 643 $ echo "manually modified before 'hg transplant --continue'" > large1
622 644 $ hg transplant --continue
623 645 07d6153b5c04 transplanted as f1bf30eb88cc
624 646 $ hg diff -c tip .hglf/large1 | grep '^[+-][0-9a-z]'
625 647 -e5bb990443d6a92aaf7223813720f7566c9dd05b
626 648 +6a4f36d4075fbe0f30ec1d26ca44e63c05903671
627 649 $ rm -f large1
628 650 $ hg update -q -C tip
629 651 $ cat large1
630 652 manually modified before 'hg transplant --continue'
631 653
632 654 Test that "hg status" doesn't show removal of largefiles not managed
633 655 in the target context.
634 656
635 657 $ hg update -q -C 4
636 658 $ hg remove largeX
637 659 $ hg status -A largeX
638 660 R largeX
639 661 $ hg status -A --rev '.^1' largeX
640 662
641 663 #if execbit
642 664
643 665 Test that "hg status" against revisions other than parent notices exec
644 666 bit changes of largefiles.
645 667
646 668 $ hg update -q -C 4
647 669
648 670 (the case that large2 doesn't have exec bit in the target context but
649 671 in the working context)
650 672
651 673 $ chmod +x large2
652 674 $ hg status -A --rev 0 large2
653 675 M large2
654 676 $ hg commit -m 'chmod +x large2'
655 677
656 678 (the case that large2 has exec bit in the target context but not in
657 679 the working context)
658 680
659 681 $ echo dummy > dummy
660 682 $ hg add dummy
661 683 $ hg commit -m 'revision for separation'
662 684 $ chmod -x large2
663 685 $ hg status -A --rev '.^1' large2
664 686 M large2
665 687
666 688 #else
667 689
668 690 Test that "hg status" against revisions other than parent ignores exec
669 691 bit correctly on the platform being unaware of it.
670 692
671 693 $ hg update -q -C 4
672 694
673 695 $ cat > exec-bit.patch <<EOF
674 696 > # HG changeset patch
675 697 > # User test
676 698 > # Date 0 0
677 699 > # Thu Jan 01 00:00:00 1970 +0000
678 700 > # Node ID be1b433a65b12b27b5519d92213e14f7e1769b90
679 701 > # Parent 07d6153b5c04313efb75deec9ba577de7faeb727
680 702 > chmod +x large2
681 703 >
682 704 > diff --git a/.hglf/large2 b/.hglf/large2
683 705 > old mode 100644
684 706 > new mode 100755
685 707 > EOF
686 708 $ hg import --exact --bypass exec-bit.patch
687 709 applying exec-bit.patch
688 710 $ hg status -A --rev tip large2
689 711 C large2
690 712
691 713 #endif
692 714
693 715 $ cd ..
694 716
695 717 Test that "hg convert" avoids copying largefiles from the working
696 718 directory into store, because "hg convert" doesn't update largefiles
697 719 in the working directory (removing files under ".cache/largefiles"
698 720 forces "hg convert" to copy corresponding largefiles)
699 721
700 722 $ cat >> $HGRCPATH <<EOF
701 723 > [extensions]
702 724 > convert =
703 725 > EOF
704 726
705 727 $ rm $TESTTMP/.cache/largefiles/6a4f36d4075fbe0f30ec1d26ca44e63c05903671
706 728 $ hg convert -q repo repo.converted
General Comments 0
You need to be logged in to leave comments. Login now