##// END OF EJS Templates
revert: fix the inconsistency of status msgs in --interactive mode...
Sushil khanchi -
r39442:cb70501d default
parent child Browse files
Show More
@@ -1,3295 +1,3317 b''
1 1 # cmdutil.py - help for command processing in mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import os
12 12 import re
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 hex,
17 17 nullid,
18 18 nullrev,
19 19 short,
20 20 )
21 21
22 22 from . import (
23 23 bookmarks,
24 24 changelog,
25 25 copies,
26 26 crecord as crecordmod,
27 27 dirstateguard,
28 28 encoding,
29 29 error,
30 30 formatter,
31 31 logcmdutil,
32 32 match as matchmod,
33 33 merge as mergemod,
34 34 mergeutil,
35 35 obsolete,
36 36 patch,
37 37 pathutil,
38 38 phases,
39 39 pycompat,
40 40 revlog,
41 41 rewriteutil,
42 42 scmutil,
43 43 smartset,
44 44 subrepoutil,
45 45 templatekw,
46 46 templater,
47 47 util,
48 48 vfs as vfsmod,
49 49 )
50 50
51 51 from .utils import (
52 52 dateutil,
53 53 stringutil,
54 54 )
55 55
56 56 stringio = util.stringio
57 57
58 58 # templates of common command options
59 59
60 60 dryrunopts = [
61 61 ('n', 'dry-run', None,
62 62 _('do not perform actions, just print output')),
63 63 ]
64 64
65 65 confirmopts = [
66 66 ('', 'confirm', None,
67 67 _('ask before applying actions')),
68 68 ]
69 69
70 70 remoteopts = [
71 71 ('e', 'ssh', '',
72 72 _('specify ssh command to use'), _('CMD')),
73 73 ('', 'remotecmd', '',
74 74 _('specify hg command to run on the remote side'), _('CMD')),
75 75 ('', 'insecure', None,
76 76 _('do not verify server certificate (ignoring web.cacerts config)')),
77 77 ]
78 78
79 79 walkopts = [
80 80 ('I', 'include', [],
81 81 _('include names matching the given patterns'), _('PATTERN')),
82 82 ('X', 'exclude', [],
83 83 _('exclude names matching the given patterns'), _('PATTERN')),
84 84 ]
85 85
86 86 commitopts = [
87 87 ('m', 'message', '',
88 88 _('use text as commit message'), _('TEXT')),
89 89 ('l', 'logfile', '',
90 90 _('read commit message from file'), _('FILE')),
91 91 ]
92 92
93 93 commitopts2 = [
94 94 ('d', 'date', '',
95 95 _('record the specified date as commit date'), _('DATE')),
96 96 ('u', 'user', '',
97 97 _('record the specified user as committer'), _('USER')),
98 98 ]
99 99
100 100 # hidden for now
101 101 formatteropts = [
102 102 ('T', 'template', '',
103 103 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
104 104 ]
105 105
106 106 templateopts = [
107 107 ('', 'style', '',
108 108 _('display using template map file (DEPRECATED)'), _('STYLE')),
109 109 ('T', 'template', '',
110 110 _('display with template'), _('TEMPLATE')),
111 111 ]
112 112
113 113 logopts = [
114 114 ('p', 'patch', None, _('show patch')),
115 115 ('g', 'git', None, _('use git extended diff format')),
116 116 ('l', 'limit', '',
117 117 _('limit number of changes displayed'), _('NUM')),
118 118 ('M', 'no-merges', None, _('do not show merges')),
119 119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 120 ('G', 'graph', None, _("show the revision DAG")),
121 121 ] + templateopts
122 122
123 123 diffopts = [
124 124 ('a', 'text', None, _('treat all files as text')),
125 125 ('g', 'git', None, _('use git extended diff format')),
126 126 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
127 127 ('', 'nodates', None, _('omit dates from diff headers'))
128 128 ]
129 129
130 130 diffwsopts = [
131 131 ('w', 'ignore-all-space', None,
132 132 _('ignore white space when comparing lines')),
133 133 ('b', 'ignore-space-change', None,
134 134 _('ignore changes in the amount of white space')),
135 135 ('B', 'ignore-blank-lines', None,
136 136 _('ignore changes whose lines are all blank')),
137 137 ('Z', 'ignore-space-at-eol', None,
138 138 _('ignore changes in whitespace at EOL')),
139 139 ]
140 140
141 141 diffopts2 = [
142 142 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
143 143 ('p', 'show-function', None, _('show which function each change is in')),
144 144 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 145 ] + diffwsopts + [
146 146 ('U', 'unified', '',
147 147 _('number of lines of context to show'), _('NUM')),
148 148 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 149 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
150 150 ]
151 151
152 152 mergetoolopts = [
153 153 ('t', 'tool', '', _('specify merge tool')),
154 154 ]
155 155
156 156 similarityopts = [
157 157 ('s', 'similarity', '',
158 158 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 159 ]
160 160
161 161 subrepoopts = [
162 162 ('S', 'subrepos', None,
163 163 _('recurse into subrepositories'))
164 164 ]
165 165
166 166 debugrevlogopts = [
167 167 ('c', 'changelog', False, _('open changelog')),
168 168 ('m', 'manifest', False, _('open manifest')),
169 169 ('', 'dir', '', _('open directory manifest')),
170 170 ]
171 171
172 172 # special string such that everything below this line will be ingored in the
173 173 # editor text
174 174 _linebelow = "^HG: ------------------------ >8 ------------------------$"
175 175
176 176 def ishunk(x):
177 177 hunkclasses = (crecordmod.uihunk, patch.recordhunk)
178 178 return isinstance(x, hunkclasses)
179 179
180 180 def newandmodified(chunks, originalchunks):
181 181 newlyaddedandmodifiedfiles = set()
182 182 for chunk in chunks:
183 183 if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
184 184 originalchunks:
185 185 newlyaddedandmodifiedfiles.add(chunk.header.filename())
186 186 return newlyaddedandmodifiedfiles
187 187
188 188 def parsealiases(cmd):
189 189 return cmd.lstrip("^").split("|")
190 190
191 191 def setupwrapcolorwrite(ui):
192 192 # wrap ui.write so diff output can be labeled/colorized
193 193 def wrapwrite(orig, *args, **kw):
194 194 label = kw.pop(r'label', '')
195 195 for chunk, l in patch.difflabel(lambda: args):
196 196 orig(chunk, label=label + l)
197 197
198 198 oldwrite = ui.write
199 199 def wrap(*args, **kwargs):
200 200 return wrapwrite(oldwrite, *args, **kwargs)
201 201 setattr(ui, 'write', wrap)
202 202 return oldwrite
203 203
204 204 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
205 205 try:
206 206 if usecurses:
207 207 if testfile:
208 208 recordfn = crecordmod.testdecorator(
209 209 testfile, crecordmod.testchunkselector)
210 210 else:
211 211 recordfn = crecordmod.chunkselector
212 212
213 213 return crecordmod.filterpatch(ui, originalhunks, recordfn,
214 214 operation)
215 215 except crecordmod.fallbackerror as e:
216 216 ui.warn('%s\n' % e.message)
217 217 ui.warn(_('falling back to text mode\n'))
218 218
219 219 return patch.filterpatch(ui, originalhunks, operation)
220 220
221 221 def recordfilter(ui, originalhunks, operation=None):
222 222 """ Prompts the user to filter the originalhunks and return a list of
223 223 selected hunks.
224 224 *operation* is used for to build ui messages to indicate the user what
225 225 kind of filtering they are doing: reverting, committing, shelving, etc.
226 226 (see patch.filterpatch).
227 227 """
228 228 usecurses = crecordmod.checkcurses(ui)
229 229 testfile = ui.config('experimental', 'crecordtest')
230 230 oldwrite = setupwrapcolorwrite(ui)
231 231 try:
232 232 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
233 233 testfile, operation)
234 234 finally:
235 235 ui.write = oldwrite
236 236 return newchunks, newopts
237 237
238 238 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
239 239 filterfn, *pats, **opts):
240 240 opts = pycompat.byteskwargs(opts)
241 241 if not ui.interactive():
242 242 if cmdsuggest:
243 243 msg = _('running non-interactively, use %s instead') % cmdsuggest
244 244 else:
245 245 msg = _('running non-interactively')
246 246 raise error.Abort(msg)
247 247
248 248 # make sure username is set before going interactive
249 249 if not opts.get('user'):
250 250 ui.username() # raise exception, username not provided
251 251
252 252 def recordfunc(ui, repo, message, match, opts):
253 253 """This is generic record driver.
254 254
255 255 Its job is to interactively filter local changes, and
256 256 accordingly prepare working directory into a state in which the
257 257 job can be delegated to a non-interactive commit command such as
258 258 'commit' or 'qrefresh'.
259 259
260 260 After the actual job is done by non-interactive command, the
261 261 working directory is restored to its original state.
262 262
263 263 In the end we'll record interesting changes, and everything else
264 264 will be left in place, so the user can continue working.
265 265 """
266 266
267 267 checkunfinished(repo, commit=True)
268 268 wctx = repo[None]
269 269 merge = len(wctx.parents()) > 1
270 270 if merge:
271 271 raise error.Abort(_('cannot partially commit a merge '
272 272 '(use "hg commit" instead)'))
273 273
274 274 def fail(f, msg):
275 275 raise error.Abort('%s: %s' % (f, msg))
276 276
277 277 force = opts.get('force')
278 278 if not force:
279 279 vdirs = []
280 280 match.explicitdir = vdirs.append
281 281 match.bad = fail
282 282
283 283 status = repo.status(match=match)
284 284 if not force:
285 285 repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
286 286 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
287 287 diffopts.nodates = True
288 288 diffopts.git = True
289 289 diffopts.showfunc = True
290 290 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
291 291 originalchunks = patch.parsepatch(originaldiff)
292 292
293 293 # 1. filter patch, since we are intending to apply subset of it
294 294 try:
295 295 chunks, newopts = filterfn(ui, originalchunks)
296 296 except error.PatchError as err:
297 297 raise error.Abort(_('error parsing patch: %s') % err)
298 298 opts.update(newopts)
299 299
300 300 # We need to keep a backup of files that have been newly added and
301 301 # modified during the recording process because there is a previous
302 302 # version without the edit in the workdir
303 303 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
304 304 contenders = set()
305 305 for h in chunks:
306 306 try:
307 307 contenders.update(set(h.files()))
308 308 except AttributeError:
309 309 pass
310 310
311 311 changed = status.modified + status.added + status.removed
312 312 newfiles = [f for f in changed if f in contenders]
313 313 if not newfiles:
314 314 ui.status(_('no changes to record\n'))
315 315 return 0
316 316
317 317 modified = set(status.modified)
318 318
319 319 # 2. backup changed files, so we can restore them in the end
320 320
321 321 if backupall:
322 322 tobackup = changed
323 323 else:
324 324 tobackup = [f for f in newfiles if f in modified or f in \
325 325 newlyaddedandmodifiedfiles]
326 326 backups = {}
327 327 if tobackup:
328 328 backupdir = repo.vfs.join('record-backups')
329 329 try:
330 330 os.mkdir(backupdir)
331 331 except OSError as err:
332 332 if err.errno != errno.EEXIST:
333 333 raise
334 334 try:
335 335 # backup continues
336 336 for f in tobackup:
337 337 fd, tmpname = pycompat.mkstemp(prefix=f.replace('/', '_') + '.',
338 338 dir=backupdir)
339 339 os.close(fd)
340 340 ui.debug('backup %r as %r\n' % (f, tmpname))
341 341 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
342 342 backups[f] = tmpname
343 343
344 344 fp = stringio()
345 345 for c in chunks:
346 346 fname = c.filename()
347 347 if fname in backups:
348 348 c.write(fp)
349 349 dopatch = fp.tell()
350 350 fp.seek(0)
351 351
352 352 # 2.5 optionally review / modify patch in text editor
353 353 if opts.get('review', False):
354 354 patchtext = (crecordmod.diffhelptext
355 355 + crecordmod.patchhelptext
356 356 + fp.read())
357 357 reviewedpatch = ui.edit(patchtext, "",
358 358 action="diff",
359 359 repopath=repo.path)
360 360 fp.truncate(0)
361 361 fp.write(reviewedpatch)
362 362 fp.seek(0)
363 363
364 364 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
365 365 # 3a. apply filtered patch to clean repo (clean)
366 366 if backups:
367 367 # Equivalent to hg.revert
368 368 m = scmutil.matchfiles(repo, backups.keys())
369 369 mergemod.update(repo, repo.dirstate.p1(),
370 370 False, True, matcher=m)
371 371
372 372 # 3b. (apply)
373 373 if dopatch:
374 374 try:
375 375 ui.debug('applying patch\n')
376 376 ui.debug(fp.getvalue())
377 377 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
378 378 except error.PatchError as err:
379 379 raise error.Abort(pycompat.bytestr(err))
380 380 del fp
381 381
382 382 # 4. We prepared working directory according to filtered
383 383 # patch. Now is the time to delegate the job to
384 384 # commit/qrefresh or the like!
385 385
386 386 # Make all of the pathnames absolute.
387 387 newfiles = [repo.wjoin(nf) for nf in newfiles]
388 388 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
389 389 finally:
390 390 # 5. finally restore backed-up files
391 391 try:
392 392 dirstate = repo.dirstate
393 393 for realname, tmpname in backups.iteritems():
394 394 ui.debug('restoring %r to %r\n' % (tmpname, realname))
395 395
396 396 if dirstate[realname] == 'n':
397 397 # without normallookup, restoring timestamp
398 398 # may cause partially committed files
399 399 # to be treated as unmodified
400 400 dirstate.normallookup(realname)
401 401
402 402 # copystat=True here and above are a hack to trick any
403 403 # editors that have f open that we haven't modified them.
404 404 #
405 405 # Also note that this racy as an editor could notice the
406 406 # file's mtime before we've finished writing it.
407 407 util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
408 408 os.unlink(tmpname)
409 409 if tobackup:
410 410 os.rmdir(backupdir)
411 411 except OSError:
412 412 pass
413 413
414 414 def recordinwlock(ui, repo, message, match, opts):
415 415 with repo.wlock():
416 416 return recordfunc(ui, repo, message, match, opts)
417 417
418 418 return commit(ui, repo, recordinwlock, pats, opts)
419 419
420 420 class dirnode(object):
421 421 """
422 422 Represent a directory in user working copy with information required for
423 423 the purpose of tersing its status.
424 424
425 425 path is the path to the directory, without a trailing '/'
426 426
427 427 statuses is a set of statuses of all files in this directory (this includes
428 428 all the files in all the subdirectories too)
429 429
430 430 files is a list of files which are direct child of this directory
431 431
432 432 subdirs is a dictionary of sub-directory name as the key and it's own
433 433 dirnode object as the value
434 434 """
435 435
436 436 def __init__(self, dirpath):
437 437 self.path = dirpath
438 438 self.statuses = set([])
439 439 self.files = []
440 440 self.subdirs = {}
441 441
442 442 def _addfileindir(self, filename, status):
443 443 """Add a file in this directory as a direct child."""
444 444 self.files.append((filename, status))
445 445
446 446 def addfile(self, filename, status):
447 447 """
448 448 Add a file to this directory or to its direct parent directory.
449 449
450 450 If the file is not direct child of this directory, we traverse to the
451 451 directory of which this file is a direct child of and add the file
452 452 there.
453 453 """
454 454
455 455 # the filename contains a path separator, it means it's not the direct
456 456 # child of this directory
457 457 if '/' in filename:
458 458 subdir, filep = filename.split('/', 1)
459 459
460 460 # does the dirnode object for subdir exists
461 461 if subdir not in self.subdirs:
462 462 subdirpath = pathutil.join(self.path, subdir)
463 463 self.subdirs[subdir] = dirnode(subdirpath)
464 464
465 465 # try adding the file in subdir
466 466 self.subdirs[subdir].addfile(filep, status)
467 467
468 468 else:
469 469 self._addfileindir(filename, status)
470 470
471 471 if status not in self.statuses:
472 472 self.statuses.add(status)
473 473
474 474 def iterfilepaths(self):
475 475 """Yield (status, path) for files directly under this directory."""
476 476 for f, st in self.files:
477 477 yield st, pathutil.join(self.path, f)
478 478
479 479 def tersewalk(self, terseargs):
480 480 """
481 481 Yield (status, path) obtained by processing the status of this
482 482 dirnode.
483 483
484 484 terseargs is the string of arguments passed by the user with `--terse`
485 485 flag.
486 486
487 487 Following are the cases which can happen:
488 488
489 489 1) All the files in the directory (including all the files in its
490 490 subdirectories) share the same status and the user has asked us to terse
491 491 that status. -> yield (status, dirpath). dirpath will end in '/'.
492 492
493 493 2) Otherwise, we do following:
494 494
495 495 a) Yield (status, filepath) for all the files which are in this
496 496 directory (only the ones in this directory, not the subdirs)
497 497
498 498 b) Recurse the function on all the subdirectories of this
499 499 directory
500 500 """
501 501
502 502 if len(self.statuses) == 1:
503 503 onlyst = self.statuses.pop()
504 504
505 505 # Making sure we terse only when the status abbreviation is
506 506 # passed as terse argument
507 507 if onlyst in terseargs:
508 508 yield onlyst, self.path + '/'
509 509 return
510 510
511 511 # add the files to status list
512 512 for st, fpath in self.iterfilepaths():
513 513 yield st, fpath
514 514
515 515 #recurse on the subdirs
516 516 for dirobj in self.subdirs.values():
517 517 for st, fpath in dirobj.tersewalk(terseargs):
518 518 yield st, fpath
519 519
520 520 def tersedir(statuslist, terseargs):
521 521 """
522 522 Terse the status if all the files in a directory shares the same status.
523 523
524 524 statuslist is scmutil.status() object which contains a list of files for
525 525 each status.
526 526 terseargs is string which is passed by the user as the argument to `--terse`
527 527 flag.
528 528
529 529 The function makes a tree of objects of dirnode class, and at each node it
530 530 stores the information required to know whether we can terse a certain
531 531 directory or not.
532 532 """
533 533 # the order matters here as that is used to produce final list
534 534 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
535 535
536 536 # checking the argument validity
537 537 for s in pycompat.bytestr(terseargs):
538 538 if s not in allst:
539 539 raise error.Abort(_("'%s' not recognized") % s)
540 540
541 541 # creating a dirnode object for the root of the repo
542 542 rootobj = dirnode('')
543 543 pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
544 544 'ignored', 'removed')
545 545
546 546 tersedict = {}
547 547 for attrname in pstatus:
548 548 statuschar = attrname[0:1]
549 549 for f in getattr(statuslist, attrname):
550 550 rootobj.addfile(f, statuschar)
551 551 tersedict[statuschar] = []
552 552
553 553 # we won't be tersing the root dir, so add files in it
554 554 for st, fpath in rootobj.iterfilepaths():
555 555 tersedict[st].append(fpath)
556 556
557 557 # process each sub-directory and build tersedict
558 558 for subdir in rootobj.subdirs.values():
559 559 for st, f in subdir.tersewalk(terseargs):
560 560 tersedict[st].append(f)
561 561
562 562 tersedlist = []
563 563 for st in allst:
564 564 tersedict[st].sort()
565 565 tersedlist.append(tersedict[st])
566 566
567 567 return tersedlist
568 568
569 569 def _commentlines(raw):
570 570 '''Surround lineswith a comment char and a new line'''
571 571 lines = raw.splitlines()
572 572 commentedlines = ['# %s' % line for line in lines]
573 573 return '\n'.join(commentedlines) + '\n'
574 574
575 575 def _conflictsmsg(repo):
576 576 mergestate = mergemod.mergestate.read(repo)
577 577 if not mergestate.active():
578 578 return
579 579
580 580 m = scmutil.match(repo[None])
581 581 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
582 582 if unresolvedlist:
583 583 mergeliststr = '\n'.join(
584 584 [' %s' % util.pathto(repo.root, pycompat.getcwd(), path)
585 585 for path in unresolvedlist])
586 586 msg = _('''Unresolved merge conflicts:
587 587
588 588 %s
589 589
590 590 To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
591 591 else:
592 592 msg = _('No unresolved merge conflicts.')
593 593
594 594 return _commentlines(msg)
595 595
596 596 def _helpmessage(continuecmd, abortcmd):
597 597 msg = _('To continue: %s\n'
598 598 'To abort: %s') % (continuecmd, abortcmd)
599 599 return _commentlines(msg)
600 600
601 601 def _rebasemsg():
602 602 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
603 603
604 604 def _histeditmsg():
605 605 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
606 606
607 607 def _unshelvemsg():
608 608 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
609 609
610 610 def _graftmsg():
611 611 # tweakdefaults requires `update` to have a rev hence the `.`
612 612 return _helpmessage('hg graft --continue', 'hg graft --abort')
613 613
614 614 def _mergemsg():
615 615 # tweakdefaults requires `update` to have a rev hence the `.`
616 616 return _helpmessage('hg commit', 'hg merge --abort')
617 617
618 618 def _bisectmsg():
619 619 msg = _('To mark the changeset good: hg bisect --good\n'
620 620 'To mark the changeset bad: hg bisect --bad\n'
621 621 'To abort: hg bisect --reset\n')
622 622 return _commentlines(msg)
623 623
624 624 def fileexistspredicate(filename):
625 625 return lambda repo: repo.vfs.exists(filename)
626 626
627 627 def _mergepredicate(repo):
628 628 return len(repo[None].parents()) > 1
629 629
630 630 STATES = (
631 631 # (state, predicate to detect states, helpful message function)
632 632 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
633 633 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
634 634 ('graft', fileexistspredicate('graftstate'), _graftmsg),
635 635 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
636 636 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
637 637 # The merge state is part of a list that will be iterated over.
638 638 # They need to be last because some of the other unfinished states may also
639 639 # be in a merge or update state (eg. rebase, histedit, graft, etc).
640 640 # We want those to have priority.
641 641 ('merge', _mergepredicate, _mergemsg),
642 642 )
643 643
644 644 def _getrepostate(repo):
645 645 # experimental config: commands.status.skipstates
646 646 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
647 647 for state, statedetectionpredicate, msgfn in STATES:
648 648 if state in skip:
649 649 continue
650 650 if statedetectionpredicate(repo):
651 651 return (state, statedetectionpredicate, msgfn)
652 652
653 653 def morestatus(repo, fm):
654 654 statetuple = _getrepostate(repo)
655 655 label = 'status.morestatus'
656 656 if statetuple:
657 657 fm.startitem()
658 658 state, statedetectionpredicate, helpfulmsg = statetuple
659 659 statemsg = _('The repository is in an unfinished *%s* state.') % state
660 660 fm.write('statemsg', '%s\n', _commentlines(statemsg), label=label)
661 661 conmsg = _conflictsmsg(repo)
662 662 if conmsg:
663 663 fm.write('conflictsmsg', '%s\n', conmsg, label=label)
664 664 if helpfulmsg:
665 665 helpmsg = helpfulmsg()
666 666 fm.write('helpmsg', '%s\n', helpmsg, label=label)
667 667
668 668 def findpossible(cmd, table, strict=False):
669 669 """
670 670 Return cmd -> (aliases, command table entry)
671 671 for each matching command.
672 672 Return debug commands (or their aliases) only if no normal command matches.
673 673 """
674 674 choice = {}
675 675 debugchoice = {}
676 676
677 677 if cmd in table:
678 678 # short-circuit exact matches, "log" alias beats "^log|history"
679 679 keys = [cmd]
680 680 else:
681 681 keys = table.keys()
682 682
683 683 allcmds = []
684 684 for e in keys:
685 685 aliases = parsealiases(e)
686 686 allcmds.extend(aliases)
687 687 found = None
688 688 if cmd in aliases:
689 689 found = cmd
690 690 elif not strict:
691 691 for a in aliases:
692 692 if a.startswith(cmd):
693 693 found = a
694 694 break
695 695 if found is not None:
696 696 if aliases[0].startswith("debug") or found.startswith("debug"):
697 697 debugchoice[found] = (aliases, table[e])
698 698 else:
699 699 choice[found] = (aliases, table[e])
700 700
701 701 if not choice and debugchoice:
702 702 choice = debugchoice
703 703
704 704 return choice, allcmds
705 705
706 706 def findcmd(cmd, table, strict=True):
707 707 """Return (aliases, command table entry) for command string."""
708 708 choice, allcmds = findpossible(cmd, table, strict)
709 709
710 710 if cmd in choice:
711 711 return choice[cmd]
712 712
713 713 if len(choice) > 1:
714 714 clist = sorted(choice)
715 715 raise error.AmbiguousCommand(cmd, clist)
716 716
717 717 if choice:
718 718 return list(choice.values())[0]
719 719
720 720 raise error.UnknownCommand(cmd, allcmds)
721 721
722 722 def changebranch(ui, repo, revs, label):
723 723 """ Change the branch name of given revs to label """
724 724
725 725 with repo.wlock(), repo.lock(), repo.transaction('branches'):
726 726 # abort in case of uncommitted merge or dirty wdir
727 727 bailifchanged(repo)
728 728 revs = scmutil.revrange(repo, revs)
729 729 if not revs:
730 730 raise error.Abort("empty revision set")
731 731 roots = repo.revs('roots(%ld)', revs)
732 732 if len(roots) > 1:
733 733 raise error.Abort(_("cannot change branch of non-linear revisions"))
734 734 rewriteutil.precheck(repo, revs, 'change branch of')
735 735
736 736 root = repo[roots.first()]
737 737 if not root.p1().branch() == label and label in repo.branchmap():
738 738 raise error.Abort(_("a branch of the same name already exists"))
739 739
740 740 if repo.revs('merge() and %ld', revs):
741 741 raise error.Abort(_("cannot change branch of a merge commit"))
742 742 if repo.revs('obsolete() and %ld', revs):
743 743 raise error.Abort(_("cannot change branch of a obsolete changeset"))
744 744
745 745 # make sure only topological heads
746 746 if repo.revs('heads(%ld) - head()', revs):
747 747 raise error.Abort(_("cannot change branch in middle of a stack"))
748 748
749 749 replacements = {}
750 750 # avoid import cycle mercurial.cmdutil -> mercurial.context ->
751 751 # mercurial.subrepo -> mercurial.cmdutil
752 752 from . import context
753 753 for rev in revs:
754 754 ctx = repo[rev]
755 755 oldbranch = ctx.branch()
756 756 # check if ctx has same branch
757 757 if oldbranch == label:
758 758 continue
759 759
760 760 def filectxfn(repo, newctx, path):
761 761 try:
762 762 return ctx[path]
763 763 except error.ManifestLookupError:
764 764 return None
765 765
766 766 ui.debug("changing branch of '%s' from '%s' to '%s'\n"
767 767 % (hex(ctx.node()), oldbranch, label))
768 768 extra = ctx.extra()
769 769 extra['branch_change'] = hex(ctx.node())
770 770 # While changing branch of set of linear commits, make sure that
771 771 # we base our commits on new parent rather than old parent which
772 772 # was obsoleted while changing the branch
773 773 p1 = ctx.p1().node()
774 774 p2 = ctx.p2().node()
775 775 if p1 in replacements:
776 776 p1 = replacements[p1][0]
777 777 if p2 in replacements:
778 778 p2 = replacements[p2][0]
779 779
780 780 mc = context.memctx(repo, (p1, p2),
781 781 ctx.description(),
782 782 ctx.files(),
783 783 filectxfn,
784 784 user=ctx.user(),
785 785 date=ctx.date(),
786 786 extra=extra,
787 787 branch=label)
788 788
789 789 newnode = repo.commitctx(mc)
790 790 replacements[ctx.node()] = (newnode,)
791 791 ui.debug('new node id is %s\n' % hex(newnode))
792 792
793 793 # create obsmarkers and move bookmarks
794 794 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True)
795 795
796 796 # move the working copy too
797 797 wctx = repo[None]
798 798 # in-progress merge is a bit too complex for now.
799 799 if len(wctx.parents()) == 1:
800 800 newid = replacements.get(wctx.p1().node())
801 801 if newid is not None:
802 802 # avoid import cycle mercurial.cmdutil -> mercurial.hg ->
803 803 # mercurial.cmdutil
804 804 from . import hg
805 805 hg.update(repo, newid[0], quietempty=True)
806 806
807 807 ui.status(_("changed branch on %d changesets\n") % len(replacements))
808 808
809 809 def findrepo(p):
810 810 while not os.path.isdir(os.path.join(p, ".hg")):
811 811 oldp, p = p, os.path.dirname(p)
812 812 if p == oldp:
813 813 return None
814 814
815 815 return p
816 816
817 817 def bailifchanged(repo, merge=True, hint=None):
818 818 """ enforce the precondition that working directory must be clean.
819 819
820 820 'merge' can be set to false if a pending uncommitted merge should be
821 821 ignored (such as when 'update --check' runs).
822 822
823 823 'hint' is the usual hint given to Abort exception.
824 824 """
825 825
826 826 if merge and repo.dirstate.p2() != nullid:
827 827 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
828 828 modified, added, removed, deleted = repo.status()[:4]
829 829 if modified or added or removed or deleted:
830 830 raise error.Abort(_('uncommitted changes'), hint=hint)
831 831 ctx = repo[None]
832 832 for s in sorted(ctx.substate):
833 833 ctx.sub(s).bailifchanged(hint=hint)
834 834
835 835 def logmessage(ui, opts):
836 836 """ get the log message according to -m and -l option """
837 837 message = opts.get('message')
838 838 logfile = opts.get('logfile')
839 839
840 840 if message and logfile:
841 841 raise error.Abort(_('options --message and --logfile are mutually '
842 842 'exclusive'))
843 843 if not message and logfile:
844 844 try:
845 845 if isstdiofilename(logfile):
846 846 message = ui.fin.read()
847 847 else:
848 848 message = '\n'.join(util.readfile(logfile).splitlines())
849 849 except IOError as inst:
850 850 raise error.Abort(_("can't read commit message '%s': %s") %
851 851 (logfile, encoding.strtolocal(inst.strerror)))
852 852 return message
853 853
854 854 def mergeeditform(ctxorbool, baseformname):
855 855 """return appropriate editform name (referencing a committemplate)
856 856
857 857 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
858 858 merging is committed.
859 859
860 860 This returns baseformname with '.merge' appended if it is a merge,
861 861 otherwise '.normal' is appended.
862 862 """
863 863 if isinstance(ctxorbool, bool):
864 864 if ctxorbool:
865 865 return baseformname + ".merge"
866 866 elif 1 < len(ctxorbool.parents()):
867 867 return baseformname + ".merge"
868 868
869 869 return baseformname + ".normal"
870 870
871 871 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
872 872 editform='', **opts):
873 873 """get appropriate commit message editor according to '--edit' option
874 874
875 875 'finishdesc' is a function to be called with edited commit message
876 876 (= 'description' of the new changeset) just after editing, but
877 877 before checking empty-ness. It should return actual text to be
878 878 stored into history. This allows to change description before
879 879 storing.
880 880
881 881 'extramsg' is a extra message to be shown in the editor instead of
882 882 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
883 883 is automatically added.
884 884
885 885 'editform' is a dot-separated list of names, to distinguish
886 886 the purpose of commit text editing.
887 887
888 888 'getcommiteditor' returns 'commitforceeditor' regardless of
889 889 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
890 890 they are specific for usage in MQ.
891 891 """
892 892 if edit or finishdesc or extramsg:
893 893 return lambda r, c, s: commitforceeditor(r, c, s,
894 894 finishdesc=finishdesc,
895 895 extramsg=extramsg,
896 896 editform=editform)
897 897 elif editform:
898 898 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
899 899 else:
900 900 return commiteditor
901 901
902 902 def _escapecommandtemplate(tmpl):
903 903 parts = []
904 904 for typ, start, end in templater.scantemplate(tmpl, raw=True):
905 905 if typ == b'string':
906 906 parts.append(stringutil.escapestr(tmpl[start:end]))
907 907 else:
908 908 parts.append(tmpl[start:end])
909 909 return b''.join(parts)
910 910
911 911 def rendercommandtemplate(ui, tmpl, props):
912 912 r"""Expand a literal template 'tmpl' in a way suitable for command line
913 913
914 914 '\' in outermost string is not taken as an escape character because it
915 915 is a directory separator on Windows.
916 916
917 917 >>> from . import ui as uimod
918 918 >>> ui = uimod.ui()
919 919 >>> rendercommandtemplate(ui, b'c:\\{path}', {b'path': b'foo'})
920 920 'c:\\foo'
921 921 >>> rendercommandtemplate(ui, b'{"c:\\{path}"}', {'path': b'foo'})
922 922 'c:{path}'
923 923 """
924 924 if not tmpl:
925 925 return tmpl
926 926 t = formatter.maketemplater(ui, _escapecommandtemplate(tmpl))
927 927 return t.renderdefault(props)
928 928
929 929 def rendertemplate(ctx, tmpl, props=None):
930 930 """Expand a literal template 'tmpl' byte-string against one changeset
931 931
932 932 Each props item must be a stringify-able value or a callable returning
933 933 such value, i.e. no bare list nor dict should be passed.
934 934 """
935 935 repo = ctx.repo()
936 936 tres = formatter.templateresources(repo.ui, repo)
937 937 t = formatter.maketemplater(repo.ui, tmpl, defaults=templatekw.keywords,
938 938 resources=tres)
939 939 mapping = {'ctx': ctx}
940 940 if props:
941 941 mapping.update(props)
942 942 return t.renderdefault(mapping)
943 943
944 944 def _buildfntemplate(pat, total=None, seqno=None, revwidth=None, pathname=None):
945 945 r"""Convert old-style filename format string to template string
946 946
947 947 >>> _buildfntemplate(b'foo-%b-%n.patch', seqno=0)
948 948 'foo-{reporoot|basename}-{seqno}.patch'
949 949 >>> _buildfntemplate(b'%R{tags % "{tag}"}%H')
950 950 '{rev}{tags % "{tag}"}{node}'
951 951
952 952 '\' in outermost strings has to be escaped because it is a directory
953 953 separator on Windows:
954 954
955 955 >>> _buildfntemplate(b'c:\\tmp\\%R\\%n.patch', seqno=0)
956 956 'c:\\\\tmp\\\\{rev}\\\\{seqno}.patch'
957 957 >>> _buildfntemplate(b'\\\\foo\\bar.patch')
958 958 '\\\\\\\\foo\\\\bar.patch'
959 959 >>> _buildfntemplate(b'\\{tags % "{tag}"}')
960 960 '\\\\{tags % "{tag}"}'
961 961
962 962 but inner strings follow the template rules (i.e. '\' is taken as an
963 963 escape character):
964 964
965 965 >>> _buildfntemplate(br'{"c:\tmp"}', seqno=0)
966 966 '{"c:\\tmp"}'
967 967 """
968 968 expander = {
969 969 b'H': b'{node}',
970 970 b'R': b'{rev}',
971 971 b'h': b'{node|short}',
972 972 b'm': br'{sub(r"[^\w]", "_", desc|firstline)}',
973 973 b'r': b'{if(revwidth, pad(rev, revwidth, "0", left=True), rev)}',
974 974 b'%': b'%',
975 975 b'b': b'{reporoot|basename}',
976 976 }
977 977 if total is not None:
978 978 expander[b'N'] = b'{total}'
979 979 if seqno is not None:
980 980 expander[b'n'] = b'{seqno}'
981 981 if total is not None and seqno is not None:
982 982 expander[b'n'] = b'{pad(seqno, total|stringify|count, "0", left=True)}'
983 983 if pathname is not None:
984 984 expander[b's'] = b'{pathname|basename}'
985 985 expander[b'd'] = b'{if(pathname|dirname, pathname|dirname, ".")}'
986 986 expander[b'p'] = b'{pathname}'
987 987
988 988 newname = []
989 989 for typ, start, end in templater.scantemplate(pat, raw=True):
990 990 if typ != b'string':
991 991 newname.append(pat[start:end])
992 992 continue
993 993 i = start
994 994 while i < end:
995 995 n = pat.find(b'%', i, end)
996 996 if n < 0:
997 997 newname.append(stringutil.escapestr(pat[i:end]))
998 998 break
999 999 newname.append(stringutil.escapestr(pat[i:n]))
1000 1000 if n + 2 > end:
1001 1001 raise error.Abort(_("incomplete format spec in output "
1002 1002 "filename"))
1003 1003 c = pat[n + 1:n + 2]
1004 1004 i = n + 2
1005 1005 try:
1006 1006 newname.append(expander[c])
1007 1007 except KeyError:
1008 1008 raise error.Abort(_("invalid format spec '%%%s' in output "
1009 1009 "filename") % c)
1010 1010 return ''.join(newname)
1011 1011
1012 1012 def makefilename(ctx, pat, **props):
1013 1013 if not pat:
1014 1014 return pat
1015 1015 tmpl = _buildfntemplate(pat, **props)
1016 1016 # BUG: alias expansion shouldn't be made against template fragments
1017 1017 # rewritten from %-format strings, but we have no easy way to partially
1018 1018 # disable the expansion.
1019 1019 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props))
1020 1020
1021 1021 def isstdiofilename(pat):
1022 1022 """True if the given pat looks like a filename denoting stdin/stdout"""
1023 1023 return not pat or pat == '-'
1024 1024
1025 1025 class _unclosablefile(object):
1026 1026 def __init__(self, fp):
1027 1027 self._fp = fp
1028 1028
1029 1029 def close(self):
1030 1030 pass
1031 1031
1032 1032 def __iter__(self):
1033 1033 return iter(self._fp)
1034 1034
1035 1035 def __getattr__(self, attr):
1036 1036 return getattr(self._fp, attr)
1037 1037
1038 1038 def __enter__(self):
1039 1039 return self
1040 1040
1041 1041 def __exit__(self, exc_type, exc_value, exc_tb):
1042 1042 pass
1043 1043
1044 1044 def makefileobj(ctx, pat, mode='wb', **props):
1045 1045 writable = mode not in ('r', 'rb')
1046 1046
1047 1047 if isstdiofilename(pat):
1048 1048 repo = ctx.repo()
1049 1049 if writable:
1050 1050 fp = repo.ui.fout
1051 1051 else:
1052 1052 fp = repo.ui.fin
1053 1053 return _unclosablefile(fp)
1054 1054 fn = makefilename(ctx, pat, **props)
1055 1055 return open(fn, mode)
1056 1056
1057 1057 def openstorage(repo, cmd, file_, opts, returnrevlog=False):
1058 1058 """opens the changelog, manifest, a filelog or a given revlog"""
1059 1059 cl = opts['changelog']
1060 1060 mf = opts['manifest']
1061 1061 dir = opts['dir']
1062 1062 msg = None
1063 1063 if cl and mf:
1064 1064 msg = _('cannot specify --changelog and --manifest at the same time')
1065 1065 elif cl and dir:
1066 1066 msg = _('cannot specify --changelog and --dir at the same time')
1067 1067 elif cl or mf or dir:
1068 1068 if file_:
1069 1069 msg = _('cannot specify filename with --changelog or --manifest')
1070 1070 elif not repo:
1071 1071 msg = _('cannot specify --changelog or --manifest or --dir '
1072 1072 'without a repository')
1073 1073 if msg:
1074 1074 raise error.Abort(msg)
1075 1075
1076 1076 r = None
1077 1077 if repo:
1078 1078 if cl:
1079 1079 r = repo.unfiltered().changelog
1080 1080 elif dir:
1081 1081 if 'treemanifest' not in repo.requirements:
1082 1082 raise error.Abort(_("--dir can only be used on repos with "
1083 1083 "treemanifest enabled"))
1084 1084 if not dir.endswith('/'):
1085 1085 dir = dir + '/'
1086 1086 dirlog = repo.manifestlog.getstorage(dir)
1087 1087 if len(dirlog):
1088 1088 r = dirlog
1089 1089 elif mf:
1090 1090 r = repo.manifestlog.getstorage(b'')
1091 1091 elif file_:
1092 1092 filelog = repo.file(file_)
1093 1093 if len(filelog):
1094 1094 r = filelog
1095 1095
1096 1096 # Not all storage may be revlogs. If requested, try to return an actual
1097 1097 # revlog instance.
1098 1098 if returnrevlog:
1099 1099 if isinstance(r, revlog.revlog):
1100 1100 pass
1101 1101 elif util.safehasattr(r, '_revlog'):
1102 1102 r = r._revlog
1103 1103 elif r is not None:
1104 1104 raise error.Abort(_('%r does not appear to be a revlog') % r)
1105 1105
1106 1106 if not r:
1107 1107 if not returnrevlog:
1108 1108 raise error.Abort(_('cannot give path to non-revlog'))
1109 1109
1110 1110 if not file_:
1111 1111 raise error.CommandError(cmd, _('invalid arguments'))
1112 1112 if not os.path.isfile(file_):
1113 1113 raise error.Abort(_("revlog '%s' not found") % file_)
1114 1114 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
1115 1115 file_[:-2] + ".i")
1116 1116 return r
1117 1117
1118 1118 def openrevlog(repo, cmd, file_, opts):
1119 1119 """Obtain a revlog backing storage of an item.
1120 1120
1121 1121 This is similar to ``openstorage()`` except it always returns a revlog.
1122 1122
1123 1123 In most cases, a caller cares about the main storage object - not the
1124 1124 revlog backing it. Therefore, this function should only be used by code
1125 1125 that needs to examine low-level revlog implementation details. e.g. debug
1126 1126 commands.
1127 1127 """
1128 1128 return openstorage(repo, cmd, file_, opts, returnrevlog=True)
1129 1129
1130 1130 def copy(ui, repo, pats, opts, rename=False):
1131 1131 # called with the repo lock held
1132 1132 #
1133 1133 # hgsep => pathname that uses "/" to separate directories
1134 1134 # ossep => pathname that uses os.sep to separate directories
1135 1135 cwd = repo.getcwd()
1136 1136 targets = {}
1137 1137 after = opts.get("after")
1138 1138 dryrun = opts.get("dry_run")
1139 1139 wctx = repo[None]
1140 1140
1141 1141 def walkpat(pat):
1142 1142 srcs = []
1143 1143 if after:
1144 1144 badstates = '?'
1145 1145 else:
1146 1146 badstates = '?r'
1147 1147 m = scmutil.match(wctx, [pat], opts, globbed=True)
1148 1148 for abs in wctx.walk(m):
1149 1149 state = repo.dirstate[abs]
1150 1150 rel = m.rel(abs)
1151 1151 exact = m.exact(abs)
1152 1152 if state in badstates:
1153 1153 if exact and state == '?':
1154 1154 ui.warn(_('%s: not copying - file is not managed\n') % rel)
1155 1155 if exact and state == 'r':
1156 1156 ui.warn(_('%s: not copying - file has been marked for'
1157 1157 ' remove\n') % rel)
1158 1158 continue
1159 1159 # abs: hgsep
1160 1160 # rel: ossep
1161 1161 srcs.append((abs, rel, exact))
1162 1162 return srcs
1163 1163
1164 1164 # abssrc: hgsep
1165 1165 # relsrc: ossep
1166 1166 # otarget: ossep
1167 1167 def copyfile(abssrc, relsrc, otarget, exact):
1168 1168 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
1169 1169 if '/' in abstarget:
1170 1170 # We cannot normalize abstarget itself, this would prevent
1171 1171 # case only renames, like a => A.
1172 1172 abspath, absname = abstarget.rsplit('/', 1)
1173 1173 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
1174 1174 reltarget = repo.pathto(abstarget, cwd)
1175 1175 target = repo.wjoin(abstarget)
1176 1176 src = repo.wjoin(abssrc)
1177 1177 state = repo.dirstate[abstarget]
1178 1178
1179 1179 scmutil.checkportable(ui, abstarget)
1180 1180
1181 1181 # check for collisions
1182 1182 prevsrc = targets.get(abstarget)
1183 1183 if prevsrc is not None:
1184 1184 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1185 1185 (reltarget, repo.pathto(abssrc, cwd),
1186 1186 repo.pathto(prevsrc, cwd)))
1187 1187 return True # report a failure
1188 1188
1189 1189 # check for overwrites
1190 1190 exists = os.path.lexists(target)
1191 1191 samefile = False
1192 1192 if exists and abssrc != abstarget:
1193 1193 if (repo.dirstate.normalize(abssrc) ==
1194 1194 repo.dirstate.normalize(abstarget)):
1195 1195 if not rename:
1196 1196 ui.warn(_("%s: can't copy - same file\n") % reltarget)
1197 1197 return True # report a failure
1198 1198 exists = False
1199 1199 samefile = True
1200 1200
1201 1201 if not after and exists or after and state in 'mn':
1202 1202 if not opts['force']:
1203 1203 if state in 'mn':
1204 1204 msg = _('%s: not overwriting - file already committed\n')
1205 1205 if after:
1206 1206 flags = '--after --force'
1207 1207 else:
1208 1208 flags = '--force'
1209 1209 if rename:
1210 1210 hint = _("('hg rename %s' to replace the file by "
1211 1211 'recording a rename)\n') % flags
1212 1212 else:
1213 1213 hint = _("('hg copy %s' to replace the file by "
1214 1214 'recording a copy)\n') % flags
1215 1215 else:
1216 1216 msg = _('%s: not overwriting - file exists\n')
1217 1217 if rename:
1218 1218 hint = _("('hg rename --after' to record the rename)\n")
1219 1219 else:
1220 1220 hint = _("('hg copy --after' to record the copy)\n")
1221 1221 ui.warn(msg % reltarget)
1222 1222 ui.warn(hint)
1223 1223 return True # report a failure
1224 1224
1225 1225 if after:
1226 1226 if not exists:
1227 1227 if rename:
1228 1228 ui.warn(_('%s: not recording move - %s does not exist\n') %
1229 1229 (relsrc, reltarget))
1230 1230 else:
1231 1231 ui.warn(_('%s: not recording copy - %s does not exist\n') %
1232 1232 (relsrc, reltarget))
1233 1233 return True # report a failure
1234 1234 elif not dryrun:
1235 1235 try:
1236 1236 if exists:
1237 1237 os.unlink(target)
1238 1238 targetdir = os.path.dirname(target) or '.'
1239 1239 if not os.path.isdir(targetdir):
1240 1240 os.makedirs(targetdir)
1241 1241 if samefile:
1242 1242 tmp = target + "~hgrename"
1243 1243 os.rename(src, tmp)
1244 1244 os.rename(tmp, target)
1245 1245 else:
1246 1246 # Preserve stat info on renames, not on copies; this matches
1247 1247 # Linux CLI behavior.
1248 1248 util.copyfile(src, target, copystat=rename)
1249 1249 srcexists = True
1250 1250 except IOError as inst:
1251 1251 if inst.errno == errno.ENOENT:
1252 1252 ui.warn(_('%s: deleted in working directory\n') % relsrc)
1253 1253 srcexists = False
1254 1254 else:
1255 1255 ui.warn(_('%s: cannot copy - %s\n') %
1256 1256 (relsrc, encoding.strtolocal(inst.strerror)))
1257 1257 if rename:
1258 1258 hint = _("('hg rename --after' to record the rename)\n")
1259 1259 else:
1260 1260 hint = _("('hg copy --after' to record the copy)\n")
1261 1261 return True # report a failure
1262 1262
1263 1263 if ui.verbose or not exact:
1264 1264 if rename:
1265 1265 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
1266 1266 else:
1267 1267 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1268 1268
1269 1269 targets[abstarget] = abssrc
1270 1270
1271 1271 # fix up dirstate
1272 1272 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
1273 1273 dryrun=dryrun, cwd=cwd)
1274 1274 if rename and not dryrun:
1275 1275 if not after and srcexists and not samefile:
1276 1276 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
1277 1277 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir)
1278 1278 wctx.forget([abssrc])
1279 1279
1280 1280 # pat: ossep
1281 1281 # dest ossep
1282 1282 # srcs: list of (hgsep, hgsep, ossep, bool)
1283 1283 # return: function that takes hgsep and returns ossep
1284 1284 def targetpathfn(pat, dest, srcs):
1285 1285 if os.path.isdir(pat):
1286 1286 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1287 1287 abspfx = util.localpath(abspfx)
1288 1288 if destdirexists:
1289 1289 striplen = len(os.path.split(abspfx)[0])
1290 1290 else:
1291 1291 striplen = len(abspfx)
1292 1292 if striplen:
1293 1293 striplen += len(pycompat.ossep)
1294 1294 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
1295 1295 elif destdirexists:
1296 1296 res = lambda p: os.path.join(dest,
1297 1297 os.path.basename(util.localpath(p)))
1298 1298 else:
1299 1299 res = lambda p: dest
1300 1300 return res
1301 1301
1302 1302 # pat: ossep
1303 1303 # dest ossep
1304 1304 # srcs: list of (hgsep, hgsep, ossep, bool)
1305 1305 # return: function that takes hgsep and returns ossep
1306 1306 def targetpathafterfn(pat, dest, srcs):
1307 1307 if matchmod.patkind(pat):
1308 1308 # a mercurial pattern
1309 1309 res = lambda p: os.path.join(dest,
1310 1310 os.path.basename(util.localpath(p)))
1311 1311 else:
1312 1312 abspfx = pathutil.canonpath(repo.root, cwd, pat)
1313 1313 if len(abspfx) < len(srcs[0][0]):
1314 1314 # A directory. Either the target path contains the last
1315 1315 # component of the source path or it does not.
1316 1316 def evalpath(striplen):
1317 1317 score = 0
1318 1318 for s in srcs:
1319 1319 t = os.path.join(dest, util.localpath(s[0])[striplen:])
1320 1320 if os.path.lexists(t):
1321 1321 score += 1
1322 1322 return score
1323 1323
1324 1324 abspfx = util.localpath(abspfx)
1325 1325 striplen = len(abspfx)
1326 1326 if striplen:
1327 1327 striplen += len(pycompat.ossep)
1328 1328 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1329 1329 score = evalpath(striplen)
1330 1330 striplen1 = len(os.path.split(abspfx)[0])
1331 1331 if striplen1:
1332 1332 striplen1 += len(pycompat.ossep)
1333 1333 if evalpath(striplen1) > score:
1334 1334 striplen = striplen1
1335 1335 res = lambda p: os.path.join(dest,
1336 1336 util.localpath(p)[striplen:])
1337 1337 else:
1338 1338 # a file
1339 1339 if destdirexists:
1340 1340 res = lambda p: os.path.join(dest,
1341 1341 os.path.basename(util.localpath(p)))
1342 1342 else:
1343 1343 res = lambda p: dest
1344 1344 return res
1345 1345
1346 1346 pats = scmutil.expandpats(pats)
1347 1347 if not pats:
1348 1348 raise error.Abort(_('no source or destination specified'))
1349 1349 if len(pats) == 1:
1350 1350 raise error.Abort(_('no destination specified'))
1351 1351 dest = pats.pop()
1352 1352 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
1353 1353 if not destdirexists:
1354 1354 if len(pats) > 1 or matchmod.patkind(pats[0]):
1355 1355 raise error.Abort(_('with multiple sources, destination must be an '
1356 1356 'existing directory'))
1357 1357 if util.endswithsep(dest):
1358 1358 raise error.Abort(_('destination %s is not a directory') % dest)
1359 1359
1360 1360 tfn = targetpathfn
1361 1361 if after:
1362 1362 tfn = targetpathafterfn
1363 1363 copylist = []
1364 1364 for pat in pats:
1365 1365 srcs = walkpat(pat)
1366 1366 if not srcs:
1367 1367 continue
1368 1368 copylist.append((tfn(pat, dest, srcs), srcs))
1369 1369 if not copylist:
1370 1370 raise error.Abort(_('no files to copy'))
1371 1371
1372 1372 errors = 0
1373 1373 for targetpath, srcs in copylist:
1374 1374 for abssrc, relsrc, exact in srcs:
1375 1375 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
1376 1376 errors += 1
1377 1377
1378 1378 return errors != 0
1379 1379
1380 1380 ## facility to let extension process additional data into an import patch
1381 1381 # list of identifier to be executed in order
1382 1382 extrapreimport = [] # run before commit
1383 1383 extrapostimport = [] # run after commit
1384 1384 # mapping from identifier to actual import function
1385 1385 #
1386 1386 # 'preimport' are run before the commit is made and are provided the following
1387 1387 # arguments:
1388 1388 # - repo: the localrepository instance,
1389 1389 # - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
1390 1390 # - extra: the future extra dictionary of the changeset, please mutate it,
1391 1391 # - opts: the import options.
1392 1392 # XXX ideally, we would just pass an ctx ready to be computed, that would allow
1393 1393 # mutation of in memory commit and more. Feel free to rework the code to get
1394 1394 # there.
1395 1395 extrapreimportmap = {}
1396 1396 # 'postimport' are run after the commit is made and are provided the following
1397 1397 # argument:
1398 1398 # - ctx: the changectx created by import.
1399 1399 extrapostimportmap = {}
1400 1400
1401 1401 def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
1402 1402 """Utility function used by commands.import to import a single patch
1403 1403
1404 1404 This function is explicitly defined here to help the evolve extension to
1405 1405 wrap this part of the import logic.
1406 1406
1407 1407 The API is currently a bit ugly because it a simple code translation from
1408 1408 the import command. Feel free to make it better.
1409 1409
1410 1410 :patchdata: a dictionary containing parsed patch data (such as from
1411 1411 ``patch.extract()``)
1412 1412 :parents: nodes that will be parent of the created commit
1413 1413 :opts: the full dict of option passed to the import command
1414 1414 :msgs: list to save commit message to.
1415 1415 (used in case we need to save it when failing)
1416 1416 :updatefunc: a function that update a repo to a given node
1417 1417 updatefunc(<repo>, <node>)
1418 1418 """
1419 1419 # avoid cycle context -> subrepo -> cmdutil
1420 1420 from . import context
1421 1421
1422 1422 tmpname = patchdata.get('filename')
1423 1423 message = patchdata.get('message')
1424 1424 user = opts.get('user') or patchdata.get('user')
1425 1425 date = opts.get('date') or patchdata.get('date')
1426 1426 branch = patchdata.get('branch')
1427 1427 nodeid = patchdata.get('nodeid')
1428 1428 p1 = patchdata.get('p1')
1429 1429 p2 = patchdata.get('p2')
1430 1430
1431 1431 nocommit = opts.get('no_commit')
1432 1432 importbranch = opts.get('import_branch')
1433 1433 update = not opts.get('bypass')
1434 1434 strip = opts["strip"]
1435 1435 prefix = opts["prefix"]
1436 1436 sim = float(opts.get('similarity') or 0)
1437 1437
1438 1438 if not tmpname:
1439 1439 return None, None, False
1440 1440
1441 1441 rejects = False
1442 1442
1443 1443 cmdline_message = logmessage(ui, opts)
1444 1444 if cmdline_message:
1445 1445 # pickup the cmdline msg
1446 1446 message = cmdline_message
1447 1447 elif message:
1448 1448 # pickup the patch msg
1449 1449 message = message.strip()
1450 1450 else:
1451 1451 # launch the editor
1452 1452 message = None
1453 1453 ui.debug('message:\n%s\n' % (message or ''))
1454 1454
1455 1455 if len(parents) == 1:
1456 1456 parents.append(repo[nullid])
1457 1457 if opts.get('exact'):
1458 1458 if not nodeid or not p1:
1459 1459 raise error.Abort(_('not a Mercurial patch'))
1460 1460 p1 = repo[p1]
1461 1461 p2 = repo[p2 or nullid]
1462 1462 elif p2:
1463 1463 try:
1464 1464 p1 = repo[p1]
1465 1465 p2 = repo[p2]
1466 1466 # Without any options, consider p2 only if the
1467 1467 # patch is being applied on top of the recorded
1468 1468 # first parent.
1469 1469 if p1 != parents[0]:
1470 1470 p1 = parents[0]
1471 1471 p2 = repo[nullid]
1472 1472 except error.RepoError:
1473 1473 p1, p2 = parents
1474 1474 if p2.node() == nullid:
1475 1475 ui.warn(_("warning: import the patch as a normal revision\n"
1476 1476 "(use --exact to import the patch as a merge)\n"))
1477 1477 else:
1478 1478 p1, p2 = parents
1479 1479
1480 1480 n = None
1481 1481 if update:
1482 1482 if p1 != parents[0]:
1483 1483 updatefunc(repo, p1.node())
1484 1484 if p2 != parents[1]:
1485 1485 repo.setparents(p1.node(), p2.node())
1486 1486
1487 1487 if opts.get('exact') or importbranch:
1488 1488 repo.dirstate.setbranch(branch or 'default')
1489 1489
1490 1490 partial = opts.get('partial', False)
1491 1491 files = set()
1492 1492 try:
1493 1493 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
1494 1494 files=files, eolmode=None, similarity=sim / 100.0)
1495 1495 except error.PatchError as e:
1496 1496 if not partial:
1497 1497 raise error.Abort(pycompat.bytestr(e))
1498 1498 if partial:
1499 1499 rejects = True
1500 1500
1501 1501 files = list(files)
1502 1502 if nocommit:
1503 1503 if message:
1504 1504 msgs.append(message)
1505 1505 else:
1506 1506 if opts.get('exact') or p2:
1507 1507 # If you got here, you either use --force and know what
1508 1508 # you are doing or used --exact or a merge patch while
1509 1509 # being updated to its first parent.
1510 1510 m = None
1511 1511 else:
1512 1512 m = scmutil.matchfiles(repo, files or [])
1513 1513 editform = mergeeditform(repo[None], 'import.normal')
1514 1514 if opts.get('exact'):
1515 1515 editor = None
1516 1516 else:
1517 1517 editor = getcommiteditor(editform=editform,
1518 1518 **pycompat.strkwargs(opts))
1519 1519 extra = {}
1520 1520 for idfunc in extrapreimport:
1521 1521 extrapreimportmap[idfunc](repo, patchdata, extra, opts)
1522 1522 overrides = {}
1523 1523 if partial:
1524 1524 overrides[('ui', 'allowemptycommit')] = True
1525 1525 with repo.ui.configoverride(overrides, 'import'):
1526 1526 n = repo.commit(message, user,
1527 1527 date, match=m,
1528 1528 editor=editor, extra=extra)
1529 1529 for idfunc in extrapostimport:
1530 1530 extrapostimportmap[idfunc](repo[n])
1531 1531 else:
1532 1532 if opts.get('exact') or importbranch:
1533 1533 branch = branch or 'default'
1534 1534 else:
1535 1535 branch = p1.branch()
1536 1536 store = patch.filestore()
1537 1537 try:
1538 1538 files = set()
1539 1539 try:
1540 1540 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
1541 1541 files, eolmode=None)
1542 1542 except error.PatchError as e:
1543 1543 raise error.Abort(stringutil.forcebytestr(e))
1544 1544 if opts.get('exact'):
1545 1545 editor = None
1546 1546 else:
1547 1547 editor = getcommiteditor(editform='import.bypass')
1548 1548 memctx = context.memctx(repo, (p1.node(), p2.node()),
1549 1549 message,
1550 1550 files=files,
1551 1551 filectxfn=store,
1552 1552 user=user,
1553 1553 date=date,
1554 1554 branch=branch,
1555 1555 editor=editor)
1556 1556 n = memctx.commit()
1557 1557 finally:
1558 1558 store.close()
1559 1559 if opts.get('exact') and nocommit:
1560 1560 # --exact with --no-commit is still useful in that it does merge
1561 1561 # and branch bits
1562 1562 ui.warn(_("warning: can't check exact import with --no-commit\n"))
1563 1563 elif opts.get('exact') and (not n or hex(n) != nodeid):
1564 1564 raise error.Abort(_('patch is damaged or loses information'))
1565 1565 msg = _('applied to working directory')
1566 1566 if n:
1567 1567 # i18n: refers to a short changeset id
1568 1568 msg = _('created %s') % short(n)
1569 1569 return msg, n, rejects
1570 1570
1571 1571 # facility to let extensions include additional data in an exported patch
1572 1572 # list of identifiers to be executed in order
1573 1573 extraexport = []
1574 1574 # mapping from identifier to actual export function
1575 1575 # function as to return a string to be added to the header or None
1576 1576 # it is given two arguments (sequencenumber, changectx)
1577 1577 extraexportmap = {}
1578 1578
1579 1579 def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
1580 1580 node = scmutil.binnode(ctx)
1581 1581 parents = [p.node() for p in ctx.parents() if p]
1582 1582 branch = ctx.branch()
1583 1583 if switch_parent:
1584 1584 parents.reverse()
1585 1585
1586 1586 if parents:
1587 1587 prev = parents[0]
1588 1588 else:
1589 1589 prev = nullid
1590 1590
1591 1591 fm.context(ctx=ctx)
1592 1592 fm.plain('# HG changeset patch\n')
1593 1593 fm.write('user', '# User %s\n', ctx.user())
1594 1594 fm.plain('# Date %d %d\n' % ctx.date())
1595 1595 fm.write('date', '# %s\n', fm.formatdate(ctx.date()))
1596 1596 fm.condwrite(branch and branch != 'default',
1597 1597 'branch', '# Branch %s\n', branch)
1598 1598 fm.write('node', '# Node ID %s\n', hex(node))
1599 1599 fm.plain('# Parent %s\n' % hex(prev))
1600 1600 if len(parents) > 1:
1601 1601 fm.plain('# Parent %s\n' % hex(parents[1]))
1602 1602 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
1603 1603
1604 1604 # TODO: redesign extraexportmap function to support formatter
1605 1605 for headerid in extraexport:
1606 1606 header = extraexportmap[headerid](seqno, ctx)
1607 1607 if header is not None:
1608 1608 fm.plain('# %s\n' % header)
1609 1609
1610 1610 fm.write('desc', '%s\n', ctx.description().rstrip())
1611 1611 fm.plain('\n')
1612 1612
1613 1613 if fm.isplain():
1614 1614 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
1615 1615 for chunk, label in chunkiter:
1616 1616 fm.plain(chunk, label=label)
1617 1617 else:
1618 1618 chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
1619 1619 # TODO: make it structured?
1620 1620 fm.data(diff=b''.join(chunkiter))
1621 1621
1622 1622 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match):
1623 1623 """Export changesets to stdout or a single file"""
1624 1624 for seqno, rev in enumerate(revs, 1):
1625 1625 ctx = repo[rev]
1626 1626 if not dest.startswith('<'):
1627 1627 repo.ui.note("%s\n" % dest)
1628 1628 fm.startitem()
1629 1629 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
1630 1630
1631 1631 def _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, diffopts,
1632 1632 match):
1633 1633 """Export changesets to possibly multiple files"""
1634 1634 total = len(revs)
1635 1635 revwidth = max(len(str(rev)) for rev in revs)
1636 1636 filemap = util.sortdict() # filename: [(seqno, rev), ...]
1637 1637
1638 1638 for seqno, rev in enumerate(revs, 1):
1639 1639 ctx = repo[rev]
1640 1640 dest = makefilename(ctx, fntemplate,
1641 1641 total=total, seqno=seqno, revwidth=revwidth)
1642 1642 filemap.setdefault(dest, []).append((seqno, rev))
1643 1643
1644 1644 for dest in filemap:
1645 1645 with formatter.maybereopen(basefm, dest) as fm:
1646 1646 repo.ui.note("%s\n" % dest)
1647 1647 for seqno, rev in filemap[dest]:
1648 1648 fm.startitem()
1649 1649 ctx = repo[rev]
1650 1650 _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
1651 1651 diffopts)
1652 1652
1653 1653 def export(repo, revs, basefm, fntemplate='hg-%h.patch', switch_parent=False,
1654 1654 opts=None, match=None):
1655 1655 '''export changesets as hg patches
1656 1656
1657 1657 Args:
1658 1658 repo: The repository from which we're exporting revisions.
1659 1659 revs: A list of revisions to export as revision numbers.
1660 1660 basefm: A formatter to which patches should be written.
1661 1661 fntemplate: An optional string to use for generating patch file names.
1662 1662 switch_parent: If True, show diffs against second parent when not nullid.
1663 1663 Default is false, which always shows diff against p1.
1664 1664 opts: diff options to use for generating the patch.
1665 1665 match: If specified, only export changes to files matching this matcher.
1666 1666
1667 1667 Returns:
1668 1668 Nothing.
1669 1669
1670 1670 Side Effect:
1671 1671 "HG Changeset Patch" data is emitted to one of the following
1672 1672 destinations:
1673 1673 fntemplate specified: Each rev is written to a unique file named using
1674 1674 the given template.
1675 1675 Otherwise: All revs will be written to basefm.
1676 1676 '''
1677 1677 scmutil.prefetchfiles(repo, revs, match)
1678 1678
1679 1679 if not fntemplate:
1680 1680 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match)
1681 1681 else:
1682 1682 _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, opts,
1683 1683 match)
1684 1684
1685 1685 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None):
1686 1686 """Export changesets to the given file stream"""
1687 1687 scmutil.prefetchfiles(repo, revs, match)
1688 1688
1689 1689 dest = getattr(fp, 'name', '<unnamed>')
1690 1690 with formatter.formatter(repo.ui, fp, 'export', {}) as fm:
1691 1691 _exportfile(repo, revs, fm, dest, switch_parent, opts, match)
1692 1692
1693 1693 def showmarker(fm, marker, index=None):
1694 1694 """utility function to display obsolescence marker in a readable way
1695 1695
1696 1696 To be used by debug function."""
1697 1697 if index is not None:
1698 1698 fm.write('index', '%i ', index)
1699 1699 fm.write('prednode', '%s ', hex(marker.prednode()))
1700 1700 succs = marker.succnodes()
1701 1701 fm.condwrite(succs, 'succnodes', '%s ',
1702 1702 fm.formatlist(map(hex, succs), name='node'))
1703 1703 fm.write('flag', '%X ', marker.flags())
1704 1704 parents = marker.parentnodes()
1705 1705 if parents is not None:
1706 1706 fm.write('parentnodes', '{%s} ',
1707 1707 fm.formatlist(map(hex, parents), name='node', sep=', '))
1708 1708 fm.write('date', '(%s) ', fm.formatdate(marker.date()))
1709 1709 meta = marker.metadata().copy()
1710 1710 meta.pop('date', None)
1711 1711 smeta = pycompat.rapply(pycompat.maybebytestr, meta)
1712 1712 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
1713 1713 fm.plain('\n')
1714 1714
1715 1715 def finddate(ui, repo, date):
1716 1716 """Find the tipmost changeset that matches the given date spec"""
1717 1717
1718 1718 df = dateutil.matchdate(date)
1719 1719 m = scmutil.matchall(repo)
1720 1720 results = {}
1721 1721
1722 1722 def prep(ctx, fns):
1723 1723 d = ctx.date()
1724 1724 if df(d[0]):
1725 1725 results[ctx.rev()] = d
1726 1726
1727 1727 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1728 1728 rev = ctx.rev()
1729 1729 if rev in results:
1730 1730 ui.status(_("found revision %s from %s\n") %
1731 1731 (rev, dateutil.datestr(results[rev])))
1732 1732 return '%d' % rev
1733 1733
1734 1734 raise error.Abort(_("revision matching date not found"))
1735 1735
1736 1736 def increasingwindows(windowsize=8, sizelimit=512):
1737 1737 while True:
1738 1738 yield windowsize
1739 1739 if windowsize < sizelimit:
1740 1740 windowsize *= 2
1741 1741
1742 1742 def _walkrevs(repo, opts):
1743 1743 # Default --rev value depends on --follow but --follow behavior
1744 1744 # depends on revisions resolved from --rev...
1745 1745 follow = opts.get('follow') or opts.get('follow_first')
1746 1746 if opts.get('rev'):
1747 1747 revs = scmutil.revrange(repo, opts['rev'])
1748 1748 elif follow and repo.dirstate.p1() == nullid:
1749 1749 revs = smartset.baseset()
1750 1750 elif follow:
1751 1751 revs = repo.revs('reverse(:.)')
1752 1752 else:
1753 1753 revs = smartset.spanset(repo)
1754 1754 revs.reverse()
1755 1755 return revs
1756 1756
1757 1757 class FileWalkError(Exception):
1758 1758 pass
1759 1759
1760 1760 def walkfilerevs(repo, match, follow, revs, fncache):
1761 1761 '''Walks the file history for the matched files.
1762 1762
1763 1763 Returns the changeset revs that are involved in the file history.
1764 1764
1765 1765 Throws FileWalkError if the file history can't be walked using
1766 1766 filelogs alone.
1767 1767 '''
1768 1768 wanted = set()
1769 1769 copies = []
1770 1770 minrev, maxrev = min(revs), max(revs)
1771 1771 def filerevgen(filelog, last):
1772 1772 """
1773 1773 Only files, no patterns. Check the history of each file.
1774 1774
1775 1775 Examines filelog entries within minrev, maxrev linkrev range
1776 1776 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1777 1777 tuples in backwards order
1778 1778 """
1779 1779 cl_count = len(repo)
1780 1780 revs = []
1781 1781 for j in pycompat.xrange(0, last + 1):
1782 1782 linkrev = filelog.linkrev(j)
1783 1783 if linkrev < minrev:
1784 1784 continue
1785 1785 # only yield rev for which we have the changelog, it can
1786 1786 # happen while doing "hg log" during a pull or commit
1787 1787 if linkrev >= cl_count:
1788 1788 break
1789 1789
1790 1790 parentlinkrevs = []
1791 1791 for p in filelog.parentrevs(j):
1792 1792 if p != nullrev:
1793 1793 parentlinkrevs.append(filelog.linkrev(p))
1794 1794 n = filelog.node(j)
1795 1795 revs.append((linkrev, parentlinkrevs,
1796 1796 follow and filelog.renamed(n)))
1797 1797
1798 1798 return reversed(revs)
1799 1799 def iterfiles():
1800 1800 pctx = repo['.']
1801 1801 for filename in match.files():
1802 1802 if follow:
1803 1803 if filename not in pctx:
1804 1804 raise error.Abort(_('cannot follow file not in parent '
1805 1805 'revision: "%s"') % filename)
1806 1806 yield filename, pctx[filename].filenode()
1807 1807 else:
1808 1808 yield filename, None
1809 1809 for filename_node in copies:
1810 1810 yield filename_node
1811 1811
1812 1812 for file_, node in iterfiles():
1813 1813 filelog = repo.file(file_)
1814 1814 if not len(filelog):
1815 1815 if node is None:
1816 1816 # A zero count may be a directory or deleted file, so
1817 1817 # try to find matching entries on the slow path.
1818 1818 if follow:
1819 1819 raise error.Abort(
1820 1820 _('cannot follow nonexistent file: "%s"') % file_)
1821 1821 raise FileWalkError("Cannot walk via filelog")
1822 1822 else:
1823 1823 continue
1824 1824
1825 1825 if node is None:
1826 1826 last = len(filelog) - 1
1827 1827 else:
1828 1828 last = filelog.rev(node)
1829 1829
1830 1830 # keep track of all ancestors of the file
1831 1831 ancestors = {filelog.linkrev(last)}
1832 1832
1833 1833 # iterate from latest to oldest revision
1834 1834 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1835 1835 if not follow:
1836 1836 if rev > maxrev:
1837 1837 continue
1838 1838 else:
1839 1839 # Note that last might not be the first interesting
1840 1840 # rev to us:
1841 1841 # if the file has been changed after maxrev, we'll
1842 1842 # have linkrev(last) > maxrev, and we still need
1843 1843 # to explore the file graph
1844 1844 if rev not in ancestors:
1845 1845 continue
1846 1846 # XXX insert 1327 fix here
1847 1847 if flparentlinkrevs:
1848 1848 ancestors.update(flparentlinkrevs)
1849 1849
1850 1850 fncache.setdefault(rev, []).append(file_)
1851 1851 wanted.add(rev)
1852 1852 if copied:
1853 1853 copies.append(copied)
1854 1854
1855 1855 return wanted
1856 1856
1857 1857 class _followfilter(object):
1858 1858 def __init__(self, repo, onlyfirst=False):
1859 1859 self.repo = repo
1860 1860 self.startrev = nullrev
1861 1861 self.roots = set()
1862 1862 self.onlyfirst = onlyfirst
1863 1863
1864 1864 def match(self, rev):
1865 1865 def realparents(rev):
1866 1866 if self.onlyfirst:
1867 1867 return self.repo.changelog.parentrevs(rev)[0:1]
1868 1868 else:
1869 1869 return filter(lambda x: x != nullrev,
1870 1870 self.repo.changelog.parentrevs(rev))
1871 1871
1872 1872 if self.startrev == nullrev:
1873 1873 self.startrev = rev
1874 1874 return True
1875 1875
1876 1876 if rev > self.startrev:
1877 1877 # forward: all descendants
1878 1878 if not self.roots:
1879 1879 self.roots.add(self.startrev)
1880 1880 for parent in realparents(rev):
1881 1881 if parent in self.roots:
1882 1882 self.roots.add(rev)
1883 1883 return True
1884 1884 else:
1885 1885 # backwards: all parents
1886 1886 if not self.roots:
1887 1887 self.roots.update(realparents(self.startrev))
1888 1888 if rev in self.roots:
1889 1889 self.roots.remove(rev)
1890 1890 self.roots.update(realparents(rev))
1891 1891 return True
1892 1892
1893 1893 return False
1894 1894
1895 1895 def walkchangerevs(repo, match, opts, prepare):
1896 1896 '''Iterate over files and the revs in which they changed.
1897 1897
1898 1898 Callers most commonly need to iterate backwards over the history
1899 1899 in which they are interested. Doing so has awful (quadratic-looking)
1900 1900 performance, so we use iterators in a "windowed" way.
1901 1901
1902 1902 We walk a window of revisions in the desired order. Within the
1903 1903 window, we first walk forwards to gather data, then in the desired
1904 1904 order (usually backwards) to display it.
1905 1905
1906 1906 This function returns an iterator yielding contexts. Before
1907 1907 yielding each context, the iterator will first call the prepare
1908 1908 function on each context in the window in forward order.'''
1909 1909
1910 1910 allfiles = opts.get('all_files')
1911 1911 follow = opts.get('follow') or opts.get('follow_first')
1912 1912 revs = _walkrevs(repo, opts)
1913 1913 if not revs:
1914 1914 return []
1915 1915 wanted = set()
1916 1916 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
1917 1917 fncache = {}
1918 1918 change = repo.__getitem__
1919 1919
1920 1920 # First step is to fill wanted, the set of revisions that we want to yield.
1921 1921 # When it does not induce extra cost, we also fill fncache for revisions in
1922 1922 # wanted: a cache of filenames that were changed (ctx.files()) and that
1923 1923 # match the file filtering conditions.
1924 1924
1925 1925 if match.always() or allfiles:
1926 1926 # No files, no patterns. Display all revs.
1927 1927 wanted = revs
1928 1928 elif not slowpath:
1929 1929 # We only have to read through the filelog to find wanted revisions
1930 1930
1931 1931 try:
1932 1932 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1933 1933 except FileWalkError:
1934 1934 slowpath = True
1935 1935
1936 1936 # We decided to fall back to the slowpath because at least one
1937 1937 # of the paths was not a file. Check to see if at least one of them
1938 1938 # existed in history, otherwise simply return
1939 1939 for path in match.files():
1940 1940 if path == '.' or path in repo.store:
1941 1941 break
1942 1942 else:
1943 1943 return []
1944 1944
1945 1945 if slowpath:
1946 1946 # We have to read the changelog to match filenames against
1947 1947 # changed files
1948 1948
1949 1949 if follow:
1950 1950 raise error.Abort(_('can only follow copies/renames for explicit '
1951 1951 'filenames'))
1952 1952
1953 1953 # The slow path checks files modified in every changeset.
1954 1954 # This is really slow on large repos, so compute the set lazily.
1955 1955 class lazywantedset(object):
1956 1956 def __init__(self):
1957 1957 self.set = set()
1958 1958 self.revs = set(revs)
1959 1959
1960 1960 # No need to worry about locality here because it will be accessed
1961 1961 # in the same order as the increasing window below.
1962 1962 def __contains__(self, value):
1963 1963 if value in self.set:
1964 1964 return True
1965 1965 elif not value in self.revs:
1966 1966 return False
1967 1967 else:
1968 1968 self.revs.discard(value)
1969 1969 ctx = change(value)
1970 1970 matches = [f for f in ctx.files() if match(f)]
1971 1971 if matches:
1972 1972 fncache[value] = matches
1973 1973 self.set.add(value)
1974 1974 return True
1975 1975 return False
1976 1976
1977 1977 def discard(self, value):
1978 1978 self.revs.discard(value)
1979 1979 self.set.discard(value)
1980 1980
1981 1981 wanted = lazywantedset()
1982 1982
1983 1983 # it might be worthwhile to do this in the iterator if the rev range
1984 1984 # is descending and the prune args are all within that range
1985 1985 for rev in opts.get('prune', ()):
1986 1986 rev = repo[rev].rev()
1987 1987 ff = _followfilter(repo)
1988 1988 stop = min(revs[0], revs[-1])
1989 1989 for x in pycompat.xrange(rev, stop - 1, -1):
1990 1990 if ff.match(x):
1991 1991 wanted = wanted - [x]
1992 1992
1993 1993 # Now that wanted is correctly initialized, we can iterate over the
1994 1994 # revision range, yielding only revisions in wanted.
1995 1995 def iterate():
1996 1996 if follow and match.always():
1997 1997 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
1998 1998 def want(rev):
1999 1999 return ff.match(rev) and rev in wanted
2000 2000 else:
2001 2001 def want(rev):
2002 2002 return rev in wanted
2003 2003
2004 2004 it = iter(revs)
2005 2005 stopiteration = False
2006 2006 for windowsize in increasingwindows():
2007 2007 nrevs = []
2008 2008 for i in pycompat.xrange(windowsize):
2009 2009 rev = next(it, None)
2010 2010 if rev is None:
2011 2011 stopiteration = True
2012 2012 break
2013 2013 elif want(rev):
2014 2014 nrevs.append(rev)
2015 2015 for rev in sorted(nrevs):
2016 2016 fns = fncache.get(rev)
2017 2017 ctx = change(rev)
2018 2018 if not fns:
2019 2019 def fns_generator():
2020 2020 if allfiles:
2021 2021 fiter = iter(ctx)
2022 2022 else:
2023 2023 fiter = ctx.files()
2024 2024 for f in fiter:
2025 2025 if match(f):
2026 2026 yield f
2027 2027 fns = fns_generator()
2028 2028 prepare(ctx, fns)
2029 2029 for rev in nrevs:
2030 2030 yield change(rev)
2031 2031
2032 2032 if stopiteration:
2033 2033 break
2034 2034
2035 2035 return iterate()
2036 2036
2037 2037 def add(ui, repo, match, prefix, explicitonly, **opts):
2038 2038 join = lambda f: os.path.join(prefix, f)
2039 2039 bad = []
2040 2040
2041 2041 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2042 2042 names = []
2043 2043 wctx = repo[None]
2044 2044 cca = None
2045 2045 abort, warn = scmutil.checkportabilityalert(ui)
2046 2046 if abort or warn:
2047 2047 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2048 2048
2049 2049 badmatch = matchmod.badmatch(match, badfn)
2050 2050 dirstate = repo.dirstate
2051 2051 # We don't want to just call wctx.walk here, since it would return a lot of
2052 2052 # clean files, which we aren't interested in and takes time.
2053 2053 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
2054 2054 unknown=True, ignored=False, full=False)):
2055 2055 exact = match.exact(f)
2056 2056 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2057 2057 if cca:
2058 2058 cca(f)
2059 2059 names.append(f)
2060 2060 if ui.verbose or not exact:
2061 2061 ui.status(_('adding %s\n') % match.rel(f),
2062 2062 label='addremove.added')
2063 2063
2064 2064 for subpath in sorted(wctx.substate):
2065 2065 sub = wctx.sub(subpath)
2066 2066 try:
2067 2067 submatch = matchmod.subdirmatcher(subpath, match)
2068 2068 if opts.get(r'subrepos'):
2069 2069 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2070 2070 else:
2071 2071 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2072 2072 except error.LookupError:
2073 2073 ui.status(_("skipping missing subrepository: %s\n")
2074 2074 % join(subpath))
2075 2075
2076 2076 if not opts.get(r'dry_run'):
2077 2077 rejected = wctx.add(names, prefix)
2078 2078 bad.extend(f for f in rejected if f in match.files())
2079 2079 return bad
2080 2080
2081 2081 def addwebdirpath(repo, serverpath, webconf):
2082 2082 webconf[serverpath] = repo.root
2083 2083 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
2084 2084
2085 2085 for r in repo.revs('filelog("path:.hgsub")'):
2086 2086 ctx = repo[r]
2087 2087 for subpath in ctx.substate:
2088 2088 ctx.sub(subpath).addwebdirpath(serverpath, webconf)
2089 2089
2090 2090 def forget(ui, repo, match, prefix, explicitonly, dryrun, interactive):
2091 2091 if dryrun and interactive:
2092 2092 raise error.Abort(_("cannot specify both --dry-run and --interactive"))
2093 2093 join = lambda f: os.path.join(prefix, f)
2094 2094 bad = []
2095 2095 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
2096 2096 wctx = repo[None]
2097 2097 forgot = []
2098 2098
2099 2099 s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
2100 2100 forget = sorted(s.modified + s.added + s.deleted + s.clean)
2101 2101 if explicitonly:
2102 2102 forget = [f for f in forget if match.exact(f)]
2103 2103
2104 2104 for subpath in sorted(wctx.substate):
2105 2105 sub = wctx.sub(subpath)
2106 2106 try:
2107 2107 submatch = matchmod.subdirmatcher(subpath, match)
2108 2108 subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun,
2109 2109 interactive=interactive)
2110 2110 bad.extend([subpath + '/' + f for f in subbad])
2111 2111 forgot.extend([subpath + '/' + f for f in subforgot])
2112 2112 except error.LookupError:
2113 2113 ui.status(_("skipping missing subrepository: %s\n")
2114 2114 % join(subpath))
2115 2115
2116 2116 if not explicitonly:
2117 2117 for f in match.files():
2118 2118 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2119 2119 if f not in forgot:
2120 2120 if repo.wvfs.exists(f):
2121 2121 # Don't complain if the exact case match wasn't given.
2122 2122 # But don't do this until after checking 'forgot', so
2123 2123 # that subrepo files aren't normalized, and this op is
2124 2124 # purely from data cached by the status walk above.
2125 2125 if repo.dirstate.normalize(f) in repo.dirstate:
2126 2126 continue
2127 2127 ui.warn(_('not removing %s: '
2128 2128 'file is already untracked\n')
2129 2129 % match.rel(f))
2130 2130 bad.append(f)
2131 2131
2132 2132 if interactive:
2133 2133 responses = _('[Ynsa?]'
2134 2134 '$$ &Yes, forget this file'
2135 2135 '$$ &No, skip this file'
2136 2136 '$$ &Skip remaining files'
2137 2137 '$$ Include &all remaining files'
2138 2138 '$$ &? (display help)')
2139 2139 for filename in forget[:]:
2140 2140 r = ui.promptchoice(_('forget %s %s') % (filename, responses))
2141 2141 if r == 4: # ?
2142 2142 while r == 4:
2143 2143 for c, t in ui.extractchoices(responses)[1]:
2144 2144 ui.write('%s - %s\n' % (c, encoding.lower(t)))
2145 2145 r = ui.promptchoice(_('forget %s %s') % (filename,
2146 2146 responses))
2147 2147 if r == 0: # yes
2148 2148 continue
2149 2149 elif r == 1: # no
2150 2150 forget.remove(filename)
2151 2151 elif r == 2: # Skip
2152 2152 fnindex = forget.index(filename)
2153 2153 del forget[fnindex:]
2154 2154 break
2155 2155 elif r == 3: # All
2156 2156 break
2157 2157
2158 2158 for f in forget:
2159 2159 if ui.verbose or not match.exact(f) or interactive:
2160 2160 ui.status(_('removing %s\n') % match.rel(f),
2161 2161 label='addremove.removed')
2162 2162
2163 2163 if not dryrun:
2164 2164 rejected = wctx.forget(forget, prefix)
2165 2165 bad.extend(f for f in rejected if f in match.files())
2166 2166 forgot.extend(f for f in forget if f not in rejected)
2167 2167 return bad, forgot
2168 2168
2169 2169 def files(ui, ctx, m, fm, fmt, subrepos):
2170 2170 ret = 1
2171 2171
2172 2172 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint()
2173 2173 for f in ctx.matches(m):
2174 2174 fm.startitem()
2175 2175 fm.context(ctx=ctx)
2176 2176 if needsfctx:
2177 2177 fc = ctx[f]
2178 2178 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2179 2179 fm.data(path=f)
2180 2180 fm.plain(fmt % m.rel(f))
2181 2181 ret = 0
2182 2182
2183 2183 for subpath in sorted(ctx.substate):
2184 2184 submatch = matchmod.subdirmatcher(subpath, m)
2185 2185 if (subrepos or m.exact(subpath) or any(submatch.files())):
2186 2186 sub = ctx.sub(subpath)
2187 2187 try:
2188 2188 recurse = m.exact(subpath) or subrepos
2189 2189 if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
2190 2190 ret = 0
2191 2191 except error.LookupError:
2192 2192 ui.status(_("skipping missing subrepository: %s\n")
2193 2193 % m.abs(subpath))
2194 2194
2195 2195 return ret
2196 2196
2197 2197 def remove(ui, repo, m, prefix, after, force, subrepos, dryrun, warnings=None):
2198 2198 join = lambda f: os.path.join(prefix, f)
2199 2199 ret = 0
2200 2200 s = repo.status(match=m, clean=True)
2201 2201 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2202 2202
2203 2203 wctx = repo[None]
2204 2204
2205 2205 if warnings is None:
2206 2206 warnings = []
2207 2207 warn = True
2208 2208 else:
2209 2209 warn = False
2210 2210
2211 2211 subs = sorted(wctx.substate)
2212 2212 progress = ui.makeprogress(_('searching'), total=len(subs),
2213 2213 unit=_('subrepos'))
2214 2214 for subpath in subs:
2215 2215 submatch = matchmod.subdirmatcher(subpath, m)
2216 2216 if subrepos or m.exact(subpath) or any(submatch.files()):
2217 2217 progress.increment()
2218 2218 sub = wctx.sub(subpath)
2219 2219 try:
2220 2220 if sub.removefiles(submatch, prefix, after, force, subrepos,
2221 2221 dryrun, warnings):
2222 2222 ret = 1
2223 2223 except error.LookupError:
2224 2224 warnings.append(_("skipping missing subrepository: %s\n")
2225 2225 % join(subpath))
2226 2226 progress.complete()
2227 2227
2228 2228 # warn about failure to delete explicit files/dirs
2229 2229 deleteddirs = util.dirs(deleted)
2230 2230 files = m.files()
2231 2231 progress = ui.makeprogress(_('deleting'), total=len(files),
2232 2232 unit=_('files'))
2233 2233 for f in files:
2234 2234 def insubrepo():
2235 2235 for subpath in wctx.substate:
2236 2236 if f.startswith(subpath + '/'):
2237 2237 return True
2238 2238 return False
2239 2239
2240 2240 progress.increment()
2241 2241 isdir = f in deleteddirs or wctx.hasdir(f)
2242 2242 if (f in repo.dirstate or isdir or f == '.'
2243 2243 or insubrepo() or f in subs):
2244 2244 continue
2245 2245
2246 2246 if repo.wvfs.exists(f):
2247 2247 if repo.wvfs.isdir(f):
2248 2248 warnings.append(_('not removing %s: no tracked files\n')
2249 2249 % m.rel(f))
2250 2250 else:
2251 2251 warnings.append(_('not removing %s: file is untracked\n')
2252 2252 % m.rel(f))
2253 2253 # missing files will generate a warning elsewhere
2254 2254 ret = 1
2255 2255 progress.complete()
2256 2256
2257 2257 if force:
2258 2258 list = modified + deleted + clean + added
2259 2259 elif after:
2260 2260 list = deleted
2261 2261 remaining = modified + added + clean
2262 2262 progress = ui.makeprogress(_('skipping'), total=len(remaining),
2263 2263 unit=_('files'))
2264 2264 for f in remaining:
2265 2265 progress.increment()
2266 2266 if ui.verbose or (f in files):
2267 2267 warnings.append(_('not removing %s: file still exists\n')
2268 2268 % m.rel(f))
2269 2269 ret = 1
2270 2270 progress.complete()
2271 2271 else:
2272 2272 list = deleted + clean
2273 2273 progress = ui.makeprogress(_('skipping'),
2274 2274 total=(len(modified) + len(added)),
2275 2275 unit=_('files'))
2276 2276 for f in modified:
2277 2277 progress.increment()
2278 2278 warnings.append(_('not removing %s: file is modified (use -f'
2279 2279 ' to force removal)\n') % m.rel(f))
2280 2280 ret = 1
2281 2281 for f in added:
2282 2282 progress.increment()
2283 2283 warnings.append(_("not removing %s: file has been marked for add"
2284 2284 " (use 'hg forget' to undo add)\n") % m.rel(f))
2285 2285 ret = 1
2286 2286 progress.complete()
2287 2287
2288 2288 list = sorted(list)
2289 2289 progress = ui.makeprogress(_('deleting'), total=len(list),
2290 2290 unit=_('files'))
2291 2291 for f in list:
2292 2292 if ui.verbose or not m.exact(f):
2293 2293 progress.increment()
2294 2294 ui.status(_('removing %s\n') % m.rel(f),
2295 2295 label='addremove.removed')
2296 2296 progress.complete()
2297 2297
2298 2298 if not dryrun:
2299 2299 with repo.wlock():
2300 2300 if not after:
2301 2301 for f in list:
2302 2302 if f in added:
2303 2303 continue # we never unlink added files on remove
2304 2304 rmdir = repo.ui.configbool('experimental',
2305 2305 'removeemptydirs')
2306 2306 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir)
2307 2307 repo[None].forget(list)
2308 2308
2309 2309 if warn:
2310 2310 for warning in warnings:
2311 2311 ui.warn(warning)
2312 2312
2313 2313 return ret
2314 2314
2315 2315 def _updatecatformatter(fm, ctx, matcher, path, decode):
2316 2316 """Hook for adding data to the formatter used by ``hg cat``.
2317 2317
2318 2318 Extensions (e.g., lfs) can wrap this to inject keywords/data, but must call
2319 2319 this method first."""
2320 2320 data = ctx[path].data()
2321 2321 if decode:
2322 2322 data = ctx.repo().wwritedata(path, data)
2323 2323 fm.startitem()
2324 2324 fm.context(ctx=ctx)
2325 2325 fm.write('data', '%s', data)
2326 2326 fm.data(path=path)
2327 2327
2328 2328 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
2329 2329 err = 1
2330 2330 opts = pycompat.byteskwargs(opts)
2331 2331
2332 2332 def write(path):
2333 2333 filename = None
2334 2334 if fntemplate:
2335 2335 filename = makefilename(ctx, fntemplate,
2336 2336 pathname=os.path.join(prefix, path))
2337 2337 # attempt to create the directory if it does not already exist
2338 2338 try:
2339 2339 os.makedirs(os.path.dirname(filename))
2340 2340 except OSError:
2341 2341 pass
2342 2342 with formatter.maybereopen(basefm, filename) as fm:
2343 2343 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode'))
2344 2344
2345 2345 # Automation often uses hg cat on single files, so special case it
2346 2346 # for performance to avoid the cost of parsing the manifest.
2347 2347 if len(matcher.files()) == 1 and not matcher.anypats():
2348 2348 file = matcher.files()[0]
2349 2349 mfl = repo.manifestlog
2350 2350 mfnode = ctx.manifestnode()
2351 2351 try:
2352 2352 if mfnode and mfl[mfnode].find(file)[0]:
2353 2353 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2354 2354 write(file)
2355 2355 return 0
2356 2356 except KeyError:
2357 2357 pass
2358 2358
2359 2359 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
2360 2360
2361 2361 for abs in ctx.walk(matcher):
2362 2362 write(abs)
2363 2363 err = 0
2364 2364
2365 2365 for subpath in sorted(ctx.substate):
2366 2366 sub = ctx.sub(subpath)
2367 2367 try:
2368 2368 submatch = matchmod.subdirmatcher(subpath, matcher)
2369 2369
2370 2370 if not sub.cat(submatch, basefm, fntemplate,
2371 2371 os.path.join(prefix, sub._path),
2372 2372 **pycompat.strkwargs(opts)):
2373 2373 err = 0
2374 2374 except error.RepoLookupError:
2375 2375 ui.status(_("skipping missing subrepository: %s\n")
2376 2376 % os.path.join(prefix, subpath))
2377 2377
2378 2378 return err
2379 2379
2380 2380 def commit(ui, repo, commitfunc, pats, opts):
2381 2381 '''commit the specified files or all outstanding changes'''
2382 2382 date = opts.get('date')
2383 2383 if date:
2384 2384 opts['date'] = dateutil.parsedate(date)
2385 2385 message = logmessage(ui, opts)
2386 2386 matcher = scmutil.match(repo[None], pats, opts)
2387 2387
2388 2388 dsguard = None
2389 2389 # extract addremove carefully -- this function can be called from a command
2390 2390 # that doesn't support addremove
2391 2391 if opts.get('addremove'):
2392 2392 dsguard = dirstateguard.dirstateguard(repo, 'commit')
2393 2393 with dsguard or util.nullcontextmanager():
2394 2394 if dsguard:
2395 2395 if scmutil.addremove(repo, matcher, "", opts) != 0:
2396 2396 raise error.Abort(
2397 2397 _("failed to mark all new/missing files as added/removed"))
2398 2398
2399 2399 return commitfunc(ui, repo, message, matcher, opts)
2400 2400
2401 2401 def samefile(f, ctx1, ctx2):
2402 2402 if f in ctx1.manifest():
2403 2403 a = ctx1.filectx(f)
2404 2404 if f in ctx2.manifest():
2405 2405 b = ctx2.filectx(f)
2406 2406 return (not a.cmp(b)
2407 2407 and a.flags() == b.flags())
2408 2408 else:
2409 2409 return False
2410 2410 else:
2411 2411 return f not in ctx2.manifest()
2412 2412
2413 2413 def amend(ui, repo, old, extra, pats, opts):
2414 2414 # avoid cycle context -> subrepo -> cmdutil
2415 2415 from . import context
2416 2416
2417 2417 # amend will reuse the existing user if not specified, but the obsolete
2418 2418 # marker creation requires that the current user's name is specified.
2419 2419 if obsolete.isenabled(repo, obsolete.createmarkersopt):
2420 2420 ui.username() # raise exception if username not set
2421 2421
2422 2422 ui.note(_('amending changeset %s\n') % old)
2423 2423 base = old.p1()
2424 2424
2425 2425 with repo.wlock(), repo.lock(), repo.transaction('amend'):
2426 2426 # Participating changesets:
2427 2427 #
2428 2428 # wctx o - workingctx that contains changes from working copy
2429 2429 # | to go into amending commit
2430 2430 # |
2431 2431 # old o - changeset to amend
2432 2432 # |
2433 2433 # base o - first parent of the changeset to amend
2434 2434 wctx = repo[None]
2435 2435
2436 2436 # Copy to avoid mutating input
2437 2437 extra = extra.copy()
2438 2438 # Update extra dict from amended commit (e.g. to preserve graft
2439 2439 # source)
2440 2440 extra.update(old.extra())
2441 2441
2442 2442 # Also update it from the from the wctx
2443 2443 extra.update(wctx.extra())
2444 2444
2445 2445 user = opts.get('user') or old.user()
2446 2446 date = opts.get('date') or old.date()
2447 2447
2448 2448 # Parse the date to allow comparison between date and old.date()
2449 2449 date = dateutil.parsedate(date)
2450 2450
2451 2451 if len(old.parents()) > 1:
2452 2452 # ctx.files() isn't reliable for merges, so fall back to the
2453 2453 # slower repo.status() method
2454 2454 files = set([fn for st in base.status(old)[:3]
2455 2455 for fn in st])
2456 2456 else:
2457 2457 files = set(old.files())
2458 2458
2459 2459 # add/remove the files to the working copy if the "addremove" option
2460 2460 # was specified.
2461 2461 matcher = scmutil.match(wctx, pats, opts)
2462 2462 if (opts.get('addremove')
2463 2463 and scmutil.addremove(repo, matcher, "", opts)):
2464 2464 raise error.Abort(
2465 2465 _("failed to mark all new/missing files as added/removed"))
2466 2466
2467 2467 # Check subrepos. This depends on in-place wctx._status update in
2468 2468 # subrepo.precommit(). To minimize the risk of this hack, we do
2469 2469 # nothing if .hgsub does not exist.
2470 2470 if '.hgsub' in wctx or '.hgsub' in old:
2471 2471 subs, commitsubs, newsubstate = subrepoutil.precommit(
2472 2472 ui, wctx, wctx._status, matcher)
2473 2473 # amend should abort if commitsubrepos is enabled
2474 2474 assert not commitsubs
2475 2475 if subs:
2476 2476 subrepoutil.writestate(repo, newsubstate)
2477 2477
2478 2478 ms = mergemod.mergestate.read(repo)
2479 2479 mergeutil.checkunresolved(ms)
2480 2480
2481 2481 filestoamend = set(f for f in wctx.files() if matcher(f))
2482 2482
2483 2483 changes = (len(filestoamend) > 0)
2484 2484 if changes:
2485 2485 # Recompute copies (avoid recording a -> b -> a)
2486 2486 copied = copies.pathcopies(base, wctx, matcher)
2487 2487 if old.p2:
2488 2488 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
2489 2489
2490 2490 # Prune files which were reverted by the updates: if old
2491 2491 # introduced file X and the file was renamed in the working
2492 2492 # copy, then those two files are the same and
2493 2493 # we can discard X from our list of files. Likewise if X
2494 2494 # was removed, it's no longer relevant. If X is missing (aka
2495 2495 # deleted), old X must be preserved.
2496 2496 files.update(filestoamend)
2497 2497 files = [f for f in files if (not samefile(f, wctx, base)
2498 2498 or f in wctx.deleted())]
2499 2499
2500 2500 def filectxfn(repo, ctx_, path):
2501 2501 try:
2502 2502 # If the file being considered is not amongst the files
2503 2503 # to be amended, we should return the file context from the
2504 2504 # old changeset. This avoids issues when only some files in
2505 2505 # the working copy are being amended but there are also
2506 2506 # changes to other files from the old changeset.
2507 2507 if path not in filestoamend:
2508 2508 return old.filectx(path)
2509 2509
2510 2510 # Return None for removed files.
2511 2511 if path in wctx.removed():
2512 2512 return None
2513 2513
2514 2514 fctx = wctx[path]
2515 2515 flags = fctx.flags()
2516 2516 mctx = context.memfilectx(repo, ctx_,
2517 2517 fctx.path(), fctx.data(),
2518 2518 islink='l' in flags,
2519 2519 isexec='x' in flags,
2520 2520 copied=copied.get(path))
2521 2521 return mctx
2522 2522 except KeyError:
2523 2523 return None
2524 2524 else:
2525 2525 ui.note(_('copying changeset %s to %s\n') % (old, base))
2526 2526
2527 2527 # Use version of files as in the old cset
2528 2528 def filectxfn(repo, ctx_, path):
2529 2529 try:
2530 2530 return old.filectx(path)
2531 2531 except KeyError:
2532 2532 return None
2533 2533
2534 2534 # See if we got a message from -m or -l, if not, open the editor with
2535 2535 # the message of the changeset to amend.
2536 2536 message = logmessage(ui, opts)
2537 2537
2538 2538 editform = mergeeditform(old, 'commit.amend')
2539 2539 editor = getcommiteditor(editform=editform,
2540 2540 **pycompat.strkwargs(opts))
2541 2541
2542 2542 if not message:
2543 2543 editor = getcommiteditor(edit=True, editform=editform)
2544 2544 message = old.description()
2545 2545
2546 2546 pureextra = extra.copy()
2547 2547 extra['amend_source'] = old.hex()
2548 2548
2549 2549 new = context.memctx(repo,
2550 2550 parents=[base.node(), old.p2().node()],
2551 2551 text=message,
2552 2552 files=files,
2553 2553 filectxfn=filectxfn,
2554 2554 user=user,
2555 2555 date=date,
2556 2556 extra=extra,
2557 2557 editor=editor)
2558 2558
2559 2559 newdesc = changelog.stripdesc(new.description())
2560 2560 if ((not changes)
2561 2561 and newdesc == old.description()
2562 2562 and user == old.user()
2563 2563 and date == old.date()
2564 2564 and pureextra == old.extra()):
2565 2565 # nothing changed. continuing here would create a new node
2566 2566 # anyway because of the amend_source noise.
2567 2567 #
2568 2568 # This not what we expect from amend.
2569 2569 return old.node()
2570 2570
2571 2571 commitphase = None
2572 2572 if opts.get('secret'):
2573 2573 commitphase = phases.secret
2574 2574 newid = repo.commitctx(new)
2575 2575
2576 2576 # Reroute the working copy parent to the new changeset
2577 2577 repo.setparents(newid, nullid)
2578 2578 mapping = {old.node(): (newid,)}
2579 2579 obsmetadata = None
2580 2580 if opts.get('note'):
2581 2581 obsmetadata = {'note': encoding.fromlocal(opts['note'])}
2582 2582 backup = ui.configbool('ui', 'history-editing-backup')
2583 2583 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata,
2584 2584 fixphase=True, targetphase=commitphase,
2585 2585 backup=backup)
2586 2586
2587 2587 # Fixing the dirstate because localrepo.commitctx does not update
2588 2588 # it. This is rather convenient because we did not need to update
2589 2589 # the dirstate for all the files in the new commit which commitctx
2590 2590 # could have done if it updated the dirstate. Now, we can
2591 2591 # selectively update the dirstate only for the amended files.
2592 2592 dirstate = repo.dirstate
2593 2593
2594 2594 # Update the state of the files which were added and
2595 2595 # and modified in the amend to "normal" in the dirstate.
2596 2596 normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
2597 2597 for f in normalfiles:
2598 2598 dirstate.normal(f)
2599 2599
2600 2600 # Update the state of files which were removed in the amend
2601 2601 # to "removed" in the dirstate.
2602 2602 removedfiles = set(wctx.removed()) & filestoamend
2603 2603 for f in removedfiles:
2604 2604 dirstate.drop(f)
2605 2605
2606 2606 return newid
2607 2607
2608 2608 def commiteditor(repo, ctx, subs, editform=''):
2609 2609 if ctx.description():
2610 2610 return ctx.description()
2611 2611 return commitforceeditor(repo, ctx, subs, editform=editform,
2612 2612 unchangedmessagedetection=True)
2613 2613
2614 2614 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2615 2615 editform='', unchangedmessagedetection=False):
2616 2616 if not extramsg:
2617 2617 extramsg = _("Leave message empty to abort commit.")
2618 2618
2619 2619 forms = [e for e in editform.split('.') if e]
2620 2620 forms.insert(0, 'changeset')
2621 2621 templatetext = None
2622 2622 while forms:
2623 2623 ref = '.'.join(forms)
2624 2624 if repo.ui.config('committemplate', ref):
2625 2625 templatetext = committext = buildcommittemplate(
2626 2626 repo, ctx, subs, extramsg, ref)
2627 2627 break
2628 2628 forms.pop()
2629 2629 else:
2630 2630 committext = buildcommittext(repo, ctx, subs, extramsg)
2631 2631
2632 2632 # run editor in the repository root
2633 2633 olddir = pycompat.getcwd()
2634 2634 os.chdir(repo.root)
2635 2635
2636 2636 # make in-memory changes visible to external process
2637 2637 tr = repo.currenttransaction()
2638 2638 repo.dirstate.write(tr)
2639 2639 pending = tr and tr.writepending() and repo.root
2640 2640
2641 2641 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
2642 2642 editform=editform, pending=pending,
2643 2643 repopath=repo.path, action='commit')
2644 2644 text = editortext
2645 2645
2646 2646 # strip away anything below this special string (used for editors that want
2647 2647 # to display the diff)
2648 2648 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
2649 2649 if stripbelow:
2650 2650 text = text[:stripbelow.start()]
2651 2651
2652 2652 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2653 2653 os.chdir(olddir)
2654 2654
2655 2655 if finishdesc:
2656 2656 text = finishdesc(text)
2657 2657 if not text.strip():
2658 2658 raise error.Abort(_("empty commit message"))
2659 2659 if unchangedmessagedetection and editortext == templatetext:
2660 2660 raise error.Abort(_("commit message unchanged"))
2661 2661
2662 2662 return text
2663 2663
2664 2664 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
2665 2665 ui = repo.ui
2666 2666 spec = formatter.templatespec(ref, None, None)
2667 2667 t = logcmdutil.changesettemplater(ui, repo, spec)
2668 2668 t.t.cache.update((k, templater.unquotestring(v))
2669 2669 for k, v in repo.ui.configitems('committemplate'))
2670 2670
2671 2671 if not extramsg:
2672 2672 extramsg = '' # ensure that extramsg is string
2673 2673
2674 2674 ui.pushbuffer()
2675 2675 t.show(ctx, extramsg=extramsg)
2676 2676 return ui.popbuffer()
2677 2677
2678 2678 def hgprefix(msg):
2679 2679 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
2680 2680
2681 2681 def buildcommittext(repo, ctx, subs, extramsg):
2682 2682 edittext = []
2683 2683 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2684 2684 if ctx.description():
2685 2685 edittext.append(ctx.description())
2686 2686 edittext.append("")
2687 2687 edittext.append("") # Empty line between message and comments.
2688 2688 edittext.append(hgprefix(_("Enter commit message."
2689 2689 " Lines beginning with 'HG:' are removed.")))
2690 2690 edittext.append(hgprefix(extramsg))
2691 2691 edittext.append("HG: --")
2692 2692 edittext.append(hgprefix(_("user: %s") % ctx.user()))
2693 2693 if ctx.p2():
2694 2694 edittext.append(hgprefix(_("branch merge")))
2695 2695 if ctx.branch():
2696 2696 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
2697 2697 if bookmarks.isactivewdirparent(repo):
2698 2698 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
2699 2699 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
2700 2700 edittext.extend([hgprefix(_("added %s") % f) for f in added])
2701 2701 edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
2702 2702 edittext.extend([hgprefix(_("removed %s") % f) for f in removed])
2703 2703 if not added and not modified and not removed:
2704 2704 edittext.append(hgprefix(_("no files changed")))
2705 2705 edittext.append("")
2706 2706
2707 2707 return "\n".join(edittext)
2708 2708
2709 2709 def commitstatus(repo, node, branch, bheads=None, opts=None):
2710 2710 if opts is None:
2711 2711 opts = {}
2712 2712 ctx = repo[node]
2713 2713 parents = ctx.parents()
2714 2714
2715 2715 if (not opts.get('amend') and bheads and node not in bheads and not
2716 2716 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2717 2717 repo.ui.status(_('created new head\n'))
2718 2718 # The message is not printed for initial roots. For the other
2719 2719 # changesets, it is printed in the following situations:
2720 2720 #
2721 2721 # Par column: for the 2 parents with ...
2722 2722 # N: null or no parent
2723 2723 # B: parent is on another named branch
2724 2724 # C: parent is a regular non head changeset
2725 2725 # H: parent was a branch head of the current branch
2726 2726 # Msg column: whether we print "created new head" message
2727 2727 # In the following, it is assumed that there already exists some
2728 2728 # initial branch heads of the current branch, otherwise nothing is
2729 2729 # printed anyway.
2730 2730 #
2731 2731 # Par Msg Comment
2732 2732 # N N y additional topo root
2733 2733 #
2734 2734 # B N y additional branch root
2735 2735 # C N y additional topo head
2736 2736 # H N n usual case
2737 2737 #
2738 2738 # B B y weird additional branch root
2739 2739 # C B y branch merge
2740 2740 # H B n merge with named branch
2741 2741 #
2742 2742 # C C y additional head from merge
2743 2743 # C H n merge with a head
2744 2744 #
2745 2745 # H H n head merge: head count decreases
2746 2746
2747 2747 if not opts.get('close_branch'):
2748 2748 for r in parents:
2749 2749 if r.closesbranch() and r.branch() == branch:
2750 2750 repo.ui.status(_('reopening closed branch head %d\n') % r.rev())
2751 2751
2752 2752 if repo.ui.debugflag:
2753 2753 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()))
2754 2754 elif repo.ui.verbose:
2755 2755 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx))
2756 2756
2757 2757 def postcommitstatus(repo, pats, opts):
2758 2758 return repo.status(match=scmutil.match(repo[None], pats, opts))
2759 2759
2760 2760 def revert(ui, repo, ctx, parents, *pats, **opts):
2761 2761 opts = pycompat.byteskwargs(opts)
2762 2762 parent, p2 = parents
2763 2763 node = ctx.node()
2764 2764
2765 2765 mf = ctx.manifest()
2766 2766 if node == p2:
2767 2767 parent = p2
2768 2768
2769 2769 # need all matching names in dirstate and manifest of target rev,
2770 2770 # so have to walk both. do not print errors if files exist in one
2771 2771 # but not other. in both cases, filesets should be evaluated against
2772 2772 # workingctx to get consistent result (issue4497). this means 'set:**'
2773 2773 # cannot be used to select missing files from target rev.
2774 2774
2775 2775 # `names` is a mapping for all elements in working copy and target revision
2776 2776 # The mapping is in the form:
2777 2777 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2778 2778 names = {}
2779 2779
2780 2780 with repo.wlock():
2781 2781 ## filling of the `names` mapping
2782 2782 # walk dirstate to fill `names`
2783 2783
2784 2784 interactive = opts.get('interactive', False)
2785 2785 wctx = repo[None]
2786 2786 m = scmutil.match(wctx, pats, opts)
2787 2787
2788 2788 # we'll need this later
2789 2789 targetsubs = sorted(s for s in wctx.substate if m(s))
2790 2790
2791 2791 if not m.always():
2792 2792 matcher = matchmod.badmatch(m, lambda x, y: False)
2793 2793 for abs in wctx.walk(matcher):
2794 2794 names[abs] = m.rel(abs), m.exact(abs)
2795 2795
2796 2796 # walk target manifest to fill `names`
2797 2797
2798 2798 def badfn(path, msg):
2799 2799 if path in names:
2800 2800 return
2801 2801 if path in ctx.substate:
2802 2802 return
2803 2803 path_ = path + '/'
2804 2804 for f in names:
2805 2805 if f.startswith(path_):
2806 2806 return
2807 2807 ui.warn("%s: %s\n" % (m.rel(path), msg))
2808 2808
2809 2809 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
2810 2810 if abs not in names:
2811 2811 names[abs] = m.rel(abs), m.exact(abs)
2812 2812
2813 2813 # Find status of all file in `names`.
2814 2814 m = scmutil.matchfiles(repo, names)
2815 2815
2816 2816 changes = repo.status(node1=node, match=m,
2817 2817 unknown=True, ignored=True, clean=True)
2818 2818 else:
2819 2819 changes = repo.status(node1=node, match=m)
2820 2820 for kind in changes:
2821 2821 for abs in kind:
2822 2822 names[abs] = m.rel(abs), m.exact(abs)
2823 2823
2824 2824 m = scmutil.matchfiles(repo, names)
2825 2825
2826 2826 modified = set(changes.modified)
2827 2827 added = set(changes.added)
2828 2828 removed = set(changes.removed)
2829 2829 _deleted = set(changes.deleted)
2830 2830 unknown = set(changes.unknown)
2831 2831 unknown.update(changes.ignored)
2832 2832 clean = set(changes.clean)
2833 2833 modadded = set()
2834 2834
2835 2835 # We need to account for the state of the file in the dirstate,
2836 2836 # even when we revert against something else than parent. This will
2837 2837 # slightly alter the behavior of revert (doing back up or not, delete
2838 2838 # or just forget etc).
2839 2839 if parent == node:
2840 2840 dsmodified = modified
2841 2841 dsadded = added
2842 2842 dsremoved = removed
2843 2843 # store all local modifications, useful later for rename detection
2844 2844 localchanges = dsmodified | dsadded
2845 2845 modified, added, removed = set(), set(), set()
2846 2846 else:
2847 2847 changes = repo.status(node1=parent, match=m)
2848 2848 dsmodified = set(changes.modified)
2849 2849 dsadded = set(changes.added)
2850 2850 dsremoved = set(changes.removed)
2851 2851 # store all local modifications, useful later for rename detection
2852 2852 localchanges = dsmodified | dsadded
2853 2853
2854 2854 # only take into account for removes between wc and target
2855 2855 clean |= dsremoved - removed
2856 2856 dsremoved &= removed
2857 2857 # distinct between dirstate remove and other
2858 2858 removed -= dsremoved
2859 2859
2860 2860 modadded = added & dsmodified
2861 2861 added -= modadded
2862 2862
2863 2863 # tell newly modified apart.
2864 2864 dsmodified &= modified
2865 2865 dsmodified |= modified & dsadded # dirstate added may need backup
2866 2866 modified -= dsmodified
2867 2867
2868 2868 # We need to wait for some post-processing to update this set
2869 2869 # before making the distinction. The dirstate will be used for
2870 2870 # that purpose.
2871 2871 dsadded = added
2872 2872
2873 2873 # in case of merge, files that are actually added can be reported as
2874 2874 # modified, we need to post process the result
2875 2875 if p2 != nullid:
2876 2876 mergeadd = set(dsmodified)
2877 2877 for path in dsmodified:
2878 2878 if path in mf:
2879 2879 mergeadd.remove(path)
2880 2880 dsadded |= mergeadd
2881 2881 dsmodified -= mergeadd
2882 2882
2883 2883 # if f is a rename, update `names` to also revert the source
2884 2884 cwd = repo.getcwd()
2885 2885 for f in localchanges:
2886 2886 src = repo.dirstate.copied(f)
2887 2887 # XXX should we check for rename down to target node?
2888 2888 if src and src not in names and repo.dirstate[src] == 'r':
2889 2889 dsremoved.add(src)
2890 2890 names[src] = (repo.pathto(src, cwd), True)
2891 2891
2892 2892 # determine the exact nature of the deleted changesets
2893 2893 deladded = set(_deleted)
2894 2894 for path in _deleted:
2895 2895 if path in mf:
2896 2896 deladded.remove(path)
2897 2897 deleted = _deleted - deladded
2898 2898
2899 2899 # distinguish between file to forget and the other
2900 2900 added = set()
2901 2901 for abs in dsadded:
2902 2902 if repo.dirstate[abs] != 'a':
2903 2903 added.add(abs)
2904 2904 dsadded -= added
2905 2905
2906 2906 for abs in deladded:
2907 2907 if repo.dirstate[abs] == 'a':
2908 2908 dsadded.add(abs)
2909 2909 deladded -= dsadded
2910 2910
2911 2911 # For files marked as removed, we check if an unknown file is present at
2912 2912 # the same path. If a such file exists it may need to be backed up.
2913 2913 # Making the distinction at this stage helps have simpler backup
2914 2914 # logic.
2915 2915 removunk = set()
2916 2916 for abs in removed:
2917 2917 target = repo.wjoin(abs)
2918 2918 if os.path.lexists(target):
2919 2919 removunk.add(abs)
2920 2920 removed -= removunk
2921 2921
2922 2922 dsremovunk = set()
2923 2923 for abs in dsremoved:
2924 2924 target = repo.wjoin(abs)
2925 2925 if os.path.lexists(target):
2926 2926 dsremovunk.add(abs)
2927 2927 dsremoved -= dsremovunk
2928 2928
2929 2929 # action to be actually performed by revert
2930 2930 # (<list of file>, message>) tuple
2931 2931 actions = {'revert': ([], _('reverting %s\n')),
2932 2932 'add': ([], _('adding %s\n')),
2933 2933 'remove': ([], _('removing %s\n')),
2934 2934 'drop': ([], _('removing %s\n')),
2935 2935 'forget': ([], _('forgetting %s\n')),
2936 2936 'undelete': ([], _('undeleting %s\n')),
2937 2937 'noop': (None, _('no changes needed to %s\n')),
2938 2938 'unknown': (None, _('file not managed: %s\n')),
2939 2939 }
2940 2940
2941 2941 # "constant" that convey the backup strategy.
2942 2942 # All set to `discard` if `no-backup` is set do avoid checking
2943 2943 # no_backup lower in the code.
2944 2944 # These values are ordered for comparison purposes
2945 2945 backupinteractive = 3 # do backup if interactively modified
2946 2946 backup = 2 # unconditionally do backup
2947 2947 check = 1 # check if the existing file differs from target
2948 2948 discard = 0 # never do backup
2949 2949 if opts.get('no_backup'):
2950 2950 backupinteractive = backup = check = discard
2951 2951 if interactive:
2952 2952 dsmodifiedbackup = backupinteractive
2953 2953 else:
2954 2954 dsmodifiedbackup = backup
2955 2955 tobackup = set()
2956 2956
2957 2957 backupanddel = actions['remove']
2958 2958 if not opts.get('no_backup'):
2959 2959 backupanddel = actions['drop']
2960 2960
2961 2961 disptable = (
2962 2962 # dispatch table:
2963 2963 # file state
2964 2964 # action
2965 2965 # make backup
2966 2966
2967 2967 ## Sets that results that will change file on disk
2968 2968 # Modified compared to target, no local change
2969 2969 (modified, actions['revert'], discard),
2970 2970 # Modified compared to target, but local file is deleted
2971 2971 (deleted, actions['revert'], discard),
2972 2972 # Modified compared to target, local change
2973 2973 (dsmodified, actions['revert'], dsmodifiedbackup),
2974 2974 # Added since target
2975 2975 (added, actions['remove'], discard),
2976 2976 # Added in working directory
2977 2977 (dsadded, actions['forget'], discard),
2978 2978 # Added since target, have local modification
2979 2979 (modadded, backupanddel, backup),
2980 2980 # Added since target but file is missing in working directory
2981 2981 (deladded, actions['drop'], discard),
2982 2982 # Removed since target, before working copy parent
2983 2983 (removed, actions['add'], discard),
2984 2984 # Same as `removed` but an unknown file exists at the same path
2985 2985 (removunk, actions['add'], check),
2986 2986 # Removed since targe, marked as such in working copy parent
2987 2987 (dsremoved, actions['undelete'], discard),
2988 2988 # Same as `dsremoved` but an unknown file exists at the same path
2989 2989 (dsremovunk, actions['undelete'], check),
2990 2990 ## the following sets does not result in any file changes
2991 2991 # File with no modification
2992 2992 (clean, actions['noop'], discard),
2993 2993 # Existing file, not tracked anywhere
2994 2994 (unknown, actions['unknown'], discard),
2995 2995 )
2996 2996
2997 2997 for abs, (rel, exact) in sorted(names.items()):
2998 2998 # target file to be touch on disk (relative to cwd)
2999 2999 target = repo.wjoin(abs)
3000 3000 # search the entry in the dispatch table.
3001 3001 # if the file is in any of these sets, it was touched in the working
3002 3002 # directory parent and we are sure it needs to be reverted.
3003 3003 for table, (xlist, msg), dobackup in disptable:
3004 3004 if abs not in table:
3005 3005 continue
3006 3006 if xlist is not None:
3007 3007 xlist.append(abs)
3008 3008 if dobackup:
3009 3009 # If in interactive mode, don't automatically create
3010 3010 # .orig files (issue4793)
3011 3011 if dobackup == backupinteractive:
3012 3012 tobackup.add(abs)
3013 3013 elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
3014 3014 bakname = scmutil.origpath(ui, repo, rel)
3015 3015 ui.note(_('saving current version of %s as %s\n') %
3016 3016 (rel, bakname))
3017 3017 if not opts.get('dry_run'):
3018 3018 if interactive:
3019 3019 util.copyfile(target, bakname)
3020 3020 else:
3021 3021 util.rename(target, bakname)
3022 if ui.verbose or not exact:
3023 ui.status(msg % rel)
3022 if opts.get('dry_run'):
3023 if ui.verbose or not exact:
3024 ui.status(msg % rel)
3024 3025 elif exact:
3025 3026 ui.warn(msg % rel)
3026 3027 break
3027 3028
3028 3029 if not opts.get('dry_run'):
3029 3030 needdata = ('revert', 'add', 'undelete')
3030 3031 oplist = [actions[name][0] for name in needdata]
3031 3032 prefetch = scmutil.prefetchfiles
3032 3033 matchfiles = scmutil.matchfiles
3033 3034 prefetch(repo, [ctx.rev()],
3034 3035 matchfiles(repo,
3035 3036 [f for sublist in oplist for f in sublist]))
3036 _performrevert(repo, parents, ctx, actions, interactive, tobackup)
3037 _performrevert(repo, parents, ctx, names, actions, interactive,
3038 tobackup)
3037 3039
3038 3040 if targetsubs:
3039 3041 # Revert the subrepos on the revert list
3040 3042 for sub in targetsubs:
3041 3043 try:
3042 3044 wctx.sub(sub).revert(ctx.substate[sub], *pats,
3043 3045 **pycompat.strkwargs(opts))
3044 3046 except KeyError:
3045 3047 raise error.Abort("subrepository '%s' does not exist in %s!"
3046 3048 % (sub, short(ctx.node())))
3047 3049
3048 def _performrevert(repo, parents, ctx, actions, interactive=False,
3050 def _performrevert(repo, parents, ctx, names, actions, interactive=False,
3049 3051 tobackup=None):
3050 3052 """function that actually perform all the actions computed for revert
3051 3053
3052 3054 This is an independent function to let extension to plug in and react to
3053 3055 the imminent revert.
3054 3056
3055 3057 Make sure you have the working directory locked when calling this function.
3056 3058 """
3057 3059 parent, p2 = parents
3058 3060 node = ctx.node()
3059 3061 excluded_files = []
3060 3062
3061 3063 def checkout(f):
3062 3064 fc = ctx[f]
3063 3065 repo.wwrite(f, fc.data(), fc.flags())
3064 3066
3065 3067 def doremove(f):
3066 3068 try:
3067 3069 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
3068 3070 repo.wvfs.unlinkpath(f, rmdir=rmdir)
3069 3071 except OSError:
3070 3072 pass
3071 3073 repo.dirstate.remove(f)
3072 3074
3075 def prntstatusmsg(action, f):
3076 rel, exact = names[f]
3077 if repo.ui.verbose or not exact:
3078 repo.ui.status(actions[action][1] % rel)
3079
3073 3080 audit_path = pathutil.pathauditor(repo.root, cached=True)
3074 3081 for f in actions['forget'][0]:
3075 3082 if interactive:
3076 3083 choice = repo.ui.promptchoice(
3077 3084 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
3078 3085 if choice == 0:
3086 prntstatusmsg('forget', f)
3079 3087 repo.dirstate.drop(f)
3080 3088 else:
3081 3089 excluded_files.append(f)
3082 3090 else:
3091 prntstatusmsg('forget', f)
3083 3092 repo.dirstate.drop(f)
3084 3093 for f in actions['remove'][0]:
3085 3094 audit_path(f)
3086 3095 if interactive:
3087 3096 choice = repo.ui.promptchoice(
3088 3097 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
3089 3098 if choice == 0:
3099 prntstatusmsg('remove', f)
3090 3100 doremove(f)
3091 3101 else:
3092 3102 excluded_files.append(f)
3093 3103 else:
3104 prntstatusmsg('remove', f)
3094 3105 doremove(f)
3095 3106 for f in actions['drop'][0]:
3096 3107 audit_path(f)
3108 prntstatusmsg('drop', f)
3097 3109 repo.dirstate.remove(f)
3098 3110
3099 3111 normal = None
3100 3112 if node == parent:
3101 3113 # We're reverting to our parent. If possible, we'd like status
3102 3114 # to report the file as clean. We have to use normallookup for
3103 3115 # merges to avoid losing information about merged/dirty files.
3104 3116 if p2 != nullid:
3105 3117 normal = repo.dirstate.normallookup
3106 3118 else:
3107 3119 normal = repo.dirstate.normal
3108 3120
3109 3121 newlyaddedandmodifiedfiles = set()
3110 3122 if interactive:
3111 3123 # Prompt the user for changes to revert
3112 3124 torevert = [f for f in actions['revert'][0] if f not in excluded_files]
3113 3125 m = scmutil.matchfiles(repo, torevert)
3114 3126 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
3115 3127 diffopts.nodates = True
3116 3128 diffopts.git = True
3117 3129 operation = 'discard'
3118 3130 reversehunks = True
3119 3131 if node != parent:
3120 3132 operation = 'apply'
3121 3133 reversehunks = False
3122 3134 if reversehunks:
3123 3135 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
3124 3136 else:
3125 3137 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
3126 3138 originalchunks = patch.parsepatch(diff)
3127 3139
3128 3140 try:
3129 3141
3130 3142 chunks, opts = recordfilter(repo.ui, originalchunks,
3131 3143 operation=operation)
3132 3144 if reversehunks:
3133 3145 chunks = patch.reversehunks(chunks)
3134 3146
3135 3147 except error.PatchError as err:
3136 3148 raise error.Abort(_('error parsing patch: %s') % err)
3137 3149
3138 3150 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
3139 3151 if tobackup is None:
3140 3152 tobackup = set()
3141 3153 # Apply changes
3142 3154 fp = stringio()
3155 # `fnames` keeps track of filenames for which we have initiated changes,
3156 # to make sure that we print status msg only once per file.
3157 fnames = set()
3143 3158 for c in chunks:
3144 # Create a backup file only if this hunk should be backed up
3145 if ishunk(c) and c.header.filename() in tobackup:
3159 if ishunk(c):
3146 3160 abs = c.header.filename()
3147 target = repo.wjoin(abs)
3148 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3149 util.copyfile(target, bakname)
3150 tobackup.remove(abs)
3161 if abs not in fnames:
3162 fnames.add(abs)
3163 prntstatusmsg('revert', abs)
3164 # Create a backup file only if this hunk should be backed up
3165 if c.header.filename() in tobackup:
3166 target = repo.wjoin(abs)
3167 bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
3168 util.copyfile(target, bakname)
3169 tobackup.remove(abs)
3151 3170 c.write(fp)
3152 3171 dopatch = fp.tell()
3153 3172 fp.seek(0)
3154 3173 if dopatch:
3155 3174 try:
3156 3175 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
3157 3176 except error.PatchError as err:
3158 3177 raise error.Abort(pycompat.bytestr(err))
3159 3178 del fp
3160 3179 else:
3161 3180 for f in actions['revert'][0]:
3181 prntstatusmsg('revert', f)
3162 3182 checkout(f)
3163 3183 if normal:
3164 3184 normal(f)
3165 3185
3166 3186 for f in actions['add'][0]:
3167 3187 # Don't checkout modified files, they are already created by the diff
3168 3188 if f not in newlyaddedandmodifiedfiles:
3189 prntstatusmsg('add', f)
3169 3190 checkout(f)
3170 3191 repo.dirstate.add(f)
3171 3192
3172 3193 normal = repo.dirstate.normallookup
3173 3194 if node == parent and p2 == nullid:
3174 3195 normal = repo.dirstate.normal
3175 3196 for f in actions['undelete'][0]:
3197 prntstatusmsg('undelete', f)
3176 3198 checkout(f)
3177 3199 normal(f)
3178 3200
3179 3201 copied = copies.pathcopies(repo[parent], ctx)
3180 3202
3181 3203 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3182 3204 if f in copied:
3183 3205 repo.dirstate.copy(copied[f], f)
3184 3206
3185 3207 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3186 3208 # commands.outgoing. "missing" is "missing" of the result of
3187 3209 # "findcommonoutgoing()"
3188 3210 outgoinghooks = util.hooks()
3189 3211
3190 3212 # a list of (ui, repo) functions called by commands.summary
3191 3213 summaryhooks = util.hooks()
3192 3214
3193 3215 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3194 3216 #
3195 3217 # functions should return tuple of booleans below, if 'changes' is None:
3196 3218 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3197 3219 #
3198 3220 # otherwise, 'changes' is a tuple of tuples below:
3199 3221 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3200 3222 # - (desturl, destbranch, destpeer, outgoing)
3201 3223 summaryremotehooks = util.hooks()
3202 3224
3203 3225 # A list of state files kept by multistep operations like graft.
3204 3226 # Since graft cannot be aborted, it is considered 'clearable' by update.
3205 3227 # note: bisect is intentionally excluded
3206 3228 # (state file, clearable, allowcommit, error, hint)
3207 3229 unfinishedstates = [
3208 3230 ('graftstate', True, False, _('graft in progress'),
3209 3231 _("use 'hg graft --continue' or 'hg graft --stop' to stop")),
3210 3232 ('updatestate', True, False, _('last update was interrupted'),
3211 3233 _("use 'hg update' to get a consistent checkout"))
3212 3234 ]
3213 3235
3214 3236 def checkunfinished(repo, commit=False):
3215 3237 '''Look for an unfinished multistep operation, like graft, and abort
3216 3238 if found. It's probably good to check this right before
3217 3239 bailifchanged().
3218 3240 '''
3219 3241 # Check for non-clearable states first, so things like rebase will take
3220 3242 # precedence over update.
3221 3243 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3222 3244 if clearable or (commit and allowcommit):
3223 3245 continue
3224 3246 if repo.vfs.exists(f):
3225 3247 raise error.Abort(msg, hint=hint)
3226 3248
3227 3249 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3228 3250 if not clearable or (commit and allowcommit):
3229 3251 continue
3230 3252 if repo.vfs.exists(f):
3231 3253 raise error.Abort(msg, hint=hint)
3232 3254
3233 3255 def clearunfinished(repo):
3234 3256 '''Check for unfinished operations (as above), and clear the ones
3235 3257 that are clearable.
3236 3258 '''
3237 3259 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3238 3260 if not clearable and repo.vfs.exists(f):
3239 3261 raise error.Abort(msg, hint=hint)
3240 3262 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3241 3263 if clearable and repo.vfs.exists(f):
3242 3264 util.unlink(repo.vfs.join(f))
3243 3265
3244 3266 afterresolvedstates = [
3245 3267 ('graftstate',
3246 3268 _('hg graft --continue')),
3247 3269 ]
3248 3270
3249 3271 def howtocontinue(repo):
3250 3272 '''Check for an unfinished operation and return the command to finish
3251 3273 it.
3252 3274
3253 3275 afterresolvedstates tuples define a .hg/{file} and the corresponding
3254 3276 command needed to finish it.
3255 3277
3256 3278 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
3257 3279 a boolean.
3258 3280 '''
3259 3281 contmsg = _("continue: %s")
3260 3282 for f, msg in afterresolvedstates:
3261 3283 if repo.vfs.exists(f):
3262 3284 return contmsg % msg, True
3263 3285 if repo[None].dirty(missing=True, merge=False, branch=False):
3264 3286 return contmsg % _("hg commit"), False
3265 3287 return None, None
3266 3288
3267 3289 def checkafterresolved(repo):
3268 3290 '''Inform the user about the next action after completing hg resolve
3269 3291
3270 3292 If there's a matching afterresolvedstates, howtocontinue will yield
3271 3293 repo.ui.warn as the reporter.
3272 3294
3273 3295 Otherwise, it will yield repo.ui.note.
3274 3296 '''
3275 3297 msg, warning = howtocontinue(repo)
3276 3298 if msg is not None:
3277 3299 if warning:
3278 3300 repo.ui.warn("%s\n" % msg)
3279 3301 else:
3280 3302 repo.ui.note("%s\n" % msg)
3281 3303
3282 3304 def wrongtooltocontinue(repo, task):
3283 3305 '''Raise an abort suggesting how to properly continue if there is an
3284 3306 active task.
3285 3307
3286 3308 Uses howtocontinue() to find the active task.
3287 3309
3288 3310 If there's no task (repo.ui.note for 'hg commit'), it does not offer
3289 3311 a hint.
3290 3312 '''
3291 3313 after = howtocontinue(repo)
3292 3314 hint = None
3293 3315 if after[1]:
3294 3316 hint = after[0]
3295 3317 raise error.Abort(_('no %s in progress') % task, hint=hint)
@@ -1,763 +1,763 b''
1 1 $ hg init basic
2 2 $ cd basic
3 3
4 4 should complain
5 5
6 6 $ hg backout
7 7 abort: please specify a revision to backout
8 8 [255]
9 9 $ hg backout -r 0 0
10 10 abort: please specify just one revision
11 11 [255]
12 12
13 13 basic operation
14 14 (this also tests that editor is invoked if the commit message is not
15 15 specified explicitly)
16 16
17 17 $ echo a > a
18 18 $ hg commit -d '0 0' -A -m a
19 19 adding a
20 20 $ echo b >> a
21 21 $ hg commit -d '1 0' -m b
22 22
23 23 $ hg status --rev tip --rev "tip^1"
24 24 M a
25 25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 26 reverting a
27 27 Backed out changeset a820f4f40a57
28 28
29 29
30 30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 31 HG: Leave message empty to abort commit.
32 32 HG: --
33 33 HG: user: test
34 34 HG: branch 'default'
35 35 HG: changed a
36 36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 37 $ cat a
38 38 a
39 39 $ hg summary
40 40 parent: 2:2929462c3dff tip
41 41 Backed out changeset a820f4f40a57
42 42 branch: default
43 43 commit: (clean)
44 44 update: (current)
45 45 phases: 3 draft
46 46
47 47 commit option
48 48
49 49 $ cd ..
50 50 $ hg init commit
51 51 $ cd commit
52 52
53 53 $ echo tomatoes > a
54 54 $ hg add a
55 55 $ hg commit -d '0 0' -m tomatoes
56 56
57 57 $ echo chair > b
58 58 $ hg add b
59 59 $ hg commit -d '1 0' -m chair
60 60
61 61 $ echo grapes >> a
62 62 $ hg commit -d '2 0' -m grapes
63 63
64 64 $ hg backout -d '4 0' 1 --tool=:fail
65 65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 67 $ hg summary
68 68 parent: 3:1c2161e97c0a tip
69 69 Backed out changeset 22cb4f70d813
70 70 branch: default
71 71 commit: (clean)
72 72 update: (current)
73 73 phases: 4 draft
74 74
75 75 $ echo ypples > a
76 76 $ hg commit -d '5 0' -m ypples
77 77
78 78 $ hg backout -d '6 0' 2 --tool=:fail
79 79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 80 use 'hg resolve' to retry unresolved file merges
81 81 [1]
82 82 $ hg summary
83 83 parent: 4:ed99997b793d tip
84 84 ypples
85 85 branch: default
86 86 commit: 1 unresolved (clean)
87 87 update: (current)
88 88 phases: 5 draft
89 89
90 90 file that was removed is recreated
91 91 (this also tests that editor is not invoked if the commit message is
92 92 specified explicitly)
93 93
94 94 $ cd ..
95 95 $ hg init remove
96 96 $ cd remove
97 97
98 98 $ echo content > a
99 99 $ hg commit -d '0 0' -A -m a
100 100 adding a
101 101
102 102 $ hg rm a
103 103 $ hg commit -d '1 0' -m b
104 104
105 105 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
106 106 adding a
107 107 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
108 108 $ cat a
109 109 content
110 110 $ hg summary
111 111 parent: 2:de31bdc76c0d tip
112 112 Backed out changeset 76862dcce372
113 113 branch: default
114 114 commit: (clean)
115 115 update: (current)
116 116 phases: 3 draft
117 117
118 118 backout of backout is as if nothing happened
119 119
120 120 $ hg backout -d '3 0' --merge tip --tool=true
121 121 removing a
122 122 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
123 123 $ test -f a
124 124 [1]
125 125 $ hg summary
126 126 parent: 3:7f6d0f120113 tip
127 127 Backed out changeset de31bdc76c0d
128 128 branch: default
129 129 commit: (clean)
130 130 update: (current)
131 131 phases: 4 draft
132 132
133 133 Test that 'hg rollback' restores dirstate just before opening
134 134 transaction: in-memory dirstate changes should be written into
135 135 '.hg/journal.dirstate' as expected.
136 136
137 137 $ echo 'removed soon' > b
138 138 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
139 139 adding b
140 140 $ echo 'newly added' > c
141 141 $ hg add c
142 142 $ hg remove b
143 143 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
144 144 $ touch -t 200001010000 c
145 145 $ hg status -A
146 146 C c
147 147 $ hg debugstate --nodates
148 148 n 644 12 set c
149 149 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
150 removing c
150 151 adding b
151 removing c
152 152 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
153 153 $ hg rollback -q
154 154 $ hg status -A
155 155 A b
156 156 R c
157 157 $ hg debugstate --nodates
158 158 a 0 -1 unset b
159 159 r 0 0 set c
160 160
161 161 across branch
162 162
163 163 $ cd ..
164 164 $ hg init branch
165 165 $ cd branch
166 166 $ echo a > a
167 167 $ hg ci -Am0
168 168 adding a
169 169 $ echo b > b
170 170 $ hg ci -Am1
171 171 adding b
172 172 $ hg co -C 0
173 173 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
174 174 $ hg summary
175 175 parent: 0:f7b1eb17ad24
176 176 0
177 177 branch: default
178 178 commit: (clean)
179 179 update: 1 new changesets (update)
180 180 phases: 2 draft
181 181
182 182 should fail
183 183
184 184 $ hg backout 1
185 185 abort: cannot backout change that is not an ancestor
186 186 [255]
187 187 $ echo c > c
188 188 $ hg ci -Am2
189 189 adding c
190 190 created new head
191 191 $ hg summary
192 192 parent: 2:db815d6d32e6 tip
193 193 2
194 194 branch: default
195 195 commit: (clean)
196 196 update: 1 new changesets, 2 branch heads (merge)
197 197 phases: 3 draft
198 198
199 199 should fail
200 200
201 201 $ hg backout 1
202 202 abort: cannot backout change that is not an ancestor
203 203 [255]
204 204 $ hg summary
205 205 parent: 2:db815d6d32e6 tip
206 206 2
207 207 branch: default
208 208 commit: (clean)
209 209 update: 1 new changesets, 2 branch heads (merge)
210 210 phases: 3 draft
211 211
212 212 backout with merge
213 213
214 214 $ cd ..
215 215 $ hg init merge
216 216 $ cd merge
217 217
218 218 $ echo line 1 > a
219 219 $ echo line 2 >> a
220 220 $ hg commit -d '0 0' -A -m a
221 221 adding a
222 222 $ hg summary
223 223 parent: 0:59395513a13a tip
224 224 a
225 225 branch: default
226 226 commit: (clean)
227 227 update: (current)
228 228 phases: 1 draft
229 229
230 230 remove line 1
231 231
232 232 $ echo line 2 > a
233 233 $ hg commit -d '1 0' -m b
234 234
235 235 $ echo line 3 >> a
236 236 $ hg commit -d '2 0' -m c
237 237
238 238 $ hg backout --merge -d '3 0' 1 --tool=true
239 239 reverting a
240 240 created new head
241 241 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
242 242 merging with changeset 3:26b8ccb9ad91
243 243 merging a
244 244 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
245 245 (branch merge, don't forget to commit)
246 246 $ hg commit -d '4 0' -m d
247 247 $ hg summary
248 248 parent: 4:c7df5e0b9c09 tip
249 249 d
250 250 branch: default
251 251 commit: (clean)
252 252 update: (current)
253 253 phases: 5 draft
254 254
255 255 check line 1 is back
256 256
257 257 $ cat a
258 258 line 1
259 259 line 2
260 260 line 3
261 261
262 262 Test visibility of in-memory dirstate changes outside transaction to
263 263 external hook process
264 264
265 265 $ cat > $TESTTMP/checkvisibility.sh <<EOF
266 266 > echo "==== \$1:"
267 267 > hg parents --template "{rev}:{node|short}\n"
268 268 > echo "===="
269 269 > EOF
270 270
271 271 "hg backout --merge REV1" at REV2 below implies steps below:
272 272
273 273 (1) update to REV1 (REV2 => REV1)
274 274 (2) revert by REV1^1
275 275 (3) commit backing out revision (REV3)
276 276 (4) update to REV2 (REV3 => REV2)
277 277 (5) merge with REV3 (REV2 => REV2, REV3)
278 278
279 279 == test visibility to external preupdate hook
280 280
281 281 $ hg update -q -C 2
282 282 $ hg --config extensions.strip= strip 3
283 283 saved backup bundle to * (glob)
284 284
285 285 $ cat >> .hg/hgrc <<EOF
286 286 > [hooks]
287 287 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
288 288 > EOF
289 289
290 290 ("-m" is needed to avoid writing dirstate changes out at other than
291 291 invocation of the hook to be examined)
292 292
293 293 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
294 294 ==== preupdate:
295 295 2:6ea3f2a197a2
296 296 ====
297 297 reverting a
298 298 created new head
299 299 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
300 300 ==== preupdate:
301 301 3:d92a3f57f067
302 302 ====
303 303 merging with changeset 3:d92a3f57f067
304 304 ==== preupdate:
305 305 2:6ea3f2a197a2
306 306 ====
307 307 merging a
308 308 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
309 309 (branch merge, don't forget to commit)
310 310
311 311 $ cat >> .hg/hgrc <<EOF
312 312 > [hooks]
313 313 > preupdate.visibility =
314 314 > EOF
315 315
316 316 == test visibility to external update hook
317 317
318 318 $ hg update -q -C 2
319 319 $ hg --config extensions.strip= strip 3
320 320 saved backup bundle to * (glob)
321 321
322 322 $ cat >> .hg/hgrc <<EOF
323 323 > [hooks]
324 324 > update.visibility = sh $TESTTMP/checkvisibility.sh update
325 325 > EOF
326 326
327 327 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
328 328 ==== update:
329 329 1:5a50a024c182
330 330 ====
331 331 reverting a
332 332 created new head
333 333 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
334 334 ==== update:
335 335 2:6ea3f2a197a2
336 336 ====
337 337 merging with changeset 3:d92a3f57f067
338 338 merging a
339 339 ==== update:
340 340 2:6ea3f2a197a2
341 341 3:d92a3f57f067
342 342 ====
343 343 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
344 344 (branch merge, don't forget to commit)
345 345
346 346 $ cat >> .hg/hgrc <<EOF
347 347 > [hooks]
348 348 > update.visibility =
349 349 > EOF
350 350
351 351 $ cd ..
352 352
353 353 backout should not back out subsequent changesets
354 354
355 355 $ hg init onecs
356 356 $ cd onecs
357 357 $ echo 1 > a
358 358 $ hg commit -d '0 0' -A -m a
359 359 adding a
360 360 $ echo 2 >> a
361 361 $ hg commit -d '1 0' -m b
362 362 $ echo 1 > b
363 363 $ hg commit -d '2 0' -A -m c
364 364 adding b
365 365 $ hg summary
366 366 parent: 2:882396649954 tip
367 367 c
368 368 branch: default
369 369 commit: (clean)
370 370 update: (current)
371 371 phases: 3 draft
372 372
373 373 without --merge
374 374 $ hg backout --no-commit -d '3 0' 1 --tool=true
375 375 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 376 changeset 22bca4c721e5 backed out, don't forget to commit.
377 377 $ hg locate b
378 378 b
379 379 $ hg update -C tip
380 380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 381 $ hg locate b
382 382 b
383 383 $ hg summary
384 384 parent: 2:882396649954 tip
385 385 c
386 386 branch: default
387 387 commit: (clean)
388 388 update: (current)
389 389 phases: 3 draft
390 390
391 391 with --merge
392 392 $ hg backout --merge -d '3 0' 1 --tool=true
393 393 reverting a
394 394 created new head
395 395 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
396 396 merging with changeset 3:3202beb76721
397 397 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 398 (branch merge, don't forget to commit)
399 399 $ hg locate b
400 400 b
401 401 $ hg update -C tip
402 402 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
403 403 $ hg locate b
404 404 [1]
405 405
406 406 $ cd ..
407 407 $ hg init m
408 408 $ cd m
409 409 $ echo a > a
410 410 $ hg commit -d '0 0' -A -m a
411 411 adding a
412 412 $ echo b > b
413 413 $ hg commit -d '1 0' -A -m b
414 414 adding b
415 415 $ echo c > c
416 416 $ hg commit -d '2 0' -A -m b
417 417 adding c
418 418 $ hg update 1
419 419 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 420 $ echo d > d
421 421 $ hg commit -d '3 0' -A -m c
422 422 adding d
423 423 created new head
424 424 $ hg merge 2
425 425 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 426 (branch merge, don't forget to commit)
427 427 $ hg commit -d '4 0' -A -m d
428 428 $ hg summary
429 429 parent: 4:b2f3bb92043e tip
430 430 d
431 431 branch: default
432 432 commit: (clean)
433 433 update: (current)
434 434 phases: 5 draft
435 435
436 436 backout of merge should fail
437 437
438 438 $ hg backout 4
439 439 abort: cannot backout a merge changeset
440 440 [255]
441 441
442 442 backout of merge with bad parent should fail
443 443
444 444 $ hg backout --parent 0 4
445 445 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
446 446 [255]
447 447
448 448 backout of non-merge with parent should fail
449 449
450 450 $ hg backout --parent 0 3
451 451 abort: cannot use --parent on non-merge changeset
452 452 [255]
453 453
454 454 backout with valid parent should be ok
455 455
456 456 $ hg backout -d '5 0' --parent 2 4 --tool=true
457 457 removing d
458 458 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
459 459 $ hg summary
460 460 parent: 5:10e5328c8435 tip
461 461 Backed out changeset b2f3bb92043e
462 462 branch: default
463 463 commit: (clean)
464 464 update: (current)
465 465 phases: 6 draft
466 466
467 467 $ hg rollback
468 468 repository tip rolled back to revision 4 (undo commit)
469 469 working directory now based on revision 4
470 470 $ hg update -C
471 471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 472 $ hg summary
473 473 parent: 4:b2f3bb92043e tip
474 474 d
475 475 branch: default
476 476 commit: (clean)
477 477 update: (current)
478 478 phases: 5 draft
479 479
480 480 $ hg backout -d '6 0' --parent 3 4 --tool=true
481 481 removing c
482 482 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
483 483 $ hg summary
484 484 parent: 5:033590168430 tip
485 485 Backed out changeset b2f3bb92043e
486 486 branch: default
487 487 commit: (clean)
488 488 update: (current)
489 489 phases: 6 draft
490 490
491 491 $ cd ..
492 492
493 493 named branches
494 494
495 495 $ hg init named_branches
496 496 $ cd named_branches
497 497
498 498 $ echo default > default
499 499 $ hg ci -d '0 0' -Am default
500 500 adding default
501 501 $ hg branch branch1
502 502 marked working directory as branch branch1
503 503 (branches are permanent and global, did you want a bookmark?)
504 504 $ echo branch1 > file1
505 505 $ hg ci -d '1 0' -Am file1
506 506 adding file1
507 507 $ hg branch branch2
508 508 marked working directory as branch branch2
509 509 $ echo branch2 > file2
510 510 $ hg ci -d '2 0' -Am file2
511 511 adding file2
512 512
513 513 without --merge
514 514 $ hg backout --no-commit -r 1 --tool=true
515 515 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
516 516 changeset bf1602f437f3 backed out, don't forget to commit.
517 517 $ hg branch
518 518 branch2
519 519 $ hg status -A
520 520 R file1
521 521 C default
522 522 C file2
523 523 $ hg summary
524 524 parent: 2:45bbcd363bf0 tip
525 525 file2
526 526 branch: branch2
527 527 commit: 1 removed
528 528 update: (current)
529 529 phases: 3 draft
530 530
531 531 with --merge
532 532 (this also tests that editor is invoked if '--edit' is specified
533 533 explicitly regardless of '--message')
534 534
535 535 $ hg update -qC
536 536 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
537 537 removing file1
538 538 backout on branch1
539 539
540 540
541 541 HG: Enter commit message. Lines beginning with 'HG:' are removed.
542 542 HG: Leave message empty to abort commit.
543 543 HG: --
544 544 HG: user: test
545 545 HG: branch 'branch2'
546 546 HG: removed file1
547 547 created new head
548 548 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
549 549 merging with changeset 3:d4e8f6db59fb
550 550 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 551 (branch merge, don't forget to commit)
552 552 $ hg summary
553 553 parent: 2:45bbcd363bf0
554 554 file2
555 555 parent: 3:d4e8f6db59fb tip
556 556 backout on branch1
557 557 branch: branch2
558 558 commit: 1 removed (merge)
559 559 update: (current)
560 560 phases: 4 draft
561 561 $ hg update -q -C 2
562 562
563 563 on branch2 with branch1 not merged, so file1 should still exist:
564 564
565 565 $ hg id
566 566 45bbcd363bf0 (branch2)
567 567 $ hg st -A
568 568 C default
569 569 C file1
570 570 C file2
571 571 $ hg summary
572 572 parent: 2:45bbcd363bf0
573 573 file2
574 574 branch: branch2
575 575 commit: (clean)
576 576 update: 1 new changesets, 2 branch heads (merge)
577 577 phases: 4 draft
578 578
579 579 on branch2 with branch1 merged, so file1 should be gone:
580 580
581 581 $ hg merge
582 582 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
583 583 (branch merge, don't forget to commit)
584 584 $ hg ci -d '4 0' -m 'merge backout of branch1'
585 585 $ hg id
586 586 22149cdde76d (branch2) tip
587 587 $ hg st -A
588 588 C default
589 589 C file2
590 590 $ hg summary
591 591 parent: 4:22149cdde76d tip
592 592 merge backout of branch1
593 593 branch: branch2
594 594 commit: (clean)
595 595 update: (current)
596 596 phases: 5 draft
597 597
598 598 on branch1, so no file1 and file2:
599 599
600 600 $ hg co -C branch1
601 601 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
602 602 $ hg id
603 603 bf1602f437f3 (branch1)
604 604 $ hg st -A
605 605 C default
606 606 C file1
607 607 $ hg summary
608 608 parent: 1:bf1602f437f3
609 609 file1
610 610 branch: branch1
611 611 commit: (clean)
612 612 update: (current)
613 613 phases: 5 draft
614 614
615 615 $ cd ..
616 616
617 617 backout of empty changeset (issue4190)
618 618
619 619 $ hg init emptycommit
620 620 $ cd emptycommit
621 621
622 622 $ touch file1
623 623 $ hg ci -Aqm file1
624 624 $ hg branch -q branch1
625 625 $ hg ci -qm branch1
626 626 $ hg backout -v 1
627 627 resolving manifests
628 628 nothing changed
629 629 [1]
630 630
631 631 $ cd ..
632 632
633 633
634 634 Test usage of `hg resolve` in case of conflict
635 635 (issue4163)
636 636
637 637 $ hg init issue4163
638 638 $ cd issue4163
639 639 $ touch foo
640 640 $ hg add foo
641 641 $ cat > foo << EOF
642 642 > one
643 643 > two
644 644 > three
645 645 > four
646 646 > five
647 647 > six
648 648 > seven
649 649 > height
650 650 > nine
651 651 > ten
652 652 > EOF
653 653 $ hg ci -m 'initial'
654 654 $ cat > foo << EOF
655 655 > one
656 656 > two
657 657 > THREE
658 658 > four
659 659 > five
660 660 > six
661 661 > seven
662 662 > height
663 663 > nine
664 664 > ten
665 665 > EOF
666 666 $ hg ci -m 'capital three'
667 667 $ cat > foo << EOF
668 668 > one
669 669 > two
670 670 > THREE
671 671 > four
672 672 > five
673 673 > six
674 674 > seven
675 675 > height
676 676 > nine
677 677 > TEN
678 678 > EOF
679 679 $ hg ci -m 'capital ten'
680 680 $ hg backout -r 'desc("capital three")' --tool internal:fail
681 681 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
682 682 use 'hg resolve' to retry unresolved file merges
683 683 [1]
684 684 $ hg status
685 685 $ hg debugmergestate
686 686 * version 2 records
687 687 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
688 688 other: a30dd8addae3ce71b8667868478542bc417439e6
689 689 file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553)
690 690 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
691 691 local path: foo (flags "")
692 692 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
693 693 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
694 694 $ mv .hg/merge/state2 .hg/merge/state2-moved
695 695 $ hg debugmergestate
696 696 * version 1 records
697 697 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
698 698 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
699 699 local path: foo (flags "")
700 700 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
701 701 other path: foo (node not stored in v1 format)
702 702 $ mv .hg/merge/state2-moved .hg/merge/state2
703 703 $ hg resolve -l # still unresolved
704 704 U foo
705 705 $ hg summary
706 706 parent: 2:b71750c4b0fd tip
707 707 capital ten
708 708 branch: default
709 709 commit: 1 unresolved (clean)
710 710 update: (current)
711 711 phases: 3 draft
712 712 $ hg resolve --all --debug
713 713 picked tool ':merge' for foo (binary False symlink False changedelete False)
714 714 merging foo
715 715 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
716 716 premerge successful
717 717 (no more unresolved files)
718 718 continue: hg commit
719 719 $ hg status
720 720 M foo
721 721 ? foo.orig
722 722 $ hg resolve -l
723 723 R foo
724 724 $ hg summary
725 725 parent: 2:b71750c4b0fd tip
726 726 capital ten
727 727 branch: default
728 728 commit: 1 modified, 1 unknown
729 729 update: (current)
730 730 phases: 3 draft
731 731 $ cat foo
732 732 one
733 733 two
734 734 three
735 735 four
736 736 five
737 737 six
738 738 seven
739 739 height
740 740 nine
741 741 TEN
742 742
743 743 --no-commit shouldn't commit
744 744
745 745 $ hg init a
746 746 $ cd a
747 747 $ for i in 1 2 3; do
748 748 > touch $i
749 749 > hg ci -Am $i
750 750 > done
751 751 adding 1
752 752 adding 2
753 753 adding 3
754 754 $ hg backout --no-commit .
755 755 removing 3
756 756 changeset cccc23d9d68f backed out, don't forget to commit.
757 757 $ hg revert -aq
758 758
759 759 --no-commit can't be used with --merge
760 760
761 761 $ hg backout --merge --no-commit 2
762 762 abort: cannot use --merge with --no-commit
763 763 [255]
@@ -1,82 +1,82 b''
1 1 $ hg init
2 2 $ echo foo > a
3 3 $ hg add a
4 4 $ hg commit -m "1"
5 5
6 6 $ echo bar > b
7 7 $ hg add b
8 8 $ hg remove a
9 9
10 10 Should show a removed and b added:
11 11
12 12 $ hg status
13 13 A b
14 14 R a
15 15
16 16 $ hg revert --all
17 forgetting b
17 18 undeleting a
18 forgetting b
19 19
20 20 Should show b unknown and a back to normal:
21 21
22 22 $ hg status
23 23 ? b
24 24
25 25 $ rm b
26 26
27 27 $ hg co -C 0
28 28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 29 $ echo foo-a > a
30 30 $ hg commit -m "2a"
31 31
32 32 $ hg co -C 0
33 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 34 $ echo foo-b > a
35 35 $ hg commit -m "2b"
36 36 created new head
37 37
38 38 $ HGMERGE=true hg merge 1
39 39 merging a
40 40 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
41 41 (branch merge, don't forget to commit)
42 42
43 43 Should show foo-b:
44 44
45 45 $ cat a
46 46 foo-b
47 47
48 48 $ echo bar > b
49 49 $ hg add b
50 50 $ rm a
51 51 $ hg remove a
52 52
53 53 Should show a removed and b added:
54 54
55 55 $ hg status
56 56 A b
57 57 R a
58 58
59 59 Revert should fail:
60 60
61 61 $ hg revert
62 62 abort: uncommitted merge with no revision specified
63 63 (use 'hg update' or see 'hg help revert')
64 64 [255]
65 65
66 66 Revert should be ok now:
67 67
68 68 $ hg revert -r2 --all
69 forgetting b
69 70 undeleting a
70 forgetting b
71 71
72 72 Should show b unknown and a marked modified (merged):
73 73
74 74 $ hg status
75 75 M a
76 76 ? b
77 77
78 78 Should show foo-b:
79 79
80 80 $ cat a
81 81 foo-b
82 82
@@ -1,198 +1,198 b''
1 1 $ hg init
2 2
3 3 Set up history and working copy
4 4
5 5 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
6 6 $ hg addremove -q --similarity 0
7 7 $ hg commit -m first
8 8
9 9 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
10 10 $ hg addremove -q --similarity 0
11 11 $ hg commit -m second
12 12
13 13 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
14 14 $ hg addremove -q --similarity 0
15 15 $ hg forget *_*_*-untracked
16 16 $ rm *_*_missing-*
17 17
18 18 Test status
19 19
20 20 $ hg st -A 'set:modified()'
21 21 M content1_content1_content3-tracked
22 22 M content1_content2_content1-tracked
23 23 M content1_content2_content3-tracked
24 24 M missing_content2_content3-tracked
25 25
26 26 $ hg st -A 'set:added()'
27 27 A content1_missing_content1-tracked
28 28 A content1_missing_content3-tracked
29 29 A missing_missing_content3-tracked
30 30
31 31 $ hg st -A 'set:removed()'
32 32 R content1_content1_content1-untracked
33 33 R content1_content1_content3-untracked
34 34 R content1_content1_missing-untracked
35 35 R content1_content2_content1-untracked
36 36 R content1_content2_content2-untracked
37 37 R content1_content2_content3-untracked
38 38 R content1_content2_missing-untracked
39 39 R missing_content2_content2-untracked
40 40 R missing_content2_content3-untracked
41 41 R missing_content2_missing-untracked
42 42
43 43 $ hg st -A 'set:deleted()'
44 44 ! content1_content1_missing-tracked
45 45 ! content1_content2_missing-tracked
46 46 ! content1_missing_missing-tracked
47 47 ! missing_content2_missing-tracked
48 48 ! missing_missing_missing-tracked
49 49
50 50 $ hg st -A 'set:missing()'
51 51 ! content1_content1_missing-tracked
52 52 ! content1_content2_missing-tracked
53 53 ! content1_missing_missing-tracked
54 54 ! missing_content2_missing-tracked
55 55 ! missing_missing_missing-tracked
56 56
57 57 $ hg st -A 'set:unknown()'
58 58 ? content1_missing_content1-untracked
59 59 ? content1_missing_content3-untracked
60 60 ? missing_missing_content3-untracked
61 61
62 62 $ hg st -A 'set:clean()'
63 63 C content1_content1_content1-tracked
64 64 C content1_content2_content2-tracked
65 65 C missing_content2_content2-tracked
66 66
67 67 Test log
68 68
69 69 $ hg log -T '{rev}\n' --stat 'set:modified()'
70 70 1
71 71 content1_content2_content1-tracked | 2 +-
72 72 content1_content2_content3-tracked | 2 +-
73 73 missing_content2_content3-tracked | 1 +
74 74 3 files changed, 3 insertions(+), 2 deletions(-)
75 75
76 76 0
77 77 content1_content1_content3-tracked | 1 +
78 78 content1_content2_content1-tracked | 1 +
79 79 content1_content2_content3-tracked | 1 +
80 80 3 files changed, 3 insertions(+), 0 deletions(-)
81 81
82 82 Largefiles doesn't crash
83 83 $ hg log -T '{rev}\n' --stat 'set:modified()' --config extensions.largefiles=
84 84 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
85 85 1
86 86 content1_content2_content1-tracked | 2 +-
87 87 content1_content2_content3-tracked | 2 +-
88 88 missing_content2_content3-tracked | 1 +
89 89 3 files changed, 3 insertions(+), 2 deletions(-)
90 90
91 91 0
92 92 content1_content1_content3-tracked | 1 +
93 93 content1_content2_content1-tracked | 1 +
94 94 content1_content2_content3-tracked | 1 +
95 95 3 files changed, 3 insertions(+), 0 deletions(-)
96 96
97 97 $ hg log -T '{rev}\n' --stat 'set:added()'
98 98 1
99 99 content1_missing_content1-tracked | 1 -
100 100 content1_missing_content3-tracked | 1 -
101 101 2 files changed, 0 insertions(+), 2 deletions(-)
102 102
103 103 0
104 104 content1_missing_content1-tracked | 1 +
105 105 content1_missing_content3-tracked | 1 +
106 106 2 files changed, 2 insertions(+), 0 deletions(-)
107 107
108 108 $ hg log -T '{rev}\n' --stat 'set:removed()'
109 109 1
110 110 content1_content2_content1-untracked | 2 +-
111 111 content1_content2_content2-untracked | 2 +-
112 112 content1_content2_content3-untracked | 2 +-
113 113 content1_content2_missing-untracked | 2 +-
114 114 missing_content2_content2-untracked | 1 +
115 115 missing_content2_content3-untracked | 1 +
116 116 missing_content2_missing-untracked | 1 +
117 117 7 files changed, 7 insertions(+), 4 deletions(-)
118 118
119 119 0
120 120 content1_content1_content1-untracked | 1 +
121 121 content1_content1_content3-untracked | 1 +
122 122 content1_content1_missing-untracked | 1 +
123 123 content1_content2_content1-untracked | 1 +
124 124 content1_content2_content2-untracked | 1 +
125 125 content1_content2_content3-untracked | 1 +
126 126 content1_content2_missing-untracked | 1 +
127 127 7 files changed, 7 insertions(+), 0 deletions(-)
128 128
129 129 $ hg log -T '{rev}\n' --stat 'set:deleted()'
130 130 1
131 131 content1_content2_missing-tracked | 2 +-
132 132 content1_missing_missing-tracked | 1 -
133 133 missing_content2_missing-tracked | 1 +
134 134 3 files changed, 2 insertions(+), 2 deletions(-)
135 135
136 136 0
137 137 content1_content1_missing-tracked | 1 +
138 138 content1_content2_missing-tracked | 1 +
139 139 content1_missing_missing-tracked | 1 +
140 140 3 files changed, 3 insertions(+), 0 deletions(-)
141 141
142 142 $ hg log -T '{rev}\n' --stat 'set:unknown()'
143 143 1
144 144 content1_missing_content1-untracked | 1 -
145 145 content1_missing_content3-untracked | 1 -
146 146 2 files changed, 0 insertions(+), 2 deletions(-)
147 147
148 148 0
149 149 content1_missing_content1-untracked | 1 +
150 150 content1_missing_content3-untracked | 1 +
151 151 2 files changed, 2 insertions(+), 0 deletions(-)
152 152
153 153 $ hg log -T '{rev}\n' --stat 'set:clean()'
154 154 1
155 155 content1_content2_content2-tracked | 2 +-
156 156 missing_content2_content2-tracked | 1 +
157 157 2 files changed, 2 insertions(+), 1 deletions(-)
158 158
159 159 0
160 160 content1_content1_content1-tracked | 1 +
161 161 content1_content2_content2-tracked | 1 +
162 162 2 files changed, 2 insertions(+), 0 deletions(-)
163 163
164 164 Test revert
165 165
166 166 $ hg revert 'set:modified()'
167 167 reverting content1_content1_content3-tracked
168 168 reverting content1_content2_content1-tracked
169 169 reverting content1_content2_content3-tracked
170 170 reverting missing_content2_content3-tracked
171 171
172 172 $ hg revert 'set:added()'
173 173 forgetting content1_missing_content1-tracked
174 174 forgetting content1_missing_content3-tracked
175 175 forgetting missing_missing_content3-tracked
176 176
177 177 $ hg revert 'set:removed()'
178 178 undeleting content1_content1_content1-untracked
179 179 undeleting content1_content1_content3-untracked
180 180 undeleting content1_content1_missing-untracked
181 181 undeleting content1_content2_content1-untracked
182 182 undeleting content1_content2_content2-untracked
183 183 undeleting content1_content2_content3-untracked
184 184 undeleting content1_content2_missing-untracked
185 185 undeleting missing_content2_content2-untracked
186 186 undeleting missing_content2_content3-untracked
187 187 undeleting missing_content2_missing-untracked
188 188
189 189 $ hg revert 'set:deleted()'
190 forgetting content1_missing_missing-tracked
191 forgetting missing_missing_missing-tracked
190 192 reverting content1_content1_missing-tracked
191 193 reverting content1_content2_missing-tracked
192 forgetting content1_missing_missing-tracked
193 194 reverting missing_content2_missing-tracked
194 forgetting missing_missing_missing-tracked
195 195
196 196 $ hg revert 'set:unknown()'
197 197
198 198 $ hg revert 'set:clean()'
@@ -1,848 +1,848 b''
1 1 $ hg init repo
2 2 $ cd repo
3 3
4 4 New file:
5 5
6 6 $ hg import -d "1000000 0" -mnew - <<EOF
7 7 > diff --git a/new b/new
8 8 > new file mode 100644
9 9 > index 0000000..7898192
10 10 > --- /dev/null
11 11 > +++ b/new
12 12 > @@ -0,0 +1 @@
13 13 > +a
14 14 > EOF
15 15 applying patch from stdin
16 16
17 17 $ hg tip -q
18 18 0:ae3ee40d2079
19 19
20 20 New empty file:
21 21
22 22 $ hg import -d "1000000 0" -mempty - <<EOF
23 23 > diff --git a/empty b/empty
24 24 > new file mode 100644
25 25 > EOF
26 26 applying patch from stdin
27 27
28 28 $ hg tip -q
29 29 1:ab199dc869b5
30 30
31 31 $ hg locate empty
32 32 empty
33 33
34 34 chmod +x:
35 35
36 36 $ hg import -d "1000000 0" -msetx - <<EOF
37 37 > diff --git a/new b/new
38 38 > old mode 100644
39 39 > new mode 100755
40 40 > EOF
41 41 applying patch from stdin
42 42
43 43 #if execbit
44 44 $ hg tip -q
45 45 2:3a34410f282e
46 46 $ test -x new
47 47 $ hg rollback -q
48 48 #else
49 49 $ hg tip -q
50 50 1:ab199dc869b5
51 51 #endif
52 52
53 53 Copy and removing x bit:
54 54
55 55 $ hg import -f -d "1000000 0" -mcopy - <<EOF
56 56 > diff --git a/new b/copy
57 57 > old mode 100755
58 58 > new mode 100644
59 59 > similarity index 100%
60 60 > copy from new
61 61 > copy to copy
62 62 > diff --git a/new b/copyx
63 63 > similarity index 100%
64 64 > copy from new
65 65 > copy to copyx
66 66 > EOF
67 67 applying patch from stdin
68 68
69 69 $ test -f copy
70 70 #if execbit
71 71 $ test ! -x copy
72 72 $ test -x copyx
73 73 $ hg tip -q
74 74 2:21dfaae65c71
75 75 #else
76 76 $ hg tip -q
77 77 2:0efdaa8e3bf3
78 78 #endif
79 79
80 80 $ hg up -qCr1
81 81 $ hg rollback -q
82 82
83 83 Copy (like above but independent of execbit):
84 84
85 85 $ hg import -d "1000000 0" -mcopy - <<EOF
86 86 > diff --git a/new b/copy
87 87 > similarity index 100%
88 88 > copy from new
89 89 > copy to copy
90 90 > diff --git a/new b/copyx
91 91 > similarity index 100%
92 92 > copy from new
93 93 > copy to copyx
94 94 > EOF
95 95 applying patch from stdin
96 96
97 97 $ hg tip -q
98 98 2:0efdaa8e3bf3
99 99 $ test -f copy
100 100
101 101 $ cat copy
102 102 a
103 103
104 104 $ hg cat copy
105 105 a
106 106
107 107 Rename:
108 108
109 109 $ hg import -d "1000000 0" -mrename - <<EOF
110 110 > diff --git a/copy b/rename
111 111 > similarity index 100%
112 112 > rename from copy
113 113 > rename to rename
114 114 > EOF
115 115 applying patch from stdin
116 116
117 117 $ hg tip -q
118 118 3:b1f57753fad2
119 119
120 120 $ hg locate
121 121 copyx
122 122 empty
123 123 new
124 124 rename
125 125
126 126 Delete:
127 127
128 128 $ hg import -d "1000000 0" -mdelete - <<EOF
129 129 > diff --git a/copyx b/copyx
130 130 > deleted file mode 100755
131 131 > index 7898192..0000000
132 132 > --- a/copyx
133 133 > +++ /dev/null
134 134 > @@ -1 +0,0 @@
135 135 > -a
136 136 > EOF
137 137 applying patch from stdin
138 138
139 139 $ hg tip -q
140 140 4:1bd1da94b9b2
141 141
142 142 $ hg locate
143 143 empty
144 144 new
145 145 rename
146 146
147 147 $ test -f copyx
148 148 [1]
149 149
150 150 Regular diff:
151 151
152 152 $ hg import -d "1000000 0" -mregular - <<EOF
153 153 > diff --git a/rename b/rename
154 154 > index 7898192..72e1fe3 100644
155 155 > --- a/rename
156 156 > +++ b/rename
157 157 > @@ -1 +1,5 @@
158 158 > a
159 159 > +a
160 160 > +a
161 161 > +a
162 162 > +a
163 163 > EOF
164 164 applying patch from stdin
165 165
166 166 $ hg tip -q
167 167 5:46fe99cb3035
168 168
169 169 Copy and modify:
170 170
171 171 $ hg import -d "1000000 0" -mcopymod - <<EOF
172 172 > diff --git a/rename b/copy2
173 173 > similarity index 80%
174 174 > copy from rename
175 175 > copy to copy2
176 176 > index 72e1fe3..b53c148 100644
177 177 > --- a/rename
178 178 > +++ b/copy2
179 179 > @@ -1,5 +1,5 @@
180 180 > a
181 181 > a
182 182 > -a
183 183 > +b
184 184 > a
185 185 > a
186 186 > EOF
187 187 applying patch from stdin
188 188
189 189 $ hg tip -q
190 190 6:ffeb3197c12d
191 191
192 192 $ hg cat copy2
193 193 a
194 194 a
195 195 b
196 196 a
197 197 a
198 198
199 199 Rename and modify:
200 200
201 201 $ hg import -d "1000000 0" -mrenamemod - <<EOF
202 202 > diff --git a/copy2 b/rename2
203 203 > similarity index 80%
204 204 > rename from copy2
205 205 > rename to rename2
206 206 > index b53c148..8f81e29 100644
207 207 > --- a/copy2
208 208 > +++ b/rename2
209 209 > @@ -1,5 +1,5 @@
210 210 > a
211 211 > a
212 212 > b
213 213 > -a
214 214 > +c
215 215 > a
216 216 > EOF
217 217 applying patch from stdin
218 218
219 219 $ hg tip -q
220 220 7:401aede9e6bb
221 221
222 222 $ hg locate copy2
223 223 [1]
224 224 $ hg cat rename2
225 225 a
226 226 a
227 227 b
228 228 c
229 229 a
230 230
231 231 One file renamed multiple times:
232 232
233 233 $ hg import -d "1000000 0" -mmultirenames - <<EOF
234 234 > diff --git a/rename2 b/rename3
235 235 > rename from rename2
236 236 > rename to rename3
237 237 > diff --git a/rename2 b/rename3-2
238 238 > rename from rename2
239 239 > rename to rename3-2
240 240 > EOF
241 241 applying patch from stdin
242 242
243 243 $ hg tip -q
244 244 8:2ef727e684e8
245 245
246 246 $ hg log -vr. --template '{rev} {files} / {file_copies}\n'
247 247 8 rename2 rename3 rename3-2 / rename3 (rename2)rename3-2 (rename2)
248 248
249 249 $ hg locate rename2 rename3 rename3-2
250 250 rename3
251 251 rename3-2
252 252
253 253 $ hg cat rename3
254 254 a
255 255 a
256 256 b
257 257 c
258 258 a
259 259
260 260 $ hg cat rename3-2
261 261 a
262 262 a
263 263 b
264 264 c
265 265 a
266 266
267 267 $ echo foo > foo
268 268 $ hg add foo
269 269 $ hg ci -m 'add foo'
270 270
271 271 Binary files and regular patch hunks:
272 272
273 273 $ hg import -d "1000000 0" -m binaryregular - <<EOF
274 274 > diff --git a/binary b/binary
275 275 > new file mode 100644
276 276 > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
277 277 > GIT binary patch
278 278 > literal 4
279 279 > Lc\${NkU|;|M00aO5
280 280 >
281 281 > diff --git a/foo b/foo2
282 282 > rename from foo
283 283 > rename to foo2
284 284 > EOF
285 285 applying patch from stdin
286 286
287 287 $ hg tip -q
288 288 10:27377172366e
289 289
290 290 $ cat foo2
291 291 foo
292 292
293 293 $ hg manifest --debug | grep binary
294 294 045c85ba38952325e126c70962cc0f9d9077bc67 644 binary
295 295
296 296 Multiple binary files:
297 297
298 298 $ hg import -d "1000000 0" -m multibinary - <<EOF
299 299 > diff --git a/mbinary1 b/mbinary1
300 300 > new file mode 100644
301 301 > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
302 302 > GIT binary patch
303 303 > literal 4
304 304 > Lc\${NkU|;|M00aO5
305 305 >
306 306 > diff --git a/mbinary2 b/mbinary2
307 307 > new file mode 100644
308 308 > index 0000000000000000000000000000000000000000..112363ac1917b417ffbd7f376ca786a1e5fa7490
309 309 > GIT binary patch
310 310 > literal 5
311 311 > Mc\${NkU|\`?^000jF3jhEB
312 312 >
313 313 > EOF
314 314 applying patch from stdin
315 315
316 316 $ hg tip -q
317 317 11:18b73a84b4ab
318 318
319 319 $ hg manifest --debug | grep mbinary
320 320 045c85ba38952325e126c70962cc0f9d9077bc67 644 mbinary1
321 321 a874b471193996e7cb034bb301cac7bdaf3e3f46 644 mbinary2
322 322
323 323 Binary file and delta hunk (we build the patch using this sed hack to
324 324 avoid an unquoted ^, which check-code says breaks sh on Solaris):
325 325
326 326 $ sed 's/ caret /^/g;s/ dollarparen /$(/g' > quote-hack.patch <<'EOF'
327 327 > diff --git a/delta b/delta
328 328 > new file mode 100644
329 329 > index 0000000000000000000000000000000000000000..8c9b7831b231c2600843e303e66b521353a200b3
330 330 > GIT binary patch
331 331 > literal 3749
332 332 > zcmV;W4qEYvP)<h;3K|Lk000e1NJLTq006iE002D*0ssI2kt{U(0000PbVXQnQ*UN;
333 333 > zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU=M@d9MRCwC#oC!>o#}>x{(W-y~UN*tK
334 334 > z%A%sxiUy2Ys)0Vm#ueArYKoYqX;GuiqZpgirM6nCVoYk?YNAz3G~z;BZ~@~&OQEe4
335 335 > zmGvS5isFJI;Pd_7J+EKxyHZeu` caret t4r2>F;h-+VK3{_{WoGv8dSpFDYDrA%3UX03pt
336 336 > zOaVoi0*W#P6lDr1$`nwPDWE7*rhuYM0Y#YtiZTThWeO<D6i}2YpqR<%$s>bRRaI42
337 337 > zS3iFIxJ8Q=EnBv1Z7?pBw_bLjJb3V+tgP(Tty_2R-mR#p04x78n2n7MSOFyt4i1iv
338 338 > zjxH`PPEJmgD7U?IK&h;(EGQ@_DJc<@01=4fiNXHcKZ8LhZQ8T}E3U4tUS3}OrcgQW
339 339 > zWdX{K8#l7Ev&#$ysR)G#0*rC+<WGZ3?CtG4bm-ve>Dj$|_qJ`@D*stNP_AFUe&x!Q
340 340 > zJ9q9B7Z=ym)MyZ?Tg1ROunUYr81nV?B@!tYS~5_|%gfW#(_s<4UN1!Q?Dv8d>g#m6
341 341 > z%*@R2@bI2JdnzxQ!EDU`$eQY!tgI~Zn$prz;gaXNod5*5p(1Bz=P$qfvZ$y?dC@X~
342 342 > zlAD+NAKhB{=;6bMwzjqn>9mavvKOGd`s%A+fBiL>Q;xJWpa72C+}u{JTHUX>{~}Qj
343 343 > zUb%hyHgN~c?cBLjInvUALMD9g-aXt54ZL8AOCvXL-V6!~ijR*kEG$&Mv?!pE61OlI
344 344 > z8nzMSPE8F7bH|Py*RNl1VUCggq<V)>@_6gkEeiz7{rmTeuNTW6+KVS#0FG%IHf-3L
345 345 > zGiS21vn>WCCr+GLx caret !uNetzB6u3o(w6&1C2?_LW8ij$+$sZ*zZ`|US3H@8N~%&V%Z
346 346 > zAeA0HdhFS=$6|nzn3%YH`SN<>DQRO;Qc caret )dfdvA caret 5u`Xf;Zzu<ZQHgG?28V-#s<;T
347 347 > zzkh#LA)v7gpoE5ou3o*GoUUF%b#iht&kl9d0)><$FE1}ACr68;uCA`6DrGmz_U+rp
348 348 > zL>Rx;X_yhk$fP_yJrTCQ|NgsW0A<985g&c@k-NKly<>mgU8n||ZPPV<`SN8#%$+-T
349 349 > zfP$T!ou8jypFVwnzqhxyUvIxXd-wF~*U!ht=hCH1wzjqn9x#)IrhDa;S0JbK caret z_$W
350 350 > zd(8rX@;7|t*;GJ5h$SZ{v(}+UBEs$4w~?{@9%`_Z<P<kox5bMWuUWH(sF9hONgd$Q
351 351 > zunCgwT@1|CU9+;X caret 4z&|M~@yw23Ay50NFWn=FqF%yLZEUty;AT2??1oV@B)Nt))J7
352 352 > zh>{5j2@f7T=-an%L_`E)h;mZ4D_5>?7tjQtVPRo2XU-&;mX(!l-MSTJP4XWY82JAC
353 353 > z@57+y&!1=P{Mn{W8)-HzEsgAtd63}Cazc>O6vGb>51%@9DzbyI3?4j~$ijmT95_IS
354 354 > zS#r!LCDW%*4-O7CGnkr$xXR1RQ&UrA<CQt} caret 73NL%zk`)Jk!yxUAt-1r}ggLn-Zq}
355 355 > z*s){8pw68;i+kiG%CpBKYSJLLFyq&*U8}qDp+kpe&6<Vp(Z58%l#~>ZK?&s7y?b}i
356 356 > zuwcOgO%x-27A;y785zknl_{sU;E6v$8{pWmVS{KaJPpu`i;HP$#flY@u~Ua~K3%tN
357 357 > z-LhrNh{9SoHgDd%WXTc$$~Dq{?AWou3!H&?V8K{ caret {P9Ot5vecD?%1&-E-ntBFj87(
358 358 > zy5`QE%QRX7qcHC%1{Ua}M~}L6=`wQUNEQ=I;qc+ZMMXtK2T+0os;jEco;}OV9z1w3
359 359 > zARqv caret bm-85xnRCng3OT|MyVSmR3ND7 caret ?KaQGG! caret (aTbo1N;Nz;X3Q9FJbwK6`0?Yp
360 360 > zj*X2ac;Pw3!I2|JShDaF>-gJmzm1NLj){rk&o|$E caret WAsfrK=x&@B!`w7Hik81sPz4
361 361 > zuJTaiCppM>-+c!wPzcUw)5@?J4U-u|pJ~xbWUe-C+60k caret 7>9!)56DbjmA~`OJJ40v
362 362 > zu3hCA7eJXZWeN|1iJLu87$;+fS8+Kq6O`aT)*_x@sY#t7LxwoEcVw*)cWhhQW@l%!
363 363 > z{#Z=y+qcK@%z{p*D=8_Fcg278AnH3fI5;~yGu?9TscxXaaP*4$f<LIv! caret 5Lfr%vKg
364 364 > zpxmunH#%=+ICMvZA~wyNH%~eMl!-g caret R!cYJ#WmLq5N8viz#J%%LPtkO?V)tZ81cp>
365 365 > z{ALK?fNPePmd;289&M8Q3>YwgZX5GcGY&n>K1<x)!`;Qjg&}bb!Lrnl@xH#kS~VYE
366 366 > zpJmIJO`A3iy+Y3X`k>cY-@}Iw2Onq`=!ba3eATgs3yg3Wej=+P-Z8WF#w=RXvS@J3
367 367 > zEyhVTj-gO?kfDu1g9afo<RkPrYzG#_yF41IFxF%Ylg>9lx6<clPweR-b7Hn+r)e1l
368 368 > zO6c6FbNt@;;*w$z;N|H>h{czme)_4V6UC4hv**kX2@L caret Bgds dollarparen &P7M4dhfmWe)!=B
369 369 > zR3X=Y{P9N}p@-##@1ZNW1YbVaiP~D@8m&<dzEP&cO|87Ju#j*=;wH~Exr>i*Hpp&@
370 370 > z`9!Sj+O;byD~s8qZ>6QB8uv7Bpn&&?xe;;e<M4F8KEID&pT7QmqoSgq&06adp5T=U
371 371 > z6DH*4=AB7C1D9Amu?ia-wtxSAlmTEO96XHx)-+rKP;ip$pukuSJGW3P1aUmc2yo%)
372 372 > z&<t3F>d1X+1qzaag-%x+eKHx{?Afz3GBQSw9u0lw<mB+I#v11TKRpKWQS+lvVL7=u
373 373 > zHr6)1ynEF<i3kO6A8&ppPMo-F=PnWfXkSj@i*7J6C<F}wR?s(O0niC?t+6;+k}pPq
374 374 > zrok&TPU40rL0ZYDwenNrrmPZ`gjo@DEF`7 caret cKP||pUr;+r)hyn9O37=xA`3%Bj-ih
375 375 > z+1usk<%5G-y+R?tA`qY=)6&vNjL{P?QzHg%P%>`ZxP=QB%DHY6L26?36V_p caret {}n$q
376 376 > z3@9W=KmGI*Ng_Q#AzA%-z|Z caret |#oW(hkfgpuS$RKRhlrarX%efMMCs}GLChec5+y{6
377 377 > z1Qnxim_C-fmQuaAK_NUHUBV&;1c0V)wji<RcdZ*aAWTwyt>hVnlt caret asFCe0&a@tqp
378 378 > zEEy;$L}D$X6)wfQNl8gu6Z>oB3_RrP=gTyK2@@w#LbQfLNHj>Q&z(C5wUFhK+}0aV
379 379 > zSohlc=7K+spN<ctf}5KgKqNyJDNP9;LZd)nTE=9|6Xdr9%Hzk63-tL2c9FD*rsyYY
380 380 > z!}t+Yljq7-p$X;4_YL?6d;mdY3R##o1e%rlPxrsMh8|;sKTr~ caret QD#sw3&vS$FwlTk
381 381 > zp1#Gw!Qo-$LtvpXt#ApV0g) caret F=qFB`VB!W297x=$mr<$>rco3v$QKih_xN!k6;M=@
382 382 > zCr?gDNQj7tm@;JwD;Ty&NlBSCYZk(b3dZeN8D4h2{r20dSFc7;(>E&r`s=TVtzpB4
383 383 > zk+ caret N&zCAiRns(?p6iBlk9v&h{1ve(FNtc)td51M>)TkXhc6{>5C)`fS$&)A1*CP1%
384 384 > zld+peue4aYbg3C0!+4mu+}vE caret j_feX+ZijvffBI7Ofh#RZ*U3<3J5(+nfRCzexqQ5
385 385 > zgM&##Y4Dd{e%ZKjqrbm@|Ni}l4jo!AqtFynj3Xsd$o caret ?yV4$|UQ(j&UWCH>M=o_&N
386 386 > zmclXc3i|Q#<;#EoG>~V}4unTHbUK}u=y4;rA3S&vzC3 caret aJP!&D4RvvGfoyo(>C>la
387 387 > zijP<=v>X{3Ne&2BXo}DV8l0V-jdv`$am0ubG{Wuh%CTd|l9Q7m;G&|U@#Dvbhlj(d
388 388 > zg6W{3ATxYt#T?)3;SmIgOP4M|Dki~I_TX7SxP0x}wI~DQI7Lhm2BI7gph(aPIFAd;
389 389 > zQ&UsF`Q{rOz+z=87c5v%@5u~d6dWV5OlX`oH3cAH&UlvsZUEo(Q(P|lKs17rXvaiU
390 390 > zQcj}IEufi1+Bnh6&(EhF{7O3vLHp`jjlp0J<M1kh$+$2xGm~Zk7OY7(q=&Rdhq*RG
391 391 > zwrmcd5MnP}xByB_)P@{J>DR9x6;`cUwPM8z){yooNiXPOc9_{W-gtwxE5TUg0vJk6
392 392 > zO#JGruV&1cL6VGK2?+_YQr4`+EY8;Sm$9U$uuGRN=uj3k7?O9b+R~J7t_y*K64ZnI
393 393 > zM+{aE<b(v?vSmw;9zFP!aE266zHIhlmdI@ caret xa6o2jwdRk54a$>pcRbC29ZyG!Cfdp
394 394 > zutFf`Q`vljgo!(wHf=)F#m2_MIuj;L(2ja2YsQRX+rswV{d<H`Ar;(@%aNa9VPU8Z
395 395 > z;tq*`y}dm#NDJHKlV}uTIm!_vAq5E7!X-p{P=Z=Sh668>PuVS1*6e}OwOiMc;u3OQ
396 396 > z@Bs)w3=lzfKoufH$SFuPG@uZ4NOnM#+=8LnQ2Q4zUd+nM+OT26;lqbN{P07dhH{jH
397 397 > zManE8 caret dLms-Q2;1kB<*Q1a3f8kZr;xX=!Qro@`~@xN*Qj>gx;i;0Z24!~i2uLb`}v
398 398 > zA?R$|wvC+m caret Ups=*(4lDh*=UN8{5h(A?p#D caret 2N$8u4Z55!q?ZAh(iEEng9_Zi>IgO
399 399 > z#~**JC8hE4@n{hO&8btT5F*?nC_%LhA3i)PDhh-pB_&1wGrDIl caret *=8x3n&;akBf caret -
400 400 > zJd&86kq$%%907v caret tgWoQdwI`|oNK%VvU~S#C<o caret F?6c48?Cjj#-4P<>HFD%&|Ni~t
401 401 > zKJ(|#H`$<5W+6ZkBb213rXonKZLB+X> caret L}J@W6osP3piLD_5?R!`S}*{xLBzFiL4@
402 402 > zX+}l{`A%?f@T5tT%ztu60p;)be`fWC`tP@WpO=?cpf8Xuf1OSj6d3f@Ki(ovDYq%0
403 403 > z{4ZSe`kOay5@=lAT!}vFzxyemC{sXDrhuYM0Y#ZI1r%ipD9W11{w=@&xgJ}t2x;ep
404 404 > P00000NkvXXu0mjfZ5|Er
405 405 >
406 406 > literal 0
407 407 > HcmV?d00001
408 408 >
409 409 > EOF
410 410 $ hg import -d "1000000 0" -m delta quote-hack.patch
411 411 applying quote-hack.patch
412 412 $ rm quote-hack.patch
413 413
414 414 $ hg manifest --debug | grep delta
415 415 9600f98bb60ce732634d126aaa4ac1ec959c573e 644 delta
416 416
417 417 $ hg import -d "1000000 0" -m delta - <<'EOF'
418 418 > diff --git a/delta b/delta
419 419 > index 8c9b7831b231c2600843e303e66b521353a200b3..0021dd95bc0dba53c39ce81377126d43731d68df 100644
420 420 > GIT binary patch
421 421 > delta 49
422 422 > zcmZ1~yHs|=21Z8J$r~9bFdA-lVv=EEw4WT$qRf2QSa5SIOAHI6(&k4T8H|kLo4vWB
423 423 > FSO9ZT4bA`n
424 424 >
425 425 > delta 49
426 426 > zcmV-10M7rV9i<(xumJ(}ld%Di0Xefm0vrMXpOaq%BLm9I%d>?9Tm%6Vv*HM70RcC&
427 427 > HOA1;9yU-AD
428 428 >
429 429 > EOF
430 430 applying patch from stdin
431 431
432 432 $ hg manifest --debug | grep delta
433 433 56094bbea136dcf8dbd4088f6af469bde1a98b75 644 delta
434 434
435 435 Filenames with spaces:
436 436
437 437 $ sed 's,EOL$,,g' <<EOF | hg import -d "1000000 0" -m spaces -
438 438 > diff --git a/foo bar b/foo bar
439 439 > new file mode 100644
440 440 > index 0000000..257cc56
441 441 > --- /dev/null
442 442 > +++ b/foo bar EOL
443 443 > @@ -0,0 +1 @@
444 444 > +foo
445 445 > EOF
446 446 applying patch from stdin
447 447
448 448 $ hg tip -q
449 449 14:4b79479c9a6d
450 450
451 451 $ cat "foo bar"
452 452 foo
453 453
454 454 Copy then modify the original file:
455 455
456 456 $ hg import -d "1000000 0" -m copy-mod-orig - <<EOF
457 457 > diff --git a/foo2 b/foo2
458 458 > index 257cc56..fe08ec6 100644
459 459 > --- a/foo2
460 460 > +++ b/foo2
461 461 > @@ -1 +1,2 @@
462 462 > foo
463 463 > +new line
464 464 > diff --git a/foo2 b/foo3
465 465 > similarity index 100%
466 466 > copy from foo2
467 467 > copy to foo3
468 468 > EOF
469 469 applying patch from stdin
470 470
471 471 $ hg tip -q
472 472 15:9cbe44af4ae9
473 473
474 474 $ cat foo3
475 475 foo
476 476
477 477 Move text file and patch as binary
478 478
479 479 $ echo a > text2
480 480 $ hg ci -Am0
481 481 adding text2
482 482 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
483 483 > diff --git a/text2 b/binary2
484 484 > rename from text2
485 485 > rename to binary2
486 486 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
487 487 > GIT binary patch
488 488 > literal 5
489 489 > Mc$`b*O5$Pw00T?_*Z=?k
490 490 >
491 491 > EOF
492 492 applying patch from stdin
493 493
494 494 $ cat binary2
495 495 a
496 496 b
497 497 \x00 (no-eol) (esc)
498 498
499 499 $ hg st --copies --change .
500 500 A binary2
501 501 text2
502 502 R text2
503 503
504 504 Invalid base85 content
505 505
506 506 $ hg rollback
507 507 repository tip rolled back to revision 16 (undo import)
508 508 working directory now based on revision 16
509 509 $ hg revert -aq
510 510 $ hg import -d "1000000 0" -m invalid-binary - <<"EOF"
511 511 > diff --git a/text2 b/binary2
512 512 > rename from text2
513 513 > rename to binary2
514 514 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
515 515 > GIT binary patch
516 516 > literal 5
517 517 > Mc$`b*O.$Pw00T?_*Z=?k
518 518 >
519 519 > EOF
520 520 applying patch from stdin
521 521 abort: could not decode "binary2" binary patch: bad base85 character at position 6
522 522 [255]
523 523
524 524 $ hg revert -aq
525 525 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
526 526 > diff --git a/text2 b/binary2
527 527 > rename from text2
528 528 > rename to binary2
529 529 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
530 530 > GIT binary patch
531 531 > literal 6
532 532 > Mc$`b*O5$Pw00T?_*Z=?k
533 533 >
534 534 > EOF
535 535 applying patch from stdin
536 536 abort: "binary2" length is 5 bytes, should be 6
537 537 [255]
538 538
539 539 $ hg revert -aq
540 540 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
541 541 > diff --git a/text2 b/binary2
542 542 > rename from text2
543 543 > rename to binary2
544 544 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
545 545 > GIT binary patch
546 546 > Mc$`b*O5$Pw00T?_*Z=?k
547 547 >
548 548 > EOF
549 549 applying patch from stdin
550 550 abort: could not extract "binary2" binary data
551 551 [255]
552 552
553 553 Simulate a copy/paste turning LF into CRLF (issue2870)
554 554
555 555 $ hg revert -aq
556 556 $ cat > binary.diff <<"EOF"
557 557 > diff --git a/text2 b/binary2
558 558 > rename from text2
559 559 > rename to binary2
560 560 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
561 561 > GIT binary patch
562 562 > literal 5
563 563 > Mc$`b*O5$Pw00T?_*Z=?k
564 564 >
565 565 > EOF
566 566 >>> fp = open('binary.diff', 'rb')
567 567 >>> data = fp.read()
568 568 >>> fp.close()
569 569 >>> open('binary.diff', 'wb').write(data.replace(b'\n', b'\r\n')) and None
570 570 $ rm binary2
571 571 $ hg import --no-commit binary.diff
572 572 applying binary.diff
573 573
574 574 $ cd ..
575 575
576 576 Consecutive import with renames (issue2459)
577 577
578 578 $ hg init issue2459
579 579 $ cd issue2459
580 580 $ hg import --no-commit --force - <<EOF
581 581 > diff --git a/a b/a
582 582 > new file mode 100644
583 583 > EOF
584 584 applying patch from stdin
585 585 $ hg import --no-commit --force - <<EOF
586 586 > diff --git a/a b/b
587 587 > rename from a
588 588 > rename to b
589 589 > EOF
590 590 applying patch from stdin
591 591 a has not been committed yet, so no copy data will be stored for b.
592 592 $ hg debugstate
593 593 a 0 -1 unset b
594 594 $ hg ci -m done
595 595 $ cd ..
596 596
597 597 Renames and strip
598 598
599 599 $ hg init renameandstrip
600 600 $ cd renameandstrip
601 601 $ echo a > a
602 602 $ hg ci -Am adda
603 603 adding a
604 604 $ hg import --no-commit -p2 - <<EOF
605 605 > diff --git a/foo/a b/foo/b
606 606 > rename from foo/a
607 607 > rename to foo/b
608 608 > EOF
609 609 applying patch from stdin
610 610 $ hg st --copies
611 611 A b
612 612 a
613 613 R a
614 614
615 615 Prefix with strip, renames, creates etc
616 616
617 617 $ hg revert -aC
618 forgetting b
618 619 undeleting a
619 forgetting b
620 620 $ rm b
621 621 $ mkdir -p dir/dir2
622 622 $ echo b > dir/dir2/b
623 623 $ echo c > dir/dir2/c
624 624 $ echo d > dir/d
625 625 $ hg ci -Am addbcd
626 626 adding dir/d
627 627 adding dir/dir2/b
628 628 adding dir/dir2/c
629 629
630 630 prefix '.' is the same as no prefix
631 631 $ hg import --no-commit --prefix . - <<EOF
632 632 > diff --git a/dir/a b/dir/a
633 633 > --- /dev/null
634 634 > +++ b/dir/a
635 635 > @@ -0,0 +1 @@
636 636 > +aaaa
637 637 > diff --git a/dir/d b/dir/d
638 638 > --- a/dir/d
639 639 > +++ b/dir/d
640 640 > @@ -1,1 +1,2 @@
641 641 > d
642 642 > +dddd
643 643 > EOF
644 644 applying patch from stdin
645 645 $ cat dir/a
646 646 aaaa
647 647 $ cat dir/d
648 648 d
649 649 dddd
650 650 $ hg revert -aC
651 651 forgetting dir/a
652 652 reverting dir/d
653 653 $ rm dir/a
654 654
655 655 prefix with default strip
656 656 $ hg import --no-commit --prefix dir/ - <<EOF
657 657 > diff --git a/a b/a
658 658 > --- /dev/null
659 659 > +++ b/a
660 660 > @@ -0,0 +1 @@
661 661 > +aaa
662 662 > diff --git a/d b/d
663 663 > --- a/d
664 664 > +++ b/d
665 665 > @@ -1,1 +1,2 @@
666 666 > d
667 667 > +dd
668 668 > EOF
669 669 applying patch from stdin
670 670 $ cat dir/a
671 671 aaa
672 672 $ cat dir/d
673 673 d
674 674 dd
675 675 $ hg revert -aC
676 676 forgetting dir/a
677 677 reverting dir/d
678 678 $ rm dir/a
679 679 (test that prefixes are relative to the cwd)
680 680 $ mkdir tmpdir
681 681 $ cd tmpdir
682 682 $ hg import --no-commit -p2 --prefix ../dir/ - <<EOF
683 683 > diff --git a/foo/a b/foo/a
684 684 > new file mode 100644
685 685 > --- /dev/null
686 686 > +++ b/foo/a
687 687 > @@ -0,0 +1 @@
688 688 > +a
689 689 > diff --git a/foo/dir2/b b/foo/dir2/b2
690 690 > rename from foo/dir2/b
691 691 > rename to foo/dir2/b2
692 692 > diff --git a/foo/dir2/c b/foo/dir2/c
693 693 > --- a/foo/dir2/c
694 694 > +++ b/foo/dir2/c
695 695 > @@ -0,0 +1 @@
696 696 > +cc
697 697 > diff --git a/foo/d b/foo/d
698 698 > deleted file mode 100644
699 699 > --- a/foo/d
700 700 > +++ /dev/null
701 701 > @@ -1,1 +0,0 @@
702 702 > -d
703 703 > EOF
704 704 applying patch from stdin
705 705 $ hg st --copies
706 706 M dir/dir2/c
707 707 A dir/a
708 708 A dir/dir2/b2
709 709 dir/dir2/b
710 710 R dir/d
711 711 R dir/dir2/b
712 712 $ cd ..
713 713
714 714 Renames, similarity and git diff
715 715
716 716 $ hg revert -aC
717 717 forgetting dir/a
718 forgetting dir/dir2/b2
719 reverting dir/dir2/c
718 720 undeleting dir/d
719 721 undeleting dir/dir2/b
720 forgetting dir/dir2/b2
721 reverting dir/dir2/c
722 722 $ rm dir/a dir/dir2/b2
723 723 $ hg import --similarity 90 --no-commit - <<EOF
724 724 > diff --git a/a b/b
725 725 > rename from a
726 726 > rename to b
727 727 > EOF
728 728 applying patch from stdin
729 729 $ hg st --copies
730 730 A b
731 731 a
732 732 R a
733 733 $ cd ..
734 734
735 735 Pure copy with existing destination
736 736
737 737 $ hg init copytoexisting
738 738 $ cd copytoexisting
739 739 $ echo a > a
740 740 $ echo b > b
741 741 $ hg ci -Am add
742 742 adding a
743 743 adding b
744 744 $ hg import --no-commit - <<EOF
745 745 > diff --git a/a b/b
746 746 > copy from a
747 747 > copy to b
748 748 > EOF
749 749 applying patch from stdin
750 750 abort: cannot create b: destination already exists
751 751 [255]
752 752 $ cat b
753 753 b
754 754
755 755 Copy and changes with existing destination
756 756
757 757 $ hg import --no-commit - <<EOF
758 758 > diff --git a/a b/b
759 759 > copy from a
760 760 > copy to b
761 761 > --- a/a
762 762 > +++ b/b
763 763 > @@ -1,1 +1,2 @@
764 764 > a
765 765 > +b
766 766 > EOF
767 767 applying patch from stdin
768 768 cannot create b: destination already exists
769 769 1 out of 1 hunks FAILED -- saving rejects to file b.rej
770 770 abort: patch failed to apply
771 771 [255]
772 772 $ cat b
773 773 b
774 774
775 775 #if symlink
776 776
777 777 $ ln -s b linkb
778 778 $ hg add linkb
779 779 $ hg ci -m addlinkb
780 780 $ hg import --no-commit - <<EOF
781 781 > diff --git a/linkb b/linkb
782 782 > deleted file mode 120000
783 783 > --- a/linkb
784 784 > +++ /dev/null
785 785 > @@ -1,1 +0,0 @@
786 786 > -badhunk
787 787 > \ No newline at end of file
788 788 > EOF
789 789 applying patch from stdin
790 790 patching file linkb
791 791 Hunk #1 FAILED at 0
792 792 1 out of 1 hunks FAILED -- saving rejects to file linkb.rej
793 793 abort: patch failed to apply
794 794 [255]
795 795 $ hg st
796 796 ? b.rej
797 797 ? linkb.rej
798 798
799 799 #endif
800 800
801 801 Test corner case involving copies and multiple hunks (issue3384)
802 802
803 803 $ hg revert -qa
804 804 $ hg import --no-commit - <<EOF
805 805 > diff --git a/a b/c
806 806 > copy from a
807 807 > copy to c
808 808 > --- a/a
809 809 > +++ b/c
810 810 > @@ -1,1 +1,2 @@
811 811 > a
812 812 > +a
813 813 > @@ -2,1 +2,2 @@
814 814 > a
815 815 > +a
816 816 > diff --git a/a b/a
817 817 > --- a/a
818 818 > +++ b/a
819 819 > @@ -1,1 +1,2 @@
820 820 > a
821 821 > +b
822 822 > EOF
823 823 applying patch from stdin
824 824
825 825 Test email metadata
826 826
827 827 $ hg revert -qa
828 828 $ hg --encoding utf-8 import - <<EOF
829 829 > From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
830 830 > Subject: [PATCH] =?UTF-8?q?=C5=A7=E2=82=AC=C3=9F=E1=B9=AA?=
831 831 >
832 832 > diff --git a/a b/a
833 833 > --- a/a
834 834 > +++ b/a
835 835 > @@ -1,1 +1,2 @@
836 836 > a
837 837 > +a
838 838 > EOF
839 839 applying patch from stdin
840 840 $ hg --encoding utf-8 log -r .
841 841 changeset: *:* (glob)
842 842 tag: tip
843 843 user: Rapha\xc3\xabl Hertzog <hertzog@debian.org> (esc)
844 844 date: * (glob)
845 845 summary: \xc5\xa7\xe2\x82\xac\xc3\x9f\xe1\xb9\xaa (esc)
846 846
847 847
848 848 $ cd ..
@@ -1,1978 +1,1978 b''
1 1 $ hg init a
2 2 $ mkdir a/d1
3 3 $ mkdir a/d1/d2
4 4 $ echo line 1 > a/a
5 5 $ echo line 1 > a/d1/d2/a
6 6 $ hg --cwd a ci -Ama
7 7 adding a
8 8 adding d1/d2/a
9 9
10 10 $ echo line 2 >> a/a
11 11 $ hg --cwd a ci -u someone -d '1 0' -m'second change'
12 12
13 13 import with no args:
14 14
15 15 $ hg --cwd a import
16 16 abort: need at least one patch to import
17 17 [255]
18 18
19 19 generate patches for the test
20 20
21 21 $ hg --cwd a export tip > exported-tip.patch
22 22 $ hg --cwd a diff -r0:1 > diffed-tip.patch
23 23
24 24
25 25 import exported patch
26 26 (this also tests that editor is not invoked, if the patch contains the
27 27 commit message and '--edit' is not specified)
28 28
29 29 $ hg clone -r0 a b
30 30 adding changesets
31 31 adding manifests
32 32 adding file changes
33 33 added 1 changesets with 2 changes to 2 files
34 34 new changesets 80971e65b431
35 35 updating to branch default
36 36 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 37 $ HGEDITOR=cat hg --cwd b import ../exported-tip.patch
38 38 applying ../exported-tip.patch
39 39
40 40 message and committer and date should be same
41 41
42 42 $ hg --cwd b tip
43 43 changeset: 1:1d4bd90af0e4
44 44 tag: tip
45 45 user: someone
46 46 date: Thu Jan 01 00:00:01 1970 +0000
47 47 summary: second change
48 48
49 49 $ rm -r b
50 50
51 51
52 52 import exported patch with external patcher
53 53 (this also tests that editor is invoked, if the '--edit' is specified,
54 54 regardless of the commit message in the patch)
55 55
56 56 $ cat > dummypatch.py <<EOF
57 57 > from __future__ import print_function
58 58 > print('patching file a')
59 59 > open('a', 'wb').write(b'line2\n')
60 60 > EOF
61 61 $ hg clone -r0 a b
62 62 adding changesets
63 63 adding manifests
64 64 adding file changes
65 65 added 1 changesets with 2 changes to 2 files
66 66 new changesets 80971e65b431
67 67 updating to branch default
68 68 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 69 $ HGEDITOR=cat hg --config ui.patch="$PYTHON ../dummypatch.py" --cwd b import --edit ../exported-tip.patch
70 70 applying ../exported-tip.patch
71 71 second change
72 72
73 73
74 74 HG: Enter commit message. Lines beginning with 'HG:' are removed.
75 75 HG: Leave message empty to abort commit.
76 76 HG: --
77 77 HG: user: someone
78 78 HG: branch 'default'
79 79 HG: changed a
80 80 $ cat b/a
81 81 line2
82 82 $ rm -r b
83 83
84 84
85 85 import of plain diff should fail without message
86 86 (this also tests that editor is invoked, if the patch doesn't contain
87 87 the commit message, regardless of '--edit')
88 88
89 89 $ hg clone -r0 a b
90 90 adding changesets
91 91 adding manifests
92 92 adding file changes
93 93 added 1 changesets with 2 changes to 2 files
94 94 new changesets 80971e65b431
95 95 updating to branch default
96 96 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 97 $ cat > $TESTTMP/editor.sh <<EOF
98 98 > env | grep HGEDITFORM
99 99 > cat \$1
100 100 > EOF
101 101 $ HGEDITOR="sh $TESTTMP/editor.sh" hg --cwd b import ../diffed-tip.patch
102 102 applying ../diffed-tip.patch
103 103 HGEDITFORM=import.normal.normal
104 104
105 105
106 106 HG: Enter commit message. Lines beginning with 'HG:' are removed.
107 107 HG: Leave message empty to abort commit.
108 108 HG: --
109 109 HG: user: test
110 110 HG: branch 'default'
111 111 HG: changed a
112 112 abort: empty commit message
113 113 [255]
114 114
115 115 Test avoiding editor invocation at applying the patch with --exact,
116 116 even if commit message is empty
117 117
118 118 $ echo a >> b/a
119 119 $ hg --cwd b commit -m ' '
120 120 $ hg --cwd b tip -T "{node}\n"
121 121 d8804f3f5396d800812f579c8452796a5993bdb2
122 122 $ hg --cwd b export -o ../empty-log.diff .
123 123 $ hg --cwd b update -q -C ".^1"
124 124 $ hg --cwd b --config extensions.strip= strip -q tip
125 125 $ HGEDITOR=cat hg --cwd b import --exact ../empty-log.diff
126 126 applying ../empty-log.diff
127 127 $ hg --cwd b tip -T "{node}\n"
128 128 d8804f3f5396d800812f579c8452796a5993bdb2
129 129
130 130 $ rm -r b
131 131
132 132
133 133 import of plain diff should be ok with message
134 134
135 135 $ hg clone -r0 a b
136 136 adding changesets
137 137 adding manifests
138 138 adding file changes
139 139 added 1 changesets with 2 changes to 2 files
140 140 new changesets 80971e65b431
141 141 updating to branch default
142 142 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 143 $ hg --cwd b import -mpatch ../diffed-tip.patch
144 144 applying ../diffed-tip.patch
145 145 $ rm -r b
146 146
147 147
148 148 import of plain diff with specific date and user
149 149 (this also tests that editor is not invoked, if
150 150 '--message'/'--logfile' is specified and '--edit' is not)
151 151
152 152 $ hg clone -r0 a b
153 153 adding changesets
154 154 adding manifests
155 155 adding file changes
156 156 added 1 changesets with 2 changes to 2 files
157 157 new changesets 80971e65b431
158 158 updating to branch default
159 159 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 160 $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
161 161 applying ../diffed-tip.patch
162 162 $ hg -R b tip -pv
163 163 changeset: 1:ca68f19f3a40
164 164 tag: tip
165 165 user: user@nowhere.net
166 166 date: Thu Jan 01 00:00:01 1970 +0000
167 167 files: a
168 168 description:
169 169 patch
170 170
171 171
172 172 diff -r 80971e65b431 -r ca68f19f3a40 a
173 173 --- a/a Thu Jan 01 00:00:00 1970 +0000
174 174 +++ b/a Thu Jan 01 00:00:01 1970 +0000
175 175 @@ -1,1 +1,2 @@
176 176 line 1
177 177 +line 2
178 178
179 179 $ rm -r b
180 180
181 181
182 182 import of plain diff should be ok with --no-commit
183 183 (this also tests that editor is not invoked, if '--no-commit' is
184 184 specified, regardless of '--edit')
185 185
186 186 $ hg clone -r0 a b
187 187 adding changesets
188 188 adding manifests
189 189 adding file changes
190 190 added 1 changesets with 2 changes to 2 files
191 191 new changesets 80971e65b431
192 192 updating to branch default
193 193 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 194 $ HGEDITOR=cat hg --cwd b import --no-commit --edit ../diffed-tip.patch
195 195 applying ../diffed-tip.patch
196 196 $ hg --cwd b diff --nodates
197 197 diff -r 80971e65b431 a
198 198 --- a/a
199 199 +++ b/a
200 200 @@ -1,1 +1,2 @@
201 201 line 1
202 202 +line 2
203 203 $ rm -r b
204 204
205 205
206 206 import of malformed plain diff should fail
207 207
208 208 $ hg clone -r0 a b
209 209 adding changesets
210 210 adding manifests
211 211 adding file changes
212 212 added 1 changesets with 2 changes to 2 files
213 213 new changesets 80971e65b431
214 214 updating to branch default
215 215 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 216 $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
217 217 $ hg --cwd b import -mpatch ../broken.patch
218 218 applying ../broken.patch
219 219 abort: bad hunk #1
220 220 [255]
221 221 $ rm -r b
222 222
223 223
224 224 hg -R repo import
225 225 put the clone in a subdir - having a directory named "a"
226 226 used to hide a bug.
227 227
228 228 $ mkdir dir
229 229 $ hg clone -r0 a dir/b
230 230 adding changesets
231 231 adding manifests
232 232 adding file changes
233 233 added 1 changesets with 2 changes to 2 files
234 234 new changesets 80971e65b431
235 235 updating to branch default
236 236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 237 $ cd dir
238 238 $ hg -R b import ../exported-tip.patch
239 239 applying ../exported-tip.patch
240 240 $ cd ..
241 241 $ rm -r dir
242 242
243 243
244 244 import from stdin
245 245
246 246 $ hg clone -r0 a b
247 247 adding changesets
248 248 adding manifests
249 249 adding file changes
250 250 added 1 changesets with 2 changes to 2 files
251 251 new changesets 80971e65b431
252 252 updating to branch default
253 253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 254 $ hg --cwd b import - < exported-tip.patch
255 255 applying patch from stdin
256 256 $ rm -r b
257 257
258 258
259 259 import two patches in one stream
260 260
261 261 $ hg init b
262 262 $ hg --cwd a export 0:tip | hg --cwd b import -
263 263 applying patch from stdin
264 264 $ hg --cwd a id
265 265 1d4bd90af0e4 tip
266 266 $ hg --cwd b id
267 267 1d4bd90af0e4 tip
268 268 $ rm -r b
269 269
270 270
271 271 override commit message
272 272
273 273 $ hg clone -r0 a b
274 274 adding changesets
275 275 adding manifests
276 276 adding file changes
277 277 added 1 changesets with 2 changes to 2 files
278 278 new changesets 80971e65b431
279 279 updating to branch default
280 280 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 281 $ hg --cwd b import -m 'override' - < exported-tip.patch
282 282 applying patch from stdin
283 283 $ hg --cwd b tip | grep override
284 284 summary: override
285 285 $ rm -r b
286 286
287 287 $ cat > mkmsg.py <<EOF
288 288 > import email.message, sys
289 289 > msg = email.message.Message()
290 290 > patch = open(sys.argv[1], 'rb').read()
291 291 > msg.set_payload(b'email commit message\n' + patch)
292 292 > msg['Subject'] = 'email patch'
293 293 > msg['From'] = 'email patcher'
294 294 > open(sys.argv[2], 'wb').write(bytes(msg))
295 295 > EOF
296 296
297 297
298 298 plain diff in email, subject, message body
299 299
300 300 $ hg clone -r0 a b
301 301 adding changesets
302 302 adding manifests
303 303 adding file changes
304 304 added 1 changesets with 2 changes to 2 files
305 305 new changesets 80971e65b431
306 306 updating to branch default
307 307 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 308 $ $PYTHON mkmsg.py diffed-tip.patch msg.patch
309 309 $ hg --cwd b import ../msg.patch
310 310 applying ../msg.patch
311 311 $ hg --cwd b tip | grep email
312 312 user: email patcher
313 313 summary: email patch
314 314 $ rm -r b
315 315
316 316
317 317 plain diff in email, no subject, message body
318 318
319 319 $ hg clone -r0 a b
320 320 adding changesets
321 321 adding manifests
322 322 adding file changes
323 323 added 1 changesets with 2 changes to 2 files
324 324 new changesets 80971e65b431
325 325 updating to branch default
326 326 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
327 327 $ grep -v '^Subject:' msg.patch | hg --cwd b import -
328 328 applying patch from stdin
329 329 $ rm -r b
330 330
331 331
332 332 plain diff in email, subject, no message body
333 333
334 334 $ hg clone -r0 a b
335 335 adding changesets
336 336 adding manifests
337 337 adding file changes
338 338 added 1 changesets with 2 changes to 2 files
339 339 new changesets 80971e65b431
340 340 updating to branch default
341 341 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 342 $ grep -v '^email ' msg.patch | hg --cwd b import -
343 343 applying patch from stdin
344 344 $ rm -r b
345 345
346 346
347 347 plain diff in email, no subject, no message body, should fail
348 348
349 349 $ hg clone -r0 a b
350 350 adding changesets
351 351 adding manifests
352 352 adding file changes
353 353 added 1 changesets with 2 changes to 2 files
354 354 new changesets 80971e65b431
355 355 updating to branch default
356 356 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 357 $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
358 358 applying patch from stdin
359 359 abort: empty commit message
360 360 [255]
361 361 $ rm -r b
362 362
363 363
364 364 hg export in email, should use patch header
365 365
366 366 $ hg clone -r0 a b
367 367 adding changesets
368 368 adding manifests
369 369 adding file changes
370 370 added 1 changesets with 2 changes to 2 files
371 371 new changesets 80971e65b431
372 372 updating to branch default
373 373 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 374 $ $PYTHON mkmsg.py exported-tip.patch msg.patch
375 375 $ cat msg.patch | hg --cwd b import -
376 376 applying patch from stdin
377 377 $ hg --cwd b tip | grep second
378 378 summary: second change
379 379 $ rm -r b
380 380
381 381
382 382 subject: duplicate detection, removal of [PATCH]
383 383 The '---' tests the gitsendmail handling without proper mail headers
384 384
385 385 $ cat > mkmsg2.py <<EOF
386 386 > import email.message, sys
387 387 > msg = email.message.Message()
388 388 > patch = open(sys.argv[1], 'rb').read()
389 389 > msg.set_payload(b'email patch\n\nnext line\n---\n' + patch)
390 390 > msg['Subject'] = '[PATCH] email patch'
391 391 > msg['From'] = 'email patcher'
392 392 > open(sys.argv[2], 'wb').write(bytes(msg))
393 393 > EOF
394 394
395 395
396 396 plain diff in email, [PATCH] subject, message body with subject
397 397
398 398 $ hg clone -r0 a b
399 399 adding changesets
400 400 adding manifests
401 401 adding file changes
402 402 added 1 changesets with 2 changes to 2 files
403 403 new changesets 80971e65b431
404 404 updating to branch default
405 405 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 406 $ $PYTHON mkmsg2.py diffed-tip.patch msg.patch
407 407 $ cat msg.patch | hg --cwd b import -
408 408 applying patch from stdin
409 409 $ hg --cwd b tip --template '{desc}\n'
410 410 email patch
411 411
412 412 next line
413 413 $ rm -r b
414 414
415 415
416 416 Issue963: Parent of working dir incorrect after import of multiple
417 417 patches and rollback
418 418
419 419 We weren't backing up the correct dirstate file when importing many
420 420 patches: import patch1 patch2; rollback
421 421
422 422 $ echo line 3 >> a/a
423 423 $ hg --cwd a ci -m'third change'
424 424 $ hg --cwd a export -o '../patch%R' 1 2
425 425 $ hg clone -qr0 a b
426 426 $ hg --cwd b parents --template 'parent: {rev}\n'
427 427 parent: 0
428 428 $ hg --cwd b import -v ../patch1 ../patch2
429 429 applying ../patch1
430 430 patching file a
431 431 committing files:
432 432 a
433 433 committing manifest
434 434 committing changelog
435 435 created 1d4bd90af0e4
436 436 applying ../patch2
437 437 patching file a
438 438 committing files:
439 439 a
440 440 committing manifest
441 441 committing changelog
442 442 created 6d019af21222
443 443 $ hg --cwd b rollback
444 444 repository tip rolled back to revision 0 (undo import)
445 445 working directory now based on revision 0
446 446 $ hg --cwd b parents --template 'parent: {rev}\n'
447 447 parent: 0
448 448
449 449 Test that "hg rollback" doesn't restore dirstate to one at the
450 450 beginning of the rolled back transaction in not-"parent-gone" case.
451 451
452 452 invoking pretxncommit hook will cause marking '.hg/dirstate' as a file
453 453 to be restored when rolling back, after DirstateTransactionPlan (see wiki
454 454 page for detail).
455 455
456 456 $ hg --cwd b branch -q foobar
457 457 $ hg --cwd b commit -m foobar
458 458 $ hg --cwd b update 0 -q
459 459 $ hg --cwd b import ../patch1 ../patch2 --config hooks.pretxncommit=true
460 460 applying ../patch1
461 461 applying ../patch2
462 462 $ hg --cwd b update -q 1
463 463 $ hg --cwd b rollback -q
464 464 $ hg --cwd b parents --template 'parent: {rev}\n'
465 465 parent: 1
466 466
467 467 $ hg --cwd b update -q -C 0
468 468 $ hg --cwd b --config extensions.strip= strip -q 1
469 469
470 470 Test visibility of in-memory dirstate changes inside transaction to
471 471 external process
472 472
473 473 $ echo foo > a/foo
474 474 $ hg --cwd a commit -A -m 'adding foo' foo
475 475 $ hg --cwd a export -o '../patch%R' 3
476 476
477 477 $ cat > $TESTTMP/checkvisibility.sh <<EOF
478 478 > echo "===="
479 479 > hg parents --template "VISIBLE {rev}:{node|short}\n"
480 480 > hg status -amr
481 481 > # test that pending changes are hidden
482 482 > unset HG_PENDING
483 483 > hg parents --template "ACTUAL {rev}:{node|short}\n"
484 484 > hg status -amr
485 485 > echo "===="
486 486 > EOF
487 487
488 488 == test visibility to external editor
489 489
490 490 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
491 491 ====
492 492 VISIBLE 0:80971e65b431
493 493 ACTUAL 0:80971e65b431
494 494 ====
495 495
496 496 $ HGEDITOR="sh $TESTTMP/checkvisibility.sh" hg --cwd b import -v --edit ../patch1 ../patch2 ../patch3
497 497 applying ../patch1
498 498 patching file a
499 499 ====
500 500 VISIBLE 0:80971e65b431
501 501 M a
502 502 ACTUAL 0:80971e65b431
503 503 M a
504 504 ====
505 505 committing files:
506 506 a
507 507 committing manifest
508 508 committing changelog
509 509 created 1d4bd90af0e4
510 510 applying ../patch2
511 511 patching file a
512 512 ====
513 513 VISIBLE 1:1d4bd90af0e4
514 514 M a
515 515 ACTUAL 0:80971e65b431
516 516 M a
517 517 ====
518 518 committing files:
519 519 a
520 520 committing manifest
521 521 committing changelog
522 522 created 6d019af21222
523 523 applying ../patch3
524 524 patching file foo
525 525 adding foo
526 526 ====
527 527 VISIBLE 2:6d019af21222
528 528 A foo
529 529 ACTUAL 0:80971e65b431
530 530 M a
531 531 ====
532 532 committing files:
533 533 foo
534 534 committing manifest
535 535 committing changelog
536 536 created 55e3f75b2378
537 537
538 538 $ hg --cwd b rollback -q
539 539
540 540 (content of file "a" is already changed and it should be recognized as
541 541 "M", even though dirstate is restored to one before "hg import")
542 542
543 543 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
544 544 ====
545 545 VISIBLE 0:80971e65b431
546 546 M a
547 547 ACTUAL 0:80971e65b431
548 548 M a
549 549 ====
550 550 $ hg --cwd b revert --no-backup a
551 551 $ rm -f b/foo
552 552
553 553 == test visibility to precommit external hook
554 554
555 555 $ cat >> b/.hg/hgrc <<EOF
556 556 > [hooks]
557 557 > precommit.visibility = sh $TESTTMP/checkvisibility.sh
558 558 > EOF
559 559
560 560 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
561 561 ====
562 562 VISIBLE 0:80971e65b431
563 563 ACTUAL 0:80971e65b431
564 564 ====
565 565
566 566 $ hg --cwd b import ../patch1 ../patch2 ../patch3
567 567 applying ../patch1
568 568 ====
569 569 VISIBLE 0:80971e65b431
570 570 M a
571 571 ACTUAL 0:80971e65b431
572 572 M a
573 573 ====
574 574 applying ../patch2
575 575 ====
576 576 VISIBLE 1:1d4bd90af0e4
577 577 M a
578 578 ACTUAL 0:80971e65b431
579 579 M a
580 580 ====
581 581 applying ../patch3
582 582 ====
583 583 VISIBLE 2:6d019af21222
584 584 A foo
585 585 ACTUAL 0:80971e65b431
586 586 M a
587 587 ====
588 588
589 589 $ hg --cwd b rollback -q
590 590 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
591 591 ====
592 592 VISIBLE 0:80971e65b431
593 593 M a
594 594 ACTUAL 0:80971e65b431
595 595 M a
596 596 ====
597 597 $ hg --cwd b revert --no-backup a
598 598 $ rm -f b/foo
599 599
600 600 $ cat >> b/.hg/hgrc <<EOF
601 601 > [hooks]
602 602 > precommit.visibility =
603 603 > EOF
604 604
605 605 == test visibility to pretxncommit external hook
606 606
607 607 $ cat >> b/.hg/hgrc <<EOF
608 608 > [hooks]
609 609 > pretxncommit.visibility = sh $TESTTMP/checkvisibility.sh
610 610 > EOF
611 611
612 612 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
613 613 ====
614 614 VISIBLE 0:80971e65b431
615 615 ACTUAL 0:80971e65b431
616 616 ====
617 617
618 618 $ hg --cwd b import ../patch1 ../patch2 ../patch3
619 619 applying ../patch1
620 620 ====
621 621 VISIBLE 0:80971e65b431
622 622 M a
623 623 ACTUAL 0:80971e65b431
624 624 M a
625 625 ====
626 626 applying ../patch2
627 627 ====
628 628 VISIBLE 1:1d4bd90af0e4
629 629 M a
630 630 ACTUAL 0:80971e65b431
631 631 M a
632 632 ====
633 633 applying ../patch3
634 634 ====
635 635 VISIBLE 2:6d019af21222
636 636 A foo
637 637 ACTUAL 0:80971e65b431
638 638 M a
639 639 ====
640 640
641 641 $ hg --cwd b rollback -q
642 642 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
643 643 ====
644 644 VISIBLE 0:80971e65b431
645 645 M a
646 646 ACTUAL 0:80971e65b431
647 647 M a
648 648 ====
649 649 $ hg --cwd b revert --no-backup a
650 650 $ rm -f b/foo
651 651
652 652 $ cat >> b/.hg/hgrc <<EOF
653 653 > [hooks]
654 654 > pretxncommit.visibility =
655 655 > EOF
656 656
657 657 $ rm -r b
658 658
659 659
660 660 importing a patch in a subdirectory failed at the commit stage
661 661
662 662 $ echo line 2 >> a/d1/d2/a
663 663 $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
664 664
665 665 hg import in a subdirectory
666 666
667 667 $ hg clone -r0 a b
668 668 adding changesets
669 669 adding manifests
670 670 adding file changes
671 671 added 1 changesets with 2 changes to 2 files
672 672 new changesets 80971e65b431
673 673 updating to branch default
674 674 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
675 675 $ hg --cwd a export tip > tmp
676 676 $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
677 677 $ dir=`pwd`
678 678 $ cd b/d1/d2 2>&1 > /dev/null
679 679 $ hg import ../../../subdir-tip.patch
680 680 applying ../../../subdir-tip.patch
681 681 $ cd "$dir"
682 682
683 683 message should be 'subdir change'
684 684 committer should be 'someoneelse'
685 685
686 686 $ hg --cwd b tip
687 687 changeset: 1:3577f5aea227
688 688 tag: tip
689 689 user: someoneelse
690 690 date: Thu Jan 01 00:00:01 1970 +0000
691 691 summary: subdir change
692 692
693 693
694 694 should be empty
695 695
696 696 $ hg --cwd b status
697 697
698 698
699 699 Test fuzziness (ambiguous patch location, fuzz=2)
700 700
701 701 $ hg init fuzzy
702 702 $ cd fuzzy
703 703 $ echo line1 > a
704 704 $ echo line0 >> a
705 705 $ echo line3 >> a
706 706 $ hg ci -Am adda
707 707 adding a
708 708 $ echo line1 > a
709 709 $ echo line2 >> a
710 710 $ echo line0 >> a
711 711 $ echo line3 >> a
712 712 $ hg ci -m change a
713 713 $ hg export tip > fuzzy-tip.patch
714 714 $ hg up -C 0
715 715 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
716 716 $ echo line1 > a
717 717 $ echo line0 >> a
718 718 $ echo line1 >> a
719 719 $ echo line0 >> a
720 720 $ hg ci -m brancha
721 721 created new head
722 722 $ hg import --config patch.fuzz=0 -v fuzzy-tip.patch
723 723 applying fuzzy-tip.patch
724 724 patching file a
725 725 Hunk #1 FAILED at 0
726 726 1 out of 1 hunks FAILED -- saving rejects to file a.rej
727 727 abort: patch failed to apply
728 728 [255]
729 729 $ hg import --no-commit -v fuzzy-tip.patch
730 730 applying fuzzy-tip.patch
731 731 patching file a
732 732 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
733 733 applied to working directory
734 734 $ hg revert -a
735 735 reverting a
736 736
737 737 Test --exact failure
738 738
739 739 $ sed 's/^# Parent .*/# Parent '"`hg log -r. -T '{node}'`"'/' \
740 740 > < fuzzy-tip.patch > fuzzy-reparent.patch
741 741 $ hg import --config patch.fuzz=0 --exact fuzzy-reparent.patch
742 742 applying fuzzy-reparent.patch
743 743 patching file a
744 744 Hunk #1 FAILED at 0
745 745 1 out of 1 hunks FAILED -- saving rejects to file a.rej
746 746 abort: patch failed to apply
747 747 [255]
748 748 $ hg up -qC
749 749 $ hg import --config patch.fuzz=2 --exact fuzzy-reparent.patch
750 750 applying fuzzy-reparent.patch
751 751 patching file a
752 752 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
753 753 transaction abort!
754 754 rollback completed
755 755 abort: patch is damaged or loses information
756 756 [255]
757 757 $ hg up -qC
758 758
759 759 $ grep '^#' fuzzy-tip.patch > empty.patch
760 760 $ cat <<'EOF' >> empty.patch
761 761 > change
762 762 >
763 763 > diff -r bb90ef1daa38 -r 0e9b883378d4 a
764 764 > --- a/a Thu Jan 01 00:00:00 1970 +0000
765 765 > --- b/a Thu Jan 01 00:00:00 1970 +0000
766 766 > EOF
767 767 $ hg import --exact empty.patch
768 768 applying empty.patch
769 769 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
770 770 abort: patch is damaged or loses information
771 771 [255]
772 772 $ hg up -qC
773 773
774 774 import with --no-commit should have written .hg/last-message.txt
775 775
776 776 $ cat .hg/last-message.txt
777 777 change (no-eol)
778 778
779 779
780 780 test fuzziness with eol=auto
781 781
782 782 $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
783 783 applying fuzzy-tip.patch
784 784 patching file a
785 785 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
786 786 applied to working directory
787 787 $ cd ..
788 788
789 789
790 790 Test hunk touching empty files (issue906)
791 791
792 792 $ hg init empty
793 793 $ cd empty
794 794 $ touch a
795 795 $ touch b1
796 796 $ touch c1
797 797 $ echo d > d
798 798 $ hg ci -Am init
799 799 adding a
800 800 adding b1
801 801 adding c1
802 802 adding d
803 803 $ echo a > a
804 804 $ echo b > b1
805 805 $ hg mv b1 b2
806 806 $ echo c > c1
807 807 $ hg copy c1 c2
808 808 $ rm d
809 809 $ touch d
810 810 $ hg diff --git
811 811 diff --git a/a b/a
812 812 --- a/a
813 813 +++ b/a
814 814 @@ -0,0 +1,1 @@
815 815 +a
816 816 diff --git a/b1 b/b2
817 817 rename from b1
818 818 rename to b2
819 819 --- a/b1
820 820 +++ b/b2
821 821 @@ -0,0 +1,1 @@
822 822 +b
823 823 diff --git a/c1 b/c1
824 824 --- a/c1
825 825 +++ b/c1
826 826 @@ -0,0 +1,1 @@
827 827 +c
828 828 diff --git a/c1 b/c2
829 829 copy from c1
830 830 copy to c2
831 831 --- a/c1
832 832 +++ b/c2
833 833 @@ -0,0 +1,1 @@
834 834 +c
835 835 diff --git a/d b/d
836 836 --- a/d
837 837 +++ b/d
838 838 @@ -1,1 +0,0 @@
839 839 -d
840 840 $ hg ci -m empty
841 841 $ hg export --git tip > empty.diff
842 842 $ hg up -C 0
843 843 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
844 844 $ hg import empty.diff
845 845 applying empty.diff
846 846 $ for name in a b1 b2 c1 c2 d; do
847 847 > echo % $name file
848 848 > test -f $name && cat $name
849 849 > done
850 850 % a file
851 851 a
852 852 % b1 file
853 853 % b2 file
854 854 b
855 855 % c1 file
856 856 c
857 857 % c2 file
858 858 c
859 859 % d file
860 860 $ cd ..
861 861
862 862
863 863 Test importing a patch ending with a binary file removal
864 864
865 865 $ hg init binaryremoval
866 866 $ cd binaryremoval
867 867 $ echo a > a
868 868 $ $PYTHON -c "open('b', 'wb').write(b'a\x00b')"
869 869 $ hg ci -Am addall
870 870 adding a
871 871 adding b
872 872 $ hg rm a
873 873 $ hg rm b
874 874 $ hg st
875 875 R a
876 876 R b
877 877 $ hg ci -m remove
878 878 $ hg export --git . > remove.diff
879 879 $ cat remove.diff | grep git
880 880 diff --git a/a b/a
881 881 diff --git a/b b/b
882 882 $ hg up -C 0
883 883 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
884 884 $ hg import remove.diff
885 885 applying remove.diff
886 886 $ hg manifest
887 887 $ cd ..
888 888
889 889
890 890 Issue927: test update+rename with common name
891 891
892 892 $ hg init t
893 893 $ cd t
894 894 $ touch a
895 895 $ hg ci -Am t
896 896 adding a
897 897 $ echo a > a
898 898
899 899 Here, bfile.startswith(afile)
900 900
901 901 $ hg copy a a2
902 902 $ hg ci -m copya
903 903 $ hg export --git tip > copy.diff
904 904 $ hg up -C 0
905 905 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
906 906 $ hg import copy.diff
907 907 applying copy.diff
908 908
909 909 a should contain an 'a'
910 910
911 911 $ cat a
912 912 a
913 913
914 914 and a2 should have duplicated it
915 915
916 916 $ cat a2
917 917 a
918 918 $ cd ..
919 919
920 920
921 921 test -p0
922 922
923 923 $ hg init p0
924 924 $ cd p0
925 925 $ echo a > a
926 926 $ hg ci -Am t
927 927 adding a
928 928 $ hg import -p foo
929 929 abort: invalid value 'foo' for option -p, expected int
930 930 [255]
931 931 $ hg import -p0 - << EOF
932 932 > foobar
933 933 > --- a Sat Apr 12 22:43:58 2008 -0400
934 934 > +++ a Sat Apr 12 22:44:05 2008 -0400
935 935 > @@ -1,1 +1,1 @@
936 936 > -a
937 937 > +bb
938 938 > EOF
939 939 applying patch from stdin
940 940 $ hg status
941 941 $ cat a
942 942 bb
943 943
944 944 test --prefix
945 945
946 946 $ mkdir -p dir/dir2
947 947 $ echo b > dir/dir2/b
948 948 $ hg ci -Am b
949 949 adding dir/dir2/b
950 950 $ hg import -p2 --prefix dir - << EOF
951 951 > foobar
952 952 > --- drop1/drop2/dir2/b
953 953 > +++ drop1/drop2/dir2/b
954 954 > @@ -1,1 +1,1 @@
955 955 > -b
956 956 > +cc
957 957 > EOF
958 958 applying patch from stdin
959 959 $ hg status
960 960 $ cat dir/dir2/b
961 961 cc
962 962 $ cd ..
963 963
964 964
965 965 test paths outside repo root
966 966
967 967 $ mkdir outside
968 968 $ touch outside/foo
969 969 $ hg init inside
970 970 $ cd inside
971 971 $ hg import - <<EOF
972 972 > diff --git a/a b/b
973 973 > rename from ../outside/foo
974 974 > rename to bar
975 975 > EOF
976 976 applying patch from stdin
977 977 abort: path contains illegal component: ../outside/foo
978 978 [255]
979 979 $ cd ..
980 980
981 981
982 982 test import with similarity and git and strip (issue295 et al.)
983 983
984 984 $ hg init sim
985 985 $ cd sim
986 986 $ echo 'this is a test' > a
987 987 $ hg ci -Ama
988 988 adding a
989 989 $ cat > ../rename.diff <<EOF
990 990 > diff --git a/foo/a b/foo/a
991 991 > deleted file mode 100644
992 992 > --- a/foo/a
993 993 > +++ /dev/null
994 994 > @@ -1,1 +0,0 @@
995 995 > -this is a test
996 996 > diff --git a/foo/b b/foo/b
997 997 > new file mode 100644
998 998 > --- /dev/null
999 999 > +++ b/foo/b
1000 1000 > @@ -0,0 +1,2 @@
1001 1001 > +this is a test
1002 1002 > +foo
1003 1003 > EOF
1004 1004 $ hg import --no-commit -v -s 1 ../rename.diff -p2
1005 1005 applying ../rename.diff
1006 1006 patching file a
1007 1007 patching file b
1008 1008 adding b
1009 1009 recording removal of a as rename to b (88% similar)
1010 1010 applied to working directory
1011 1011 $ echo 'mod b' > b
1012 1012 $ hg st -C
1013 1013 A b
1014 1014 a
1015 1015 R a
1016 1016 $ hg revert -a
1017 forgetting b
1017 1018 undeleting a
1018 forgetting b
1019 1019 $ cat b
1020 1020 mod b
1021 1021 $ rm b
1022 1022 $ hg import --no-commit -v -s 100 ../rename.diff -p2
1023 1023 applying ../rename.diff
1024 1024 patching file a
1025 1025 patching file b
1026 1026 adding b
1027 1027 applied to working directory
1028 1028 $ hg st -C
1029 1029 A b
1030 1030 R a
1031 1031 $ cd ..
1032 1032
1033 1033
1034 1034 Issue1495: add empty file from the end of patch
1035 1035
1036 1036 $ hg init addemptyend
1037 1037 $ cd addemptyend
1038 1038 $ touch a
1039 1039 $ hg addremove
1040 1040 adding a
1041 1041 $ hg ci -m "commit"
1042 1042 $ cat > a.patch <<EOF
1043 1043 > add a, b
1044 1044 > diff --git a/a b/a
1045 1045 > --- a/a
1046 1046 > +++ b/a
1047 1047 > @@ -0,0 +1,1 @@
1048 1048 > +a
1049 1049 > diff --git a/b b/b
1050 1050 > new file mode 100644
1051 1051 > EOF
1052 1052 $ hg import --no-commit a.patch
1053 1053 applying a.patch
1054 1054
1055 1055 apply a good patch followed by an empty patch (mainly to ensure
1056 1056 that dirstate is *not* updated when import crashes)
1057 1057 $ hg update -q -C .
1058 1058 $ rm b
1059 1059 $ touch empty.patch
1060 1060 $ hg import a.patch empty.patch
1061 1061 applying a.patch
1062 1062 applying empty.patch
1063 1063 transaction abort!
1064 1064 rollback completed
1065 1065 abort: empty.patch: no diffs found
1066 1066 [255]
1067 1067 $ hg tip --template '{rev} {desc|firstline}\n'
1068 1068 0 commit
1069 1069 $ hg -q status
1070 1070 M a
1071 1071 $ cd ..
1072 1072
1073 1073 create file when source is not /dev/null
1074 1074
1075 1075 $ cat > create.patch <<EOF
1076 1076 > diff -Naur proj-orig/foo proj-new/foo
1077 1077 > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
1078 1078 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
1079 1079 > @@ -0,0 +1,1 @@
1080 1080 > +a
1081 1081 > EOF
1082 1082
1083 1083 some people have patches like the following too
1084 1084
1085 1085 $ cat > create2.patch <<EOF
1086 1086 > diff -Naur proj-orig/foo proj-new/foo
1087 1087 > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
1088 1088 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
1089 1089 > @@ -0,0 +1,1 @@
1090 1090 > +a
1091 1091 > EOF
1092 1092 $ hg init oddcreate
1093 1093 $ cd oddcreate
1094 1094 $ hg import --no-commit ../create.patch
1095 1095 applying ../create.patch
1096 1096 $ cat foo
1097 1097 a
1098 1098 $ rm foo
1099 1099 $ hg revert foo
1100 1100 $ hg import --no-commit ../create2.patch
1101 1101 applying ../create2.patch
1102 1102 $ cat foo
1103 1103 a
1104 1104
1105 1105 $ cd ..
1106 1106
1107 1107 Issue1859: first line mistaken for email headers
1108 1108
1109 1109 $ hg init emailconfusion
1110 1110 $ cd emailconfusion
1111 1111 $ cat > a.patch <<EOF
1112 1112 > module: summary
1113 1113 >
1114 1114 > description
1115 1115 >
1116 1116 >
1117 1117 > diff -r 000000000000 -r 9b4c1e343b55 test.txt
1118 1118 > --- /dev/null
1119 1119 > +++ b/a
1120 1120 > @@ -0,0 +1,1 @@
1121 1121 > +a
1122 1122 > EOF
1123 1123 $ hg import -d '0 0' a.patch
1124 1124 applying a.patch
1125 1125 $ hg parents -v
1126 1126 changeset: 0:5a681217c0ad
1127 1127 tag: tip
1128 1128 user: test
1129 1129 date: Thu Jan 01 00:00:00 1970 +0000
1130 1130 files: a
1131 1131 description:
1132 1132 module: summary
1133 1133
1134 1134 description
1135 1135
1136 1136
1137 1137 $ cd ..
1138 1138
1139 1139
1140 1140 in commit message
1141 1141
1142 1142 $ hg init commitconfusion
1143 1143 $ cd commitconfusion
1144 1144 $ cat > a.patch <<EOF
1145 1145 > module: summary
1146 1146 >
1147 1147 > --- description
1148 1148 >
1149 1149 > diff --git a/a b/a
1150 1150 > new file mode 100644
1151 1151 > --- /dev/null
1152 1152 > +++ b/a
1153 1153 > @@ -0,0 +1,1 @@
1154 1154 > +a
1155 1155 > EOF
1156 1156 > hg import -d '0 0' a.patch
1157 1157 > hg parents -v
1158 1158 > cd ..
1159 1159 >
1160 1160 > echo '% tricky header splitting'
1161 1161 > cat > trickyheaders.patch <<EOF
1162 1162 > From: User A <user@a>
1163 1163 > Subject: [PATCH] from: tricky!
1164 1164 >
1165 1165 > # HG changeset patch
1166 1166 > # User User B
1167 1167 > # Date 1266264441 18000
1168 1168 > # Branch stable
1169 1169 > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
1170 1170 > # Parent 0000000000000000000000000000000000000000
1171 1171 > from: tricky!
1172 1172 >
1173 1173 > That is not a header.
1174 1174 >
1175 1175 > diff -r 000000000000 -r f2be6a1170ac foo
1176 1176 > --- /dev/null
1177 1177 > +++ b/foo
1178 1178 > @@ -0,0 +1,1 @@
1179 1179 > +foo
1180 1180 > EOF
1181 1181 applying a.patch
1182 1182 changeset: 0:f34d9187897d
1183 1183 tag: tip
1184 1184 user: test
1185 1185 date: Thu Jan 01 00:00:00 1970 +0000
1186 1186 files: a
1187 1187 description:
1188 1188 module: summary
1189 1189
1190 1190
1191 1191 % tricky header splitting
1192 1192
1193 1193 $ hg init trickyheaders
1194 1194 $ cd trickyheaders
1195 1195 $ hg import -d '0 0' ../trickyheaders.patch
1196 1196 applying ../trickyheaders.patch
1197 1197 $ hg export --git tip
1198 1198 # HG changeset patch
1199 1199 # User User B
1200 1200 # Date 0 0
1201 1201 # Thu Jan 01 00:00:00 1970 +0000
1202 1202 # Node ID eb56ab91903632294ac504838508cb370c0901d2
1203 1203 # Parent 0000000000000000000000000000000000000000
1204 1204 from: tricky!
1205 1205
1206 1206 That is not a header.
1207 1207
1208 1208 diff --git a/foo b/foo
1209 1209 new file mode 100644
1210 1210 --- /dev/null
1211 1211 +++ b/foo
1212 1212 @@ -0,0 +1,1 @@
1213 1213 +foo
1214 1214 $ cd ..
1215 1215
1216 1216
1217 1217 Issue2102: hg export and hg import speak different languages
1218 1218
1219 1219 $ hg init issue2102
1220 1220 $ cd issue2102
1221 1221 $ mkdir -p src/cmd/gc
1222 1222 $ touch src/cmd/gc/mksys.bash
1223 1223 $ hg ci -Am init
1224 1224 adding src/cmd/gc/mksys.bash
1225 1225 $ hg import - <<EOF
1226 1226 > # HG changeset patch
1227 1227 > # User Rob Pike
1228 1228 > # Date 1216685449 25200
1229 1229 > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
1230 1230 > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
1231 1231 > help management of empty pkg and lib directories in perforce
1232 1232 >
1233 1233 > R=gri
1234 1234 > DELTA=4 (4 added, 0 deleted, 0 changed)
1235 1235 > OCL=13328
1236 1236 > CL=13328
1237 1237 >
1238 1238 > diff --git a/lib/place-holder b/lib/place-holder
1239 1239 > new file mode 100644
1240 1240 > --- /dev/null
1241 1241 > +++ b/lib/place-holder
1242 1242 > @@ -0,0 +1,2 @@
1243 1243 > +perforce does not maintain empty directories.
1244 1244 > +this file helps.
1245 1245 > diff --git a/pkg/place-holder b/pkg/place-holder
1246 1246 > new file mode 100644
1247 1247 > --- /dev/null
1248 1248 > +++ b/pkg/place-holder
1249 1249 > @@ -0,0 +1,2 @@
1250 1250 > +perforce does not maintain empty directories.
1251 1251 > +this file helps.
1252 1252 > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1253 1253 > old mode 100644
1254 1254 > new mode 100755
1255 1255 > EOF
1256 1256 applying patch from stdin
1257 1257
1258 1258 #if execbit
1259 1259
1260 1260 $ hg sum
1261 1261 parent: 1:d59915696727 tip
1262 1262 help management of empty pkg and lib directories in perforce
1263 1263 branch: default
1264 1264 commit: (clean)
1265 1265 update: (current)
1266 1266 phases: 2 draft
1267 1267
1268 1268 $ hg diff --git -c tip
1269 1269 diff --git a/lib/place-holder b/lib/place-holder
1270 1270 new file mode 100644
1271 1271 --- /dev/null
1272 1272 +++ b/lib/place-holder
1273 1273 @@ -0,0 +1,2 @@
1274 1274 +perforce does not maintain empty directories.
1275 1275 +this file helps.
1276 1276 diff --git a/pkg/place-holder b/pkg/place-holder
1277 1277 new file mode 100644
1278 1278 --- /dev/null
1279 1279 +++ b/pkg/place-holder
1280 1280 @@ -0,0 +1,2 @@
1281 1281 +perforce does not maintain empty directories.
1282 1282 +this file helps.
1283 1283 diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1284 1284 old mode 100644
1285 1285 new mode 100755
1286 1286
1287 1287 #else
1288 1288
1289 1289 $ hg sum
1290 1290 parent: 1:28f089cc9ccc tip
1291 1291 help management of empty pkg and lib directories in perforce
1292 1292 branch: default
1293 1293 commit: (clean)
1294 1294 update: (current)
1295 1295 phases: 2 draft
1296 1296
1297 1297 $ hg diff --git -c tip
1298 1298 diff --git a/lib/place-holder b/lib/place-holder
1299 1299 new file mode 100644
1300 1300 --- /dev/null
1301 1301 +++ b/lib/place-holder
1302 1302 @@ -0,0 +1,2 @@
1303 1303 +perforce does not maintain empty directories.
1304 1304 +this file helps.
1305 1305 diff --git a/pkg/place-holder b/pkg/place-holder
1306 1306 new file mode 100644
1307 1307 --- /dev/null
1308 1308 +++ b/pkg/place-holder
1309 1309 @@ -0,0 +1,2 @@
1310 1310 +perforce does not maintain empty directories.
1311 1311 +this file helps.
1312 1312
1313 1313 /* The mode change for mksys.bash is missing here, because on platforms */
1314 1314 /* that don't support execbits, mode changes in patches are ignored when */
1315 1315 /* they are imported. This is obviously also the reason for why the hash */
1316 1316 /* in the created changeset is different to the one you see above the */
1317 1317 /* #else clause */
1318 1318
1319 1319 #endif
1320 1320 $ cd ..
1321 1321
1322 1322
1323 1323 diff lines looking like headers
1324 1324
1325 1325 $ hg init difflineslikeheaders
1326 1326 $ cd difflineslikeheaders
1327 1327 $ echo a >a
1328 1328 $ echo b >b
1329 1329 $ echo c >c
1330 1330 $ hg ci -Am1
1331 1331 adding a
1332 1332 adding b
1333 1333 adding c
1334 1334
1335 1335 $ echo "key: value" >>a
1336 1336 $ echo "key: value" >>b
1337 1337 $ echo "foo" >>c
1338 1338 $ hg ci -m2
1339 1339
1340 1340 $ hg up -C 0
1341 1341 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1342 1342 $ hg diff --git -c1 >want
1343 1343 $ hg diff -c1 | hg import --no-commit -
1344 1344 applying patch from stdin
1345 1345 $ hg diff --git >have
1346 1346 $ diff want have
1347 1347 $ cd ..
1348 1348
1349 1349 import a unified diff with no lines of context (diff -U0)
1350 1350
1351 1351 $ hg init diffzero
1352 1352 $ cd diffzero
1353 1353 $ cat > f << EOF
1354 1354 > c2
1355 1355 > c4
1356 1356 > c5
1357 1357 > EOF
1358 1358 $ hg commit -Am0
1359 1359 adding f
1360 1360
1361 1361 $ hg import --no-commit - << EOF
1362 1362 > # HG changeset patch
1363 1363 > # User test
1364 1364 > # Date 0 0
1365 1365 > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
1366 1366 > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
1367 1367 > 1
1368 1368 > diff -r 8679a12a975b -r f4974ab632f3 f
1369 1369 > --- a/f Thu Jan 01 00:00:00 1970 +0000
1370 1370 > +++ b/f Thu Jan 01 00:00:00 1970 +0000
1371 1371 > @@ -0,0 +1,1 @@
1372 1372 > +c1
1373 1373 > @@ -1,0 +3,1 @@
1374 1374 > +c3
1375 1375 > @@ -3,1 +4,0 @@
1376 1376 > -c5
1377 1377 > EOF
1378 1378 applying patch from stdin
1379 1379
1380 1380 $ cat f
1381 1381 c1
1382 1382 c2
1383 1383 c3
1384 1384 c4
1385 1385
1386 1386 $ cd ..
1387 1387
1388 1388 commit message that looks like a diff header (issue1879)
1389 1389
1390 1390 $ hg init headerlikemsg
1391 1391 $ cd headerlikemsg
1392 1392 $ touch empty
1393 1393 $ echo nonempty >> nonempty
1394 1394 $ hg ci -qAl - <<EOF
1395 1395 > blah blah
1396 1396 > diff blah
1397 1397 > blah blah
1398 1398 > EOF
1399 1399 $ hg --config diff.git=1 log -pv
1400 1400 changeset: 0:c6ef204ef767
1401 1401 tag: tip
1402 1402 user: test
1403 1403 date: Thu Jan 01 00:00:00 1970 +0000
1404 1404 files: empty nonempty
1405 1405 description:
1406 1406 blah blah
1407 1407 diff blah
1408 1408 blah blah
1409 1409
1410 1410
1411 1411 diff --git a/empty b/empty
1412 1412 new file mode 100644
1413 1413 diff --git a/nonempty b/nonempty
1414 1414 new file mode 100644
1415 1415 --- /dev/null
1416 1416 +++ b/nonempty
1417 1417 @@ -0,0 +1,1 @@
1418 1418 +nonempty
1419 1419
1420 1420
1421 1421 (without --git, empty file is lost, but commit message should be preserved)
1422 1422
1423 1423 $ hg init plain
1424 1424 $ hg export 0 | hg -R plain import -
1425 1425 applying patch from stdin
1426 1426 $ hg --config diff.git=1 -R plain log -pv
1427 1427 changeset: 0:60a2d231e71f
1428 1428 tag: tip
1429 1429 user: test
1430 1430 date: Thu Jan 01 00:00:00 1970 +0000
1431 1431 files: nonempty
1432 1432 description:
1433 1433 blah blah
1434 1434 diff blah
1435 1435 blah blah
1436 1436
1437 1437
1438 1438 diff --git a/nonempty b/nonempty
1439 1439 new file mode 100644
1440 1440 --- /dev/null
1441 1441 +++ b/nonempty
1442 1442 @@ -0,0 +1,1 @@
1443 1443 +nonempty
1444 1444
1445 1445
1446 1446 (with --git, patch contents should be fully preserved)
1447 1447
1448 1448 $ hg init git
1449 1449 $ hg --config diff.git=1 export 0 | hg -R git import -
1450 1450 applying patch from stdin
1451 1451 $ hg --config diff.git=1 -R git log -pv
1452 1452 changeset: 0:c6ef204ef767
1453 1453 tag: tip
1454 1454 user: test
1455 1455 date: Thu Jan 01 00:00:00 1970 +0000
1456 1456 files: empty nonempty
1457 1457 description:
1458 1458 blah blah
1459 1459 diff blah
1460 1460 blah blah
1461 1461
1462 1462
1463 1463 diff --git a/empty b/empty
1464 1464 new file mode 100644
1465 1465 diff --git a/nonempty b/nonempty
1466 1466 new file mode 100644
1467 1467 --- /dev/null
1468 1468 +++ b/nonempty
1469 1469 @@ -0,0 +1,1 @@
1470 1470 +nonempty
1471 1471
1472 1472
1473 1473 $ cd ..
1474 1474
1475 1475 no segfault while importing a unified diff which start line is zero but chunk
1476 1476 size is non-zero
1477 1477
1478 1478 $ hg init startlinezero
1479 1479 $ cd startlinezero
1480 1480 $ echo foo > foo
1481 1481 $ hg commit -Amfoo
1482 1482 adding foo
1483 1483
1484 1484 $ hg import --no-commit - << EOF
1485 1485 > diff a/foo b/foo
1486 1486 > --- a/foo
1487 1487 > +++ b/foo
1488 1488 > @@ -0,1 +0,1 @@
1489 1489 > foo
1490 1490 > EOF
1491 1491 applying patch from stdin
1492 1492
1493 1493 $ cd ..
1494 1494
1495 1495 Test corner case involving fuzz and skew
1496 1496
1497 1497 $ hg init morecornercases
1498 1498 $ cd morecornercases
1499 1499
1500 1500 $ cat > 01-no-context-beginning-of-file.diff <<EOF
1501 1501 > diff --git a/a b/a
1502 1502 > --- a/a
1503 1503 > +++ b/a
1504 1504 > @@ -1,0 +1,1 @@
1505 1505 > +line
1506 1506 > EOF
1507 1507
1508 1508 $ cat > 02-no-context-middle-of-file.diff <<EOF
1509 1509 > diff --git a/a b/a
1510 1510 > --- a/a
1511 1511 > +++ b/a
1512 1512 > @@ -1,1 +1,1 @@
1513 1513 > -2
1514 1514 > +add some skew
1515 1515 > @@ -2,0 +2,1 @@
1516 1516 > +line
1517 1517 > EOF
1518 1518
1519 1519 $ cat > 03-no-context-end-of-file.diff <<EOF
1520 1520 > diff --git a/a b/a
1521 1521 > --- a/a
1522 1522 > +++ b/a
1523 1523 > @@ -10,0 +10,1 @@
1524 1524 > +line
1525 1525 > EOF
1526 1526
1527 1527 $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
1528 1528 > diff --git a/a b/a
1529 1529 > --- a/a
1530 1530 > +++ b/a
1531 1531 > @@ -1,1 +1,1 @@
1532 1532 > -2
1533 1533 > +add some skew
1534 1534 > @@ -2,2 +2,3 @@
1535 1535 > not matching, should fuzz
1536 1536 > ... a bit
1537 1537 > +line
1538 1538 > EOF
1539 1539
1540 1540 $ cat > a <<EOF
1541 1541 > 1
1542 1542 > 2
1543 1543 > 3
1544 1544 > 4
1545 1545 > EOF
1546 1546 $ hg ci -Am adda a
1547 1547 $ for p in *.diff; do
1548 1548 > hg import -v --no-commit $p
1549 1549 > cat a
1550 1550 > hg revert -aqC a
1551 1551 > # patch -p1 < $p
1552 1552 > # cat a
1553 1553 > # hg revert -aC a
1554 1554 > done
1555 1555 applying 01-no-context-beginning-of-file.diff
1556 1556 patching file a
1557 1557 applied to working directory
1558 1558 1
1559 1559 line
1560 1560 2
1561 1561 3
1562 1562 4
1563 1563 applying 02-no-context-middle-of-file.diff
1564 1564 patching file a
1565 1565 Hunk #1 succeeded at 2 (offset 1 lines).
1566 1566 Hunk #2 succeeded at 4 (offset 1 lines).
1567 1567 applied to working directory
1568 1568 1
1569 1569 add some skew
1570 1570 3
1571 1571 line
1572 1572 4
1573 1573 applying 03-no-context-end-of-file.diff
1574 1574 patching file a
1575 1575 Hunk #1 succeeded at 5 (offset -6 lines).
1576 1576 applied to working directory
1577 1577 1
1578 1578 2
1579 1579 3
1580 1580 4
1581 1581 line
1582 1582 applying 04-middle-of-file-completely-fuzzed.diff
1583 1583 patching file a
1584 1584 Hunk #1 succeeded at 2 (offset 1 lines).
1585 1585 Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
1586 1586 applied to working directory
1587 1587 1
1588 1588 add some skew
1589 1589 3
1590 1590 4
1591 1591 line
1592 1592 $ cd ..
1593 1593
1594 1594 Test partial application
1595 1595 ------------------------
1596 1596
1597 1597 prepare a stack of patches depending on each other
1598 1598
1599 1599 $ hg init partial
1600 1600 $ cd partial
1601 1601 $ cat << EOF > a
1602 1602 > one
1603 1603 > two
1604 1604 > three
1605 1605 > four
1606 1606 > five
1607 1607 > six
1608 1608 > seven
1609 1609 > EOF
1610 1610 $ hg add a
1611 1611 $ echo 'b' > b
1612 1612 $ hg add b
1613 1613 $ hg commit -m 'initial' -u Babar
1614 1614 $ cat << EOF > a
1615 1615 > one
1616 1616 > two
1617 1617 > 3
1618 1618 > four
1619 1619 > five
1620 1620 > six
1621 1621 > seven
1622 1622 > EOF
1623 1623 $ hg commit -m 'three' -u Celeste
1624 1624 $ cat << EOF > a
1625 1625 > one
1626 1626 > two
1627 1627 > 3
1628 1628 > 4
1629 1629 > five
1630 1630 > six
1631 1631 > seven
1632 1632 > EOF
1633 1633 $ hg commit -m 'four' -u Rataxes
1634 1634 $ cat << EOF > a
1635 1635 > one
1636 1636 > two
1637 1637 > 3
1638 1638 > 4
1639 1639 > 5
1640 1640 > six
1641 1641 > seven
1642 1642 > EOF
1643 1643 $ echo bb >> b
1644 1644 $ hg commit -m 'five' -u Arthur
1645 1645 $ echo 'Babar' > jungle
1646 1646 $ hg add jungle
1647 1647 $ hg ci -m 'jungle' -u Zephir
1648 1648 $ echo 'Celeste' >> jungle
1649 1649 $ hg ci -m 'extended jungle' -u Cornelius
1650 1650 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1651 1651 @ extended jungle [Cornelius] 1: +1/-0
1652 1652 |
1653 1653 o jungle [Zephir] 1: +1/-0
1654 1654 |
1655 1655 o five [Arthur] 2: +2/-1
1656 1656 |
1657 1657 o four [Rataxes] 1: +1/-1
1658 1658 |
1659 1659 o three [Celeste] 1: +1/-1
1660 1660 |
1661 1661 o initial [Babar] 2: +8/-0
1662 1662
1663 1663 Adding those config options should not change the output of diffstat. Bugfix #4755.
1664 1664
1665 1665 $ hg log -r . --template '{diffstat}\n'
1666 1666 1: +1/-0
1667 1667 $ hg log -r . --template '{diffstat}\n' --config diff.git=1 \
1668 1668 > --config diff.noprefix=1
1669 1669 1: +1/-0
1670 1670
1671 1671 Importing with some success and some errors:
1672 1672
1673 1673 $ hg update --rev 'desc(initial)'
1674 1674 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1675 1675 $ hg export --rev 'desc(five)' | hg import --partial -
1676 1676 applying patch from stdin
1677 1677 patching file a
1678 1678 Hunk #1 FAILED at 1
1679 1679 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1680 1680 patch applied partially
1681 1681 (fix the .rej files and run `hg commit --amend`)
1682 1682 [1]
1683 1683
1684 1684 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1685 1685 @ five [Arthur] 1: +1/-0
1686 1686 |
1687 1687 | o extended jungle [Cornelius] 1: +1/-0
1688 1688 | |
1689 1689 | o jungle [Zephir] 1: +1/-0
1690 1690 | |
1691 1691 | o five [Arthur] 2: +2/-1
1692 1692 | |
1693 1693 | o four [Rataxes] 1: +1/-1
1694 1694 | |
1695 1695 | o three [Celeste] 1: +1/-1
1696 1696 |/
1697 1697 o initial [Babar] 2: +8/-0
1698 1698
1699 1699 $ hg export
1700 1700 # HG changeset patch
1701 1701 # User Arthur
1702 1702 # Date 0 0
1703 1703 # Thu Jan 01 00:00:00 1970 +0000
1704 1704 # Node ID 26e6446bb2526e2be1037935f5fca2b2706f1509
1705 1705 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1706 1706 five
1707 1707
1708 1708 diff -r 8e4f0351909e -r 26e6446bb252 b
1709 1709 --- a/b Thu Jan 01 00:00:00 1970 +0000
1710 1710 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1711 1711 @@ -1,1 +1,2 @@
1712 1712 b
1713 1713 +bb
1714 1714 $ hg status -c .
1715 1715 C a
1716 1716 C b
1717 1717 $ ls
1718 1718 a
1719 1719 a.rej
1720 1720 b
1721 1721
1722 1722 Importing with zero success:
1723 1723
1724 1724 $ hg update --rev 'desc(initial)'
1725 1725 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1726 1726 $ hg export --rev 'desc(four)' | hg import --partial -
1727 1727 applying patch from stdin
1728 1728 patching file a
1729 1729 Hunk #1 FAILED at 0
1730 1730 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1731 1731 patch applied partially
1732 1732 (fix the .rej files and run `hg commit --amend`)
1733 1733 [1]
1734 1734
1735 1735 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1736 1736 @ four [Rataxes] 0: +0/-0
1737 1737 |
1738 1738 | o five [Arthur] 1: +1/-0
1739 1739 |/
1740 1740 | o extended jungle [Cornelius] 1: +1/-0
1741 1741 | |
1742 1742 | o jungle [Zephir] 1: +1/-0
1743 1743 | |
1744 1744 | o five [Arthur] 2: +2/-1
1745 1745 | |
1746 1746 | o four [Rataxes] 1: +1/-1
1747 1747 | |
1748 1748 | o three [Celeste] 1: +1/-1
1749 1749 |/
1750 1750 o initial [Babar] 2: +8/-0
1751 1751
1752 1752 $ hg export
1753 1753 # HG changeset patch
1754 1754 # User Rataxes
1755 1755 # Date 0 0
1756 1756 # Thu Jan 01 00:00:00 1970 +0000
1757 1757 # Node ID cb9b1847a74d9ad52e93becaf14b98dbcc274e1e
1758 1758 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1759 1759 four
1760 1760
1761 1761 $ hg status -c .
1762 1762 C a
1763 1763 C b
1764 1764 $ ls
1765 1765 a
1766 1766 a.rej
1767 1767 b
1768 1768
1769 1769 Importing with unknown file:
1770 1770
1771 1771 $ hg update --rev 'desc(initial)'
1772 1772 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1773 1773 $ hg export --rev 'desc("extended jungle")' | hg import --partial -
1774 1774 applying patch from stdin
1775 1775 unable to find 'jungle' for patching
1776 1776 (use '--prefix' to apply patch relative to the current directory)
1777 1777 1 out of 1 hunks FAILED -- saving rejects to file jungle.rej
1778 1778 patch applied partially
1779 1779 (fix the .rej files and run `hg commit --amend`)
1780 1780 [1]
1781 1781
1782 1782 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1783 1783 @ extended jungle [Cornelius] 0: +0/-0
1784 1784 |
1785 1785 | o four [Rataxes] 0: +0/-0
1786 1786 |/
1787 1787 | o five [Arthur] 1: +1/-0
1788 1788 |/
1789 1789 | o extended jungle [Cornelius] 1: +1/-0
1790 1790 | |
1791 1791 | o jungle [Zephir] 1: +1/-0
1792 1792 | |
1793 1793 | o five [Arthur] 2: +2/-1
1794 1794 | |
1795 1795 | o four [Rataxes] 1: +1/-1
1796 1796 | |
1797 1797 | o three [Celeste] 1: +1/-1
1798 1798 |/
1799 1799 o initial [Babar] 2: +8/-0
1800 1800
1801 1801 $ hg export
1802 1802 # HG changeset patch
1803 1803 # User Cornelius
1804 1804 # Date 0 0
1805 1805 # Thu Jan 01 00:00:00 1970 +0000
1806 1806 # Node ID 1fb1f86bef43c5a75918178f8d23c29fb0a7398d
1807 1807 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1808 1808 extended jungle
1809 1809
1810 1810 $ hg status -c .
1811 1811 C a
1812 1812 C b
1813 1813 $ ls
1814 1814 a
1815 1815 a.rej
1816 1816 b
1817 1817 jungle.rej
1818 1818
1819 1819 Importing multiple failing patches:
1820 1820
1821 1821 $ hg update --rev 'desc(initial)'
1822 1822 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1823 1823 $ echo 'B' > b # just to make another commit
1824 1824 $ hg commit -m "a new base"
1825 1825 created new head
1826 1826 $ hg export --rev 'desc("four") + desc("extended jungle")' | hg import --partial -
1827 1827 applying patch from stdin
1828 1828 patching file a
1829 1829 Hunk #1 FAILED at 0
1830 1830 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1831 1831 patch applied partially
1832 1832 (fix the .rej files and run `hg commit --amend`)
1833 1833 [1]
1834 1834 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1835 1835 @ four [Rataxes] 0: +0/-0
1836 1836 |
1837 1837 o a new base [test] 1: +1/-1
1838 1838 |
1839 1839 | o extended jungle [Cornelius] 0: +0/-0
1840 1840 |/
1841 1841 | o four [Rataxes] 0: +0/-0
1842 1842 |/
1843 1843 | o five [Arthur] 1: +1/-0
1844 1844 |/
1845 1845 | o extended jungle [Cornelius] 1: +1/-0
1846 1846 | |
1847 1847 | o jungle [Zephir] 1: +1/-0
1848 1848 | |
1849 1849 | o five [Arthur] 2: +2/-1
1850 1850 | |
1851 1851 | o four [Rataxes] 1: +1/-1
1852 1852 | |
1853 1853 | o three [Celeste] 1: +1/-1
1854 1854 |/
1855 1855 o initial [Babar] 2: +8/-0
1856 1856
1857 1857 $ hg export
1858 1858 # HG changeset patch
1859 1859 # User Rataxes
1860 1860 # Date 0 0
1861 1861 # Thu Jan 01 00:00:00 1970 +0000
1862 1862 # Node ID a9d7b6d0ffbb4eb12b7d5939250fcd42e8930a1d
1863 1863 # Parent f59f8d2e95a8ca5b1b4ca64320140da85f3b44fd
1864 1864 four
1865 1865
1866 1866 $ hg status -c .
1867 1867 C a
1868 1868 C b
1869 1869
1870 1870 Importing some extra header
1871 1871 ===========================
1872 1872
1873 1873 $ cat > $TESTTMP/parseextra.py <<EOF
1874 1874 > import mercurial.patch
1875 1875 > import mercurial.cmdutil
1876 1876 >
1877 1877 > def processfoo(repo, data, extra, opts):
1878 1878 > if b'foo' in data:
1879 1879 > extra[b'foo'] = data[b'foo']
1880 1880 > def postimport(ctx):
1881 1881 > if b'foo' in ctx.extra():
1882 1882 > ctx.repo().ui.write(b'imported-foo: %s\n' % ctx.extra()[b'foo'])
1883 1883 >
1884 1884 > mercurial.patch.patchheadermap.append((b'Foo', b'foo'))
1885 1885 > mercurial.cmdutil.extrapreimport.append(b'foo')
1886 1886 > mercurial.cmdutil.extrapreimportmap[b'foo'] = processfoo
1887 1887 > mercurial.cmdutil.extrapostimport.append(b'foo')
1888 1888 > mercurial.cmdutil.extrapostimportmap[b'foo'] = postimport
1889 1889 > EOF
1890 1890 $ cat >> $HGRCPATH <<EOF
1891 1891 > [extensions]
1892 1892 > parseextra=$TESTTMP/parseextra.py
1893 1893 > EOF
1894 1894 $ hg up -C tip
1895 1895 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1896 1896 $ cat > $TESTTMP/foo.patch <<EOF
1897 1897 > # HG changeset patch
1898 1898 > # User Rataxes
1899 1899 > # Date 0 0
1900 1900 > # Thu Jan 01 00:00:00 1970 +0000
1901 1901 > # Foo bar
1902 1902 > height
1903 1903 >
1904 1904 > --- a/a Thu Jan 01 00:00:00 1970 +0000
1905 1905 > +++ b/a Wed Oct 07 09:17:44 2015 +0000
1906 1906 > @@ -5,3 +5,4 @@
1907 1907 > five
1908 1908 > six
1909 1909 > seven
1910 1910 > +heigt
1911 1911 > EOF
1912 1912 $ hg import $TESTTMP/foo.patch
1913 1913 applying $TESTTMP/foo.patch
1914 1914 imported-foo: bar
1915 1915 $ hg log --debug -r . | grep extra
1916 1916 extra: branch=default
1917 1917 extra: foo=bar
1918 1918
1919 1919 Warn the user that paths are relative to the root of
1920 1920 repository when file not found for patching
1921 1921
1922 1922 $ mkdir filedir
1923 1923 $ echo "file1" >> filedir/file1
1924 1924 $ hg add filedir/file1
1925 1925 $ hg commit -m "file1"
1926 1926 $ cd filedir
1927 1927 $ hg import -p 2 - <<EOF
1928 1928 > # HG changeset patch
1929 1929 > # User test
1930 1930 > # Date 0 0
1931 1931 > file2
1932 1932 >
1933 1933 > diff --git a/filedir/file1 b/filedir/file1
1934 1934 > --- a/filedir/file1
1935 1935 > +++ b/filedir/file1
1936 1936 > @@ -1,1 +1,2 @@
1937 1937 > file1
1938 1938 > +file2
1939 1939 > EOF
1940 1940 applying patch from stdin
1941 1941 unable to find 'file1' for patching
1942 1942 (use '--prefix' to apply patch relative to the current directory)
1943 1943 1 out of 1 hunks FAILED -- saving rejects to file file1.rej
1944 1944 abort: patch failed to apply
1945 1945 [255]
1946 1946
1947 1947 test import crash (issue5375)
1948 1948 $ cd ..
1949 1949 $ hg init repo
1950 1950 $ cd repo
1951 1951 $ printf "diff --git a/a b/b\nrename from a\nrename to b" | hg import -
1952 1952 applying patch from stdin
1953 1953 a not tracked!
1954 1954 abort: source file 'a' does not exist
1955 1955 [255]
1956 1956
1957 1957 test immature end of hunk
1958 1958
1959 1959 $ hg import - <<'EOF'
1960 1960 > diff --git a/foo b/foo
1961 1961 > --- a/foo
1962 1962 > --- b/foo
1963 1963 > @@ -0,0 +1,1 @@
1964 1964 > EOF
1965 1965 applying patch from stdin
1966 1966 abort: bad hunk #1: incomplete hunk
1967 1967 [255]
1968 1968
1969 1969 $ hg import - <<'EOF'
1970 1970 > diff --git a/foo b/foo
1971 1971 > --- a/foo
1972 1972 > --- b/foo
1973 1973 > @@ -0,0 +1,1 @@
1974 1974 > \ No newline at end of file
1975 1975 > EOF
1976 1976 applying patch from stdin
1977 1977 abort: bad hunk #1: incomplete hunk
1978 1978 [255]
@@ -1,154 +1,154 b''
1 1 https://bz.mercurial-scm.org/660 and:
2 2 https://bz.mercurial-scm.org/322
3 3
4 4 $ hg init
5 5 $ echo a > a
6 6 $ mkdir b
7 7 $ echo b > b/b
8 8 $ hg commit -A -m "a is file, b is dir"
9 9 adding a
10 10 adding b/b
11 11
12 12 File replaced with directory:
13 13
14 14 $ rm a
15 15 $ mkdir a
16 16 $ echo a > a/a
17 17
18 18 Should fail - would corrupt dirstate:
19 19
20 20 $ hg add a/a
21 21 abort: file 'a' in dirstate clashes with 'a/a'
22 22 [255]
23 23
24 24 Removing shadow:
25 25
26 26 $ hg rm --after a
27 27
28 28 Should succeed - shadow removed:
29 29
30 30 $ hg add a/a
31 31
32 32 Directory replaced with file:
33 33
34 34 $ rm -r b
35 35 $ echo b > b
36 36
37 37 Should fail - would corrupt dirstate:
38 38
39 39 $ hg add b
40 40 abort: directory 'b' already in dirstate
41 41 [255]
42 42
43 43 Removing shadow:
44 44
45 45 $ hg rm --after b/b
46 46
47 47 Should succeed - shadow removed:
48 48
49 49 $ hg add b
50 50
51 51 Look what we got:
52 52
53 53 $ hg st
54 54 A a/a
55 55 A b
56 56 R a
57 57 R b/b
58 58
59 59 Revert reintroducing shadow - should fail:
60 60
61 61 $ rm -r a b
62 62 $ hg revert b/b
63 63 abort: file 'b' in dirstate clashes with 'b/b'
64 64 [255]
65 65
66 66 Revert all - should succeed:
67 67
68 68 $ hg revert --all
69 undeleting a
70 69 forgetting a/a
71 70 forgetting b
71 undeleting a
72 72 undeleting b/b
73 73
74 74 $ hg st
75 75
76 76 Issue3423:
77 77
78 78 $ hg forget a
79 79 $ echo zed > a
80 80 $ hg revert a
81 81 $ hg st
82 82 ? a.orig
83 83 $ rm a.orig
84 84
85 85 addremove:
86 86
87 87 $ rm -r a b
88 88 $ mkdir a
89 89 $ echo a > a/a
90 90 $ echo b > b
91 91
92 92 $ hg addremove -s 0
93 93 removing a
94 94 adding a/a
95 95 adding b
96 96 removing b/b
97 97
98 98 $ hg st
99 99 A a/a
100 100 A b
101 101 R a
102 102 R b/b
103 103
104 104 commit:
105 105
106 106 $ hg ci -A -m "a is dir, b is file"
107 107 $ hg st --all
108 108 C a/a
109 109 C b
110 110
111 111 Long directory replaced with file:
112 112
113 113 $ mkdir d
114 114 $ mkdir d/d
115 115 $ echo d > d/d/d
116 116 $ hg commit -A -m "d is long directory"
117 117 adding d/d/d
118 118
119 119 $ rm -r d
120 120 $ echo d > d
121 121
122 122 Should fail - would corrupt dirstate:
123 123
124 124 $ hg add d
125 125 abort: directory 'd' already in dirstate
126 126 [255]
127 127
128 128 Removing shadow:
129 129
130 130 $ hg rm --after d/d/d
131 131
132 132 Should succeed - shadow removed:
133 133
134 134 $ hg add d
135 135 $ hg ci -md
136 136
137 137 Update should work at least with clean working directory:
138 138
139 139 $ rm -r a b d
140 140 $ hg up -r 0
141 141 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 142
143 143 $ hg st --all
144 144 C a
145 145 C b/b
146 146
147 147 $ rm -r a b
148 148 $ hg up -r 1
149 149 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 150
151 151 $ hg st --all
152 152 C a/a
153 153 C b
154 154
@@ -1,1270 +1,1270 b''
1 1 This file contains testcases that tend to be related to special cases or less
2 2 common commands affecting largefile.
3 3
4 4 Each sections should be independent of each others.
5 5
6 6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
7 7 $ mkdir "${USERCACHE}"
8 8 $ cat >> $HGRCPATH <<EOF
9 9 > [extensions]
10 10 > largefiles=
11 11 > purge=
12 12 > rebase=
13 13 > transplant=
14 14 > [phases]
15 15 > publish=False
16 16 > [largefiles]
17 17 > minsize=2
18 18 > patterns=glob:**.dat
19 19 > usercache=${USERCACHE}
20 20 > [hooks]
21 21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
22 22 > EOF
23 23
24 24
25 25
26 26 Test copies and moves from a directory other than root (issue3516)
27 27 =========================================================================
28 28
29 29 $ hg init lf_cpmv
30 30 $ cd lf_cpmv
31 31 $ mkdir dira
32 32 $ mkdir dira/dirb
33 33 $ touch dira/dirb/largefile
34 34 $ hg add --large dira/dirb/largefile
35 35 $ hg commit -m "added"
36 36 Invoking status precommit hook
37 37 A dira/dirb/largefile
38 38 $ cd dira
39 39 $ hg cp dirb/largefile foo/largefile
40 40
41 41 TODO: Ideally, this should mention the largefile, not the standin
42 42 $ hg log -T '{rev}\n' --stat 'set:clean()'
43 43 0
44 44 .hglf/dira/dirb/largefile | 1 +
45 45 1 files changed, 1 insertions(+), 0 deletions(-)
46 46
47 47 $ hg ci -m "deep copy"
48 48 Invoking status precommit hook
49 49 A dira/foo/largefile
50 50 $ find . | sort
51 51 .
52 52 ./dirb
53 53 ./dirb/largefile
54 54 ./foo
55 55 ./foo/largefile
56 56 $ hg mv foo/largefile baz/largefile
57 57 $ hg ci -m "moved"
58 58 Invoking status precommit hook
59 59 A dira/baz/largefile
60 60 R dira/foo/largefile
61 61 $ find . | sort
62 62 .
63 63 ./baz
64 64 ./baz/largefile
65 65 ./dirb
66 66 ./dirb/largefile
67 67 $ cd ..
68 68 $ hg mv dira dirc
69 69 moving .hglf/dira/baz/largefile to .hglf/dirc/baz/largefile
70 70 moving .hglf/dira/dirb/largefile to .hglf/dirc/dirb/largefile
71 71 $ find * | sort
72 72 dirc
73 73 dirc/baz
74 74 dirc/baz/largefile
75 75 dirc/dirb
76 76 dirc/dirb/largefile
77 77
78 78 $ hg clone -q . ../fetch
79 79 $ hg --config extensions.fetch= fetch ../fetch
80 80 abort: uncommitted changes
81 81 [255]
82 82 $ hg up -qC
83 83 $ cd ..
84 84
85 85 Clone a local repository owned by another user
86 86 ===================================================
87 87
88 88 #if unix-permissions
89 89
90 90 We have to simulate that here by setting $HOME and removing write permissions
91 91 $ ORIGHOME="$HOME"
92 92 $ mkdir alice
93 93 $ HOME="`pwd`/alice"
94 94 $ cd alice
95 95 $ hg init pubrepo
96 96 $ cd pubrepo
97 97 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
98 98 $ hg add --large a-large-file
99 99 $ hg commit -m "Add a large file"
100 100 Invoking status precommit hook
101 101 A a-large-file
102 102 $ cd ..
103 103 $ chmod -R a-w pubrepo
104 104 $ cd ..
105 105 $ mkdir bob
106 106 $ HOME="`pwd`/bob"
107 107 $ cd bob
108 108 $ hg clone --pull ../alice/pubrepo pubrepo
109 109 requesting all changes
110 110 adding changesets
111 111 adding manifests
112 112 adding file changes
113 113 added 1 changesets with 1 changes to 1 files
114 114 new changesets 09a186cfa6da
115 115 updating to branch default
116 116 getting changed largefiles
117 117 1 largefiles updated, 0 removed
118 118 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 119 $ cd ..
120 120 $ chmod -R u+w alice/pubrepo
121 121 $ HOME="$ORIGHOME"
122 122
123 123 #endif
124 124
125 125
126 126 Symlink to a large largefile should behave the same as a symlink to a normal file
127 127 =====================================================================================
128 128
129 129 #if symlink
130 130
131 131 $ hg init largesymlink
132 132 $ cd largesymlink
133 133 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
134 134 $ hg add --large largefile
135 135 $ hg commit -m "commit a large file"
136 136 Invoking status precommit hook
137 137 A largefile
138 138 $ ln -s largefile largelink
139 139 $ hg add largelink
140 140 $ hg commit -m "commit a large symlink"
141 141 Invoking status precommit hook
142 142 A largelink
143 143 $ rm -f largelink
144 144 $ hg up >/dev/null
145 145 $ test -f largelink
146 146 [1]
147 147 $ test -L largelink
148 148 [1]
149 149 $ rm -f largelink # make next part of the test independent of the previous
150 150 $ hg up -C >/dev/null
151 151 $ test -f largelink
152 152 $ test -L largelink
153 153 $ cd ..
154 154
155 155 #endif
156 156
157 157
158 158 test for pattern matching on 'hg status':
159 159 ==============================================
160 160
161 161
162 162 to boost performance, largefiles checks whether specified patterns are
163 163 related to largefiles in working directory (NOT to STANDIN) or not.
164 164
165 165 $ hg init statusmatch
166 166 $ cd statusmatch
167 167
168 168 $ mkdir -p a/b/c/d
169 169 $ echo normal > a/b/c/d/e.normal.txt
170 170 $ hg add a/b/c/d/e.normal.txt
171 171 $ echo large > a/b/c/d/e.large.txt
172 172 $ hg add --large a/b/c/d/e.large.txt
173 173 $ mkdir -p a/b/c/x
174 174 $ echo normal > a/b/c/x/y.normal.txt
175 175 $ hg add a/b/c/x/y.normal.txt
176 176 $ hg commit -m 'add files'
177 177 Invoking status precommit hook
178 178 A a/b/c/d/e.large.txt
179 179 A a/b/c/d/e.normal.txt
180 180 A a/b/c/x/y.normal.txt
181 181
182 182 (1) no pattern: no performance boost
183 183 $ hg status -A
184 184 C a/b/c/d/e.large.txt
185 185 C a/b/c/d/e.normal.txt
186 186 C a/b/c/x/y.normal.txt
187 187
188 188 (2) pattern not related to largefiles: performance boost
189 189 $ hg status -A a/b/c/x
190 190 C a/b/c/x/y.normal.txt
191 191
192 192 (3) pattern related to largefiles: no performance boost
193 193 $ hg status -A a/b/c/d
194 194 C a/b/c/d/e.large.txt
195 195 C a/b/c/d/e.normal.txt
196 196
197 197 (4) pattern related to STANDIN (not to largefiles): performance boost
198 198 $ hg status -A .hglf/a
199 199 C .hglf/a/b/c/d/e.large.txt
200 200
201 201 (5) mixed case: no performance boost
202 202 $ hg status -A a/b/c/x a/b/c/d
203 203 C a/b/c/d/e.large.txt
204 204 C a/b/c/d/e.normal.txt
205 205 C a/b/c/x/y.normal.txt
206 206
207 207 verify that largefiles doesn't break filesets
208 208
209 209 $ hg log --rev . --exclude "set:binary()"
210 210 changeset: 0:41bd42f10efa
211 211 tag: tip
212 212 user: test
213 213 date: Thu Jan 01 00:00:00 1970 +0000
214 214 summary: add files
215 215
216 216 sharing a largefile repo automatically enables largefiles on the share
217 217
218 218 $ hg share --config extensions.share= . ../shared_lfrepo
219 219 updating working directory
220 220 getting changed largefiles
221 221 1 largefiles updated, 0 removed
222 222 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 223 $ cat ../shared_lfrepo/.hg/hgrc
224 224
225 225 [extensions]
226 226 largefiles=
227 227
228 228 verify that large files in subrepos handled properly
229 229 $ hg init subrepo
230 230 $ echo "subrepo = subrepo" > .hgsub
231 231 $ hg add .hgsub
232 232 $ hg ci -m "add subrepo"
233 233 Invoking status precommit hook
234 234 A .hgsub
235 235 ? .hgsubstate
236 236 $ echo "rev 1" > subrepo/large.txt
237 237 $ hg add --large subrepo/large.txt
238 238 $ hg sum
239 239 parent: 1:8ee150ea2e9c tip
240 240 add subrepo
241 241 branch: default
242 242 commit: 1 subrepos
243 243 update: (current)
244 244 phases: 2 draft
245 245 $ hg st
246 246 $ hg st -S
247 247 A subrepo/large.txt
248 248 $ hg ci -S -m "commit top repo"
249 249 committing subrepository subrepo
250 250 Invoking status precommit hook
251 251 A large.txt
252 252 Invoking status precommit hook
253 253 M .hgsubstate
254 254 # No differences
255 255 $ hg st -S
256 256 $ hg sum
257 257 parent: 2:ce4cd0c527a6 tip
258 258 commit top repo
259 259 branch: default
260 260 commit: (clean)
261 261 update: (current)
262 262 phases: 3 draft
263 263 $ echo "rev 2" > subrepo/large.txt
264 264 $ hg st -S
265 265 M subrepo/large.txt
266 266 $ hg sum
267 267 parent: 2:ce4cd0c527a6 tip
268 268 commit top repo
269 269 branch: default
270 270 commit: 1 subrepos
271 271 update: (current)
272 272 phases: 3 draft
273 273 $ hg ci -m "this commit should fail without -S"
274 274 abort: uncommitted changes in subrepository "subrepo"
275 275 (use --subrepos for recursive commit)
276 276 [255]
277 277
278 278 Add a normal file to the subrepo, then test archiving
279 279
280 280 $ echo 'normal file' > subrepo/normal.txt
281 281 $ touch large.dat
282 282 $ mv subrepo/large.txt subrepo/renamed-large.txt
283 283 $ hg addremove -S --dry-run
284 284 adding large.dat as a largefile
285 285 removing subrepo/large.txt
286 286 adding subrepo/normal.txt
287 287 adding subrepo/renamed-large.txt
288 288 $ hg status -S
289 289 ! subrepo/large.txt
290 290 ? large.dat
291 291 ? subrepo/normal.txt
292 292 ? subrepo/renamed-large.txt
293 293
294 294 $ hg addremove --dry-run subrepo
295 295 removing subrepo/large.txt
296 296 adding subrepo/normal.txt
297 297 adding subrepo/renamed-large.txt
298 298 $ hg status -S
299 299 ! subrepo/large.txt
300 300 ? large.dat
301 301 ? subrepo/normal.txt
302 302 ? subrepo/renamed-large.txt
303 303 $ cd ..
304 304
305 305 $ hg -R statusmatch addremove --dry-run statusmatch/subrepo
306 306 removing statusmatch/subrepo/large.txt
307 307 adding statusmatch/subrepo/normal.txt
308 308 adding statusmatch/subrepo/renamed-large.txt
309 309 $ hg -R statusmatch status -S
310 310 ! subrepo/large.txt
311 311 ? large.dat
312 312 ? subrepo/normal.txt
313 313 ? subrepo/renamed-large.txt
314 314
315 315 $ hg -R statusmatch addremove --dry-run -S
316 316 adding large.dat as a largefile
317 317 removing subrepo/large.txt
318 318 adding subrepo/normal.txt
319 319 adding subrepo/renamed-large.txt
320 320 $ cd statusmatch
321 321
322 322 $ mv subrepo/renamed-large.txt subrepo/large.txt
323 323 $ hg addremove subrepo
324 324 adding subrepo/normal.txt
325 325 $ hg forget subrepo/normal.txt
326 326
327 327 $ hg addremove -S
328 328 adding large.dat as a largefile
329 329 adding subrepo/normal.txt
330 330 $ rm large.dat
331 331
332 332 $ hg addremove subrepo
333 333 $ hg addremove -S
334 334 removing large.dat
335 335
336 336 Lock in subrepo, otherwise the change isn't archived
337 337
338 338 $ hg ci -S -m "add normal file to top level"
339 339 committing subrepository subrepo
340 340 Invoking status precommit hook
341 341 M large.txt
342 342 A normal.txt
343 343 Invoking status precommit hook
344 344 M .hgsubstate
345 345 $ hg archive -S ../lf_subrepo_archive
346 346 $ find ../lf_subrepo_archive | sort
347 347 ../lf_subrepo_archive
348 348 ../lf_subrepo_archive/.hg_archival.txt
349 349 ../lf_subrepo_archive/.hgsub
350 350 ../lf_subrepo_archive/.hgsubstate
351 351 ../lf_subrepo_archive/a
352 352 ../lf_subrepo_archive/a/b
353 353 ../lf_subrepo_archive/a/b/c
354 354 ../lf_subrepo_archive/a/b/c/d
355 355 ../lf_subrepo_archive/a/b/c/d/e.large.txt
356 356 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
357 357 ../lf_subrepo_archive/a/b/c/x
358 358 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
359 359 ../lf_subrepo_archive/subrepo
360 360 ../lf_subrepo_archive/subrepo/large.txt
361 361 ../lf_subrepo_archive/subrepo/normal.txt
362 362 $ cat ../lf_subrepo_archive/.hg_archival.txt
363 363 repo: 41bd42f10efa43698cc02052ea0977771cba506d
364 364 node: d56a95e6522858bc08a724c4fe2bdee066d1c30b
365 365 branch: default
366 366 latesttag: null
367 367 latesttagdistance: 4
368 368 changessincelatesttag: 4
369 369
370 370 Test update with subrepos.
371 371
372 372 $ hg update 0
373 373 getting changed largefiles
374 374 0 largefiles updated, 1 removed
375 375 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
376 376 $ hg status -S
377 377 $ hg update tip
378 378 getting changed largefiles
379 379 1 largefiles updated, 0 removed
380 380 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 381 $ hg status -S
382 382 # modify a large file
383 383 $ echo "modified" > subrepo/large.txt
384 384 $ hg st -S
385 385 M subrepo/large.txt
386 386 # update -C should revert the change.
387 387 $ hg update -C
388 388 getting changed largefiles
389 389 1 largefiles updated, 0 removed
390 390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 391 $ hg status -S
392 392
393 393 Forget doesn't change the content of the file
394 394 $ echo 'pre-forget content' > subrepo/large.txt
395 395 $ hg forget -v subrepo/large.txt
396 396 removing subrepo/large.txt
397 397 $ cat subrepo/large.txt
398 398 pre-forget content
399 399
400 400 Test reverting a forgotten file
401 401 $ hg revert -R subrepo subrepo/large.txt
402 402 $ hg status -SA subrepo/large.txt
403 403 C subrepo/large.txt
404 404
405 405 $ hg rm -v subrepo/large.txt
406 406 removing subrepo/large.txt
407 407 $ hg revert -R subrepo subrepo/large.txt
408 408 $ rm subrepo/large.txt
409 409 $ hg addremove -S
410 410 removing subrepo/large.txt
411 411 $ hg st -S
412 412 R subrepo/large.txt
413 413
414 414 Test archiving a revision that references a subrepo that is not yet
415 415 cloned (see test-subrepo-recursion.t):
416 416
417 417 $ hg clone -U . ../empty
418 418 $ cd ../empty
419 419 $ hg archive --subrepos -r tip ../archive.tar.gz
420 420 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
421 421 $ cd ..
422 422
423 423
424 424
425 425
426 426
427 427
428 428 Test addremove, forget and others
429 429 ==============================================
430 430
431 431 Test that addremove picks up largefiles prior to the initial commit (issue3541)
432 432
433 433 $ hg init addrm2
434 434 $ cd addrm2
435 435 $ touch large.dat
436 436 $ touch large2.dat
437 437 $ touch normal
438 438 $ hg add --large large.dat
439 439 $ hg addremove -v
440 440 adding large2.dat as a largefile
441 441 adding normal
442 442
443 443 Test that forgetting all largefiles reverts to islfilesrepo() == False
444 444 (addremove will add *.dat as normal files now)
445 445 $ hg forget large.dat
446 446 $ hg forget large2.dat
447 447 $ hg addremove -v
448 448 adding large.dat
449 449 adding large2.dat
450 450
451 451 Test commit's addremove option prior to the first commit
452 452 $ hg forget large.dat
453 453 $ hg forget large2.dat
454 454 $ hg add --large large.dat
455 455 $ hg ci -Am "commit"
456 456 adding large2.dat as a largefile
457 457 Invoking status precommit hook
458 458 A large.dat
459 459 A large2.dat
460 460 A normal
461 461 $ find .hglf | sort
462 462 .hglf
463 463 .hglf/large.dat
464 464 .hglf/large2.dat
465 465
466 466 Test actions on largefiles using relative paths from subdir
467 467
468 468 $ mkdir sub
469 469 $ cd sub
470 470 $ echo anotherlarge > anotherlarge
471 471 $ hg add --large anotherlarge
472 472 $ hg st
473 473 A sub/anotherlarge
474 474 $ hg st anotherlarge
475 475 A anotherlarge
476 476 $ hg commit -m anotherlarge anotherlarge
477 477 Invoking status precommit hook
478 478 A sub/anotherlarge
479 479 $ hg log anotherlarge
480 480 changeset: 1:9627a577c5e9
481 481 tag: tip
482 482 user: test
483 483 date: Thu Jan 01 00:00:00 1970 +0000
484 484 summary: anotherlarge
485 485
486 486 $ hg --debug log -T '{rev}: {desc}\n' ../sub/anotherlarge
487 487 updated patterns: ../.hglf/sub/../sub/anotherlarge, ../sub/anotherlarge
488 488 1: anotherlarge
489 489
490 490 $ hg log -G anotherlarge
491 491 @ changeset: 1:9627a577c5e9
492 492 | tag: tip
493 493 ~ user: test
494 494 date: Thu Jan 01 00:00:00 1970 +0000
495 495 summary: anotherlarge
496 496
497 497
498 498 $ hg log glob:another*
499 499 changeset: 1:9627a577c5e9
500 500 tag: tip
501 501 user: test
502 502 date: Thu Jan 01 00:00:00 1970 +0000
503 503 summary: anotherlarge
504 504
505 505 $ hg --debug log -T '{rev}: {desc}\n' -G glob:another*
506 506 updated patterns: glob:../.hglf/sub/another*, glob:another*
507 507 @ 1: anotherlarge
508 508 |
509 509 ~
510 510
511 511 #if no-msys
512 512 $ hg --debug log -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
513 513 updated patterns: glob:../.hglf/sub/another*
514 514 1: anotherlarge
515 515
516 516 $ hg --debug log -G -T '{rev}: {desc}\n' 'glob:../.hglf/sub/another*' # no-msys
517 517 updated patterns: glob:../.hglf/sub/another*
518 518 @ 1: anotherlarge
519 519 |
520 520 ~
521 521 #endif
522 522
523 523 $ echo more >> anotherlarge
524 524 $ hg st .
525 525 M anotherlarge
526 526 $ hg cat anotherlarge
527 527 anotherlarge
528 528 $ hg revert anotherlarge
529 529 $ hg st
530 530 ? sub/anotherlarge.orig
531 531
532 532 Test orig files go where we want them
533 533 $ echo moremore >> anotherlarge
534 534 $ hg revert anotherlarge -v --config 'ui.origbackuppath=.hg/origbackups'
535 535 creating directory: $TESTTMP/addrm2/.hg/origbackups/.hglf/sub
536 536 saving current version of ../.hglf/sub/anotherlarge as $TESTTMP/addrm2/.hg/origbackups/.hglf/sub/anotherlarge
537 537 reverting ../.hglf/sub/anotherlarge
538 538 creating directory: $TESTTMP/addrm2/.hg/origbackups/sub
539 539 found 90c622cf65cebe75c5842f9136c459333faf392e in store
540 540 found 90c622cf65cebe75c5842f9136c459333faf392e in store
541 541 $ ls ../.hg/origbackups/sub
542 542 anotherlarge
543 543 $ cd ..
544 544
545 545 Test glob logging from the root dir
546 546 $ hg log glob:**another*
547 547 changeset: 1:9627a577c5e9
548 548 tag: tip
549 549 user: test
550 550 date: Thu Jan 01 00:00:00 1970 +0000
551 551 summary: anotherlarge
552 552
553 553 $ hg log -G glob:**another*
554 554 @ changeset: 1:9627a577c5e9
555 555 | tag: tip
556 556 ~ user: test
557 557 date: Thu Jan 01 00:00:00 1970 +0000
558 558 summary: anotherlarge
559 559
560 560
561 561 $ cd ..
562 562
563 563 Log from outer space
564 564 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/sub/anotherlarge'
565 565 updated patterns: addrm2/.hglf/sub/anotherlarge, addrm2/sub/anotherlarge
566 566 1: anotherlarge
567 567 $ hg --debug log -R addrm2 -T '{rev}: {desc}\n' 'addrm2/.hglf/sub/anotherlarge'
568 568 updated patterns: addrm2/.hglf/sub/anotherlarge
569 569 1: anotherlarge
570 570
571 571
572 572 Check error message while exchange
573 573 =========================================================
574 574
575 575 issue3651: summary/outgoing with largefiles shows "no remote repo"
576 576 unexpectedly
577 577
578 578 $ mkdir issue3651
579 579 $ cd issue3651
580 580
581 581 $ hg init src
582 582 $ echo a > src/a
583 583 $ hg -R src add --large src/a
584 584 $ hg -R src commit -m '#0'
585 585 Invoking status precommit hook
586 586 A a
587 587
588 588 check messages when no remote repository is specified:
589 589 "no remote repo" route for "hg outgoing --large" is not tested here,
590 590 because it can't be reproduced easily.
591 591
592 592 $ hg init clone1
593 593 $ hg -R clone1 -q pull src
594 594 $ hg -R clone1 -q update
595 595 $ hg -R clone1 paths | grep default
596 596 [1]
597 597
598 598 $ hg -R clone1 summary --large
599 599 parent: 0:fc0bd45326d3 tip
600 600 #0
601 601 branch: default
602 602 commit: (clean)
603 603 update: (current)
604 604 phases: 1 draft
605 605 largefiles: (no remote repo)
606 606
607 607 check messages when there is no files to upload:
608 608
609 609 $ hg -q clone src clone2
610 610 $ hg -R clone2 paths | grep default
611 611 default = $TESTTMP/issue3651/src
612 612
613 613 $ hg -R clone2 summary --large
614 614 parent: 0:fc0bd45326d3 tip
615 615 #0
616 616 branch: default
617 617 commit: (clean)
618 618 update: (current)
619 619 phases: 1 draft
620 620 largefiles: (no files to upload)
621 621 $ hg -R clone2 outgoing --large
622 622 comparing with $TESTTMP/issue3651/src
623 623 searching for changes
624 624 no changes found
625 625 largefiles: no files to upload
626 626 [1]
627 627
628 628 $ hg -R clone2 outgoing --large --graph --template "{rev}"
629 629 comparing with $TESTTMP/issue3651/src
630 630 searching for changes
631 631 no changes found
632 632 largefiles: no files to upload
633 633
634 634 check messages when there are files to upload:
635 635
636 636 $ echo b > clone2/b
637 637 $ hg -R clone2 add --large clone2/b
638 638 $ hg -R clone2 commit -m '#1'
639 639 Invoking status precommit hook
640 640 A b
641 641 $ hg -R clone2 summary --large
642 642 parent: 1:1acbe71ce432 tip
643 643 #1
644 644 branch: default
645 645 commit: (clean)
646 646 update: (current)
647 647 phases: 2 draft
648 648 largefiles: 1 entities for 1 files to upload
649 649 $ hg -R clone2 outgoing --large
650 650 comparing with $TESTTMP/issue3651/src
651 651 searching for changes
652 652 changeset: 1:1acbe71ce432
653 653 tag: tip
654 654 user: test
655 655 date: Thu Jan 01 00:00:00 1970 +0000
656 656 summary: #1
657 657
658 658 largefiles to upload (1 entities):
659 659 b
660 660
661 661 $ hg -R clone2 outgoing --large --graph --template "{rev}"
662 662 comparing with $TESTTMP/issue3651/src
663 663 searching for changes
664 664 @ 1
665 665
666 666 largefiles to upload (1 entities):
667 667 b
668 668
669 669
670 670 $ cp clone2/b clone2/b1
671 671 $ cp clone2/b clone2/b2
672 672 $ hg -R clone2 add --large clone2/b1 clone2/b2
673 673 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
674 674 Invoking status precommit hook
675 675 A b1
676 676 A b2
677 677 $ hg -R clone2 summary --large
678 678 parent: 2:6095d0695d70 tip
679 679 #2: add largefiles referring same entity
680 680 branch: default
681 681 commit: (clean)
682 682 update: (current)
683 683 phases: 3 draft
684 684 largefiles: 1 entities for 3 files to upload
685 685 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
686 686 comparing with $TESTTMP/issue3651/src
687 687 searching for changes
688 688 1:1acbe71ce432
689 689 2:6095d0695d70
690 690 largefiles to upload (1 entities):
691 691 b
692 692 b1
693 693 b2
694 694
695 695 $ hg -R clone2 cat -r 1 clone2/.hglf/b
696 696 89e6c98d92887913cadf06b2adb97f26cde4849b
697 697 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
698 698 comparing with $TESTTMP/issue3651/src
699 699 query 1; heads
700 700 searching for changes
701 701 all remote heads known locally
702 702 1:1acbe71ce432
703 703 2:6095d0695d70
704 704 finding outgoing largefiles: 0/2 revisions (0.00%)
705 705 finding outgoing largefiles: 1/2 revisions (50.00%)
706 706 largefiles to upload (1 entities):
707 707 b
708 708 89e6c98d92887913cadf06b2adb97f26cde4849b
709 709 b1
710 710 89e6c98d92887913cadf06b2adb97f26cde4849b
711 711 b2
712 712 89e6c98d92887913cadf06b2adb97f26cde4849b
713 713
714 714
715 715 $ echo bbb > clone2/b
716 716 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
717 717 Invoking status precommit hook
718 718 M b
719 719 $ echo bbbb > clone2/b
720 720 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
721 721 Invoking status precommit hook
722 722 M b
723 723 $ cp clone2/b1 clone2/b
724 724 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
725 725 Invoking status precommit hook
726 726 M b
727 727 $ hg -R clone2 summary --large
728 728 parent: 5:036794ea641c tip
729 729 #5: refer existing largefile entity again
730 730 branch: default
731 731 commit: (clean)
732 732 update: (current)
733 733 phases: 6 draft
734 734 largefiles: 3 entities for 3 files to upload
735 735 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
736 736 comparing with $TESTTMP/issue3651/src
737 737 searching for changes
738 738 1:1acbe71ce432
739 739 2:6095d0695d70
740 740 3:7983dce246cc
741 741 4:233f12ada4ae
742 742 5:036794ea641c
743 743 largefiles to upload (3 entities):
744 744 b
745 745 b1
746 746 b2
747 747
748 748 $ hg -R clone2 cat -r 3 clone2/.hglf/b
749 749 c801c9cfe94400963fcb683246217d5db77f9a9a
750 750 $ hg -R clone2 cat -r 4 clone2/.hglf/b
751 751 13f9ed0898e315bf59dc2973fec52037b6f441a2
752 752 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
753 753 comparing with $TESTTMP/issue3651/src
754 754 query 1; heads
755 755 searching for changes
756 756 all remote heads known locally
757 757 1:1acbe71ce432
758 758 2:6095d0695d70
759 759 3:7983dce246cc
760 760 4:233f12ada4ae
761 761 5:036794ea641c
762 762 finding outgoing largefiles: 0/5 revisions (0.00%)
763 763 finding outgoing largefiles: 1/5 revisions (20.00%)
764 764 finding outgoing largefiles: 2/5 revisions (40.00%)
765 765 finding outgoing largefiles: 3/5 revisions (60.00%)
766 766 finding outgoing largefiles: 4/5 revisions (80.00%)
767 767 largefiles to upload (3 entities):
768 768 b
769 769 13f9ed0898e315bf59dc2973fec52037b6f441a2
770 770 89e6c98d92887913cadf06b2adb97f26cde4849b
771 771 c801c9cfe94400963fcb683246217d5db77f9a9a
772 772 b1
773 773 89e6c98d92887913cadf06b2adb97f26cde4849b
774 774 b2
775 775 89e6c98d92887913cadf06b2adb97f26cde4849b
776 776
777 777
778 778 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
779 779 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
780 780
781 781 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
782 782 summary" and "hg outgoing", even though files in outgoing revision #2
783 783 and #5 refer it.
784 784
785 785 $ hg -R clone2 push -r 1 -q
786 786 $ hg -R clone2 summary --large
787 787 parent: 5:036794ea641c tip
788 788 #5: refer existing largefile entity again
789 789 branch: default
790 790 commit: (clean)
791 791 update: (current)
792 792 phases: 6 draft
793 793 largefiles: 2 entities for 1 files to upload
794 794 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
795 795 comparing with $TESTTMP/issue3651/src
796 796 searching for changes
797 797 2:6095d0695d70
798 798 3:7983dce246cc
799 799 4:233f12ada4ae
800 800 5:036794ea641c
801 801 largefiles to upload (2 entities):
802 802 b
803 803
804 804 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
805 805 comparing with $TESTTMP/issue3651/src
806 806 query 1; heads
807 807 searching for changes
808 808 all remote heads known locally
809 809 2:6095d0695d70
810 810 3:7983dce246cc
811 811 4:233f12ada4ae
812 812 5:036794ea641c
813 813 finding outgoing largefiles: 0/4 revisions (0.00%)
814 814 finding outgoing largefiles: 1/4 revisions (25.00%)
815 815 finding outgoing largefiles: 2/4 revisions (50.00%)
816 816 finding outgoing largefiles: 3/4 revisions (75.00%)
817 817 largefiles to upload (2 entities):
818 818 b
819 819 13f9ed0898e315bf59dc2973fec52037b6f441a2
820 820 c801c9cfe94400963fcb683246217d5db77f9a9a
821 821
822 822
823 823 $ cd ..
824 824
825 825 merge action 'd' for 'local renamed directory to d2/g' which has no filename
826 826 ==================================================================================
827 827
828 828 $ hg init merge-action
829 829 $ cd merge-action
830 830 $ touch l
831 831 $ hg add --large l
832 832 $ mkdir d1
833 833 $ touch d1/f
834 834 $ hg ci -Aqm0
835 835 Invoking status precommit hook
836 836 A d1/f
837 837 A l
838 838 $ echo > d1/f
839 839 $ touch d1/g
840 840 $ hg ci -Aqm1
841 841 Invoking status precommit hook
842 842 M d1/f
843 843 A d1/g
844 844 $ hg up -qr0
845 845 $ hg mv d1 d2
846 846 moving d1/f to d2/f
847 847 $ hg ci -qm2
848 848 Invoking status precommit hook
849 849 A d2/f
850 850 R d1/f
851 851 $ hg merge
852 852 merging d2/f and d1/f to d2/f
853 853 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
854 854 (branch merge, don't forget to commit)
855 855 $ cd ..
856 856
857 857
858 858 Merge conflicts:
859 859 =====================
860 860
861 861 $ hg init merge
862 862 $ cd merge
863 863 $ echo 0 > f-different
864 864 $ echo 0 > f-same
865 865 $ echo 0 > f-unchanged-1
866 866 $ echo 0 > f-unchanged-2
867 867 $ hg add --large *
868 868 $ hg ci -m0
869 869 Invoking status precommit hook
870 870 A f-different
871 871 A f-same
872 872 A f-unchanged-1
873 873 A f-unchanged-2
874 874 $ echo tmp1 > f-unchanged-1
875 875 $ echo tmp1 > f-unchanged-2
876 876 $ echo tmp1 > f-same
877 877 $ hg ci -m1
878 878 Invoking status precommit hook
879 879 M f-same
880 880 M f-unchanged-1
881 881 M f-unchanged-2
882 882 $ echo 2 > f-different
883 883 $ echo 0 > f-unchanged-1
884 884 $ echo 1 > f-unchanged-2
885 885 $ echo 1 > f-same
886 886 $ hg ci -m2
887 887 Invoking status precommit hook
888 888 M f-different
889 889 M f-same
890 890 M f-unchanged-1
891 891 M f-unchanged-2
892 892 $ hg up -qr0
893 893 $ echo tmp2 > f-unchanged-1
894 894 $ echo tmp2 > f-unchanged-2
895 895 $ echo tmp2 > f-same
896 896 $ hg ci -m3
897 897 Invoking status precommit hook
898 898 M f-same
899 899 M f-unchanged-1
900 900 M f-unchanged-2
901 901 created new head
902 902 $ echo 1 > f-different
903 903 $ echo 1 > f-unchanged-1
904 904 $ echo 0 > f-unchanged-2
905 905 $ echo 1 > f-same
906 906 $ hg ci -m4
907 907 Invoking status precommit hook
908 908 M f-different
909 909 M f-same
910 910 M f-unchanged-1
911 911 M f-unchanged-2
912 912 $ hg merge
913 913 largefile f-different has a merge conflict
914 914 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
915 915 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
916 916 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
917 917 getting changed largefiles
918 918 1 largefiles updated, 0 removed
919 919 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
920 920 (branch merge, don't forget to commit)
921 921 $ cat f-different
922 922 1
923 923 $ cat f-same
924 924 1
925 925 $ cat f-unchanged-1
926 926 1
927 927 $ cat f-unchanged-2
928 928 1
929 929 $ cd ..
930 930
931 931 Test largefile insulation (do not enabled a side effect
932 932 ========================================================
933 933
934 934 Check whether "largefiles" feature is supported only in repositories
935 935 enabling largefiles extension.
936 936
937 937 $ mkdir individualenabling
938 938 $ cd individualenabling
939 939
940 940 $ hg init enabledlocally
941 941 $ echo large > enabledlocally/large
942 942 $ hg -R enabledlocally add --large enabledlocally/large
943 943 $ hg -R enabledlocally commit -m '#0'
944 944 Invoking status precommit hook
945 945 A large
946 946
947 947 $ hg init notenabledlocally
948 948 $ echo large > notenabledlocally/large
949 949 $ hg -R notenabledlocally add --large notenabledlocally/large
950 950 $ hg -R notenabledlocally commit -m '#0'
951 951 Invoking status precommit hook
952 952 A large
953 953
954 954 $ cat >> $HGRCPATH <<EOF
955 955 > [extensions]
956 956 > # disable globally
957 957 > largefiles=!
958 958 > EOF
959 959 $ cat >> enabledlocally/.hg/hgrc <<EOF
960 960 > [extensions]
961 961 > # enable locally
962 962 > largefiles=
963 963 > EOF
964 964 $ hg -R enabledlocally root
965 965 $TESTTMP/individualenabling/enabledlocally
966 966 $ hg -R notenabledlocally root
967 967 abort: repository requires features unknown to this Mercurial: largefiles!
968 968 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
969 969 [255]
970 970
971 971 $ hg init push-dst
972 972 $ hg -R enabledlocally push push-dst
973 973 pushing to push-dst
974 974 abort: required features are not supported in the destination: largefiles
975 975 [255]
976 976
977 977 $ hg init pull-src
978 978 $ hg -R pull-src pull enabledlocally
979 979 pulling from enabledlocally
980 980 abort: required features are not supported in the destination: largefiles
981 981 [255]
982 982
983 983 $ hg clone enabledlocally clone-dst
984 984 abort: repository requires features unknown to this Mercurial: largefiles!
985 985 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
986 986 [255]
987 987 $ test -d clone-dst
988 988 [1]
989 989 $ hg clone --pull enabledlocally clone-pull-dst
990 990 abort: required features are not supported in the destination: largefiles
991 991 [255]
992 992 $ test -d clone-pull-dst
993 993 [1]
994 994
995 995 #if serve
996 996
997 997 Test largefiles specific peer setup, when largefiles is enabled
998 998 locally (issue4109)
999 999
1000 1000 $ hg showconfig extensions | grep largefiles
1001 1001 extensions.largefiles=!
1002 1002 $ mkdir -p $TESTTMP/individualenabling/usercache
1003 1003
1004 1004 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
1005 1005 $ cat hg.pid >> $DAEMON_PIDS
1006 1006
1007 1007 $ hg init pull-dst
1008 1008 $ cat > pull-dst/.hg/hgrc <<EOF
1009 1009 > [extensions]
1010 1010 > # enable locally
1011 1011 > largefiles=
1012 1012 > [largefiles]
1013 1013 > # ignore system cache to force largefiles specific wire proto access
1014 1014 > usercache=$TESTTMP/individualenabling/usercache
1015 1015 > EOF
1016 1016 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
1017 1017
1018 1018 $ killdaemons.py
1019 1019 #endif
1020 1020
1021 1021 Test overridden functions work correctly even for repos disabling
1022 1022 largefiles (issue4547)
1023 1023
1024 1024 $ hg showconfig extensions | grep largefiles
1025 1025 extensions.largefiles=!
1026 1026
1027 1027 (test updating implied by clone)
1028 1028
1029 1029 $ hg init enabled-but-no-largefiles
1030 1030 $ echo normal1 > enabled-but-no-largefiles/normal1
1031 1031 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
1032 1032 $ hg -R enabled-but-no-largefiles commit -m '#0@enabled-but-no-largefiles'
1033 1033 Invoking status precommit hook
1034 1034 A normal1
1035 1035 $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
1036 1036 > [extensions]
1037 1037 > # enable locally
1038 1038 > largefiles=
1039 1039 > EOF
1040 1040 $ hg clone -q enabled-but-no-largefiles no-largefiles
1041 1041
1042 1042 $ echo normal2 > enabled-but-no-largefiles/normal2
1043 1043 $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
1044 1044 $ hg -R enabled-but-no-largefiles commit -m '#1@enabled-but-no-largefiles'
1045 1045 Invoking status precommit hook
1046 1046 A normal2
1047 1047
1048 1048 $ echo normal3 > no-largefiles/normal3
1049 1049 $ hg -R no-largefiles add no-largefiles/normal3
1050 1050 $ hg -R no-largefiles commit -m '#1@no-largefiles'
1051 1051 Invoking status precommit hook
1052 1052 A normal3
1053 1053
1054 1054 $ hg -R no-largefiles -q pull --rebase
1055 1055 Invoking status precommit hook
1056 1056 A normal3
1057 1057
1058 1058 (test reverting)
1059 1059
1060 1060 $ hg init subrepo-root
1061 1061 $ cat >> subrepo-root/.hg/hgrc <<EOF
1062 1062 > [extensions]
1063 1063 > # enable locally
1064 1064 > largefiles=
1065 1065 > EOF
1066 1066 $ echo large > subrepo-root/large
1067 1067 $ mkdir -p subrepo-root/dir/subdir
1068 1068 $ echo large2 > subrepo-root/dir/subdir/large.bin
1069 1069 $ hg -R subrepo-root add --large subrepo-root/large subrepo-root/dir/subdir/large.bin
1070 1070 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1071 1071 $ cat > subrepo-root/.hgsub <<EOF
1072 1072 > no-largefiles = no-largefiles
1073 1073 > EOF
1074 1074 $ hg -R subrepo-root add subrepo-root/.hgsub
1075 1075 $ hg -R subrepo-root commit -m '#0'
1076 1076 Invoking status precommit hook
1077 1077 A .hgsub
1078 1078 A dir/subdir/large.bin
1079 1079 A large
1080 1080 ? .hgsubstate
1081 1081 $ echo dirty >> subrepo-root/large
1082 1082 $ echo dirty >> subrepo-root/no-largefiles/normal1
1083 1083 $ hg -R subrepo-root status -S
1084 1084 M large
1085 1085 M no-largefiles/normal1
1086 1086 $ hg -R subrepo-root extdiff -p echo -S --config extensions.extdiff=
1087 1087 "*\\no-largefiles\\normal1" "*\\no-largefiles\\normal1" (glob) (windows !)
1088 1088 */no-largefiles/normal1 */no-largefiles/normal1 (glob) (no-windows !)
1089 1089 [1]
1090 1090 $ hg -R subrepo-root revert --all
1091 1091 reverting subrepo-root/.hglf/large
1092 1092 reverting subrepo no-largefiles
1093 1093 reverting subrepo-root/no-largefiles/normal1
1094 1094
1095 1095 Move (and then undo) a directory move with only largefiles.
1096 1096
1097 1097 $ cd subrepo-root
1098 1098 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1099 1099 .hglf/
1100 1100 .hglf/dir/
1101 1101 .hglf/dir/subdir/
1102 1102 .hglf/dir/subdir/large.bin
1103 1103 .hglf/large
1104 1104 dir/
1105 1105 dir/subdir/
1106 1106 dir/subdir/large.bin
1107 1107 large
1108 1108 large.orig
1109 1109
1110 1110 $ hg mv dir/subdir dir/subdir2
1111 1111 moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin
1112 1112
1113 1113 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1114 1114 .hglf/
1115 1115 .hglf/dir/
1116 1116 .hglf/dir/subdir2/
1117 1117 .hglf/dir/subdir2/large.bin
1118 1118 .hglf/large
1119 1119 dir/
1120 1120 dir/subdir2/
1121 1121 dir/subdir2/large.bin
1122 1122 large
1123 1123 large.orig
1124 1124 $ hg status -C
1125 1125 A dir/subdir2/large.bin
1126 1126 dir/subdir/large.bin
1127 1127 R dir/subdir/large.bin
1128 1128 ? large.orig
1129 1129
1130 1130 $ echo 'modified' > dir/subdir2/large.bin
1131 1131 $ hg status -C
1132 1132 A dir/subdir2/large.bin
1133 1133 dir/subdir/large.bin
1134 1134 R dir/subdir/large.bin
1135 1135 ? large.orig
1136 1136
1137 1137 $ hg revert --all
1138 forgetting .hglf/dir/subdir2/large.bin
1138 1139 undeleting .hglf/dir/subdir/large.bin
1139 forgetting .hglf/dir/subdir2/large.bin
1140 1140 reverting subrepo no-largefiles
1141 1141
1142 1142 $ hg status -C
1143 1143 ? dir/subdir2/large.bin
1144 1144 ? large.orig
1145 1145
1146 1146 The content of the forgotten file shouldn't be clobbered
1147 1147
1148 1148 $ cat dir/subdir2/large.bin
1149 1149 modified
1150 1150
1151 1151 The standin for subdir2 should be deleted, not just dropped
1152 1152
1153 1153 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1154 1154 .hglf/
1155 1155 .hglf/dir/
1156 1156 .hglf/dir/subdir/
1157 1157 .hglf/dir/subdir/large.bin
1158 1158 .hglf/large
1159 1159 dir/
1160 1160 dir/subdir/
1161 1161 dir/subdir/large.bin
1162 1162 dir/subdir2/
1163 1163 dir/subdir2/large.bin
1164 1164 large
1165 1165 large.orig
1166 1166
1167 1167 $ rm -r dir/subdir2
1168 1168
1169 1169 'subdir' should not be in the destination. It would be if the subdir2 directory
1170 1170 existed under .hglf/.
1171 1171 $ hg mv dir/subdir dir/subdir2
1172 1172 moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin
1173 1173
1174 1174 $ hg status -C
1175 1175 A dir/subdir2/large.bin
1176 1176 dir/subdir/large.bin
1177 1177 R dir/subdir/large.bin
1178 1178 ? large.orig
1179 1179
1180 1180 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1181 1181 .hglf/
1182 1182 .hglf/dir/
1183 1183 .hglf/dir/subdir2/
1184 1184 .hglf/dir/subdir2/large.bin
1185 1185 .hglf/large
1186 1186 dir/
1187 1187 dir/subdir2/
1188 1188 dir/subdir2/large.bin
1189 1189 large
1190 1190 large.orig
1191 1191
1192 1192 Start from scratch, and rename something other than the final path component.
1193 1193
1194 1194 $ hg up -qC .
1195 1195 $ hg --config extensions.purge= purge
1196 1196
1197 1197 $ hg mv dir/subdir dir2/subdir
1198 1198 moving .hglf/dir/subdir/large.bin to .hglf/dir2/subdir/large.bin
1199 1199
1200 1200 $ hg status -C
1201 1201 A dir2/subdir/large.bin
1202 1202 dir/subdir/large.bin
1203 1203 R dir/subdir/large.bin
1204 1204
1205 1205 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1206 1206 .hglf/
1207 1207 .hglf/dir2/
1208 1208 .hglf/dir2/subdir/
1209 1209 .hglf/dir2/subdir/large.bin
1210 1210 .hglf/large
1211 1211 dir2/
1212 1212 dir2/subdir/
1213 1213 dir2/subdir/large.bin
1214 1214 large
1215 1215
1216 1216 $ hg revert --all
1217 forgetting .hglf/dir2/subdir/large.bin
1217 1218 undeleting .hglf/dir/subdir/large.bin
1218 forgetting .hglf/dir2/subdir/large.bin
1219 1219 reverting subrepo no-largefiles
1220 1220
1221 1221 $ hg status -C
1222 1222 ? dir2/subdir/large.bin
1223 1223
1224 1224 $ $PYTHON $TESTDIR/list-tree.py .hglf dir* large*
1225 1225 .hglf/
1226 1226 .hglf/dir/
1227 1227 .hglf/dir/subdir/
1228 1228 .hglf/dir/subdir/large.bin
1229 1229 .hglf/large
1230 1230 dir/
1231 1231 dir/subdir/
1232 1232 dir/subdir/large.bin
1233 1233 dir2/
1234 1234 dir2/subdir/
1235 1235 dir2/subdir/large.bin
1236 1236 large
1237 1237
1238 1238 $ cd ../..
1239 1239
1240 1240 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1241 1241 =========================================================================
1242 1242
1243 1243 $ hg showconfig extensions | grep largefiles
1244 1244 extensions.largefiles=!
1245 1245
1246 1246 $ mkdir issue3861
1247 1247 $ cd issue3861
1248 1248 $ hg init src
1249 1249 $ hg clone -q src dst
1250 1250 $ echo a > src/a
1251 1251 $ hg -R src commit -Aqm "#0"
1252 1252 Invoking status precommit hook
1253 1253 A a
1254 1254
1255 1255 $ cat >> dst/.hg/hgrc <<EOF
1256 1256 > [extensions]
1257 1257 > largefiles=
1258 1258 > EOF
1259 1259 $ hg -R dst pull --rebase
1260 1260 pulling from $TESTTMP/issue3861/src
1261 1261 requesting all changes
1262 1262 adding changesets
1263 1263 adding manifests
1264 1264 adding file changes
1265 1265 added 1 changesets with 1 changes to 1 files
1266 1266 new changesets bf5e395ced2c
1267 1267 nothing to rebase - updating instead
1268 1268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1269 1269
1270 1270 $ cd ..
@@ -1,1889 +1,1889 b''
1 1 This file used to contains all largefile tests.
2 2 Do not add any new tests in this file as it his already far too long to run.
3 3
4 4 It contains all the testing of the basic concepts of large file in a single block.
5 5
6 6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
7 7 $ mkdir "${USERCACHE}"
8 8 $ cat >> $HGRCPATH <<EOF
9 9 > [extensions]
10 10 > largefiles=
11 11 > purge=
12 12 > rebase=
13 13 > transplant=
14 14 > [phases]
15 15 > publish=False
16 16 > [largefiles]
17 17 > minsize=2
18 18 > patterns=glob:**.dat
19 19 > usercache=${USERCACHE}
20 20 > [hooks]
21 21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
22 22 > EOF
23 23
24 24 Create the repo with a couple of revisions of both large and normal
25 25 files.
26 26 Test status and dirstate of largefiles and that summary output is correct.
27 27
28 28 $ hg init a
29 29 $ cd a
30 30 $ mkdir sub
31 31 $ echo normal1 > normal1
32 32 $ echo normal2 > sub/normal2
33 33 $ echo large1 > large1
34 34 $ echo large2 > sub/large2
35 35 $ hg add normal1 sub/normal2
36 36 $ hg add --large large1 sub/large2
37 37 $ hg commit -m "add files"
38 38 Invoking status precommit hook
39 39 A large1
40 40 A normal1
41 41 A sub/large2
42 42 A sub/normal2
43 43 $ touch large1 sub/large2
44 44 $ sleep 1
45 45 $ hg st
46 46 $ hg debugstate --nodates
47 47 n 644 41 set .hglf/large1
48 48 n 644 41 set .hglf/sub/large2
49 49 n 644 8 set normal1
50 50 n 644 8 set sub/normal2
51 51 $ hg debugstate --large --nodates
52 52 n 644 7 set large1
53 53 n 644 7 set sub/large2
54 54 $ echo normal11 > normal1
55 55 $ echo normal22 > sub/normal2
56 56 $ echo large11 > large1
57 57 $ echo large22 > sub/large2
58 58 $ hg commit -m "edit files"
59 59 Invoking status precommit hook
60 60 M large1
61 61 M normal1
62 62 M sub/large2
63 63 M sub/normal2
64 64 $ hg sum --large
65 65 parent: 1:ce8896473775 tip
66 66 edit files
67 67 branch: default
68 68 commit: (clean)
69 69 update: (current)
70 70 phases: 2 draft
71 71 largefiles: (no remote repo)
72 72
73 73 Commit preserved largefile contents.
74 74
75 75 $ cat normal1
76 76 normal11
77 77 $ cat large1
78 78 large11
79 79 $ cat sub/normal2
80 80 normal22
81 81 $ cat sub/large2
82 82 large22
83 83
84 84 Test status, subdir and unknown files
85 85
86 86 $ echo unknown > sub/unknown
87 87 $ hg st --all
88 88 ? sub/unknown
89 89 C large1
90 90 C normal1
91 91 C sub/large2
92 92 C sub/normal2
93 93 $ hg st --all sub
94 94 ? sub/unknown
95 95 C sub/large2
96 96 C sub/normal2
97 97 $ rm sub/unknown
98 98
99 99 Test messages and exit codes for remove warning cases
100 100
101 101 $ hg remove -A large1
102 102 not removing large1: file still exists
103 103 [1]
104 104 $ echo 'modified' > large1
105 105 $ hg remove large1
106 106 not removing large1: file is modified (use -f to force removal)
107 107 [1]
108 108 $ echo 'new' > normalnew
109 109 $ hg add normalnew
110 110 $ echo 'new' > largenew
111 111 $ hg add --large normalnew
112 112 normalnew already tracked!
113 113 $ hg remove normalnew largenew
114 114 not removing largenew: file is untracked
115 115 not removing normalnew: file has been marked for add (use 'hg forget' to undo add)
116 116 [1]
117 117 $ rm normalnew largenew
118 118 $ hg up -Cq
119 119
120 120 Remove both largefiles and normal files.
121 121
122 122 $ hg remove normal1 large1
123 123 $ hg status large1
124 124 R large1
125 125 $ hg commit -m "remove files"
126 126 Invoking status precommit hook
127 127 R large1
128 128 R normal1
129 129 $ ls
130 130 sub
131 131 $ echo "testlargefile" > large1-test
132 132 $ hg add --large large1-test
133 133 $ hg st
134 134 A large1-test
135 135 $ hg rm large1-test
136 136 not removing large1-test: file has been marked for add (use forget to undo)
137 137 [1]
138 138 $ hg st
139 139 A large1-test
140 140 $ hg forget large1-test
141 141 $ hg st
142 142 ? large1-test
143 143 $ hg remove large1-test
144 144 not removing large1-test: file is untracked
145 145 [1]
146 146 $ hg forget large1-test
147 147 not removing large1-test: file is already untracked
148 148 [1]
149 149 $ rm large1-test
150 150
151 151 Copy both largefiles and normal files (testing that status output is correct).
152 152
153 153 $ hg cp sub/normal2 normal1
154 154 $ hg cp sub/large2 large1
155 155 $ hg commit -m "copy files"
156 156 Invoking status precommit hook
157 157 A large1
158 158 A normal1
159 159 $ cat normal1
160 160 normal22
161 161 $ cat large1
162 162 large22
163 163
164 164 Test moving largefiles and verify that normal files are also unaffected.
165 165
166 166 $ hg mv normal1 normal3
167 167 $ hg mv large1 large3
168 168 $ hg mv sub/normal2 sub/normal4
169 169 $ hg mv sub/large2 sub/large4
170 170 $ hg commit -m "move files"
171 171 Invoking status precommit hook
172 172 A large3
173 173 A normal3
174 174 A sub/large4
175 175 A sub/normal4
176 176 R large1
177 177 R normal1
178 178 R sub/large2
179 179 R sub/normal2
180 180 $ cat normal3
181 181 normal22
182 182 $ cat large3
183 183 large22
184 184 $ cat sub/normal4
185 185 normal22
186 186 $ cat sub/large4
187 187 large22
188 188
189 189
190 190 #if serve
191 191 Test display of largefiles in hgweb
192 192
193 193 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
194 194 $ cat ../hg.pid >> $DAEMON_PIDS
195 195 $ get-with-headers.py $LOCALIP:$HGPORT 'file/tip/?style=raw'
196 196 200 Script output follows
197 197
198 198
199 199 drwxr-xr-x sub
200 200 -rw-r--r-- 41 large3
201 201 -rw-r--r-- 9 normal3
202 202
203 203
204 204 $ get-with-headers.py $LOCALIP:$HGPORT 'file/tip/sub/?style=raw'
205 205 200 Script output follows
206 206
207 207
208 208 -rw-r--r-- 41 large4
209 209 -rw-r--r-- 9 normal4
210 210
211 211
212 212 $ killdaemons.py
213 213 #endif
214 214
215 215 Test largefiles can be loaded in hgweb (wrapcommand() shouldn't fail)
216 216
217 217 $ cat <<EOF > "$TESTTMP/hgweb.cgi"
218 218 > #!$PYTHON
219 219 > from mercurial import demandimport; demandimport.enable()
220 220 > from mercurial.hgweb import hgweb
221 221 > from mercurial.hgweb import wsgicgi
222 222 > application = hgweb(b'.', b'test repo')
223 223 > wsgicgi.launch(application)
224 224 > EOF
225 225 $ . "$TESTDIR/cgienv"
226 226
227 227 $ SCRIPT_NAME='' \
228 228 > $PYTHON "$TESTTMP/hgweb.cgi" > /dev/null
229 229
230 230 Test archiving the various revisions. These hit corner cases known with
231 231 archiving.
232 232
233 233 $ hg archive -r 0 ../archive0
234 234 $ hg archive -r 1 ../archive1
235 235 $ hg archive -r 2 ../archive2
236 236 $ hg archive -r 3 ../archive3
237 237 $ hg archive -r 4 ../archive4
238 238 $ cd ../archive0
239 239 $ cat normal1
240 240 normal1
241 241 $ cat large1
242 242 large1
243 243 $ cat sub/normal2
244 244 normal2
245 245 $ cat sub/large2
246 246 large2
247 247 $ cd ../archive1
248 248 $ cat normal1
249 249 normal11
250 250 $ cat large1
251 251 large11
252 252 $ cat sub/normal2
253 253 normal22
254 254 $ cat sub/large2
255 255 large22
256 256 $ cd ../archive2
257 257 $ ls
258 258 sub
259 259 $ cat sub/normal2
260 260 normal22
261 261 $ cat sub/large2
262 262 large22
263 263 $ cd ../archive3
264 264 $ cat normal1
265 265 normal22
266 266 $ cat large1
267 267 large22
268 268 $ cat sub/normal2
269 269 normal22
270 270 $ cat sub/large2
271 271 large22
272 272 $ cd ../archive4
273 273 $ cat normal3
274 274 normal22
275 275 $ cat large3
276 276 large22
277 277 $ cat sub/normal4
278 278 normal22
279 279 $ cat sub/large4
280 280 large22
281 281
282 282 Commit corner case: specify files to commit.
283 283
284 284 $ cd ../a
285 285 $ echo normal3 > normal3
286 286 $ echo large3 > large3
287 287 $ echo normal4 > sub/normal4
288 288 $ echo large4 > sub/large4
289 289 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
290 290 Invoking status precommit hook
291 291 M large3
292 292 M normal3
293 293 M sub/large4
294 294 M sub/normal4
295 295 $ cat normal3
296 296 normal3
297 297 $ cat large3
298 298 large3
299 299 $ cat sub/normal4
300 300 normal4
301 301 $ cat sub/large4
302 302 large4
303 303
304 304 One more commit corner case: commit from a subdirectory.
305 305
306 306 $ cd ../a
307 307 $ echo normal33 > normal3
308 308 $ echo large33 > large3
309 309 $ echo normal44 > sub/normal4
310 310 $ echo large44 > sub/large4
311 311 $ cd sub
312 312 $ hg commit -m "edit files yet again"
313 313 Invoking status precommit hook
314 314 M large3
315 315 M normal3
316 316 M sub/large4
317 317 M sub/normal4
318 318 $ cat ../normal3
319 319 normal33
320 320 $ cat ../large3
321 321 large33
322 322 $ cat normal4
323 323 normal44
324 324 $ cat large4
325 325 large44
326 326
327 327 Committing standins is not allowed.
328 328
329 329 $ cd ..
330 330 $ echo large3 > large3
331 331 $ hg commit .hglf/large3 -m "try to commit standin"
332 332 abort: file ".hglf/large3" is a largefile standin
333 333 (commit the largefile itself instead)
334 334 [255]
335 335
336 336 Corner cases for adding largefiles.
337 337
338 338 $ echo large5 > large5
339 339 $ hg add --large large5
340 340 $ hg add --large large5
341 341 large5 already a largefile
342 342 $ mkdir sub2
343 343 $ echo large6 > sub2/large6
344 344 $ echo large7 > sub2/large7
345 345 $ hg add --large sub2
346 346 adding sub2/large6 as a largefile
347 347 adding sub2/large7 as a largefile
348 348 $ hg st
349 349 M large3
350 350 A large5
351 351 A sub2/large6
352 352 A sub2/large7
353 353
354 354 Committing directories containing only largefiles.
355 355
356 356 $ mkdir -p z/y/x/m
357 357 $ touch z/y/x/m/large1
358 358 $ touch z/y/x/large2
359 359 $ hg add --large z/y/x/m/large1 z/y/x/large2
360 360 $ hg commit -m "Subdir with directory only containing largefiles" z
361 361 Invoking status precommit hook
362 362 M large3
363 363 A large5
364 364 A sub2/large6
365 365 A sub2/large7
366 366 A z/y/x/large2
367 367 A z/y/x/m/large1
368 368
369 369 (and a bit of log testing)
370 370
371 371 $ hg log -T '{rev}\n' z/y/x/m/large1
372 372 7
373 373 $ hg log -T '{rev}\n' z/y/x/m # with only a largefile
374 374 7
375 375
376 376 $ hg rollback --quiet
377 377 $ touch z/y/x/m/normal
378 378 $ hg add z/y/x/m/normal
379 379 $ hg commit -m "Subdir with mixed contents" z
380 380 Invoking status precommit hook
381 381 M large3
382 382 A large5
383 383 A sub2/large6
384 384 A sub2/large7
385 385 A z/y/x/large2
386 386 A z/y/x/m/large1
387 387 A z/y/x/m/normal
388 388 $ hg st
389 389 M large3
390 390 A large5
391 391 A sub2/large6
392 392 A sub2/large7
393 393 $ hg rollback --quiet
394 394 $ hg revert z/y/x/large2 z/y/x/m/large1
395 395 $ rm z/y/x/large2 z/y/x/m/large1
396 396 $ hg commit -m "Subdir with normal contents" z
397 397 Invoking status precommit hook
398 398 M large3
399 399 A large5
400 400 A sub2/large6
401 401 A sub2/large7
402 402 A z/y/x/m/normal
403 403 $ hg st
404 404 M large3
405 405 A large5
406 406 A sub2/large6
407 407 A sub2/large7
408 408 $ hg rollback --quiet
409 409 $ hg revert --quiet z
410 410 $ hg commit -m "Empty subdir" z
411 411 abort: z: no match under directory!
412 412 [255]
413 413 $ rm -rf z
414 414 $ hg ci -m "standin" .hglf
415 415 abort: file ".hglf" is a largefile standin
416 416 (commit the largefile itself instead)
417 417 [255]
418 418
419 419 Test "hg status" with combination of 'file pattern' and 'directory
420 420 pattern' for largefiles:
421 421
422 422 $ hg status sub2/large6 sub2
423 423 A sub2/large6
424 424 A sub2/large7
425 425
426 426 Config settings (pattern **.dat, minsize 2 MB) are respected.
427 427
428 428 $ echo testdata > test.dat
429 429 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
430 430 $ hg add
431 431 adding reallylarge as a largefile
432 432 adding test.dat as a largefile
433 433
434 434 Test that minsize and --lfsize handle float values;
435 435 also tests that --lfsize overrides largefiles.minsize.
436 436 (0.250 MB = 256 kB = 262144 B)
437 437
438 438 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
439 439 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
440 440 $ hg --config largefiles.minsize=.25 add
441 441 adding ratherlarge as a largefile
442 442 adding medium
443 443 $ hg forget medium
444 444 $ hg --config largefiles.minsize=.25 add --lfsize=.125
445 445 adding medium as a largefile
446 446 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
447 447 $ hg --config largefiles.minsize=.25 add --lfsize=.125
448 448 adding notlarge
449 449 $ hg forget notlarge
450 450
451 451 Test forget on largefiles.
452 452
453 453 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
454 454 $ hg commit -m "add/edit more largefiles"
455 455 Invoking status precommit hook
456 456 A sub2/large6
457 457 A sub2/large7
458 458 R large3
459 459 ? large5
460 460 ? medium
461 461 ? notlarge
462 462 ? ratherlarge
463 463 ? reallylarge
464 464 ? test.dat
465 465 $ hg st
466 466 ? large3
467 467 ? large5
468 468 ? medium
469 469 ? notlarge
470 470 ? ratherlarge
471 471 ? reallylarge
472 472 ? test.dat
473 473
474 474 Purge with largefiles: verify that largefiles are still in the working
475 475 dir after a purge.
476 476
477 477 $ hg purge --all
478 478 $ cat sub/large4
479 479 large44
480 480 $ cat sub2/large6
481 481 large6
482 482 $ cat sub2/large7
483 483 large7
484 484
485 485 Test addremove: verify that files that should be added as largefiles are added as
486 486 such and that already-existing largefiles are not added as normal files by
487 487 accident.
488 488
489 489 $ rm normal3
490 490 $ rm sub/large4
491 491 $ echo "testing addremove with patterns" > testaddremove.dat
492 492 $ echo "normaladdremove" > normaladdremove
493 493 $ hg addremove
494 494 removing sub/large4
495 495 adding testaddremove.dat as a largefile
496 496 removing normal3
497 497 adding normaladdremove
498 498
499 499 Test addremove with -R
500 500
501 501 $ hg up -C
502 502 getting changed largefiles
503 503 1 largefiles updated, 0 removed
504 504 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
505 505 $ rm normal3
506 506 $ rm sub/large4
507 507 $ echo "testing addremove with patterns" > testaddremove.dat
508 508 $ echo "normaladdremove" > normaladdremove
509 509 $ cd ..
510 510 $ hg -R a -v addremove
511 511 removing sub/large4
512 512 adding testaddremove.dat as a largefile
513 513 removing normal3
514 514 adding normaladdremove
515 515 $ cd a
516 516
517 517 Test 3364
518 518 $ hg clone . ../addrm
519 519 updating to branch default
520 520 getting changed largefiles
521 521 3 largefiles updated, 0 removed
522 522 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
523 523 $ cd ../addrm
524 524 $ cat >> .hg/hgrc <<EOF
525 525 > [hooks]
526 526 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
527 527 > EOF
528 528 $ touch foo
529 529 $ hg add --large foo
530 530 $ hg ci -m "add foo"
531 531 Invoking status precommit hook
532 532 A foo
533 533 Invoking status postcommit hook
534 534 C foo
535 535 C normal3
536 536 C sub/large4
537 537 C sub/normal4
538 538 C sub2/large6
539 539 C sub2/large7
540 540 $ rm foo
541 541 $ hg st
542 542 ! foo
543 543 hmm.. no precommit invoked, but there is a postcommit??
544 544 $ hg ci -m "will not checkin"
545 545 nothing changed (1 missing files, see 'hg status')
546 546 Invoking status postcommit hook
547 547 ! foo
548 548 C normal3
549 549 C sub/large4
550 550 C sub/normal4
551 551 C sub2/large6
552 552 C sub2/large7
553 553 [1]
554 554 $ hg addremove
555 555 removing foo
556 556 $ hg st
557 557 R foo
558 558 $ hg ci -m "used to say nothing changed"
559 559 Invoking status precommit hook
560 560 R foo
561 561 Invoking status postcommit hook
562 562 C normal3
563 563 C sub/large4
564 564 C sub/normal4
565 565 C sub2/large6
566 566 C sub2/large7
567 567 $ hg st
568 568
569 569 Test 3507 (both normal files and largefiles were a problem)
570 570
571 571 $ touch normal
572 572 $ touch large
573 573 $ hg add normal
574 574 $ hg add --large large
575 575 $ hg ci -m "added"
576 576 Invoking status precommit hook
577 577 A large
578 578 A normal
579 579 Invoking status postcommit hook
580 580 C large
581 581 C normal
582 582 C normal3
583 583 C sub/large4
584 584 C sub/normal4
585 585 C sub2/large6
586 586 C sub2/large7
587 587 $ hg remove normal
588 588 $ hg addremove --traceback
589 589 $ hg ci -m "addremoved normal"
590 590 Invoking status precommit hook
591 591 R normal
592 592 Invoking status postcommit hook
593 593 C large
594 594 C normal3
595 595 C sub/large4
596 596 C sub/normal4
597 597 C sub2/large6
598 598 C sub2/large7
599 599 $ hg up -C '.^'
600 600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
601 601 $ hg remove large
602 602 $ hg addremove --traceback
603 603 $ hg ci -m "removed large"
604 604 Invoking status precommit hook
605 605 R large
606 606 created new head
607 607 Invoking status postcommit hook
608 608 C normal
609 609 C normal3
610 610 C sub/large4
611 611 C sub/normal4
612 612 C sub2/large6
613 613 C sub2/large7
614 614
615 615 Test commit -A (issue3542)
616 616 $ echo large8 > large8
617 617 $ hg add --large large8
618 618 $ hg ci -Am 'this used to add large8 as normal and commit both'
619 619 Invoking status precommit hook
620 620 A large8
621 621 Invoking status postcommit hook
622 622 C large8
623 623 C normal
624 624 C normal3
625 625 C sub/large4
626 626 C sub/normal4
627 627 C sub2/large6
628 628 C sub2/large7
629 629 $ rm large8
630 630 $ hg ci -Am 'this used to not notice the rm'
631 631 removing large8
632 632 Invoking status precommit hook
633 633 R large8
634 634 Invoking status postcommit hook
635 635 C normal
636 636 C normal3
637 637 C sub/large4
638 638 C sub/normal4
639 639 C sub2/large6
640 640 C sub2/large7
641 641
642 642 Test that a standin can't be added as a large file
643 643
644 644 $ touch large
645 645 $ hg add --large large
646 646 $ hg ci -m "add"
647 647 Invoking status precommit hook
648 648 A large
649 649 Invoking status postcommit hook
650 650 C large
651 651 C normal
652 652 C normal3
653 653 C sub/large4
654 654 C sub/normal4
655 655 C sub2/large6
656 656 C sub2/large7
657 657 $ hg remove large
658 658 $ touch large
659 659 $ hg addremove --config largefiles.patterns=**large --traceback
660 660 adding large as a largefile
661 661
662 662 Test that outgoing --large works (with revsets too)
663 663 $ hg outgoing --rev '.^' --large
664 664 comparing with $TESTTMP/a
665 665 searching for changes
666 666 changeset: 8:c02fd3b77ec4
667 667 user: test
668 668 date: Thu Jan 01 00:00:00 1970 +0000
669 669 summary: add foo
670 670
671 671 changeset: 9:289dd08c9bbb
672 672 user: test
673 673 date: Thu Jan 01 00:00:00 1970 +0000
674 674 summary: used to say nothing changed
675 675
676 676 changeset: 10:34f23ac6ac12
677 677 user: test
678 678 date: Thu Jan 01 00:00:00 1970 +0000
679 679 summary: added
680 680
681 681 changeset: 12:710c1b2f523c
682 682 parent: 10:34f23ac6ac12
683 683 user: test
684 684 date: Thu Jan 01 00:00:00 1970 +0000
685 685 summary: removed large
686 686
687 687 changeset: 13:0a3e75774479
688 688 user: test
689 689 date: Thu Jan 01 00:00:00 1970 +0000
690 690 summary: this used to add large8 as normal and commit both
691 691
692 692 changeset: 14:84f3d378175c
693 693 user: test
694 694 date: Thu Jan 01 00:00:00 1970 +0000
695 695 summary: this used to not notice the rm
696 696
697 697 largefiles to upload (1 entities):
698 698 large8
699 699
700 700 $ cd ../a
701 701
702 702 Clone a largefiles repo.
703 703
704 704 $ hg clone . ../b
705 705 updating to branch default
706 706 getting changed largefiles
707 707 3 largefiles updated, 0 removed
708 708 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
709 709 $ cd ../b
710 710 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
711 711 7:daea875e9014 add/edit more largefiles
712 712 6:4355d653f84f edit files yet again
713 713 5:9d5af5072dbd edit files again
714 714 4:74c02385b94c move files
715 715 3:9e8fbc4bce62 copy files
716 716 2:51a0ae4d5864 remove files
717 717 1:ce8896473775 edit files
718 718 0:30d30fe6a5be add files
719 719 $ cat normal3
720 720 normal33
721 721
722 722 Test graph log
723 723
724 724 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n'
725 725 @ 7:daea875e9014 add/edit more largefiles
726 726 |
727 727 o 6:4355d653f84f edit files yet again
728 728 |
729 729 o 5:9d5af5072dbd edit files again
730 730 |
731 731 o 4:74c02385b94c move files
732 732 |
733 733 o 3:9e8fbc4bce62 copy files
734 734 |
735 735 o 2:51a0ae4d5864 remove files
736 736 |
737 737 o 1:ce8896473775 edit files
738 738 |
739 739 o 0:30d30fe6a5be add files
740 740
741 741
742 742 Test log with --patch
743 743
744 744 $ hg log --patch -r 6::7
745 745 changeset: 6:4355d653f84f
746 746 user: test
747 747 date: Thu Jan 01 00:00:00 1970 +0000
748 748 summary: edit files yet again
749 749
750 750 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/large3
751 751 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
752 752 +++ b/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
753 753 @@ -1,1 +1,1 @@
754 754 -baaf12afde9d8d67f25dab6dced0d2bf77dba47c
755 755 +7838695e10da2bb75ac1156565f40a2595fa2fa0
756 756 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
757 757 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
758 758 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
759 759 @@ -1,1 +1,1 @@
760 760 -aeb2210d19f02886dde00dac279729a48471e2f9
761 761 +971fb41e78fea4f8e0ba5244784239371cb00591
762 762 diff -r 9d5af5072dbd -r 4355d653f84f normal3
763 763 --- a/normal3 Thu Jan 01 00:00:00 1970 +0000
764 764 +++ b/normal3 Thu Jan 01 00:00:00 1970 +0000
765 765 @@ -1,1 +1,1 @@
766 766 -normal3
767 767 +normal33
768 768 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
769 769 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
770 770 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
771 771 @@ -1,1 +1,1 @@
772 772 -normal4
773 773 +normal44
774 774
775 775 changeset: 7:daea875e9014
776 776 tag: tip
777 777 user: test
778 778 date: Thu Jan 01 00:00:00 1970 +0000
779 779 summary: add/edit more largefiles
780 780
781 781 diff -r 4355d653f84f -r daea875e9014 .hglf/large3
782 782 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
783 783 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
784 784 @@ -1,1 +0,0 @@
785 785 -7838695e10da2bb75ac1156565f40a2595fa2fa0
786 786 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large6
787 787 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
788 788 +++ b/.hglf/sub2/large6 Thu Jan 01 00:00:00 1970 +0000
789 789 @@ -0,0 +1,1 @@
790 790 +0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30
791 791 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large7
792 792 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
793 793 +++ b/.hglf/sub2/large7 Thu Jan 01 00:00:00 1970 +0000
794 794 @@ -0,0 +1,1 @@
795 795 +bb3151689acb10f0c3125c560d5e63df914bc1af
796 796
797 797
798 798 $ hg log --patch -r 6::7 sub/
799 799 changeset: 6:4355d653f84f
800 800 user: test
801 801 date: Thu Jan 01 00:00:00 1970 +0000
802 802 summary: edit files yet again
803 803
804 804 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
805 805 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
806 806 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
807 807 @@ -1,1 +1,1 @@
808 808 -aeb2210d19f02886dde00dac279729a48471e2f9
809 809 +971fb41e78fea4f8e0ba5244784239371cb00591
810 810 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
811 811 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
812 812 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
813 813 @@ -1,1 +1,1 @@
814 814 -normal4
815 815 +normal44
816 816
817 817
818 818 log with both --follow and --patch
819 819
820 820 $ hg log --follow --patch --limit 2
821 821 changeset: 7:daea875e9014
822 822 tag: tip
823 823 user: test
824 824 date: Thu Jan 01 00:00:00 1970 +0000
825 825 summary: add/edit more largefiles
826 826
827 827 diff -r 4355d653f84f -r daea875e9014 .hglf/large3
828 828 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
829 829 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
830 830 @@ -1,1 +0,0 @@
831 831 -7838695e10da2bb75ac1156565f40a2595fa2fa0
832 832 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large6
833 833 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
834 834 +++ b/.hglf/sub2/large6 Thu Jan 01 00:00:00 1970 +0000
835 835 @@ -0,0 +1,1 @@
836 836 +0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30
837 837 diff -r 4355d653f84f -r daea875e9014 .hglf/sub2/large7
838 838 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
839 839 +++ b/.hglf/sub2/large7 Thu Jan 01 00:00:00 1970 +0000
840 840 @@ -0,0 +1,1 @@
841 841 +bb3151689acb10f0c3125c560d5e63df914bc1af
842 842
843 843 changeset: 6:4355d653f84f
844 844 user: test
845 845 date: Thu Jan 01 00:00:00 1970 +0000
846 846 summary: edit files yet again
847 847
848 848 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/large3
849 849 --- a/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
850 850 +++ b/.hglf/large3 Thu Jan 01 00:00:00 1970 +0000
851 851 @@ -1,1 +1,1 @@
852 852 -baaf12afde9d8d67f25dab6dced0d2bf77dba47c
853 853 +7838695e10da2bb75ac1156565f40a2595fa2fa0
854 854 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
855 855 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
856 856 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
857 857 @@ -1,1 +1,1 @@
858 858 -aeb2210d19f02886dde00dac279729a48471e2f9
859 859 +971fb41e78fea4f8e0ba5244784239371cb00591
860 860 diff -r 9d5af5072dbd -r 4355d653f84f normal3
861 861 --- a/normal3 Thu Jan 01 00:00:00 1970 +0000
862 862 +++ b/normal3 Thu Jan 01 00:00:00 1970 +0000
863 863 @@ -1,1 +1,1 @@
864 864 -normal3
865 865 +normal33
866 866 diff -r 9d5af5072dbd -r 4355d653f84f sub/normal4
867 867 --- a/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
868 868 +++ b/sub/normal4 Thu Jan 01 00:00:00 1970 +0000
869 869 @@ -1,1 +1,1 @@
870 870 -normal4
871 871 +normal44
872 872
873 873 $ hg log --follow --patch sub/large4
874 874 changeset: 6:4355d653f84f
875 875 user: test
876 876 date: Thu Jan 01 00:00:00 1970 +0000
877 877 summary: edit files yet again
878 878
879 879 diff -r 9d5af5072dbd -r 4355d653f84f .hglf/sub/large4
880 880 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
881 881 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
882 882 @@ -1,1 +1,1 @@
883 883 -aeb2210d19f02886dde00dac279729a48471e2f9
884 884 +971fb41e78fea4f8e0ba5244784239371cb00591
885 885
886 886 changeset: 5:9d5af5072dbd
887 887 user: test
888 888 date: Thu Jan 01 00:00:00 1970 +0000
889 889 summary: edit files again
890 890
891 891 diff -r 74c02385b94c -r 9d5af5072dbd .hglf/sub/large4
892 892 --- a/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
893 893 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
894 894 @@ -1,1 +1,1 @@
895 895 -eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
896 896 +aeb2210d19f02886dde00dac279729a48471e2f9
897 897
898 898 changeset: 4:74c02385b94c
899 899 user: test
900 900 date: Thu Jan 01 00:00:00 1970 +0000
901 901 summary: move files
902 902
903 903 diff -r 9e8fbc4bce62 -r 74c02385b94c .hglf/sub/large4
904 904 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
905 905 +++ b/.hglf/sub/large4 Thu Jan 01 00:00:00 1970 +0000
906 906 @@ -0,0 +1,1 @@
907 907 +eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
908 908
909 909 changeset: 1:ce8896473775
910 910 user: test
911 911 date: Thu Jan 01 00:00:00 1970 +0000
912 912 summary: edit files
913 913
914 914 diff -r 30d30fe6a5be -r ce8896473775 .hglf/sub/large2
915 915 --- a/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
916 916 +++ b/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
917 917 @@ -1,1 +1,1 @@
918 918 -1deebade43c8c498a3c8daddac0244dc55d1331d
919 919 +eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
920 920
921 921 changeset: 0:30d30fe6a5be
922 922 user: test
923 923 date: Thu Jan 01 00:00:00 1970 +0000
924 924 summary: add files
925 925
926 926 diff -r 000000000000 -r 30d30fe6a5be .hglf/sub/large2
927 927 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
928 928 +++ b/.hglf/sub/large2 Thu Jan 01 00:00:00 1970 +0000
929 929 @@ -0,0 +1,1 @@
930 930 +1deebade43c8c498a3c8daddac0244dc55d1331d
931 931
932 932 $ cat sub/normal4
933 933 normal44
934 934 $ cat sub/large4
935 935 large44
936 936 $ cat sub2/large6
937 937 large6
938 938 $ cat sub2/large7
939 939 large7
940 940 $ hg log -qf sub2/large7
941 941 7:daea875e9014
942 942 $ hg log -Gqf sub2/large7
943 943 @ 7:daea875e9014
944 944 |
945 945 ~
946 946 $ cd ..
947 947
948 948 Test log from outside repo
949 949
950 950 $ hg log b/sub -T '{rev}:{node|short} {desc|firstline}\n'
951 951 6:4355d653f84f edit files yet again
952 952 5:9d5af5072dbd edit files again
953 953 4:74c02385b94c move files
954 954 1:ce8896473775 edit files
955 955 0:30d30fe6a5be add files
956 956
957 957 Test clone at revision
958 958
959 959 $ hg clone a -r 3 c
960 960 adding changesets
961 961 adding manifests
962 962 adding file changes
963 963 added 4 changesets with 10 changes to 4 files
964 964 new changesets 30d30fe6a5be:9e8fbc4bce62
965 965 updating to branch default
966 966 getting changed largefiles
967 967 2 largefiles updated, 0 removed
968 968 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
969 969 $ cd c
970 970 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
971 971 3:9e8fbc4bce62 copy files
972 972 2:51a0ae4d5864 remove files
973 973 1:ce8896473775 edit files
974 974 0:30d30fe6a5be add files
975 975 $ cat normal1
976 976 normal22
977 977 $ cat large1
978 978 large22
979 979 $ cat sub/normal2
980 980 normal22
981 981 $ cat sub/large2
982 982 large22
983 983
984 984 Old revisions of a clone have correct largefiles content (this also
985 985 tests update).
986 986
987 987 $ hg update -r 1
988 988 getting changed largefiles
989 989 1 largefiles updated, 0 removed
990 990 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
991 991 $ cat large1
992 992 large11
993 993 $ cat sub/large2
994 994 large22
995 995 $ cd ..
996 996
997 997 Test cloning with --all-largefiles flag
998 998
999 999 $ rm "${USERCACHE}"/*
1000 1000 $ hg clone --all-largefiles a a-backup
1001 1001 updating to branch default
1002 1002 getting changed largefiles
1003 1003 3 largefiles updated, 0 removed
1004 1004 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1005 1005 8 additional largefiles cached
1006 1006
1007 1007 $ rm "${USERCACHE}"/*
1008 1008 $ hg clone --all-largefiles -u 0 a a-clone0
1009 1009 updating to branch default
1010 1010 getting changed largefiles
1011 1011 2 largefiles updated, 0 removed
1012 1012 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1013 1013 9 additional largefiles cached
1014 1014 $ hg -R a-clone0 sum
1015 1015 parent: 0:30d30fe6a5be
1016 1016 add files
1017 1017 branch: default
1018 1018 commit: (clean)
1019 1019 update: 7 new changesets (update)
1020 1020 phases: 8 draft
1021 1021
1022 1022 $ rm "${USERCACHE}"/*
1023 1023 $ hg clone --all-largefiles -u 1 a a-clone1
1024 1024 updating to branch default
1025 1025 getting changed largefiles
1026 1026 2 largefiles updated, 0 removed
1027 1027 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1028 1028 8 additional largefiles cached
1029 1029 $ hg -R a-clone1 verify --large --lfa --lfc
1030 1030 checking changesets
1031 1031 checking manifests
1032 1032 crosschecking files in changesets and manifests
1033 1033 checking files
1034 1034 10 files, 8 changesets, 24 total revisions
1035 1035 searching 8 changesets for largefiles
1036 1036 verified contents of 13 revisions of 6 largefiles
1037 1037 $ hg -R a-clone1 sum
1038 1038 parent: 1:ce8896473775
1039 1039 edit files
1040 1040 branch: default
1041 1041 commit: (clean)
1042 1042 update: 6 new changesets (update)
1043 1043 phases: 8 draft
1044 1044
1045 1045 $ rm "${USERCACHE}"/*
1046 1046 $ hg clone --all-largefiles -U a a-clone-u
1047 1047 11 additional largefiles cached
1048 1048 $ hg -R a-clone-u sum
1049 1049 parent: -1:000000000000 (no revision checked out)
1050 1050 branch: default
1051 1051 commit: (clean)
1052 1052 update: 8 new changesets (update)
1053 1053 phases: 8 draft
1054 1054
1055 1055 Show computed destination directory:
1056 1056
1057 1057 $ mkdir xyz
1058 1058 $ cd xyz
1059 1059 $ hg clone ../a
1060 1060 destination directory: a
1061 1061 updating to branch default
1062 1062 getting changed largefiles
1063 1063 3 largefiles updated, 0 removed
1064 1064 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1065 1065 $ cd ..
1066 1066
1067 1067 Clone URL without path:
1068 1068
1069 1069 $ hg clone file://
1070 1070 abort: repository / not found!
1071 1071 [255]
1072 1072
1073 1073 Ensure base clone command argument validation
1074 1074
1075 1075 $ hg clone -U -u 0 a a-clone-failure
1076 1076 abort: cannot specify both --noupdate and --updaterev
1077 1077 [255]
1078 1078
1079 1079 $ hg clone --all-largefiles a ssh://localhost/a
1080 1080 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
1081 1081 [255]
1082 1082
1083 1083 Test pulling with --all-largefiles flag. Also test that the largefiles are
1084 1084 downloaded from 'default' instead of 'default-push' when no source is specified
1085 1085 (issue3584)
1086 1086
1087 1087 $ rm -Rf a-backup
1088 1088 $ hg clone -r 1 a a-backup
1089 1089 adding changesets
1090 1090 adding manifests
1091 1091 adding file changes
1092 1092 added 2 changesets with 8 changes to 4 files
1093 1093 new changesets 30d30fe6a5be:ce8896473775
1094 1094 updating to branch default
1095 1095 getting changed largefiles
1096 1096 2 largefiles updated, 0 removed
1097 1097 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1098 1098 $ rm "${USERCACHE}"/*
1099 1099 $ cd a-backup
1100 1100 $ hg pull --all-largefiles --config paths.default-push=bogus/path
1101 1101 pulling from $TESTTMP/a
1102 1102 searching for changes
1103 1103 adding changesets
1104 1104 adding manifests
1105 1105 adding file changes
1106 1106 added 6 changesets with 16 changes to 8 files
1107 1107 new changesets 51a0ae4d5864:daea875e9014
1108 1108 (run 'hg update' to get a working copy)
1109 1109 6 largefiles cached
1110 1110
1111 1111 redo pull with --lfrev and check it pulls largefiles for the right revs
1112 1112
1113 1113 $ hg rollback
1114 1114 repository tip rolled back to revision 1 (undo pull)
1115 1115 $ hg pull -v --lfrev 'heads(pulled())+min(pulled())'
1116 1116 pulling from $TESTTMP/a
1117 1117 searching for changes
1118 1118 all local heads known remotely
1119 1119 6 changesets found
1120 1120 uncompressed size of bundle content:
1121 1121 1389 (changelog)
1122 1122 1599 (manifests)
1123 1123 254 .hglf/large1
1124 1124 564 .hglf/large3
1125 1125 572 .hglf/sub/large4
1126 1126 182 .hglf/sub2/large6
1127 1127 182 .hglf/sub2/large7
1128 1128 212 normal1
1129 1129 457 normal3
1130 1130 465 sub/normal4
1131 1131 adding changesets
1132 1132 adding manifests
1133 1133 adding file changes
1134 1134 added 6 changesets with 16 changes to 8 files
1135 1135 new changesets 51a0ae4d5864:daea875e9014
1136 1136 calling hook changegroup.lfiles: hgext.largefiles.reposetup.checkrequireslfiles
1137 1137 (run 'hg update' to get a working copy)
1138 1138 pulling largefiles for revision 7
1139 1139 found 971fb41e78fea4f8e0ba5244784239371cb00591 in store
1140 1140 found 0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30 in store
1141 1141 found bb3151689acb10f0c3125c560d5e63df914bc1af in store
1142 1142 pulling largefiles for revision 2
1143 1143 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1144 1144 0 largefiles cached
1145 1145
1146 1146 lfpull
1147 1147
1148 1148 $ hg lfpull -r : --config largefiles.usercache=usercache-lfpull
1149 1149 2 largefiles cached
1150 1150 $ hg lfpull -v -r 4+2 --config largefiles.usercache=usercache-lfpull
1151 1151 pulling largefiles for revision 4
1152 1152 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1153 1153 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1154 1154 pulling largefiles for revision 2
1155 1155 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
1156 1156 0 largefiles cached
1157 1157
1158 1158 $ ls usercache-lfpull/* | sort
1159 1159 usercache-lfpull/1deebade43c8c498a3c8daddac0244dc55d1331d
1160 1160 usercache-lfpull/4669e532d5b2c093a78eca010077e708a071bb64
1161 1161
1162 1162 $ cd ..
1163 1163
1164 1164 Rebasing between two repositories does not revert largefiles to old
1165 1165 revisions (this was a very bad bug that took a lot of work to fix).
1166 1166
1167 1167 $ hg clone a d
1168 1168 updating to branch default
1169 1169 getting changed largefiles
1170 1170 3 largefiles updated, 0 removed
1171 1171 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1172 1172 $ cd b
1173 1173 $ echo large4-modified > sub/large4
1174 1174 $ echo normal3-modified > normal3
1175 1175 $ hg commit -m "modify normal file and largefile in repo b"
1176 1176 Invoking status precommit hook
1177 1177 M normal3
1178 1178 M sub/large4
1179 1179 $ cd ../d
1180 1180 $ echo large6-modified > sub2/large6
1181 1181 $ echo normal4-modified > sub/normal4
1182 1182 $ hg commit -m "modify normal file largefile in repo d"
1183 1183 Invoking status precommit hook
1184 1184 M sub/normal4
1185 1185 M sub2/large6
1186 1186 $ cd ..
1187 1187 $ hg clone d e
1188 1188 updating to branch default
1189 1189 getting changed largefiles
1190 1190 3 largefiles updated, 0 removed
1191 1191 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1192 1192 $ cd d
1193 1193
1194 1194 More rebase testing, but also test that the largefiles are downloaded from
1195 1195 'default-push' when no source is specified (issue3584). (The largefile from the
1196 1196 pulled revision is however not downloaded but found in the local cache.)
1197 1197 Largefiles are fetched for the new pulled revision, not for existing revisions,
1198 1198 rebased or not.
1199 1199
1200 1200 $ [ ! -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
1201 1201 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
1202 1202 pulling from $TESTTMP/b
1203 1203 searching for changes
1204 1204 adding changesets
1205 1205 adding manifests
1206 1206 adding file changes
1207 1207 added 1 changesets with 2 changes to 2 files (+1 heads)
1208 1208 new changesets a381d2c8c80e
1209 1209 rebasing 8:f574fb32bb45 "modify normal file largefile in repo d"
1210 1210 Invoking status precommit hook
1211 1211 M sub/normal4
1212 1212 M sub2/large6
1213 1213 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-dd1d9f80-rebase.hg
1214 1214 0 largefiles cached
1215 1215 $ [ -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
1216 1216 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1217 1217 9:598410d3eb9a modify normal file largefile in repo d
1218 1218 8:a381d2c8c80e modify normal file and largefile in repo b
1219 1219 7:daea875e9014 add/edit more largefiles
1220 1220 6:4355d653f84f edit files yet again
1221 1221 5:9d5af5072dbd edit files again
1222 1222 4:74c02385b94c move files
1223 1223 3:9e8fbc4bce62 copy files
1224 1224 2:51a0ae4d5864 remove files
1225 1225 1:ce8896473775 edit files
1226 1226 0:30d30fe6a5be add files
1227 1227 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n'
1228 1228 @ 9:598410d3eb9a modify normal file largefile in repo d
1229 1229 |
1230 1230 o 8:a381d2c8c80e modify normal file and largefile in repo b
1231 1231 |
1232 1232 o 7:daea875e9014 add/edit more largefiles
1233 1233 |
1234 1234 o 6:4355d653f84f edit files yet again
1235 1235 |
1236 1236 o 5:9d5af5072dbd edit files again
1237 1237 |
1238 1238 o 4:74c02385b94c move files
1239 1239 |
1240 1240 o 3:9e8fbc4bce62 copy files
1241 1241 |
1242 1242 o 2:51a0ae4d5864 remove files
1243 1243 |
1244 1244 o 1:ce8896473775 edit files
1245 1245 |
1246 1246 o 0:30d30fe6a5be add files
1247 1247
1248 1248 $ cat normal3
1249 1249 normal3-modified
1250 1250 $ cat sub/normal4
1251 1251 normal4-modified
1252 1252 $ cat sub/large4
1253 1253 large4-modified
1254 1254 $ cat sub2/large6
1255 1255 large6-modified
1256 1256 $ cat sub2/large7
1257 1257 large7
1258 1258 $ cd ../e
1259 1259 $ hg pull ../b
1260 1260 pulling from ../b
1261 1261 searching for changes
1262 1262 adding changesets
1263 1263 adding manifests
1264 1264 adding file changes
1265 1265 added 1 changesets with 2 changes to 2 files (+1 heads)
1266 1266 new changesets a381d2c8c80e
1267 1267 (run 'hg heads' to see heads, 'hg merge' to merge)
1268 1268 $ hg rebase
1269 1269 rebasing 8:f574fb32bb45 "modify normal file largefile in repo d"
1270 1270 Invoking status precommit hook
1271 1271 M sub/normal4
1272 1272 M sub2/large6
1273 1273 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-dd1d9f80-rebase.hg
1274 1274 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1275 1275 9:598410d3eb9a modify normal file largefile in repo d
1276 1276 8:a381d2c8c80e modify normal file and largefile in repo b
1277 1277 7:daea875e9014 add/edit more largefiles
1278 1278 6:4355d653f84f edit files yet again
1279 1279 5:9d5af5072dbd edit files again
1280 1280 4:74c02385b94c move files
1281 1281 3:9e8fbc4bce62 copy files
1282 1282 2:51a0ae4d5864 remove files
1283 1283 1:ce8896473775 edit files
1284 1284 0:30d30fe6a5be add files
1285 1285 $ cat normal3
1286 1286 normal3-modified
1287 1287 $ cat sub/normal4
1288 1288 normal4-modified
1289 1289 $ cat sub/large4
1290 1290 large4-modified
1291 1291 $ cat sub2/large6
1292 1292 large6-modified
1293 1293 $ cat sub2/large7
1294 1294 large7
1295 1295
1296 1296 Log on largefiles
1297 1297
1298 1298 - same output
1299 1299 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1300 1300 8:a381d2c8c80e modify normal file and largefile in repo b
1301 1301 6:4355d653f84f edit files yet again
1302 1302 5:9d5af5072dbd edit files again
1303 1303 4:74c02385b94c move files
1304 1304 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1305 1305 o 8:a381d2c8c80e modify normal file and largefile in repo b
1306 1306 :
1307 1307 o 6:4355d653f84f edit files yet again
1308 1308 |
1309 1309 o 5:9d5af5072dbd edit files again
1310 1310 |
1311 1311 o 4:74c02385b94c move files
1312 1312 |
1313 1313 ~
1314 1314 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
1315 1315 8:a381d2c8c80e modify normal file and largefile in repo b
1316 1316 6:4355d653f84f edit files yet again
1317 1317 5:9d5af5072dbd edit files again
1318 1318 4:74c02385b94c move files
1319 1319 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1320 1320 o 8:a381d2c8c80e modify normal file and largefile in repo b
1321 1321 :
1322 1322 o 6:4355d653f84f edit files yet again
1323 1323 |
1324 1324 o 5:9d5af5072dbd edit files again
1325 1325 |
1326 1326 o 4:74c02385b94c move files
1327 1327 |
1328 1328 ~
1329 1329
1330 1330 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1331 1331 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1332 1332 8:a381d2c8c80e modify normal file and largefile in repo b
1333 1333 6:4355d653f84f edit files yet again
1334 1334 5:9d5af5072dbd edit files again
1335 1335 4:74c02385b94c move files
1336 1336 1:ce8896473775 edit files
1337 1337 0:30d30fe6a5be add files
1338 1338 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1339 1339 o 8:a381d2c8c80e modify normal file and largefile in repo b
1340 1340 :
1341 1341 o 6:4355d653f84f edit files yet again
1342 1342 |
1343 1343 o 5:9d5af5072dbd edit files again
1344 1344 |
1345 1345 o 4:74c02385b94c move files
1346 1346 :
1347 1347 o 1:ce8896473775 edit files
1348 1348 |
1349 1349 o 0:30d30fe6a5be add files
1350 1350
1351 1351 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1352 1352 9:598410d3eb9a modify normal file largefile in repo d
1353 1353 8:a381d2c8c80e modify normal file and largefile in repo b
1354 1354 6:4355d653f84f edit files yet again
1355 1355 5:9d5af5072dbd edit files again
1356 1356 4:74c02385b94c move files
1357 1357 1:ce8896473775 edit files
1358 1358 0:30d30fe6a5be add files
1359 1359 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' sub
1360 1360 @ 9:598410d3eb9a modify normal file largefile in repo d
1361 1361 |
1362 1362 o 8:a381d2c8c80e modify normal file and largefile in repo b
1363 1363 :
1364 1364 o 6:4355d653f84f edit files yet again
1365 1365 |
1366 1366 o 5:9d5af5072dbd edit files again
1367 1367 |
1368 1368 o 4:74c02385b94c move files
1369 1369 :
1370 1370 o 1:ce8896473775 edit files
1371 1371 |
1372 1372 o 0:30d30fe6a5be add files
1373 1373
1374 1374 - globbing gives same result
1375 1375 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1376 1376 9:598410d3eb9a modify normal file largefile in repo d
1377 1377 8:a381d2c8c80e modify normal file and largefile in repo b
1378 1378 6:4355d653f84f edit files yet again
1379 1379 5:9d5af5072dbd edit files again
1380 1380 4:74c02385b94c move files
1381 1381 1:ce8896473775 edit files
1382 1382 0:30d30fe6a5be add files
1383 1383 $ hg log -G --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1384 1384 @ 9:598410d3eb9a modify normal file largefile in repo d
1385 1385 |
1386 1386 o 8:a381d2c8c80e modify normal file and largefile in repo b
1387 1387 :
1388 1388 o 6:4355d653f84f edit files yet again
1389 1389 |
1390 1390 o 5:9d5af5072dbd edit files again
1391 1391 |
1392 1392 o 4:74c02385b94c move files
1393 1393 :
1394 1394 o 1:ce8896473775 edit files
1395 1395 |
1396 1396 o 0:30d30fe6a5be add files
1397 1397
1398 1398 Rollback on largefiles.
1399 1399
1400 1400 $ echo large4-modified-again > sub/large4
1401 1401 $ hg commit -m "Modify large4 again"
1402 1402 Invoking status precommit hook
1403 1403 M sub/large4
1404 1404 $ hg rollback
1405 1405 repository tip rolled back to revision 9 (undo commit)
1406 1406 working directory now based on revision 9
1407 1407 $ hg st
1408 1408 M sub/large4
1409 1409 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1410 1410 9:598410d3eb9a modify normal file largefile in repo d
1411 1411 8:a381d2c8c80e modify normal file and largefile in repo b
1412 1412 7:daea875e9014 add/edit more largefiles
1413 1413 6:4355d653f84f edit files yet again
1414 1414 5:9d5af5072dbd edit files again
1415 1415 4:74c02385b94c move files
1416 1416 3:9e8fbc4bce62 copy files
1417 1417 2:51a0ae4d5864 remove files
1418 1418 1:ce8896473775 edit files
1419 1419 0:30d30fe6a5be add files
1420 1420 $ cat sub/large4
1421 1421 large4-modified-again
1422 1422
1423 1423 "update --check" refuses to update with uncommitted changes.
1424 1424 $ hg update --check 8
1425 1425 abort: uncommitted changes
1426 1426 [255]
1427 1427
1428 1428 "update --clean" leaves correct largefiles in working copy, even when there is
1429 1429 .orig files from revert in .hglf.
1430 1430
1431 1431 $ echo mistake > sub2/large7
1432 1432 $ hg revert sub2/large7
1433 1433 $ cat sub2/large7
1434 1434 large7
1435 1435 $ cat sub2/large7.orig
1436 1436 mistake
1437 1437 $ test ! -f .hglf/sub2/large7.orig
1438 1438
1439 1439 $ hg -q update --clean -r null
1440 1440 $ hg update --clean
1441 1441 getting changed largefiles
1442 1442 3 largefiles updated, 0 removed
1443 1443 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1444 1444 $ cat normal3
1445 1445 normal3-modified
1446 1446 $ cat sub/normal4
1447 1447 normal4-modified
1448 1448 $ cat sub/large4
1449 1449 large4-modified
1450 1450 $ cat sub2/large6
1451 1451 large6-modified
1452 1452 $ cat sub2/large7
1453 1453 large7
1454 1454 $ cat sub2/large7.orig
1455 1455 mistake
1456 1456 $ test ! -f .hglf/sub2/large7.orig
1457 1457
1458 1458 verify that largefile .orig file no longer is overwritten on every update -C:
1459 1459 $ hg update --clean
1460 1460 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1461 1461 $ cat sub2/large7.orig
1462 1462 mistake
1463 1463 $ rm sub2/large7.orig
1464 1464
1465 1465 Now "update check" is happy.
1466 1466 $ hg update --check 8
1467 1467 getting changed largefiles
1468 1468 1 largefiles updated, 0 removed
1469 1469 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1470 1470 $ hg update --check
1471 1471 getting changed largefiles
1472 1472 1 largefiles updated, 0 removed
1473 1473 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1474 1474
1475 1475 Test removing empty largefiles directories on update
1476 1476 $ test -d sub2 && echo "sub2 exists"
1477 1477 sub2 exists
1478 1478 $ hg update -q null
1479 1479 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1480 1480 [1]
1481 1481 $ hg update -q
1482 1482
1483 1483 Test hg remove removes empty largefiles directories
1484 1484 $ test -d sub2 && echo "sub2 exists"
1485 1485 sub2 exists
1486 1486 $ hg remove sub2/*
1487 1487 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1488 1488 [1]
1489 1489 $ hg revert sub2/large6 sub2/large7
1490 1490
1491 1491 "revert" works on largefiles (and normal files too).
1492 1492 $ echo hack3 >> normal3
1493 1493 $ echo hack4 >> sub/normal4
1494 1494 $ echo hack4 >> sub/large4
1495 1495 $ rm sub2/large6
1496 1496 $ hg revert sub2/large6
1497 1497 $ hg rm sub2/large6
1498 1498 $ echo new >> sub2/large8
1499 1499 $ hg add --large sub2/large8
1500 1500 # XXX we don't really want to report that we're reverting the standin;
1501 1501 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1502 1502 $ hg revert sub
1503 1503 reverting .hglf/sub/large4
1504 1504 reverting sub/normal4
1505 1505 $ hg status
1506 1506 M normal3
1507 1507 A sub2/large8
1508 1508 R sub2/large6
1509 1509 ? sub/large4.orig
1510 1510 ? sub/normal4.orig
1511 1511 $ cat sub/normal4
1512 1512 normal4-modified
1513 1513 $ cat sub/large4
1514 1514 large4-modified
1515 1515 $ hg revert -a --no-backup
1516 undeleting .hglf/sub2/large6
1517 1516 forgetting .hglf/sub2/large8
1518 1517 reverting normal3
1518 undeleting .hglf/sub2/large6
1519 1519 $ hg status
1520 1520 ? sub/large4.orig
1521 1521 ? sub/normal4.orig
1522 1522 ? sub2/large8
1523 1523 $ cat normal3
1524 1524 normal3-modified
1525 1525 $ cat sub2/large6
1526 1526 large6-modified
1527 1527 $ rm sub/*.orig sub2/large8
1528 1528
1529 1529 revert some files to an older revision
1530 1530 $ hg revert --no-backup -r 8 sub2
1531 1531 reverting .hglf/sub2/large6
1532 1532 $ cat sub2/large6
1533 1533 large6
1534 1534 $ hg revert --no-backup -C -r '.^' sub2
1535 1535 $ hg revert --no-backup sub2
1536 1536 reverting .hglf/sub2/large6
1537 1537 $ hg status
1538 1538
1539 1539 "verify --large" actually verifies largefiles
1540 1540
1541 1541 - Where Do We Come From? What Are We? Where Are We Going?
1542 1542 $ pwd
1543 1543 $TESTTMP/e
1544 1544 $ hg paths
1545 1545 default = $TESTTMP/d
1546 1546
1547 1547 $ hg verify --large
1548 1548 checking changesets
1549 1549 checking manifests
1550 1550 crosschecking files in changesets and manifests
1551 1551 checking files
1552 1552 10 files, 10 changesets, 28 total revisions
1553 1553 searching 1 changesets for largefiles
1554 1554 verified existence of 3 revisions of 3 largefiles
1555 1555
1556 1556 - introduce missing blob in local store repo and remote store
1557 1557 and make sure that this is caught:
1558 1558
1559 1559 $ mv $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 .
1560 1560 $ rm .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1561 1561 $ hg verify --large
1562 1562 checking changesets
1563 1563 checking manifests
1564 1564 crosschecking files in changesets and manifests
1565 1565 checking files
1566 1566 10 files, 10 changesets, 28 total revisions
1567 1567 searching 1 changesets for largefiles
1568 1568 changeset 9:598410d3eb9a: sub/large4 references missing $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1569 1569 verified existence of 3 revisions of 3 largefiles
1570 1570 [1]
1571 1571
1572 1572 - introduce corruption and make sure that it is caught when checking content:
1573 1573 $ echo '5 cents' > $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1574 1574 $ hg verify -q --large --lfc
1575 1575 changeset 9:598410d3eb9a: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1576 1576 [1]
1577 1577
1578 1578 - cleanup
1579 1579 $ cp e166e74c7303192238d60af5a9c4ce9bef0b7928 $TESTTMP/d/.hg/largefiles/
1580 1580 $ mv e166e74c7303192238d60af5a9c4ce9bef0b7928 .hg/largefiles/
1581 1581
1582 1582 - verifying all revisions will fail because we didn't clone all largefiles to d:
1583 1583 $ echo 'T-shirt' > $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1584 1584 $ hg verify -q --lfa --lfc
1585 1585 changeset 0:30d30fe6a5be: large1 references missing $TESTTMP/d/.hg/largefiles/4669e532d5b2c093a78eca010077e708a071bb64
1586 1586 changeset 0:30d30fe6a5be: sub/large2 references missing $TESTTMP/d/.hg/largefiles/1deebade43c8c498a3c8daddac0244dc55d1331d
1587 1587 changeset 1:ce8896473775: large1 references missing $TESTTMP/d/.hg/largefiles/5f78770c0e77ba4287ad6ef3071c9bf9c379742f
1588 1588 changeset 1:ce8896473775: sub/large2 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1589 1589 changeset 3:9e8fbc4bce62: large1 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1590 1590 changeset 4:74c02385b94c: large3 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1591 1591 changeset 4:74c02385b94c: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1592 1592 changeset 5:9d5af5072dbd: large3 references missing $TESTTMP/d/.hg/largefiles/baaf12afde9d8d67f25dab6dced0d2bf77dba47c
1593 1593 changeset 5:9d5af5072dbd: sub/large4 references missing $TESTTMP/d/.hg/largefiles/aeb2210d19f02886dde00dac279729a48471e2f9
1594 1594 changeset 6:4355d653f84f: large3 references missing $TESTTMP/d/.hg/largefiles/7838695e10da2bb75ac1156565f40a2595fa2fa0
1595 1595 [1]
1596 1596
1597 1597 - cleanup
1598 1598 $ rm $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1599 1599 $ rm -f .hglf/sub/*.orig
1600 1600
1601 1601 Update to revision with missing largefile - and make sure it really is missing
1602 1602
1603 1603 $ rm ${USERCACHE}/7838695e10da2bb75ac1156565f40a2595fa2fa0
1604 1604 $ hg up -r 6
1605 1605 getting changed largefiles
1606 1606 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1607 1607 1 largefiles updated, 2 removed
1608 1608 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
1609 1609 $ rm normal3
1610 1610 $ echo >> sub/normal4
1611 1611 $ hg ci -m 'commit with missing files'
1612 1612 Invoking status precommit hook
1613 1613 M sub/normal4
1614 1614 ! large3
1615 1615 ! normal3
1616 1616 created new head
1617 1617 $ hg st
1618 1618 ! large3
1619 1619 ! normal3
1620 1620 $ hg up -r.
1621 1621 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1622 1622 $ hg st
1623 1623 ! large3
1624 1624 ! normal3
1625 1625 $ hg up -Cr.
1626 1626 getting changed largefiles
1627 1627 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1628 1628 0 largefiles updated, 0 removed
1629 1629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1630 1630 $ hg st
1631 1631 ! large3
1632 1632 $ hg rollback
1633 1633 repository tip rolled back to revision 9 (undo commit)
1634 1634 working directory now based on revision 6
1635 1635
1636 1636 Merge with revision with missing largefile - and make sure it tries to fetch it.
1637 1637
1638 1638 $ hg up -Cqr null
1639 1639 $ echo f > f
1640 1640 $ hg ci -Am branch
1641 1641 adding f
1642 1642 Invoking status precommit hook
1643 1643 A f
1644 1644 created new head
1645 1645 $ hg merge -r 6
1646 1646 getting changed largefiles
1647 1647 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob)
1648 1648 1 largefiles updated, 0 removed
1649 1649 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1650 1650 (branch merge, don't forget to commit)
1651 1651
1652 1652 $ hg rollback -q
1653 1653 $ hg up -Cq
1654 1654
1655 1655 Pulling 0 revisions with --all-largefiles should not fetch for all revisions
1656 1656
1657 1657 $ hg pull --all-largefiles
1658 1658 pulling from $TESTTMP/d
1659 1659 searching for changes
1660 1660 no changes found
1661 1661
1662 1662 Merging does not revert to old versions of largefiles and also check
1663 1663 that merging after having pulled from a non-default remote works
1664 1664 correctly.
1665 1665
1666 1666 $ cd ..
1667 1667 $ hg clone -r 7 e temp
1668 1668 adding changesets
1669 1669 adding manifests
1670 1670 adding file changes
1671 1671 added 8 changesets with 24 changes to 10 files
1672 1672 new changesets 30d30fe6a5be:daea875e9014
1673 1673 updating to branch default
1674 1674 getting changed largefiles
1675 1675 3 largefiles updated, 0 removed
1676 1676 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1677 1677 $ hg clone temp f
1678 1678 updating to branch default
1679 1679 getting changed largefiles
1680 1680 3 largefiles updated, 0 removed
1681 1681 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1682 1682 # Delete the largefiles in the largefiles system cache so that we have an
1683 1683 # opportunity to test that caching after a pull works.
1684 1684 $ rm "${USERCACHE}"/*
1685 1685 $ cd f
1686 1686 $ echo "large4-merge-test" > sub/large4
1687 1687 $ hg commit -m "Modify large4 to test merge"
1688 1688 Invoking status precommit hook
1689 1689 M sub/large4
1690 1690 # Test --cache-largefiles flag
1691 1691 $ hg pull --lfrev 'heads(pulled())' ../e
1692 1692 pulling from ../e
1693 1693 searching for changes
1694 1694 adding changesets
1695 1695 adding manifests
1696 1696 adding file changes
1697 1697 added 2 changesets with 4 changes to 4 files (+1 heads)
1698 1698 new changesets a381d2c8c80e:598410d3eb9a
1699 1699 (run 'hg heads' to see heads, 'hg merge' to merge)
1700 1700 2 largefiles cached
1701 1701 $ hg merge
1702 1702 largefile sub/large4 has a merge conflict
1703 1703 ancestor was 971fb41e78fea4f8e0ba5244784239371cb00591
1704 1704 keep (l)ocal d846f26643bfa8ec210be40cc93cc6b7ff1128ea or
1705 1705 take (o)ther e166e74c7303192238d60af5a9c4ce9bef0b7928? l
1706 1706 getting changed largefiles
1707 1707 1 largefiles updated, 0 removed
1708 1708 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1709 1709 (branch merge, don't forget to commit)
1710 1710 $ hg commit -m "Merge repos e and f"
1711 1711 Invoking status precommit hook
1712 1712 M normal3
1713 1713 M sub/normal4
1714 1714 M sub2/large6
1715 1715 $ cat normal3
1716 1716 normal3-modified
1717 1717 $ cat sub/normal4
1718 1718 normal4-modified
1719 1719 $ cat sub/large4
1720 1720 large4-merge-test
1721 1721 $ cat sub2/large6
1722 1722 large6-modified
1723 1723 $ cat sub2/large7
1724 1724 large7
1725 1725
1726 1726 Test status after merging with a branch that introduces a new largefile:
1727 1727
1728 1728 $ echo large > large
1729 1729 $ hg add --large large
1730 1730 $ hg commit -m 'add largefile'
1731 1731 Invoking status precommit hook
1732 1732 A large
1733 1733 $ hg update -q ".^"
1734 1734 $ echo change >> normal3
1735 1735 $ hg commit -m 'some change'
1736 1736 Invoking status precommit hook
1737 1737 M normal3
1738 1738 created new head
1739 1739 $ hg merge
1740 1740 getting changed largefiles
1741 1741 1 largefiles updated, 0 removed
1742 1742 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1743 1743 (branch merge, don't forget to commit)
1744 1744 $ hg status
1745 1745 M large
1746 1746
1747 1747 - make sure update of merge with removed largefiles fails as expected
1748 1748 $ hg rm sub2/large6
1749 1749 $ hg up -r.
1750 1750 abort: outstanding uncommitted merge
1751 1751 [255]
1752 1752
1753 1753 - revert should be able to revert files introduced in a pending merge
1754 1754 $ hg revert --all -r .
1755 1755 removing .hglf/large
1756 1756 undeleting .hglf/sub2/large6
1757 1757
1758 1758 Test that a normal file and a largefile with the same name and path cannot
1759 1759 coexist.
1760 1760
1761 1761 $ rm sub2/large7
1762 1762 $ echo "largeasnormal" > sub2/large7
1763 1763 $ hg add sub2/large7
1764 1764 sub2/large7 already a largefile
1765 1765
1766 1766 Test that transplanting a largefile change works correctly.
1767 1767
1768 1768 $ cd ..
1769 1769 $ hg clone -r 8 d g
1770 1770 adding changesets
1771 1771 adding manifests
1772 1772 adding file changes
1773 1773 added 9 changesets with 26 changes to 10 files
1774 1774 new changesets 30d30fe6a5be:a381d2c8c80e
1775 1775 updating to branch default
1776 1776 getting changed largefiles
1777 1777 3 largefiles updated, 0 removed
1778 1778 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1779 1779 $ cd g
1780 1780 $ hg transplant -s ../d 598410d3eb9a
1781 1781 searching for changes
1782 1782 searching for changes
1783 1783 adding changesets
1784 1784 adding manifests
1785 1785 adding file changes
1786 1786 added 1 changesets with 2 changes to 2 files
1787 1787 new changesets 598410d3eb9a
1788 1788 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1789 1789 9:598410d3eb9a modify normal file largefile in repo d
1790 1790 8:a381d2c8c80e modify normal file and largefile in repo b
1791 1791 7:daea875e9014 add/edit more largefiles
1792 1792 6:4355d653f84f edit files yet again
1793 1793 5:9d5af5072dbd edit files again
1794 1794 4:74c02385b94c move files
1795 1795 3:9e8fbc4bce62 copy files
1796 1796 2:51a0ae4d5864 remove files
1797 1797 1:ce8896473775 edit files
1798 1798 0:30d30fe6a5be add files
1799 1799 $ cat normal3
1800 1800 normal3-modified
1801 1801 $ cat sub/normal4
1802 1802 normal4-modified
1803 1803 $ cat sub/large4
1804 1804 large4-modified
1805 1805 $ cat sub2/large6
1806 1806 large6-modified
1807 1807 $ cat sub2/large7
1808 1808 large7
1809 1809
1810 1810 Cat a largefile
1811 1811 $ hg cat normal3
1812 1812 normal3-modified
1813 1813 $ hg cat sub/large4
1814 1814 large4-modified
1815 1815 $ rm "${USERCACHE}"/*
1816 1816 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1817 1817 $ cat cat.out
1818 1818 large4-modified
1819 1819 $ rm cat.out
1820 1820 $ hg cat -r a381d2c8c80e normal3
1821 1821 normal3-modified
1822 1822 $ hg cat -r '.^' normal3
1823 1823 normal3-modified
1824 1824 $ hg cat -r '.^' sub/large4 doesntexist
1825 1825 large4-modified
1826 1826 doesntexist: no such file in rev a381d2c8c80e
1827 1827 $ hg --cwd sub cat -r '.^' large4
1828 1828 large4-modified
1829 1829 $ hg --cwd sub cat -r '.^' ../normal3
1830 1830 normal3-modified
1831 1831 Cat a standin
1832 1832 $ hg cat .hglf/sub/large4
1833 1833 e166e74c7303192238d60af5a9c4ce9bef0b7928
1834 1834 $ hg cat .hglf/normal3
1835 1835 .hglf/normal3: no such file in rev 598410d3eb9a
1836 1836 [1]
1837 1837
1838 1838 Test that renaming a largefile results in correct output for status
1839 1839
1840 1840 $ hg rename sub/large4 large4-renamed
1841 1841 $ hg commit -m "test rename output"
1842 1842 Invoking status precommit hook
1843 1843 A large4-renamed
1844 1844 R sub/large4
1845 1845 $ cat large4-renamed
1846 1846 large4-modified
1847 1847 $ cd sub2
1848 1848 $ hg rename large6 large6-renamed
1849 1849 $ hg st
1850 1850 A sub2/large6-renamed
1851 1851 R sub2/large6
1852 1852 $ cd ..
1853 1853
1854 1854 Test --normal flag
1855 1855
1856 1856 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1857 1857 $ hg add --normal --large new-largefile
1858 1858 abort: --normal cannot be used with --large
1859 1859 [255]
1860 1860 $ hg add --normal new-largefile
1861 1861 new-largefile: up to 69 MB of RAM may be required to manage this file
1862 1862 (use 'hg revert new-largefile' to cancel the pending addition)
1863 1863 $ hg revert new-largefile
1864 1864 $ hg --config ui.large-file-limit=22M add --normal new-largefile
1865 1865
1866 1866 Test explicit commit of switch between normal and largefile - make sure both
1867 1867 the add and the remove is committed.
1868 1868
1869 1869 $ hg up -qC
1870 1870 $ hg forget normal3 large4-renamed
1871 1871 $ hg add --large normal3
1872 1872 $ hg add large4-renamed
1873 1873 $ hg commit -m 'swap' normal3 large4-renamed
1874 1874 Invoking status precommit hook
1875 1875 A large4-renamed
1876 1876 A normal3
1877 1877 ? new-largefile
1878 1878 ? sub2/large6-renamed
1879 1879 $ hg mani
1880 1880 .hglf/normal3
1881 1881 .hglf/sub2/large6
1882 1882 .hglf/sub2/large7
1883 1883 large4-renamed
1884 1884 sub/normal4
1885 1885
1886 1886 $ cd ..
1887 1887
1888 1888
1889 1889
@@ -1,941 +1,941 b''
1 1 #require no-reposimplestore no-chg
2 2 #testcases git-server hg-server
3 3
4 4 #if git-server
5 5 #require lfs-test-server
6 6 #else
7 7 #require serve
8 8 #endif
9 9
10 10 #if git-server
11 11 $ LFS_LISTEN="tcp://:$HGPORT"
12 12 $ LFS_HOST="localhost:$HGPORT"
13 13 $ LFS_PUBLIC=1
14 14 $ export LFS_LISTEN LFS_HOST LFS_PUBLIC
15 15 #else
16 16 $ LFS_HOST="localhost:$HGPORT/.git/info/lfs"
17 17 #endif
18 18
19 19 #if no-windows git-server
20 20 $ lfs-test-server &> lfs-server.log &
21 21 $ echo $! >> $DAEMON_PIDS
22 22 #endif
23 23
24 24 #if windows git-server
25 25 $ cat >> $TESTTMP/spawn.py <<EOF
26 26 > import os
27 27 > import subprocess
28 28 > import sys
29 29 >
30 30 > for path in os.environ["PATH"].split(os.pathsep):
31 31 > exe = os.path.join(path, 'lfs-test-server.exe')
32 32 > if os.path.exists(exe):
33 33 > with open('lfs-server.log', 'wb') as out:
34 34 > p = subprocess.Popen(exe, stdout=out, stderr=out)
35 35 > sys.stdout.write('%s\n' % p.pid)
36 36 > sys.exit(0)
37 37 > sys.exit(1)
38 38 > EOF
39 39 $ $PYTHON $TESTTMP/spawn.py >> $DAEMON_PIDS
40 40 #endif
41 41
42 42 $ cat >> $HGRCPATH <<EOF
43 43 > [extensions]
44 44 > lfs=
45 45 > [lfs]
46 46 > url=http://foo:bar@$LFS_HOST
47 47 > track=all()
48 48 > [web]
49 49 > push_ssl = False
50 50 > allow-push = *
51 51 > EOF
52 52
53 53 Use a separate usercache, otherwise the server sees what the client commits, and
54 54 never requests a transfer.
55 55
56 56 #if hg-server
57 57 $ hg init server
58 58 $ hg --config "lfs.usercache=$TESTTMP/servercache" -R server serve -d \
59 59 > -p $HGPORT --pid-file=hg.pid -A $TESTTMP/access.log -E $TESTTMP/errors.log
60 60 $ cat hg.pid >> $DAEMON_PIDS
61 61 #endif
62 62
63 63 $ hg init repo1
64 64 $ cd repo1
65 65 $ echo THIS-IS-LFS > a
66 66 $ hg commit -m a -A a
67 67
68 68 A push can be serviced directly from the usercache if it isn't in the local
69 69 store.
70 70
71 71 $ hg init ../repo2
72 72 $ mv .hg/store/lfs .hg/store/lfs_
73 73 $ hg push ../repo2 --debug
74 74 http auth: user foo, password ***
75 75 pushing to ../repo2
76 76 http auth: user foo, password ***
77 77 http auth: user foo, password ***
78 78 query 1; heads
79 79 searching for changes
80 80 1 total queries in *s (glob)
81 81 listing keys for "phases"
82 82 checking for updated bookmarks
83 83 listing keys for "bookmarks"
84 84 lfs: computing set of blobs to upload
85 85 Status: 200
86 86 Content-Length: 309 (git-server !)
87 87 Content-Length: 350 (hg-server !)
88 88 Content-Type: application/vnd.git-lfs+json
89 89 Date: $HTTP_DATE$
90 90 Server: testing stub value (hg-server !)
91 91 {
92 92 "objects": [
93 93 {
94 94 "actions": {
95 95 "upload": {
96 96 "expires_at": "$ISO_8601_DATE_TIME$"
97 97 "header": {
98 98 "Accept": "application/vnd.git-lfs"
99 99 }
100 100 "href": "http://localhost:$HGPORT/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (git-server !)
101 101 "href": "http://localhost:$HGPORT/.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (hg-server !)
102 102 }
103 103 }
104 104 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
105 105 "size": 12
106 106 }
107 107 ]
108 108 "transfer": "basic" (hg-server !)
109 109 }
110 110 lfs: uploading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
111 111 Status: 200 (git-server !)
112 112 Status: 201 (hg-server !)
113 113 Content-Length: 0
114 114 Content-Type: text/plain; charset=utf-8
115 115 Date: $HTTP_DATE$
116 116 Server: testing stub value (hg-server !)
117 117 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
118 118 lfs: uploaded 1 files (12 bytes)
119 119 1 changesets found
120 120 list of changesets:
121 121 99a7098854a3984a5c9eab0fc7a2906697b7cb5c
122 122 bundle2-output-bundle: "HG20", 4 parts total
123 123 bundle2-output-part: "replycaps" * bytes payload (glob)
124 124 bundle2-output-part: "check:heads" streamed payload
125 125 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
126 126 bundle2-output-part: "phase-heads" 24 bytes payload
127 127 bundle2-input-bundle: with-transaction
128 128 bundle2-input-part: "replycaps" supported
129 129 bundle2-input-part: total payload size * (glob)
130 130 bundle2-input-part: "check:heads" supported
131 131 bundle2-input-part: total payload size 20
132 132 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
133 133 adding changesets
134 134 add changeset 99a7098854a3
135 135 adding manifests
136 136 adding file changes
137 137 adding a revisions
138 138 added 1 changesets with 1 changes to 1 files
139 139 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
140 140 bundle2-input-part: total payload size 617
141 141 bundle2-input-part: "phase-heads" supported
142 142 bundle2-input-part: total payload size 24
143 143 bundle2-input-bundle: 3 parts total
144 144 updating the branch cache
145 145 bundle2-output-bundle: "HG20", 1 parts total
146 146 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
147 147 bundle2-input-bundle: no-transaction
148 148 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
149 149 bundle2-input-bundle: 0 parts total
150 150 listing keys for "phases"
151 151 $ mv .hg/store/lfs_ .hg/store/lfs
152 152
153 153 Clear the cache to force a download
154 154 $ rm -rf `hg config lfs.usercache`
155 155 $ cd ../repo2
156 156 $ hg update tip --debug
157 157 http auth: user foo, password ***
158 158 resolving manifests
159 159 branchmerge: False, force: False, partial: False
160 160 ancestor: 000000000000, local: 000000000000+, remote: 99a7098854a3
161 161 http auth: user foo, password ***
162 162 Status: 200
163 163 Content-Length: 311 (git-server !)
164 164 Content-Length: 352 (hg-server !)
165 165 Content-Type: application/vnd.git-lfs+json
166 166 Date: $HTTP_DATE$
167 167 Server: testing stub value (hg-server !)
168 168 {
169 169 "objects": [
170 170 {
171 171 "actions": {
172 172 "download": {
173 173 "expires_at": "$ISO_8601_DATE_TIME$"
174 174 "header": {
175 175 "Accept": "application/vnd.git-lfs"
176 176 }
177 177 "href": "http://localhost:$HGPORT/*/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (glob)
178 178 }
179 179 }
180 180 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
181 181 "size": 12
182 182 }
183 183 ]
184 184 "transfer": "basic" (hg-server !)
185 185 }
186 186 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
187 187 Status: 200
188 188 Content-Length: 12
189 189 Content-Type: text/plain; charset=utf-8 (git-server !)
190 190 Content-Type: application/octet-stream (hg-server !)
191 191 Date: $HTTP_DATE$
192 192 Server: testing stub value (hg-server !)
193 193 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
194 194 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
195 195 lfs: downloaded 1 files (12 bytes)
196 196 a: remote created -> g
197 197 getting a
198 198 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
199 199 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 200
201 201 When the server has some blobs already. `hg serve` doesn't offer to upload
202 202 blobs that it already knows about. Note that lfs-test-server is simply
203 203 toggling the action to 'download'. The Batch API spec says it should omit the
204 204 actions property completely.
205 205
206 206 $ hg mv a b
207 207 $ echo ANOTHER-LARGE-FILE > c
208 208 $ echo ANOTHER-LARGE-FILE2 > d
209 209 $ hg commit -m b-and-c -A b c d
210 210 $ hg push ../repo1 --debug
211 211 http auth: user foo, password ***
212 212 pushing to ../repo1
213 213 http auth: user foo, password ***
214 214 http auth: user foo, password ***
215 215 query 1; heads
216 216 searching for changes
217 217 all remote heads known locally
218 218 listing keys for "phases"
219 219 checking for updated bookmarks
220 220 listing keys for "bookmarks"
221 221 listing keys for "bookmarks"
222 222 lfs: computing set of blobs to upload
223 223 Status: 200
224 224 Content-Length: 901 (git-server !)
225 225 Content-Length: 755 (hg-server !)
226 226 Content-Type: application/vnd.git-lfs+json
227 227 Date: $HTTP_DATE$
228 228 Server: testing stub value (hg-server !)
229 229 {
230 230 "objects": [
231 231 {
232 232 "actions": { (git-server !)
233 233 "download": { (git-server !)
234 234 "expires_at": "$ISO_8601_DATE_TIME$" (git-server !)
235 235 "header": { (git-server !)
236 236 "Accept": "application/vnd.git-lfs" (git-server !)
237 237 } (git-server !)
238 238 "href": "http://localhost:$HGPORT/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (git-server !)
239 239 } (git-server !)
240 240 } (git-server !)
241 241 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
242 242 "size": 12
243 243 }
244 244 {
245 245 "actions": {
246 246 "upload": {
247 247 "expires_at": "$ISO_8601_DATE_TIME$"
248 248 "header": {
249 249 "Accept": "application/vnd.git-lfs"
250 250 }
251 251 "href": "http://localhost:$HGPORT/*/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19" (glob)
252 252 }
253 253 }
254 254 "oid": "37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19"
255 255 "size": 20
256 256 }
257 257 {
258 258 "actions": {
259 259 "upload": {
260 260 "expires_at": "$ISO_8601_DATE_TIME$"
261 261 "header": {
262 262 "Accept": "application/vnd.git-lfs"
263 263 }
264 264 "href": "http://localhost:$HGPORT/*/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (glob)
265 265 }
266 266 }
267 267 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
268 268 "size": 19
269 269 }
270 270 ]
271 271 "transfer": "basic" (hg-server !)
272 272 }
273 273 lfs: need to transfer 2 objects (39 bytes)
274 274 lfs: uploading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
275 275 Status: 200 (git-server !)
276 276 Status: 201 (hg-server !)
277 277 Content-Length: 0
278 278 Content-Type: text/plain; charset=utf-8
279 279 Date: $HTTP_DATE$
280 280 Server: testing stub value (hg-server !)
281 281 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
282 282 lfs: uploading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
283 283 Status: 200 (git-server !)
284 284 Status: 201 (hg-server !)
285 285 Content-Length: 0
286 286 Content-Type: text/plain; charset=utf-8
287 287 Date: $HTTP_DATE$
288 288 Server: testing stub value (hg-server !)
289 289 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
290 290 lfs: uploaded 2 files (39 bytes)
291 291 1 changesets found
292 292 list of changesets:
293 293 dfca2c9e2ef24996aa61ba2abd99277d884b3d63
294 294 bundle2-output-bundle: "HG20", 5 parts total
295 295 bundle2-output-part: "replycaps" * bytes payload (glob)
296 296 bundle2-output-part: "check:phases" 24 bytes payload
297 297 bundle2-output-part: "check:heads" streamed payload
298 298 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
299 299 bundle2-output-part: "phase-heads" 24 bytes payload
300 300 bundle2-input-bundle: with-transaction
301 301 bundle2-input-part: "replycaps" supported
302 302 bundle2-input-part: total payload size * (glob)
303 303 bundle2-input-part: "check:phases" supported
304 304 bundle2-input-part: total payload size 24
305 305 bundle2-input-part: "check:heads" supported
306 306 bundle2-input-part: total payload size 20
307 307 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
308 308 adding changesets
309 309 add changeset dfca2c9e2ef2
310 310 adding manifests
311 311 adding file changes
312 312 adding b revisions
313 313 adding c revisions
314 314 adding d revisions
315 315 added 1 changesets with 3 changes to 3 files
316 316 bundle2-input-part: total payload size 1315
317 317 bundle2-input-part: "phase-heads" supported
318 318 bundle2-input-part: total payload size 24
319 319 bundle2-input-bundle: 4 parts total
320 320 updating the branch cache
321 321 bundle2-output-bundle: "HG20", 1 parts total
322 322 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
323 323 bundle2-input-bundle: no-transaction
324 324 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
325 325 bundle2-input-bundle: 0 parts total
326 326 listing keys for "phases"
327 327
328 328 Clear the cache to force a download
329 329 $ rm -rf `hg config lfs.usercache`
330 330 $ hg --repo ../repo1 update tip --debug
331 331 http auth: user foo, password ***
332 332 resolving manifests
333 333 branchmerge: False, force: False, partial: False
334 334 ancestor: 99a7098854a3, local: 99a7098854a3+, remote: dfca2c9e2ef2
335 335 http auth: user foo, password ***
336 336 Status: 200
337 337 Content-Length: 608 (git-server !)
338 338 Content-Length: 670 (hg-server !)
339 339 Content-Type: application/vnd.git-lfs+json
340 340 Date: $HTTP_DATE$
341 341 Server: testing stub value (hg-server !)
342 342 {
343 343 "objects": [
344 344 {
345 345 "actions": {
346 346 "download": {
347 347 "expires_at": "$ISO_8601_DATE_TIME$"
348 348 "header": {
349 349 "Accept": "application/vnd.git-lfs"
350 350 }
351 351 "href": "http://localhost:$HGPORT/*/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19" (glob)
352 352 }
353 353 }
354 354 "oid": "37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19"
355 355 "size": 20
356 356 }
357 357 {
358 358 "actions": {
359 359 "download": {
360 360 "expires_at": "$ISO_8601_DATE_TIME$"
361 361 "header": {
362 362 "Accept": "application/vnd.git-lfs"
363 363 }
364 364 "href": "http://localhost:$HGPORT/*/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (glob)
365 365 }
366 366 }
367 367 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
368 368 "size": 19
369 369 }
370 370 ]
371 371 "transfer": "basic" (hg-server !)
372 372 }
373 373 lfs: need to transfer 2 objects (39 bytes)
374 374 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
375 375 Status: 200
376 376 Content-Length: 20
377 377 Content-Type: text/plain; charset=utf-8 (git-server !)
378 378 Content-Type: application/octet-stream (hg-server !)
379 379 Date: $HTTP_DATE$
380 380 Server: testing stub value (hg-server !)
381 381 lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 to the usercache
382 382 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
383 383 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
384 384 Status: 200
385 385 Content-Length: 19
386 386 Content-Type: text/plain; charset=utf-8 (git-server !)
387 387 Content-Type: application/octet-stream (hg-server !)
388 388 Date: $HTTP_DATE$
389 389 Server: testing stub value (hg-server !)
390 390 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
391 391 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
392 392 lfs: downloaded 2 files (39 bytes)
393 393 b: remote created -> g
394 394 getting b
395 395 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
396 396 c: remote created -> g
397 397 getting c
398 398 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
399 399 d: remote created -> g
400 400 getting d
401 401 lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 in the local lfs store
402 402 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 403
404 404 Test a corrupt file download, but clear the cache first to force a download.
405 405 `hg serve` indicates a corrupt file without transferring it, unlike
406 406 lfs-test-server.
407 407
408 408 $ rm -rf `hg config lfs.usercache`
409 409 #if git-server
410 410 $ cp $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 blob
411 411 $ echo 'damage' > $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
412 412 #else
413 413 $ cp $TESTTMP/server/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 blob
414 414 $ echo 'damage' > $TESTTMP/server/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
415 415 #endif
416 416 $ rm ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
417 417 $ rm ../repo1/*
418 418
419 419 TODO: give the proper error indication from `hg serve`
420 420
421 421 $ hg --repo ../repo1 update -C tip --debug
422 422 http auth: user foo, password ***
423 423 resolving manifests
424 424 branchmerge: False, force: True, partial: False
425 425 ancestor: dfca2c9e2ef2+, local: dfca2c9e2ef2+, remote: dfca2c9e2ef2
426 426 http auth: user foo, password ***
427 427 Status: 200
428 428 Content-Length: 311 (git-server !)
429 429 Content-Length: 183 (hg-server !)
430 430 Content-Type: application/vnd.git-lfs+json
431 431 Date: $HTTP_DATE$
432 432 Server: testing stub value (hg-server !)
433 433 {
434 434 "objects": [
435 435 {
436 436 "actions": { (git-server !)
437 437 "download": { (git-server !)
438 438 "expires_at": "$ISO_8601_DATE_TIME$" (git-server !)
439 439 "header": { (git-server !)
440 440 "Accept": "application/vnd.git-lfs" (git-server !)
441 441 } (git-server !)
442 442 "href": "http://localhost:$HGPORT/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (git-server !)
443 443 } (git-server !)
444 444 "error": { (hg-server !)
445 445 "code": 422 (hg-server !)
446 446 "message": "The object is corrupt" (hg-server !)
447 447 }
448 448 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
449 449 "size": 19
450 450 }
451 451 ]
452 452 "transfer": "basic" (hg-server !)
453 453 }
454 454 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes) (git-server !)
455 455 Status: 200 (git-server !)
456 456 Content-Length: 7 (git-server !)
457 457 Content-Type: text/plain; charset=utf-8 (git-server !)
458 458 Date: $HTTP_DATE$ (git-server !)
459 459 abort: corrupt remote lfs object: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (git-server !)
460 460 abort: LFS server error for "c": Validation error! (hg-server !)
461 461 [255]
462 462
463 463 The corrupted blob is not added to the usercache or local store
464 464
465 465 $ test -f ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
466 466 [1]
467 467 $ test -f `hg config lfs.usercache`/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
468 468 [1]
469 469 #if git-server
470 470 $ cp blob $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
471 471 #else
472 472 $ cp blob $TESTTMP/server/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
473 473 #endif
474 474
475 475 Test a corrupted file upload
476 476
477 477 $ echo 'another lfs blob' > b
478 478 $ hg ci -m 'another blob'
479 479 $ echo 'damage' > .hg/store/lfs/objects/e6/59058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
480 480 $ hg push --debug ../repo1
481 481 http auth: user foo, password ***
482 482 pushing to ../repo1
483 483 http auth: user foo, password ***
484 484 http auth: user foo, password ***
485 485 query 1; heads
486 486 searching for changes
487 487 all remote heads known locally
488 488 listing keys for "phases"
489 489 checking for updated bookmarks
490 490 listing keys for "bookmarks"
491 491 listing keys for "bookmarks"
492 492 lfs: computing set of blobs to upload
493 493 Status: 200
494 494 Content-Length: 309 (git-server !)
495 495 Content-Length: 350 (hg-server !)
496 496 Content-Type: application/vnd.git-lfs+json
497 497 Date: $HTTP_DATE$
498 498 Server: testing stub value (hg-server !)
499 499 {
500 500 "objects": [
501 501 {
502 502 "actions": {
503 503 "upload": {
504 504 "expires_at": "$ISO_8601_DATE_TIME$"
505 505 "header": {
506 506 "Accept": "application/vnd.git-lfs"
507 507 }
508 508 "href": "http://localhost:$HGPORT/*/e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0" (glob)
509 509 }
510 510 }
511 511 "oid": "e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0"
512 512 "size": 17
513 513 }
514 514 ]
515 515 "transfer": "basic" (hg-server !)
516 516 }
517 517 lfs: uploading e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0 (17 bytes)
518 518 abort: detected corrupt lfs object: e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
519 519 (run hg verify)
520 520 [255]
521 521
522 522 Archive will prefetch blobs in a group
523 523
524 524 $ rm -rf .hg/store/lfs `hg config lfs.usercache`
525 525 $ hg archive --debug -r 1 ../archive
526 526 http auth: user foo, password ***
527 527 http auth: user foo, password ***
528 528 Status: 200
529 529 Content-Length: 905 (git-server !)
530 530 Content-Length: 988 (hg-server !)
531 531 Content-Type: application/vnd.git-lfs+json
532 532 Date: $HTTP_DATE$
533 533 Server: testing stub value (hg-server !)
534 534 {
535 535 "objects": [
536 536 {
537 537 "actions": {
538 538 "download": {
539 539 "expires_at": "$ISO_8601_DATE_TIME$"
540 540 "header": {
541 541 "Accept": "application/vnd.git-lfs"
542 542 }
543 543 "href": "http://localhost:$HGPORT/*/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (glob)
544 544 }
545 545 }
546 546 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
547 547 "size": 12
548 548 }
549 549 {
550 550 "actions": {
551 551 "download": {
552 552 "expires_at": "$ISO_8601_DATE_TIME$"
553 553 "header": {
554 554 "Accept": "application/vnd.git-lfs"
555 555 }
556 556 "href": "http://localhost:$HGPORT/*/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19" (glob)
557 557 }
558 558 }
559 559 "oid": "37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19"
560 560 "size": 20
561 561 }
562 562 {
563 563 "actions": {
564 564 "download": {
565 565 "expires_at": "$ISO_8601_DATE_TIME$"
566 566 "header": {
567 567 "Accept": "application/vnd.git-lfs"
568 568 }
569 569 "href": "http://localhost:$HGPORT/*/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (glob)
570 570 }
571 571 }
572 572 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
573 573 "size": 19
574 574 }
575 575 ]
576 576 "transfer": "basic" (hg-server !)
577 577 }
578 578 lfs: need to transfer 3 objects (51 bytes)
579 579 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
580 580 Status: 200
581 581 Content-Length: 12
582 582 Content-Type: text/plain; charset=utf-8 (git-server !)
583 583 Content-Type: application/octet-stream (hg-server !)
584 584 Date: $HTTP_DATE$
585 585 Server: testing stub value (hg-server !)
586 586 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
587 587 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
588 588 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
589 589 Status: 200
590 590 Content-Length: 20
591 591 Content-Type: text/plain; charset=utf-8 (git-server !)
592 592 Content-Type: application/octet-stream (hg-server !)
593 593 Date: $HTTP_DATE$
594 594 Server: testing stub value (hg-server !)
595 595 lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 to the usercache
596 596 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
597 597 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
598 598 Status: 200
599 599 Content-Length: 19
600 600 Content-Type: text/plain; charset=utf-8 (git-server !)
601 601 Content-Type: application/octet-stream (hg-server !)
602 602 Date: $HTTP_DATE$
603 603 Server: testing stub value (hg-server !)
604 604 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
605 605 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
606 606 lfs: downloaded 3 files (51 bytes)
607 607 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
608 608 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
609 609 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
610 610 lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 in the local lfs store
611 611 $ find ../archive | sort
612 612 ../archive
613 613 ../archive/.hg_archival.txt
614 614 ../archive/a
615 615 ../archive/b
616 616 ../archive/c
617 617 ../archive/d
618 618
619 619 Cat will prefetch blobs in a group
620 620
621 621 $ rm -rf .hg/store/lfs `hg config lfs.usercache`
622 622 $ hg cat --debug -r 1 a b c nonexistent
623 623 http auth: user foo, password ***
624 624 http auth: user foo, password ***
625 625 Status: 200
626 626 Content-Length: 608 (git-server !)
627 627 Content-Length: 670 (hg-server !)
628 628 Content-Type: application/vnd.git-lfs+json
629 629 Date: $HTTP_DATE$
630 630 Server: testing stub value (hg-server !)
631 631 {
632 632 "objects": [
633 633 {
634 634 "actions": {
635 635 "download": {
636 636 "expires_at": "$ISO_8601_DATE_TIME$"
637 637 "header": {
638 638 "Accept": "application/vnd.git-lfs"
639 639 }
640 640 "href": "http://localhost:$HGPORT/*/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (glob)
641 641 }
642 642 }
643 643 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
644 644 "size": 12
645 645 }
646 646 {
647 647 "actions": {
648 648 "download": {
649 649 "expires_at": "$ISO_8601_DATE_TIME$"
650 650 "header": {
651 651 "Accept": "application/vnd.git-lfs"
652 652 }
653 653 "href": "http://localhost:$HGPORT/*/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (glob)
654 654 }
655 655 }
656 656 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
657 657 "size": 19
658 658 }
659 659 ]
660 660 "transfer": "basic" (hg-server !)
661 661 }
662 662 lfs: need to transfer 2 objects (31 bytes)
663 663 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
664 664 Status: 200
665 665 Content-Length: 12
666 666 Content-Type: text/plain; charset=utf-8 (git-server !)
667 667 Content-Type: application/octet-stream (hg-server !)
668 668 Date: $HTTP_DATE$
669 669 Server: testing stub value (hg-server !)
670 670 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
671 671 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
672 672 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
673 673 Status: 200
674 674 Content-Length: 19
675 675 Content-Type: text/plain; charset=utf-8 (git-server !)
676 676 Content-Type: application/octet-stream (hg-server !)
677 677 Date: $HTTP_DATE$
678 678 Server: testing stub value (hg-server !)
679 679 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
680 680 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
681 681 lfs: downloaded 2 files (31 bytes)
682 682 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
683 683 THIS-IS-LFS
684 684 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
685 685 THIS-IS-LFS
686 686 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
687 687 ANOTHER-LARGE-FILE
688 688 nonexistent: no such file in rev dfca2c9e2ef2
689 689
690 690 Revert will prefetch blobs in a group
691 691
692 692 $ rm -rf .hg/store/lfs
693 693 $ rm -rf `hg config lfs.usercache`
694 694 $ rm *
695 695 $ hg revert --all -r 1 --debug
696 696 http auth: user foo, password ***
697 adding a
698 reverting b
699 reverting c
700 reverting d
701 697 http auth: user foo, password ***
702 698 Status: 200
703 699 Content-Length: 905 (git-server !)
704 700 Content-Length: 988 (hg-server !)
705 701 Content-Type: application/vnd.git-lfs+json
706 702 Date: $HTTP_DATE$
707 703 Server: testing stub value (hg-server !)
708 704 {
709 705 "objects": [
710 706 {
711 707 "actions": {
712 708 "download": {
713 709 "expires_at": "$ISO_8601_DATE_TIME$"
714 710 "header": {
715 711 "Accept": "application/vnd.git-lfs"
716 712 }
717 713 "href": "http://localhost:$HGPORT/*/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b" (glob)
718 714 }
719 715 }
720 716 "oid": "31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b"
721 717 "size": 12
722 718 }
723 719 {
724 720 "actions": {
725 721 "download": {
726 722 "expires_at": "$ISO_8601_DATE_TIME$"
727 723 "header": {
728 724 "Accept": "application/vnd.git-lfs"
729 725 }
730 726 "href": "http://localhost:$HGPORT/*/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19" (glob)
731 727 }
732 728 }
733 729 "oid": "37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19"
734 730 "size": 20
735 731 }
736 732 {
737 733 "actions": {
738 734 "download": {
739 735 "expires_at": "$ISO_8601_DATE_TIME$"
740 736 "header": {
741 737 "Accept": "application/vnd.git-lfs"
742 738 }
743 739 "href": "http://localhost:$HGPORT/*/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998" (glob)
744 740 }
745 741 }
746 742 "oid": "d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998"
747 743 "size": 19
748 744 }
749 745 ]
750 746 "transfer": "basic" (hg-server !)
751 747 }
752 748 lfs: need to transfer 3 objects (51 bytes)
753 749 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
754 750 Status: 200
755 751 Content-Length: 12
756 752 Content-Type: text/plain; charset=utf-8 (git-server !)
757 753 Content-Type: application/octet-stream (hg-server !)
758 754 Date: $HTTP_DATE$
759 755 Server: testing stub value (hg-server !)
760 756 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
761 757 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
762 758 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
763 759 Status: 200
764 760 Content-Length: 20
765 761 Content-Type: text/plain; charset=utf-8 (git-server !)
766 762 Content-Type: application/octet-stream (hg-server !)
767 763 Date: $HTTP_DATE$
768 764 Server: testing stub value (hg-server !)
769 765 lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 to the usercache
770 766 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
771 767 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
772 768 Status: 200
773 769 Content-Length: 19
774 770 Content-Type: text/plain; charset=utf-8 (git-server !)
775 771 Content-Type: application/octet-stream (hg-server !)
776 772 Date: $HTTP_DATE$
777 773 Server: testing stub value (hg-server !)
778 774 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
779 775 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
780 776 lfs: downloaded 3 files (51 bytes)
777 reverting b
781 778 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
779 reverting c
782 780 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
781 reverting d
783 782 lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 in the local lfs store
783 adding a
784 784 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
785 785
786 786 Check error message when the remote missed a blob:
787 787
788 788 $ echo FFFFF > b
789 789 $ hg commit -m b -A b
790 790 $ echo FFFFF >> b
791 791 $ hg commit -m b b
792 792 $ rm -rf .hg/store/lfs
793 793 $ rm -rf `hg config lfs.usercache`
794 794 $ hg update -C '.^' --debug
795 795 http auth: user foo, password ***
796 796 resolving manifests
797 797 branchmerge: False, force: True, partial: False
798 798 ancestor: 62fdbaf221c6+, local: 62fdbaf221c6+, remote: ef0564edf47e
799 799 http auth: user foo, password ***
800 800 Status: 200
801 801 Content-Length: 308 (git-server !)
802 802 Content-Length: 186 (hg-server !)
803 803 Content-Type: application/vnd.git-lfs+json
804 804 Date: $HTTP_DATE$
805 805 Server: testing stub value (hg-server !)
806 806 {
807 807 "objects": [
808 808 {
809 809 "actions": { (git-server !)
810 810 "upload": { (git-server !)
811 811 "expires_at": "$ISO_8601_DATE_TIME$" (git-server !)
812 812 "header": { (git-server !)
813 813 "Accept": "application/vnd.git-lfs" (git-server !)
814 814 } (git-server !)
815 815 "href": "http://localhost:$HGPORT/objects/8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13" (git-server !)
816 816 } (git-server !)
817 817 "error": { (hg-server !)
818 818 "code": 404 (hg-server !)
819 819 "message": "The object does not exist" (hg-server !)
820 820 }
821 821 "oid": "8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13"
822 822 "size": 6
823 823 }
824 824 ]
825 825 "transfer": "basic" (hg-server !)
826 826 }
827 827 abort: LFS server error for "b": The object does not exist!
828 828 [255]
829 829
830 830 Check error message when object does not exist:
831 831
832 832 $ cd $TESTTMP
833 833 $ hg init test && cd test
834 834 $ echo "[extensions]" >> .hg/hgrc
835 835 $ echo "lfs=" >> .hg/hgrc
836 836 $ echo "[lfs]" >> .hg/hgrc
837 837 $ echo "threshold=1" >> .hg/hgrc
838 838 $ echo a > a
839 839 $ hg add a
840 840 $ hg commit -m 'test'
841 841 $ echo aaaaa > a
842 842 $ hg commit -m 'largefile'
843 843 $ hg debugdata a 1 # verify this is no the file content but includes "oid", the LFS "pointer".
844 844 version https://git-lfs.github.com/spec/v1
845 845 oid sha256:bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a
846 846 size 6
847 847 x-is-binary 0
848 848 $ cd ..
849 849 $ rm -rf `hg config lfs.usercache`
850 850
851 851 (Restart the server in a different location so it no longer has the content)
852 852
853 853 $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
854 854
855 855 #if hg-server
856 856 $ cat $TESTTMP/access.log $TESTTMP/errors.log
857 857 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
858 858 $LOCALIP - - [$LOGDATE$] "PUT /.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b HTTP/1.1" 201 - (glob)
859 859 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
860 860 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b HTTP/1.1" 200 - (glob)
861 861 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
862 862 $LOCALIP - - [$LOGDATE$] "PUT /.hg/lfs/objects/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 HTTP/1.1" 201 - (glob)
863 863 $LOCALIP - - [$LOGDATE$] "PUT /.hg/lfs/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 HTTP/1.1" 201 - (glob)
864 864 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
865 865 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 HTTP/1.1" 200 - (glob)
866 866 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 HTTP/1.1" 200 - (glob)
867 867 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
868 868 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
869 869 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
870 870 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b HTTP/1.1" 200 - (glob)
871 871 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 HTTP/1.1" 200 - (glob)
872 872 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 HTTP/1.1" 200 - (glob)
873 873 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
874 874 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b HTTP/1.1" 200 - (glob)
875 875 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 HTTP/1.1" 200 - (glob)
876 876 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
877 877 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b HTTP/1.1" 200 - (glob)
878 878 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 HTTP/1.1" 200 - (glob)
879 879 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 HTTP/1.1" 200 - (glob)
880 880 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
881 881 #endif
882 882
883 883 $ mkdir $TESTTMP/lfs-server2
884 884 $ cd $TESTTMP/lfs-server2
885 885 #if no-windows git-server
886 886 $ lfs-test-server &> lfs-server.log &
887 887 $ echo $! >> $DAEMON_PIDS
888 888 #endif
889 889
890 890 #if windows git-server
891 891 $ $PYTHON $TESTTMP/spawn.py >> $DAEMON_PIDS
892 892 #endif
893 893
894 894 #if hg-server
895 895 $ hg init server2
896 896 $ hg --config "lfs.usercache=$TESTTMP/servercache2" -R server2 serve -d \
897 897 > -p $HGPORT --pid-file=hg.pid -A $TESTTMP/access.log -E $TESTTMP/errors.log
898 898 $ cat hg.pid >> $DAEMON_PIDS
899 899 #endif
900 900
901 901 $ cd $TESTTMP
902 902 $ hg --debug clone test test2
903 903 http auth: user foo, password ***
904 904 linked 6 files
905 905 http auth: user foo, password ***
906 906 updating to branch default
907 907 resolving manifests
908 908 branchmerge: False, force: False, partial: False
909 909 ancestor: 000000000000, local: 000000000000+, remote: d2a338f184a8
910 910 http auth: user foo, password ***
911 911 Status: 200
912 912 Content-Length: 308 (git-server !)
913 913 Content-Length: 186 (hg-server !)
914 914 Content-Type: application/vnd.git-lfs+json
915 915 Date: $HTTP_DATE$
916 916 Server: testing stub value (hg-server !)
917 917 {
918 918 "objects": [
919 919 {
920 920 "actions": { (git-server !)
921 921 "upload": { (git-server !)
922 922 "expires_at": "$ISO_8601_DATE_TIME$" (git-server !)
923 923 "header": { (git-server !)
924 924 "Accept": "application/vnd.git-lfs" (git-server !)
925 925 } (git-server !)
926 926 "href": "http://localhost:$HGPORT/objects/bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a" (git-server !)
927 927 } (git-server !)
928 928 "error": { (hg-server !)
929 929 "code": 404 (hg-server !)
930 930 "message": "The object does not exist" (hg-server !)
931 931 }
932 932 "oid": "bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a"
933 933 "size": 6
934 934 }
935 935 ]
936 936 "transfer": "basic" (hg-server !)
937 937 }
938 938 abort: LFS server error for "a": The object does not exist!
939 939 [255]
940 940
941 941 $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
@@ -1,116 +1,116 b''
1 1 $ hg init
2 2
3 3 $ echo foo > foo
4 4 $ echo bar > bar
5 5 $ hg ci -qAm 'add foo bar'
6 6
7 7 $ echo foo2 >> foo
8 8 $ echo bleh > bar
9 9 $ hg ci -m 'change foo bar'
10 10
11 11 $ hg up -qC 0
12 12 $ hg mv foo foo1
13 13 $ echo foo1 > foo1
14 14 $ hg cat foo >> foo1
15 15 $ hg ci -m 'mv foo foo1'
16 16 created new head
17 17
18 18 $ hg merge
19 19 merging foo1 and foo to foo1
20 20 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
21 21 (branch merge, don't forget to commit)
22 22
23 23 $ hg debugstate --nodates
24 24 m 0 -2 unset bar
25 25 m 0 -2 unset foo1
26 26 copy: foo -> foo1
27 27
28 28 $ hg st -q
29 29 M bar
30 30 M foo1
31 31
32 32
33 33 Removing foo1 and bar:
34 34
35 35 $ cp foo1 F
36 36 $ cp bar B
37 37 $ hg rm -f foo1 bar
38 38
39 39 $ hg debugstate --nodates
40 40 r 0 -1 set bar
41 41 r 0 -1 set foo1
42 42 copy: foo -> foo1
43 43
44 44 $ hg st -qC
45 45 R bar
46 46 R foo1
47 47
48 48
49 49 Re-adding foo1 and bar:
50 50
51 51 $ cp F foo1
52 52 $ cp B bar
53 53 $ hg add -v foo1 bar
54 54 adding bar
55 55 adding foo1
56 56
57 57 $ hg debugstate --nodates
58 58 n 0 -2 unset bar
59 59 n 0 -2 unset foo1
60 60 copy: foo -> foo1
61 61
62 62 $ hg st -qC
63 63 M bar
64 64 M foo1
65 65 foo
66 66
67 67
68 68 Reverting foo1 and bar:
69 69
70 70 $ hg revert -vr . foo1 bar
71 71 saving current version of bar as bar.orig
72 saving current version of foo1 as foo1.orig
72 73 reverting bar
73 saving current version of foo1 as foo1.orig
74 74 reverting foo1
75 75
76 76 $ hg debugstate --nodates
77 77 n 0 -2 unset bar
78 78 n 0 -2 unset foo1
79 79 copy: foo -> foo1
80 80
81 81 $ hg st -qC
82 82 M bar
83 83 M foo1
84 84 foo
85 85
86 86 $ hg diff
87 87
88 88 Merge should not overwrite local file that is untracked after remove
89 89
90 90 $ rm *
91 91 $ hg up -qC
92 92 $ hg rm bar
93 93 $ hg ci -m 'remove bar'
94 94 $ echo 'memories of buried pirate treasure' > bar
95 95 $ hg merge
96 96 bar: untracked file differs
97 97 abort: untracked files in working directory differ from files in requested revision
98 98 [255]
99 99 $ cat bar
100 100 memories of buried pirate treasure
101 101
102 102 Those who use force will lose
103 103
104 104 $ hg merge -f
105 105 file 'bar' was deleted in local [working copy] but was modified in other [merge rev].
106 106 What do you want to do?
107 107 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
108 108 merging foo1 and foo to foo1
109 109 0 files updated, 1 files merged, 0 files removed, 1 files unresolved
110 110 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
111 111 [1]
112 112 $ cat bar
113 113 bleh
114 114 $ hg st
115 115 M bar
116 116 M foo1
@@ -1,432 +1,426 b''
1 1 Revert interactive tests
2 2 1 add and commit file f
3 3 2 add commit file folder1/g
4 4 3 add and commit file folder2/h
5 5 4 add and commit file folder1/i
6 6 5 commit change to file f
7 7 6 commit changes to files folder1/g folder2/h
8 8 7 commit changes to files folder1/g folder2/h
9 9 8 revert interactive to commit id 2 (line 3 above), check that folder1/i is removed and
10 10 9 make workdir match 7
11 11 10 run the same test than 8 from within folder1 and check same expectations
12 12
13 13 $ cat <<EOF >> $HGRCPATH
14 14 > [ui]
15 15 > interactive = true
16 16 > [extensions]
17 17 > record =
18 18 > purge =
19 19 > EOF
20 20
21 21
22 22 $ mkdir -p a/folder1 a/folder2
23 23 $ cd a
24 24 $ hg init
25 25 >>> open('f', 'wb').write(b"1\n2\n3\n4\n5\n") and None
26 26 $ hg add f ; hg commit -m "adding f"
27 27 $ cat f > folder1/g ; hg add folder1/g ; hg commit -m "adding folder1/g"
28 28 $ cat f > folder2/h ; hg add folder2/h ; hg commit -m "adding folder2/h"
29 29 $ cat f > folder1/i ; hg add folder1/i ; hg commit -m "adding folder1/i"
30 30 >>> open('f', 'wb').write(b"a\n1\n2\n3\n4\n5\nb\n") and None
31 31 $ hg commit -m "modifying f"
32 32 >>> open('folder1/g', 'wb').write(b"c\n1\n2\n3\n4\n5\nd\n") and None
33 33 $ hg commit -m "modifying folder1/g"
34 34 >>> open('folder2/h', 'wb').write(b"e\n1\n2\n3\n4\n5\nf\n") and None
35 35 $ hg commit -m "modifying folder2/h"
36 36 $ hg tip
37 37 changeset: 6:59dd6e4ab63a
38 38 tag: tip
39 39 user: test
40 40 date: Thu Jan 01 00:00:00 1970 +0000
41 41 summary: modifying folder2/h
42 42
43 43 $ hg revert -i -r 2 --all -- << EOF
44 44 > y
45 45 > y
46 46 > y
47 47 > y
48 48 > y
49 49 > ?
50 50 > y
51 51 > n
52 52 > n
53 53 > EOF
54 reverting f
55 reverting folder1/g
54 remove added file folder1/i (Yn)? y
56 55 removing folder1/i
57 reverting folder2/h
58 remove added file folder1/i (Yn)? y
59 56 diff --git a/f b/f
60 57 2 hunks, 2 lines changed
61 58 examine changes to 'f'? [Ynesfdaq?] y
62 59
63 60 @@ -1,6 +1,5 @@
64 61 -a
65 62 1
66 63 2
67 64 3
68 65 4
69 66 5
70 67 apply change 1/6 to 'f'? [Ynesfdaq?] y
71 68
72 69 @@ -2,6 +1,5 @@
73 70 1
74 71 2
75 72 3
76 73 4
77 74 5
78 75 -b
79 76 apply change 2/6 to 'f'? [Ynesfdaq?] y
80 77
81 78 diff --git a/folder1/g b/folder1/g
82 79 2 hunks, 2 lines changed
83 80 examine changes to 'folder1/g'? [Ynesfdaq?] y
84 81
85 82 @@ -1,6 +1,5 @@
86 83 -c
87 84 1
88 85 2
89 86 3
90 87 4
91 88 5
92 89 apply change 3/6 to 'folder1/g'? [Ynesfdaq?] ?
93 90
94 91 y - yes, apply this change
95 92 n - no, skip this change
96 93 e - edit this change manually
97 94 s - skip remaining changes to this file
98 95 f - apply remaining changes to this file
99 96 d - done, skip remaining changes and files
100 97 a - apply all changes to all remaining files
101 98 q - quit, applying no changes
102 99 ? - ? (display help)
103 100 apply change 3/6 to 'folder1/g'? [Ynesfdaq?] y
104 101
105 102 @@ -2,6 +1,5 @@
106 103 1
107 104 2
108 105 3
109 106 4
110 107 5
111 108 -d
112 109 apply change 4/6 to 'folder1/g'? [Ynesfdaq?] n
113 110
114 111 diff --git a/folder2/h b/folder2/h
115 112 2 hunks, 2 lines changed
116 113 examine changes to 'folder2/h'? [Ynesfdaq?] n
117 114
115 reverting folder1/g
116 reverting f
118 117 $ cat f
119 118 1
120 119 2
121 120 3
122 121 4
123 122 5
124 123 $ cat folder1/g
125 124 1
126 125 2
127 126 3
128 127 4
129 128 5
130 129 d
131 130 $ cat folder2/h
132 131 e
133 132 1
134 133 2
135 134 3
136 135 4
137 136 5
138 137 f
139 138
140 139 Test that --interactive lift the need for --all
141 140
142 141 $ echo q | hg revert -i -r 2
143 reverting folder1/g
144 reverting folder2/h
145 142 diff --git a/folder1/g b/folder1/g
146 143 1 hunks, 1 lines changed
147 144 examine changes to 'folder1/g'? [Ynesfdaq?] q
148 145
149 146 abort: user quit
150 147 [255]
151 148 $ ls folder1/
152 149 g
153 150
154 151 Test that a noop revert doesn't do an unnecessary backup
155 152 $ (echo y; echo n) | hg revert -i -r 2 folder1/g
156 153 diff --git a/folder1/g b/folder1/g
157 154 1 hunks, 1 lines changed
158 155 examine changes to 'folder1/g'? [Ynesfdaq?] y
159 156
160 157 @@ -3,4 +3,3 @@
161 158 3
162 159 4
163 160 5
164 161 -d
165 162 apply this change to 'folder1/g'? [Ynesfdaq?] n
166 163
167 164 $ ls folder1/
168 165 g
169 166
170 167 Test --no-backup
171 168 $ (echo y; echo y) | hg revert -i -C -r 2 folder1/g
172 169 diff --git a/folder1/g b/folder1/g
173 170 1 hunks, 1 lines changed
174 171 examine changes to 'folder1/g'? [Ynesfdaq?] y
175 172
176 173 @@ -3,4 +3,3 @@
177 174 3
178 175 4
179 176 5
180 177 -d
181 178 apply this change to 'folder1/g'? [Ynesfdaq?] y
182 179
183 180 $ ls folder1/
184 181 g
185 182 >>> open('folder1/g', 'wb').write(b"1\n2\n3\n4\n5\nd\n") and None
186 183
187 184
188 185 $ hg update -C 6
189 186 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 187 $ hg revert -i -r 2 --all -- << EOF
191 188 > n
192 189 > y
193 190 > y
194 191 > y
195 192 > y
196 193 > y
197 194 > n
198 195 > n
199 196 > EOF
200 reverting f
201 reverting folder1/g
202 removing folder1/i
203 reverting folder2/h
204 197 remove added file folder1/i (Yn)? n
205 198 diff --git a/f b/f
206 199 2 hunks, 2 lines changed
207 200 examine changes to 'f'? [Ynesfdaq?] y
208 201
209 202 @@ -1,6 +1,5 @@
210 203 -a
211 204 1
212 205 2
213 206 3
214 207 4
215 208 5
216 209 apply change 1/6 to 'f'? [Ynesfdaq?] y
217 210
218 211 @@ -2,6 +1,5 @@
219 212 1
220 213 2
221 214 3
222 215 4
223 216 5
224 217 -b
225 218 apply change 2/6 to 'f'? [Ynesfdaq?] y
226 219
227 220 diff --git a/folder1/g b/folder1/g
228 221 2 hunks, 2 lines changed
229 222 examine changes to 'folder1/g'? [Ynesfdaq?] y
230 223
231 224 @@ -1,6 +1,5 @@
232 225 -c
233 226 1
234 227 2
235 228 3
236 229 4
237 230 5
238 231 apply change 3/6 to 'folder1/g'? [Ynesfdaq?] y
239 232
240 233 @@ -2,6 +1,5 @@
241 234 1
242 235 2
243 236 3
244 237 4
245 238 5
246 239 -d
247 240 apply change 4/6 to 'folder1/g'? [Ynesfdaq?] n
248 241
249 242 diff --git a/folder2/h b/folder2/h
250 243 2 hunks, 2 lines changed
251 244 examine changes to 'folder2/h'? [Ynesfdaq?] n
252 245
246 reverting folder1/g
247 reverting f
253 248 $ cat f
254 249 1
255 250 2
256 251 3
257 252 4
258 253 5
259 254 $ cat folder1/g
260 255 1
261 256 2
262 257 3
263 258 4
264 259 5
265 260 d
266 261 $ cat folder2/h
267 262 e
268 263 1
269 264 2
270 265 3
271 266 4
272 267 5
273 268 f
274 269 $ hg st
275 270 M f
276 271 M folder1/g
277 272 $ hg revert --interactive f << EOF
278 273 > y
279 274 > ?
280 275 > y
281 276 > n
282 277 > n
283 278 > EOF
284 279 diff --git a/f b/f
285 280 2 hunks, 2 lines changed
286 281 examine changes to 'f'? [Ynesfdaq?] y
287 282
288 283 @@ -1,6 +1,5 @@
289 284 -a
290 285 1
291 286 2
292 287 3
293 288 4
294 289 5
295 290 discard change 1/2 to 'f'? [Ynesfdaq?] ?
296 291
297 292 y - yes, discard this change
298 293 n - no, skip this change
299 294 e - edit this change manually
300 295 s - skip remaining changes to this file
301 296 f - discard remaining changes to this file
302 297 d - done, skip remaining changes and files
303 298 a - discard all changes to all remaining files
304 299 q - quit, discarding no changes
305 300 ? - ? (display help)
306 301 discard change 1/2 to 'f'? [Ynesfdaq?] y
307 302
308 303 @@ -2,6 +1,5 @@
309 304 1
310 305 2
311 306 3
312 307 4
313 308 5
314 309 -b
315 310 discard change 2/2 to 'f'? [Ynesfdaq?] n
316 311
317 312 $ hg st
318 313 M f
319 314 M folder1/g
320 315 ? f.orig
321 316 $ cat f
322 317 a
323 318 1
324 319 2
325 320 3
326 321 4
327 322 5
328 323 $ cat f.orig
329 324 1
330 325 2
331 326 3
332 327 4
333 328 5
334 329 $ rm f.orig
335 330 $ hg update -C .
336 331 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 332
338 333 Check editing files newly added by a revert
339 334
340 335 1) Create a dummy editor changing 1 to 42
341 336 $ cat > $TESTTMP/editor.sh << '__EOF__'
342 337 > cat "$1" | sed "s/1/42/g" > tt
343 338 > mv tt "$1"
344 339 > __EOF__
345 340
346 341 2) Add k
347 342 $ printf "1\n" > k
348 343 $ hg add k
349 344 $ hg commit -m "add k"
350 345
351 346 3) Use interactive revert with editing (replacing +1 with +42):
352 347 $ printf "0\n2\n" > k
353 348 $ HGEDITOR="\"sh\" \"${TESTTMP}/editor.sh\"" hg revert -i <<EOF
354 349 > y
355 350 > e
356 351 > EOF
357 reverting k
358 352 diff --git a/k b/k
359 353 1 hunks, 2 lines changed
360 354 examine changes to 'k'? [Ynesfdaq?] y
361 355
362 356 @@ -1,1 +1,2 @@
363 357 -1
364 358 +0
365 359 +2
366 360 discard this change to 'k'? [Ynesfdaq?] e
367 361
362 reverting k
368 363 $ cat k
369 364 42
370 365
371 366 $ hg update -C .
372 367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 368 $ hg purge
374 369 $ touch newfile
375 370 $ hg add newfile
376 371 $ hg status
377 372 A newfile
378 373 $ hg revert -i <<EOF
379 374 > n
380 375 > EOF
381 forgetting newfile
382 376 forget added file newfile (Yn)? n
383 377 $ hg status
384 378 A newfile
385 379 $ hg revert -i <<EOF
386 380 > y
387 381 > EOF
382 forget added file newfile (Yn)? y
388 383 forgetting newfile
389 forget added file newfile (Yn)? y
390 384 $ hg status
391 385 ? newfile
392 386
393 387 When a line without EOL is selected during "revert -i" (issue5651)
394 388
395 389 $ hg init $TESTTMP/revert-i-eol
396 390 $ cd $TESTTMP/revert-i-eol
397 391 $ echo 0 > a
398 392 $ hg ci -qAm 0
399 393 $ printf 1 >> a
400 394 $ hg ci -qAm 1
401 395 $ cat a
402 396 0
403 397 1 (no-eol)
404 398
405 399 $ hg revert -ir'.^' <<EOF
406 400 > y
407 401 > y
408 402 > EOF
409 reverting a
410 403 diff --git a/a b/a
411 404 1 hunks, 1 lines changed
412 405 examine changes to 'a'? [Ynesfdaq?] y
413 406
414 407 @@ -1,2 +1,1 @@
415 408 0
416 409 -1
417 410 \ No newline at end of file
418 411 apply this change to 'a'? [Ynesfdaq?] y
419 412
413 reverting a
420 414 $ cat a
421 415 0
422 416
423 417 When specified pattern does not exist, we should exit early (issue5789).
424 418
425 419 $ hg files
426 420 a
427 421 $ hg rev b
428 422 b: no such file in rev b40d1912accf
429 423 $ hg rev -i b
430 424 b: no such file in rev b40d1912accf
431 425
432 426 $ cd ..
@@ -1,1147 +1,1147 b''
1 1 $ hg init repo
2 2 $ cd repo
3 3 $ echo 123 > a
4 4 $ echo 123 > c
5 5 $ echo 123 > e
6 6 $ hg add a c e
7 7 $ hg commit -m "first" a c e
8 8
9 9 nothing changed
10 10
11 11 $ hg revert
12 12 abort: no files or directories specified
13 13 (use --all to revert all files)
14 14 [255]
15 15 $ hg revert --all
16 16
17 17 Introduce some changes and revert them
18 18 --------------------------------------
19 19
20 20 $ echo 123 > b
21 21
22 22 $ hg status
23 23 ? b
24 24 $ echo 12 > c
25 25
26 26 $ hg status
27 27 M c
28 28 ? b
29 29 $ hg add b
30 30
31 31 $ hg status
32 32 M c
33 33 A b
34 34 $ hg rm a
35 35
36 36 $ hg status
37 37 M c
38 38 A b
39 39 R a
40 40
41 41 revert removal of a file
42 42
43 43 $ hg revert a
44 44 $ hg status
45 45 M c
46 46 A b
47 47
48 48 revert addition of a file
49 49
50 50 $ hg revert b
51 51 $ hg status
52 52 M c
53 53 ? b
54 54
55 55 revert modification of a file (--no-backup)
56 56
57 57 $ hg revert --no-backup c
58 58 $ hg status
59 59 ? b
60 60
61 61 revert deletion (! status) of a added file
62 62 ------------------------------------------
63 63
64 64 $ hg add b
65 65
66 66 $ hg status b
67 67 A b
68 68 $ rm b
69 69 $ hg status b
70 70 ! b
71 71 $ hg revert -v b
72 72 forgetting b
73 73 $ hg status b
74 74 b: * (glob)
75 75
76 76 $ ls
77 77 a
78 78 c
79 79 e
80 80
81 81 Test creation of backup (.orig) files
82 82 -------------------------------------
83 83
84 84 $ echo z > e
85 85 $ hg revert --all -v
86 86 saving current version of e as e.orig
87 87 reverting e
88 88
89 89 Test creation of backup (.orig) file in configured file location
90 90 ----------------------------------------------------------------
91 91
92 92 $ echo z > e
93 93 $ hg revert --all -v --config 'ui.origbackuppath=.hg/origbackups'
94 94 creating directory: $TESTTMP/repo/.hg/origbackups
95 95 saving current version of e as $TESTTMP/repo/.hg/origbackups/e
96 96 reverting e
97 97 $ rm -rf .hg/origbackups
98 98
99 99 revert on clean file (no change)
100 100 --------------------------------
101 101
102 102 $ hg revert a
103 103 no changes needed to a
104 104
105 105 revert on an untracked file
106 106 ---------------------------
107 107
108 108 $ echo q > q
109 109 $ hg revert q
110 110 file not managed: q
111 111 $ rm q
112 112
113 113 revert on file that does not exists
114 114 -----------------------------------
115 115
116 116 $ hg revert notfound
117 117 notfound: no such file in rev 334a9e57682c
118 118 $ touch d
119 119 $ hg add d
120 120 $ hg rm a
121 121 $ hg commit -m "second"
122 122 $ echo z > z
123 123 $ hg add z
124 124 $ hg st
125 125 A z
126 126 ? e.orig
127 127
128 128 revert to another revision (--rev)
129 129 ----------------------------------
130 130
131 131 $ hg revert --all -r0
132 adding a
132 forgetting z
133 133 removing d
134 forgetting z
134 adding a
135 135
136 136 revert explicitly to parent (--rev)
137 137 -----------------------------------
138 138
139 139 $ hg revert --all -rtip
140 140 forgetting a
141 141 undeleting d
142 142 $ rm a *.orig
143 143
144 144 revert to another revision (--rev) and exact match
145 145 --------------------------------------------------
146 146
147 147 exact match are more silent
148 148
149 149 $ hg revert -r0 a
150 150 $ hg st a
151 151 A a
152 152 $ hg rm d
153 153 $ hg st d
154 154 R d
155 155
156 156 should keep d removed
157 157
158 158 $ hg revert -r0 d
159 159 no changes needed to d
160 160 $ hg st d
161 161 R d
162 162
163 163 $ hg update -C
164 164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 165
166 166 revert of exec bit
167 167 ------------------
168 168
169 169 #if execbit
170 170 $ chmod +x c
171 171 $ hg revert --all
172 172 reverting c
173 173
174 174 $ test -x c || echo non-executable
175 175 non-executable
176 176
177 177 $ chmod +x c
178 178 $ hg commit -m exe
179 179
180 180 $ chmod -x c
181 181 $ hg revert --all
182 182 reverting c
183 183
184 184 $ test -x c && echo executable
185 185 executable
186 186 #endif
187 187
188 188 Test that files reverted to other than the parent are treated as
189 189 "modified", even if none of mode, size and timestamp of it isn't
190 190 changed on the filesystem (see also issue4583).
191 191
192 192 $ echo 321 > e
193 193 $ hg diff --git
194 194 diff --git a/e b/e
195 195 --- a/e
196 196 +++ b/e
197 197 @@ -1,1 +1,1 @@
198 198 -123
199 199 +321
200 200 $ hg commit -m 'ambiguity from size'
201 201
202 202 $ cat e
203 203 321
204 204 $ touch -t 200001010000 e
205 205 $ hg debugrebuildstate
206 206
207 207 $ cat >> .hg/hgrc <<EOF
208 208 > [fakedirstatewritetime]
209 209 > # emulate invoking dirstate.write() via repo.status()
210 210 > # at 2000-01-01 00:00
211 211 > fakenow = 200001010000
212 212 >
213 213 > [extensions]
214 214 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
215 215 > EOF
216 216 $ hg revert -r 0 e
217 217 $ cat >> .hg/hgrc <<EOF
218 218 > [extensions]
219 219 > fakedirstatewritetime = !
220 220 > EOF
221 221
222 222 $ cat e
223 223 123
224 224 $ touch -t 200001010000 e
225 225 $ hg status -A e
226 226 M e
227 227
228 228 $ cd ..
229 229
230 230
231 231 Issue241: update and revert produces inconsistent repositories
232 232 --------------------------------------------------------------
233 233
234 234 $ hg init a
235 235 $ cd a
236 236 $ echo a >> a
237 237 $ hg commit -A -d '1 0' -m a
238 238 adding a
239 239 $ echo a >> a
240 240 $ hg commit -d '2 0' -m a
241 241 $ hg update 0
242 242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 243 $ mkdir b
244 244 $ echo b > b/b
245 245
246 246 call `hg revert` with no file specified
247 247 ---------------------------------------
248 248
249 249 $ hg revert -rtip
250 250 abort: no files or directories specified
251 251 (use --all to revert all files, or 'hg update 1' to update)
252 252 [255]
253 253
254 254 call `hg revert` with -I
255 255 ---------------------------
256 256
257 257 $ echo a >> a
258 258 $ hg revert -I a
259 259 reverting a
260 260
261 261 call `hg revert` with -X
262 262 ---------------------------
263 263
264 264 $ echo a >> a
265 265 $ hg revert -X d
266 266 reverting a
267 267
268 268 call `hg revert` with --all
269 269 ---------------------------
270 270
271 271 $ hg revert --all -rtip
272 272 reverting a
273 273 $ rm *.orig
274 274
275 275 Issue332: confusing message when reverting directory
276 276 ----------------------------------------------------
277 277
278 278 $ hg ci -A -m b
279 279 adding b/b
280 280 created new head
281 281 $ echo foobar > b/b
282 282 $ mkdir newdir
283 283 $ echo foo > newdir/newfile
284 284 $ hg add newdir/newfile
285 285 $ hg revert b newdir
286 forgetting newdir/newfile
286 287 reverting b/b
287 forgetting newdir/newfile
288 288 $ echo foobar > b/b
289 289 $ hg revert .
290 290 reverting b/b
291 291
292 292
293 293 reverting a rename target should revert the source
294 294 --------------------------------------------------
295 295
296 296 $ hg mv a newa
297 297 $ hg revert newa
298 298 $ hg st a newa
299 299 ? newa
300 300
301 301 Also true for move overwriting an existing file
302 302
303 303 $ hg mv --force a b/b
304 304 $ hg revert b/b
305 305 $ hg status a b/b
306 306
307 307 $ cd ..
308 308
309 309 $ hg init ignored
310 310 $ cd ignored
311 311 $ echo '^ignored$' > .hgignore
312 312 $ echo '^ignoreddir$' >> .hgignore
313 313 $ echo '^removed$' >> .hgignore
314 314
315 315 $ mkdir ignoreddir
316 316 $ touch ignoreddir/file
317 317 $ touch ignoreddir/removed
318 318 $ touch ignored
319 319 $ touch removed
320 320
321 321 4 ignored files (we will add/commit everything)
322 322
323 323 $ hg st -A -X .hgignore
324 324 I ignored
325 325 I ignoreddir/file
326 326 I ignoreddir/removed
327 327 I removed
328 328 $ hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed
329 329
330 330 $ echo >> ignored
331 331 $ echo >> ignoreddir/file
332 332 $ hg rm removed ignoreddir/removed
333 333
334 334 should revert ignored* and undelete *removed
335 335 --------------------------------------------
336 336
337 337 $ hg revert -a --no-backup
338 338 reverting ignored
339 339 reverting ignoreddir/file
340 340 undeleting ignoreddir/removed
341 341 undeleting removed
342 342 $ hg st -mardi
343 343
344 344 $ hg up -qC
345 345 $ echo >> ignored
346 346 $ hg rm removed
347 347
348 348 should silently revert the named files
349 349 --------------------------------------
350 350
351 351 $ hg revert --no-backup ignored removed
352 352 $ hg st -mardi
353 353
354 354 Reverting copy (issue3920)
355 355 --------------------------
356 356
357 357 someone set up us the copies
358 358
359 359 $ rm .hgignore
360 360 $ hg update -C
361 361 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
362 362 $ hg mv ignored allyour
363 363 $ hg copy removed base
364 364 $ hg commit -m rename
365 365
366 366 copies and renames, you have no chance to survive make your time (issue3920)
367 367
368 368 $ hg update '.^'
369 369 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
370 370 $ hg revert -rtip -a
371 removing ignored
371 372 adding allyour
372 373 adding base
373 removing ignored
374 374 $ hg status -C
375 375 A allyour
376 376 ignored
377 377 A base
378 378 removed
379 379 R ignored
380 380
381 381 Test revert of a file added by one side of the merge
382 382 ====================================================
383 383
384 384 remove any pending change
385 385
386 386 $ hg revert --all
387 387 forgetting allyour
388 388 forgetting base
389 389 undeleting ignored
390 390 $ hg purge --all --config extensions.purge=
391 391
392 392 Adds a new commit
393 393
394 394 $ echo foo > newadd
395 395 $ hg add newadd
396 396 $ hg commit -m 'other adds'
397 397 created new head
398 398
399 399
400 400 merge it with the other head
401 401
402 402 $ hg merge # merge 1 into 2
403 403 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
404 404 (branch merge, don't forget to commit)
405 405 $ hg summary
406 406 parent: 2:b8ec310b2d4e tip
407 407 other adds
408 408 parent: 1:f6180deb8fbe
409 409 rename
410 410 branch: default
411 411 commit: 2 modified, 1 removed (merge)
412 412 update: (current)
413 413 phases: 3 draft
414 414
415 415 clarifies who added what
416 416
417 417 $ hg status
418 418 M allyour
419 419 M base
420 420 R ignored
421 421 $ hg status --change 'p1()'
422 422 A newadd
423 423 $ hg status --change 'p2()'
424 424 A allyour
425 425 A base
426 426 R ignored
427 427
428 428 revert file added by p1() to p1() state
429 429 -----------------------------------------
430 430
431 431 $ hg revert -r 'p1()' 'glob:newad?'
432 432 $ hg status
433 433 M allyour
434 434 M base
435 435 R ignored
436 436
437 437 revert file added by p1() to p2() state
438 438 ------------------------------------------
439 439
440 440 $ hg revert -r 'p2()' 'glob:newad?'
441 441 removing newadd
442 442 $ hg status
443 443 M allyour
444 444 M base
445 445 R ignored
446 446 R newadd
447 447
448 448 revert file added by p2() to p2() state
449 449 ------------------------------------------
450 450
451 451 $ hg revert -r 'p2()' 'glob:allyou?'
452 452 $ hg status
453 453 M allyour
454 454 M base
455 455 R ignored
456 456 R newadd
457 457
458 458 revert file added by p2() to p1() state
459 459 ------------------------------------------
460 460
461 461 $ hg revert -r 'p1()' 'glob:allyou?'
462 462 removing allyour
463 463 $ hg status
464 464 M base
465 465 R allyour
466 466 R ignored
467 467 R newadd
468 468
469 469 Systematic behavior validation of most possible cases
470 470 =====================================================
471 471
472 472 This section tests most of the possible combinations of revision states and
473 473 working directory states. The number of possible cases is significant but they
474 474 but they all have a slightly different handling. So this section commits to
475 475 and testing all of them to allow safe refactoring of the revert code.
476 476
477 477 A python script is used to generate a file history for each combination of
478 478 states, on one side the content (or lack thereof) in two revisions, and
479 479 on the other side, the content and "tracked-ness" of the working directory. The
480 480 three states generated are:
481 481
482 482 - a "base" revision
483 483 - a "parent" revision
484 484 - the working directory (based on "parent")
485 485
486 486 The files generated have names of the form:
487 487
488 488 <rev1-content>_<rev2-content>_<working-copy-content>-<tracked-ness>
489 489
490 490 All known states are not tested yet. See inline documentation for details.
491 491 Special cases from merge and rename are not tested by this section.
492 492
493 493 Write the python script to disk
494 494 -------------------------------
495 495
496 496 check list of planned files
497 497
498 498 $ $PYTHON $TESTDIR/generate-working-copy-states.py filelist 2
499 499 content1_content1_content1-tracked
500 500 content1_content1_content1-untracked
501 501 content1_content1_content3-tracked
502 502 content1_content1_content3-untracked
503 503 content1_content1_missing-tracked
504 504 content1_content1_missing-untracked
505 505 content1_content2_content1-tracked
506 506 content1_content2_content1-untracked
507 507 content1_content2_content2-tracked
508 508 content1_content2_content2-untracked
509 509 content1_content2_content3-tracked
510 510 content1_content2_content3-untracked
511 511 content1_content2_missing-tracked
512 512 content1_content2_missing-untracked
513 513 content1_missing_content1-tracked
514 514 content1_missing_content1-untracked
515 515 content1_missing_content3-tracked
516 516 content1_missing_content3-untracked
517 517 content1_missing_missing-tracked
518 518 content1_missing_missing-untracked
519 519 missing_content2_content2-tracked
520 520 missing_content2_content2-untracked
521 521 missing_content2_content3-tracked
522 522 missing_content2_content3-untracked
523 523 missing_content2_missing-tracked
524 524 missing_content2_missing-untracked
525 525 missing_missing_content3-tracked
526 526 missing_missing_content3-untracked
527 527 missing_missing_missing-tracked
528 528 missing_missing_missing-untracked
529 529
530 530 Script to make a simple text version of the content
531 531 ---------------------------------------------------
532 532
533 533 $ cat << EOF >> dircontent.py
534 534 > # generate a simple text view of the directory for easy comparison
535 535 > import os
536 536 > files = os.listdir('.')
537 537 > files.sort()
538 538 > for filename in files:
539 539 > if os.path.isdir(filename):
540 540 > continue
541 541 > content = open(filename).read()
542 542 > print '%-6s %s' % (content.strip(), filename)
543 543 > EOF
544 544
545 545 Generate appropriate repo state
546 546 -------------------------------
547 547
548 548 $ hg init revert-ref
549 549 $ cd revert-ref
550 550
551 551 Generate base changeset
552 552
553 553 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
554 554 $ hg addremove --similarity 0
555 555 adding content1_content1_content1-tracked
556 556 adding content1_content1_content1-untracked
557 557 adding content1_content1_content3-tracked
558 558 adding content1_content1_content3-untracked
559 559 adding content1_content1_missing-tracked
560 560 adding content1_content1_missing-untracked
561 561 adding content1_content2_content1-tracked
562 562 adding content1_content2_content1-untracked
563 563 adding content1_content2_content2-tracked
564 564 adding content1_content2_content2-untracked
565 565 adding content1_content2_content3-tracked
566 566 adding content1_content2_content3-untracked
567 567 adding content1_content2_missing-tracked
568 568 adding content1_content2_missing-untracked
569 569 adding content1_missing_content1-tracked
570 570 adding content1_missing_content1-untracked
571 571 adding content1_missing_content3-tracked
572 572 adding content1_missing_content3-untracked
573 573 adding content1_missing_missing-tracked
574 574 adding content1_missing_missing-untracked
575 575 $ hg status
576 576 A content1_content1_content1-tracked
577 577 A content1_content1_content1-untracked
578 578 A content1_content1_content3-tracked
579 579 A content1_content1_content3-untracked
580 580 A content1_content1_missing-tracked
581 581 A content1_content1_missing-untracked
582 582 A content1_content2_content1-tracked
583 583 A content1_content2_content1-untracked
584 584 A content1_content2_content2-tracked
585 585 A content1_content2_content2-untracked
586 586 A content1_content2_content3-tracked
587 587 A content1_content2_content3-untracked
588 588 A content1_content2_missing-tracked
589 589 A content1_content2_missing-untracked
590 590 A content1_missing_content1-tracked
591 591 A content1_missing_content1-untracked
592 592 A content1_missing_content3-tracked
593 593 A content1_missing_content3-untracked
594 594 A content1_missing_missing-tracked
595 595 A content1_missing_missing-untracked
596 596 $ hg commit -m 'base'
597 597
598 598 (create a simple text version of the content)
599 599
600 600 $ $PYTHON ../dircontent.py > ../content-base.txt
601 601 $ cat ../content-base.txt
602 602 content1 content1_content1_content1-tracked
603 603 content1 content1_content1_content1-untracked
604 604 content1 content1_content1_content3-tracked
605 605 content1 content1_content1_content3-untracked
606 606 content1 content1_content1_missing-tracked
607 607 content1 content1_content1_missing-untracked
608 608 content1 content1_content2_content1-tracked
609 609 content1 content1_content2_content1-untracked
610 610 content1 content1_content2_content2-tracked
611 611 content1 content1_content2_content2-untracked
612 612 content1 content1_content2_content3-tracked
613 613 content1 content1_content2_content3-untracked
614 614 content1 content1_content2_missing-tracked
615 615 content1 content1_content2_missing-untracked
616 616 content1 content1_missing_content1-tracked
617 617 content1 content1_missing_content1-untracked
618 618 content1 content1_missing_content3-tracked
619 619 content1 content1_missing_content3-untracked
620 620 content1 content1_missing_missing-tracked
621 621 content1 content1_missing_missing-untracked
622 622
623 623 Create parent changeset
624 624
625 625 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
626 626 $ hg addremove --similarity 0
627 627 removing content1_missing_content1-tracked
628 628 removing content1_missing_content1-untracked
629 629 removing content1_missing_content3-tracked
630 630 removing content1_missing_content3-untracked
631 631 removing content1_missing_missing-tracked
632 632 removing content1_missing_missing-untracked
633 633 adding missing_content2_content2-tracked
634 634 adding missing_content2_content2-untracked
635 635 adding missing_content2_content3-tracked
636 636 adding missing_content2_content3-untracked
637 637 adding missing_content2_missing-tracked
638 638 adding missing_content2_missing-untracked
639 639 $ hg status
640 640 M content1_content2_content1-tracked
641 641 M content1_content2_content1-untracked
642 642 M content1_content2_content2-tracked
643 643 M content1_content2_content2-untracked
644 644 M content1_content2_content3-tracked
645 645 M content1_content2_content3-untracked
646 646 M content1_content2_missing-tracked
647 647 M content1_content2_missing-untracked
648 648 A missing_content2_content2-tracked
649 649 A missing_content2_content2-untracked
650 650 A missing_content2_content3-tracked
651 651 A missing_content2_content3-untracked
652 652 A missing_content2_missing-tracked
653 653 A missing_content2_missing-untracked
654 654 R content1_missing_content1-tracked
655 655 R content1_missing_content1-untracked
656 656 R content1_missing_content3-tracked
657 657 R content1_missing_content3-untracked
658 658 R content1_missing_missing-tracked
659 659 R content1_missing_missing-untracked
660 660 $ hg commit -m 'parent'
661 661
662 662 (create a simple text version of the content)
663 663
664 664 $ $PYTHON ../dircontent.py > ../content-parent.txt
665 665 $ cat ../content-parent.txt
666 666 content1 content1_content1_content1-tracked
667 667 content1 content1_content1_content1-untracked
668 668 content1 content1_content1_content3-tracked
669 669 content1 content1_content1_content3-untracked
670 670 content1 content1_content1_missing-tracked
671 671 content1 content1_content1_missing-untracked
672 672 content2 content1_content2_content1-tracked
673 673 content2 content1_content2_content1-untracked
674 674 content2 content1_content2_content2-tracked
675 675 content2 content1_content2_content2-untracked
676 676 content2 content1_content2_content3-tracked
677 677 content2 content1_content2_content3-untracked
678 678 content2 content1_content2_missing-tracked
679 679 content2 content1_content2_missing-untracked
680 680 content2 missing_content2_content2-tracked
681 681 content2 missing_content2_content2-untracked
682 682 content2 missing_content2_content3-tracked
683 683 content2 missing_content2_content3-untracked
684 684 content2 missing_content2_missing-tracked
685 685 content2 missing_content2_missing-untracked
686 686
687 687 Setup working directory
688 688
689 689 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
690 690 $ hg addremove --similarity 0
691 691 adding content1_missing_content1-tracked
692 692 adding content1_missing_content1-untracked
693 693 adding content1_missing_content3-tracked
694 694 adding content1_missing_content3-untracked
695 695 adding content1_missing_missing-tracked
696 696 adding content1_missing_missing-untracked
697 697 adding missing_missing_content3-tracked
698 698 adding missing_missing_content3-untracked
699 699 adding missing_missing_missing-tracked
700 700 adding missing_missing_missing-untracked
701 701 $ hg forget *_*_*-untracked
702 702 $ rm *_*_missing-*
703 703 $ hg status
704 704 M content1_content1_content3-tracked
705 705 M content1_content2_content1-tracked
706 706 M content1_content2_content3-tracked
707 707 M missing_content2_content3-tracked
708 708 A content1_missing_content1-tracked
709 709 A content1_missing_content3-tracked
710 710 A missing_missing_content3-tracked
711 711 R content1_content1_content1-untracked
712 712 R content1_content1_content3-untracked
713 713 R content1_content1_missing-untracked
714 714 R content1_content2_content1-untracked
715 715 R content1_content2_content2-untracked
716 716 R content1_content2_content3-untracked
717 717 R content1_content2_missing-untracked
718 718 R missing_content2_content2-untracked
719 719 R missing_content2_content3-untracked
720 720 R missing_content2_missing-untracked
721 721 ! content1_content1_missing-tracked
722 722 ! content1_content2_missing-tracked
723 723 ! content1_missing_missing-tracked
724 724 ! missing_content2_missing-tracked
725 725 ! missing_missing_missing-tracked
726 726 ? content1_missing_content1-untracked
727 727 ? content1_missing_content3-untracked
728 728 ? missing_missing_content3-untracked
729 729
730 730 $ hg status --rev 'desc("base")'
731 731 M content1_content1_content3-tracked
732 732 M content1_content2_content2-tracked
733 733 M content1_content2_content3-tracked
734 734 M content1_missing_content3-tracked
735 735 A missing_content2_content2-tracked
736 736 A missing_content2_content3-tracked
737 737 A missing_missing_content3-tracked
738 738 R content1_content1_content1-untracked
739 739 R content1_content1_content3-untracked
740 740 R content1_content1_missing-untracked
741 741 R content1_content2_content1-untracked
742 742 R content1_content2_content2-untracked
743 743 R content1_content2_content3-untracked
744 744 R content1_content2_missing-untracked
745 745 R content1_missing_content1-untracked
746 746 R content1_missing_content3-untracked
747 747 R content1_missing_missing-untracked
748 748 ! content1_content1_missing-tracked
749 749 ! content1_content2_missing-tracked
750 750 ! content1_missing_missing-tracked
751 751 ! missing_content2_missing-tracked
752 752 ! missing_missing_missing-tracked
753 753 ? missing_missing_content3-untracked
754 754
755 755 (create a simple text version of the content)
756 756
757 757 $ $PYTHON ../dircontent.py > ../content-wc.txt
758 758 $ cat ../content-wc.txt
759 759 content1 content1_content1_content1-tracked
760 760 content1 content1_content1_content1-untracked
761 761 content3 content1_content1_content3-tracked
762 762 content3 content1_content1_content3-untracked
763 763 content1 content1_content2_content1-tracked
764 764 content1 content1_content2_content1-untracked
765 765 content2 content1_content2_content2-tracked
766 766 content2 content1_content2_content2-untracked
767 767 content3 content1_content2_content3-tracked
768 768 content3 content1_content2_content3-untracked
769 769 content1 content1_missing_content1-tracked
770 770 content1 content1_missing_content1-untracked
771 771 content3 content1_missing_content3-tracked
772 772 content3 content1_missing_content3-untracked
773 773 content2 missing_content2_content2-tracked
774 774 content2 missing_content2_content2-untracked
775 775 content3 missing_content2_content3-tracked
776 776 content3 missing_content2_content3-untracked
777 777 content3 missing_missing_content3-tracked
778 778 content3 missing_missing_content3-untracked
779 779
780 780 $ cd ..
781 781
782 782 Test revert --all to parent content
783 783 -----------------------------------
784 784
785 785 (setup from reference repo)
786 786
787 787 $ cp -R revert-ref revert-parent-all
788 788 $ cd revert-parent-all
789 789
790 790 check revert output
791 791
792 792 $ hg revert --all
793 undeleting content1_content1_content1-untracked
794 reverting content1_content1_content3-tracked
795 undeleting content1_content1_content3-untracked
796 reverting content1_content1_missing-tracked
797 undeleting content1_content1_missing-untracked
798 reverting content1_content2_content1-tracked
799 undeleting content1_content2_content1-untracked
800 undeleting content1_content2_content2-untracked
801 reverting content1_content2_content3-tracked
802 undeleting content1_content2_content3-untracked
803 reverting content1_content2_missing-tracked
804 undeleting content1_content2_missing-untracked
805 793 forgetting content1_missing_content1-tracked
806 794 forgetting content1_missing_content3-tracked
807 795 forgetting content1_missing_missing-tracked
808 undeleting missing_content2_content2-untracked
809 reverting missing_content2_content3-tracked
810 undeleting missing_content2_content3-untracked
811 reverting missing_content2_missing-tracked
812 undeleting missing_content2_missing-untracked
813 796 forgetting missing_missing_content3-tracked
814 797 forgetting missing_missing_missing-tracked
798 reverting content1_content1_content3-tracked
799 reverting content1_content1_missing-tracked
800 reverting content1_content2_content1-tracked
801 reverting content1_content2_content3-tracked
802 reverting content1_content2_missing-tracked
803 reverting missing_content2_content3-tracked
804 reverting missing_content2_missing-tracked
805 undeleting content1_content1_content1-untracked
806 undeleting content1_content1_content3-untracked
807 undeleting content1_content1_missing-untracked
808 undeleting content1_content2_content1-untracked
809 undeleting content1_content2_content2-untracked
810 undeleting content1_content2_content3-untracked
811 undeleting content1_content2_missing-untracked
812 undeleting missing_content2_content2-untracked
813 undeleting missing_content2_content3-untracked
814 undeleting missing_content2_missing-untracked
815 815
816 816 Compare resulting directory with revert target.
817 817
818 818 The diff is filtered to include change only. The only difference should be
819 819 additional `.orig` backup file when applicable.
820 820
821 821 $ $PYTHON ../dircontent.py > ../content-parent-all.txt
822 822 $ cd ..
823 823 $ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _
824 824 +content3 content1_content1_content3-tracked.orig
825 825 +content3 content1_content1_content3-untracked.orig
826 826 +content1 content1_content2_content1-tracked.orig
827 827 +content1 content1_content2_content1-untracked.orig
828 828 +content3 content1_content2_content3-tracked.orig
829 829 +content3 content1_content2_content3-untracked.orig
830 830 +content1 content1_missing_content1-tracked
831 831 +content1 content1_missing_content1-untracked
832 832 +content3 content1_missing_content3-tracked
833 833 +content3 content1_missing_content3-untracked
834 834 +content3 missing_content2_content3-tracked.orig
835 835 +content3 missing_content2_content3-untracked.orig
836 836 +content3 missing_missing_content3-tracked
837 837 +content3 missing_missing_content3-untracked
838 838
839 839 Test revert --all to "base" content
840 840 -----------------------------------
841 841
842 842 (setup from reference repo)
843 843
844 844 $ cp -R revert-ref revert-base-all
845 845 $ cd revert-base-all
846 846
847 847 check revert output
848 848
849 849 $ hg revert --all --rev 'desc(base)'
850 undeleting content1_content1_content1-untracked
851 reverting content1_content1_content3-tracked
852 undeleting content1_content1_content3-untracked
853 reverting content1_content1_missing-tracked
854 undeleting content1_content1_missing-untracked
855 undeleting content1_content2_content1-untracked
856 reverting content1_content2_content2-tracked
857 undeleting content1_content2_content2-untracked
858 reverting content1_content2_content3-tracked
859 undeleting content1_content2_content3-untracked
860 reverting content1_content2_missing-tracked
861 undeleting content1_content2_missing-untracked
862 adding content1_missing_content1-untracked
863 reverting content1_missing_content3-tracked
864 adding content1_missing_content3-untracked
865 reverting content1_missing_missing-tracked
866 adding content1_missing_missing-untracked
850 forgetting missing_missing_content3-tracked
851 forgetting missing_missing_missing-tracked
867 852 removing missing_content2_content2-tracked
868 853 removing missing_content2_content3-tracked
869 854 removing missing_content2_missing-tracked
870 forgetting missing_missing_content3-tracked
871 forgetting missing_missing_missing-tracked
855 reverting content1_content1_content3-tracked
856 reverting content1_content1_missing-tracked
857 reverting content1_content2_content2-tracked
858 reverting content1_content2_content3-tracked
859 reverting content1_content2_missing-tracked
860 reverting content1_missing_content3-tracked
861 reverting content1_missing_missing-tracked
862 adding content1_missing_content1-untracked
863 adding content1_missing_content3-untracked
864 adding content1_missing_missing-untracked
865 undeleting content1_content1_content1-untracked
866 undeleting content1_content1_content3-untracked
867 undeleting content1_content1_missing-untracked
868 undeleting content1_content2_content1-untracked
869 undeleting content1_content2_content2-untracked
870 undeleting content1_content2_content3-untracked
871 undeleting content1_content2_missing-untracked
872 872
873 873 Compare resulting directory with revert target.
874 874
875 875 The diff is filtered to include change only. The only difference should be
876 876 additional `.orig` backup file when applicable.
877 877
878 878 $ $PYTHON ../dircontent.py > ../content-base-all.txt
879 879 $ cd ..
880 880 $ diff -U 0 -- content-base.txt content-base-all.txt | grep _
881 881 +content3 content1_content1_content3-tracked.orig
882 882 +content3 content1_content1_content3-untracked.orig
883 883 +content2 content1_content2_content2-untracked.orig
884 884 +content3 content1_content2_content3-tracked.orig
885 885 +content3 content1_content2_content3-untracked.orig
886 886 +content3 content1_missing_content3-tracked.orig
887 887 +content3 content1_missing_content3-untracked.orig
888 888 +content2 missing_content2_content2-untracked
889 889 +content3 missing_content2_content3-tracked.orig
890 890 +content3 missing_content2_content3-untracked
891 891 +content3 missing_missing_content3-tracked
892 892 +content3 missing_missing_content3-untracked
893 893
894 894 Test revert to parent content with explicit file name
895 895 -----------------------------------------------------
896 896
897 897 (setup from reference repo)
898 898
899 899 $ cp -R revert-ref revert-parent-explicit
900 900 $ cd revert-parent-explicit
901 901
902 902 revert all files individually and check the output
903 903 (output is expected to be different than in the --all case)
904 904
905 905 $ for file in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 2`; do
906 906 > echo '### revert for:' $file;
907 907 > hg revert $file;
908 908 > echo
909 909 > done
910 910 ### revert for: content1_content1_content1-tracked
911 911 no changes needed to content1_content1_content1-tracked
912 912
913 913 ### revert for: content1_content1_content1-untracked
914 914
915 915 ### revert for: content1_content1_content3-tracked
916 916
917 917 ### revert for: content1_content1_content3-untracked
918 918
919 919 ### revert for: content1_content1_missing-tracked
920 920
921 921 ### revert for: content1_content1_missing-untracked
922 922
923 923 ### revert for: content1_content2_content1-tracked
924 924
925 925 ### revert for: content1_content2_content1-untracked
926 926
927 927 ### revert for: content1_content2_content2-tracked
928 928 no changes needed to content1_content2_content2-tracked
929 929
930 930 ### revert for: content1_content2_content2-untracked
931 931
932 932 ### revert for: content1_content2_content3-tracked
933 933
934 934 ### revert for: content1_content2_content3-untracked
935 935
936 936 ### revert for: content1_content2_missing-tracked
937 937
938 938 ### revert for: content1_content2_missing-untracked
939 939
940 940 ### revert for: content1_missing_content1-tracked
941 941
942 942 ### revert for: content1_missing_content1-untracked
943 943 file not managed: content1_missing_content1-untracked
944 944
945 945 ### revert for: content1_missing_content3-tracked
946 946
947 947 ### revert for: content1_missing_content3-untracked
948 948 file not managed: content1_missing_content3-untracked
949 949
950 950 ### revert for: content1_missing_missing-tracked
951 951
952 952 ### revert for: content1_missing_missing-untracked
953 953 content1_missing_missing-untracked: no such file in rev * (glob)
954 954
955 955 ### revert for: missing_content2_content2-tracked
956 956 no changes needed to missing_content2_content2-tracked
957 957
958 958 ### revert for: missing_content2_content2-untracked
959 959
960 960 ### revert for: missing_content2_content3-tracked
961 961
962 962 ### revert for: missing_content2_content3-untracked
963 963
964 964 ### revert for: missing_content2_missing-tracked
965 965
966 966 ### revert for: missing_content2_missing-untracked
967 967
968 968 ### revert for: missing_missing_content3-tracked
969 969
970 970 ### revert for: missing_missing_content3-untracked
971 971 file not managed: missing_missing_content3-untracked
972 972
973 973 ### revert for: missing_missing_missing-tracked
974 974
975 975 ### revert for: missing_missing_missing-untracked
976 976 missing_missing_missing-untracked: no such file in rev * (glob)
977 977
978 978
979 979 check resulting directory against the --all run
980 980 (There should be no difference)
981 981
982 982 $ $PYTHON ../dircontent.py > ../content-parent-explicit.txt
983 983 $ cd ..
984 984 $ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _
985 985 [1]
986 986
987 987 Test revert to "base" content with explicit file name
988 988 -----------------------------------------------------
989 989
990 990 (setup from reference repo)
991 991
992 992 $ cp -R revert-ref revert-base-explicit
993 993 $ cd revert-base-explicit
994 994
995 995 revert all files individually and check the output
996 996 (output is expected to be different than in the --all case)
997 997
998 998 $ for file in `$PYTHON $TESTDIR/generate-working-copy-states.py filelist 2`; do
999 999 > echo '### revert for:' $file;
1000 1000 > hg revert $file --rev 'desc(base)';
1001 1001 > echo
1002 1002 > done
1003 1003 ### revert for: content1_content1_content1-tracked
1004 1004 no changes needed to content1_content1_content1-tracked
1005 1005
1006 1006 ### revert for: content1_content1_content1-untracked
1007 1007
1008 1008 ### revert for: content1_content1_content3-tracked
1009 1009
1010 1010 ### revert for: content1_content1_content3-untracked
1011 1011
1012 1012 ### revert for: content1_content1_missing-tracked
1013 1013
1014 1014 ### revert for: content1_content1_missing-untracked
1015 1015
1016 1016 ### revert for: content1_content2_content1-tracked
1017 1017 no changes needed to content1_content2_content1-tracked
1018 1018
1019 1019 ### revert for: content1_content2_content1-untracked
1020 1020
1021 1021 ### revert for: content1_content2_content2-tracked
1022 1022
1023 1023 ### revert for: content1_content2_content2-untracked
1024 1024
1025 1025 ### revert for: content1_content2_content3-tracked
1026 1026
1027 1027 ### revert for: content1_content2_content3-untracked
1028 1028
1029 1029 ### revert for: content1_content2_missing-tracked
1030 1030
1031 1031 ### revert for: content1_content2_missing-untracked
1032 1032
1033 1033 ### revert for: content1_missing_content1-tracked
1034 1034 no changes needed to content1_missing_content1-tracked
1035 1035
1036 1036 ### revert for: content1_missing_content1-untracked
1037 1037
1038 1038 ### revert for: content1_missing_content3-tracked
1039 1039
1040 1040 ### revert for: content1_missing_content3-untracked
1041 1041
1042 1042 ### revert for: content1_missing_missing-tracked
1043 1043
1044 1044 ### revert for: content1_missing_missing-untracked
1045 1045
1046 1046 ### revert for: missing_content2_content2-tracked
1047 1047
1048 1048 ### revert for: missing_content2_content2-untracked
1049 1049 no changes needed to missing_content2_content2-untracked
1050 1050
1051 1051 ### revert for: missing_content2_content3-tracked
1052 1052
1053 1053 ### revert for: missing_content2_content3-untracked
1054 1054 no changes needed to missing_content2_content3-untracked
1055 1055
1056 1056 ### revert for: missing_content2_missing-tracked
1057 1057
1058 1058 ### revert for: missing_content2_missing-untracked
1059 1059 no changes needed to missing_content2_missing-untracked
1060 1060
1061 1061 ### revert for: missing_missing_content3-tracked
1062 1062
1063 1063 ### revert for: missing_missing_content3-untracked
1064 1064 file not managed: missing_missing_content3-untracked
1065 1065
1066 1066 ### revert for: missing_missing_missing-tracked
1067 1067
1068 1068 ### revert for: missing_missing_missing-untracked
1069 1069 missing_missing_missing-untracked: no such file in rev * (glob)
1070 1070
1071 1071
1072 1072 check resulting directory against the --all run
1073 1073 (There should be no difference)
1074 1074
1075 1075 $ $PYTHON ../dircontent.py > ../content-base-explicit.txt
1076 1076 $ cd ..
1077 1077 $ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _
1078 1078 [1]
1079 1079
1080 1080 Revert to an ancestor of P2 during a merge (issue5052)
1081 1081 -----------------------------------------------------
1082 1082
1083 1083 (prepare the repository)
1084 1084
1085 1085 $ hg init issue5052
1086 1086 $ cd issue5052
1087 1087 $ echo '.\.orig' > .hgignore
1088 1088 $ echo 0 > root
1089 1089 $ hg ci -qAm C0
1090 1090 $ echo 0 > A
1091 1091 $ hg ci -qAm C1
1092 1092 $ echo 1 >> A
1093 1093 $ hg ci -qm C2
1094 1094 $ hg up -q 0
1095 1095 $ echo 1 > B
1096 1096 $ hg ci -qAm C3
1097 1097 $ hg status --rev 'ancestor(.,2)' --rev 2
1098 1098 A A
1099 1099 $ hg log -G -T '{rev} ({files})\n'
1100 1100 @ 3 (B)
1101 1101 |
1102 1102 | o 2 (A)
1103 1103 | |
1104 1104 | o 1 (A)
1105 1105 |/
1106 1106 o 0 (.hgignore root)
1107 1107
1108 1108
1109 1109 actual tests: reverting to something else than a merge parent
1110 1110
1111 1111 $ hg merge
1112 1112 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1113 1113 (branch merge, don't forget to commit)
1114 1114
1115 1115 $ hg status --rev 'p1()'
1116 1116 M A
1117 1117 $ hg status --rev 'p2()'
1118 1118 A B
1119 1119 $ hg status --rev '1'
1120 1120 M A
1121 1121 A B
1122 1122 $ hg revert --rev 1 --all
1123 removing B
1123 1124 reverting A
1124 removing B
1125 1125 $ hg status --rev 1
1126 1126
1127 1127 From the other parents
1128 1128
1129 1129 $ hg up -C 'p2()'
1130 1130 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1131 1131 $ hg merge
1132 1132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1133 1133 (branch merge, don't forget to commit)
1134 1134
1135 1135 $ hg status --rev 'p1()'
1136 1136 M B
1137 1137 $ hg status --rev 'p2()'
1138 1138 A A
1139 1139 $ hg status --rev '1'
1140 1140 M A
1141 1141 A B
1142 1142 $ hg revert --rev 1 --all
1143 removing B
1143 1144 reverting A
1144 removing B
1145 1145 $ hg status --rev 1
1146 1146
1147 1147 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now