##// END OF EJS Templates
largefiles: don't interfere with logging normal files...
Matt Harbison -
r23976:34493912 stable
parent child Browse files
Show More
@@ -1,1341 +1,1346 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
15 15 archival, pathutil, revset
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18
19 19 import lfutil
20 20 import lfcommands
21 21 import basestore
22 22
23 23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 24
25 25 def composelargefilematcher(match, manifest):
26 26 '''create a matcher that matches only the largefiles in the original
27 27 matcher'''
28 28 m = copy.copy(match)
29 29 lfile = lambda f: lfutil.standin(f) in manifest
30 30 m._files = filter(lfile, m._files)
31 31 m._fmap = set(m._files)
32 32 m._always = False
33 33 origmatchfn = m.matchfn
34 34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
35 35 return m
36 36
37 37 def composenormalfilematcher(match, manifest, exclude=None):
38 38 excluded = set()
39 39 if exclude is not None:
40 40 excluded.update(exclude)
41 41
42 42 m = copy.copy(match)
43 43 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
44 44 manifest or f in excluded)
45 45 m._files = filter(notlfile, m._files)
46 46 m._fmap = set(m._files)
47 47 m._always = False
48 48 origmatchfn = m.matchfn
49 49 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
50 50 return m
51 51
52 52 def installnormalfilesmatchfn(manifest):
53 53 '''installmatchfn with a matchfn that ignores all largefiles'''
54 54 def overridematch(ctx, pats=[], opts={}, globbed=False,
55 55 default='relpath'):
56 56 match = oldmatch(ctx, pats, opts, globbed, default)
57 57 return composenormalfilematcher(match, manifest)
58 58 oldmatch = installmatchfn(overridematch)
59 59
60 60 def installmatchfn(f):
61 61 '''monkey patch the scmutil module with a custom match function.
62 62 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
63 63 oldmatch = scmutil.match
64 64 setattr(f, 'oldmatch', oldmatch)
65 65 scmutil.match = f
66 66 return oldmatch
67 67
68 68 def restorematchfn():
69 69 '''restores scmutil.match to what it was before installmatchfn
70 70 was called. no-op if scmutil.match is its original function.
71 71
72 72 Note that n calls to installmatchfn will require n calls to
73 73 restore the original matchfn.'''
74 74 scmutil.match = getattr(scmutil.match, 'oldmatch')
75 75
76 76 def installmatchandpatsfn(f):
77 77 oldmatchandpats = scmutil.matchandpats
78 78 setattr(f, 'oldmatchandpats', oldmatchandpats)
79 79 scmutil.matchandpats = f
80 80 return oldmatchandpats
81 81
82 82 def restorematchandpatsfn():
83 83 '''restores scmutil.matchandpats to what it was before
84 84 installmatchandpatsfn was called. No-op if scmutil.matchandpats
85 85 is its original function.
86 86
87 87 Note that n calls to installmatchandpatsfn will require n calls
88 88 to restore the original matchfn.'''
89 89 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
90 90 scmutil.matchandpats)
91 91
92 92 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
93 93 large = opts.get('large')
94 94 lfsize = lfutil.getminsize(
95 95 ui, lfutil.islfilesrepo(repo), opts.get('lfsize'))
96 96
97 97 lfmatcher = None
98 98 if lfutil.islfilesrepo(repo):
99 99 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
100 100 if lfpats:
101 101 lfmatcher = match_.match(repo.root, '', list(lfpats))
102 102
103 103 lfnames = []
104 104 m = copy.copy(matcher)
105 105 m.bad = lambda x, y: None
106 106 wctx = repo[None]
107 107 for f in repo.walk(m):
108 108 exact = m.exact(f)
109 109 lfile = lfutil.standin(f) in wctx
110 110 nfile = f in wctx
111 111 exists = lfile or nfile
112 112
113 113 # addremove in core gets fancy with the name, add doesn't
114 114 if isaddremove:
115 115 name = m.uipath(f)
116 116 else:
117 117 name = m.rel(f)
118 118
119 119 # Don't warn the user when they attempt to add a normal tracked file.
120 120 # The normal add code will do that for us.
121 121 if exact and exists:
122 122 if lfile:
123 123 ui.warn(_('%s already a largefile\n') % name)
124 124 continue
125 125
126 126 if (exact or not exists) and not lfutil.isstandin(f):
127 127 # In case the file was removed previously, but not committed
128 128 # (issue3507)
129 129 if not repo.wvfs.exists(f):
130 130 continue
131 131
132 132 abovemin = (lfsize and
133 133 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
134 134 if large or abovemin or (lfmatcher and lfmatcher(f)):
135 135 lfnames.append(f)
136 136 if ui.verbose or not exact:
137 137 ui.status(_('adding %s as a largefile\n') % name)
138 138
139 139 bad = []
140 140
141 141 # Need to lock, otherwise there could be a race condition between
142 142 # when standins are created and added to the repo.
143 143 wlock = repo.wlock()
144 144 try:
145 145 if not opts.get('dry_run'):
146 146 standins = []
147 147 lfdirstate = lfutil.openlfdirstate(ui, repo)
148 148 for f in lfnames:
149 149 standinname = lfutil.standin(f)
150 150 lfutil.writestandin(repo, standinname, hash='',
151 151 executable=lfutil.getexecutable(repo.wjoin(f)))
152 152 standins.append(standinname)
153 153 if lfdirstate[f] == 'r':
154 154 lfdirstate.normallookup(f)
155 155 else:
156 156 lfdirstate.add(f)
157 157 lfdirstate.write()
158 158 bad += [lfutil.splitstandin(f)
159 159 for f in repo[None].add(standins)
160 160 if f in m.files()]
161 161
162 162 added = [f for f in lfnames if f not in bad]
163 163 finally:
164 164 wlock.release()
165 165 return added, bad
166 166
167 167 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
168 168 after = opts.get('after')
169 169 m = composelargefilematcher(matcher, repo[None].manifest())
170 170 try:
171 171 repo.lfstatus = True
172 172 s = repo.status(match=m, clean=not isaddremove)
173 173 finally:
174 174 repo.lfstatus = False
175 175 manifest = repo[None].manifest()
176 176 modified, added, deleted, clean = [[f for f in list
177 177 if lfutil.standin(f) in manifest]
178 178 for list in (s.modified, s.added,
179 179 s.deleted, s.clean)]
180 180
181 181 def warn(files, msg):
182 182 for f in files:
183 183 ui.warn(msg % m.rel(f))
184 184 return int(len(files) > 0)
185 185
186 186 result = 0
187 187
188 188 if after:
189 189 remove = deleted
190 190 result = warn(modified + added + clean,
191 191 _('not removing %s: file still exists\n'))
192 192 else:
193 193 remove = deleted + clean
194 194 result = warn(modified, _('not removing %s: file is modified (use -f'
195 195 ' to force removal)\n'))
196 196 result = warn(added, _('not removing %s: file has been marked for add'
197 197 ' (use forget to undo)\n')) or result
198 198
199 199 # Need to lock because standin files are deleted then removed from the
200 200 # repository and we could race in-between.
201 201 wlock = repo.wlock()
202 202 try:
203 203 lfdirstate = lfutil.openlfdirstate(ui, repo)
204 204 for f in sorted(remove):
205 205 if ui.verbose or not m.exact(f):
206 206 # addremove in core gets fancy with the name, remove doesn't
207 207 if isaddremove:
208 208 name = m.uipath(f)
209 209 else:
210 210 name = m.rel(f)
211 211 ui.status(_('removing %s\n') % name)
212 212
213 213 if not opts.get('dry_run'):
214 214 if not after:
215 215 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
216 216
217 217 if opts.get('dry_run'):
218 218 return result
219 219
220 220 remove = [lfutil.standin(f) for f in remove]
221 221 # If this is being called by addremove, let the original addremove
222 222 # function handle this.
223 223 if not isaddremove:
224 224 for f in remove:
225 225 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
226 226 repo[None].forget(remove)
227 227
228 228 for f in remove:
229 229 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
230 230 False)
231 231
232 232 lfdirstate.write()
233 233 finally:
234 234 wlock.release()
235 235
236 236 return result
237 237
238 238 # For overriding mercurial.hgweb.webcommands so that largefiles will
239 239 # appear at their right place in the manifests.
240 240 def decodepath(orig, path):
241 241 return lfutil.splitstandin(path) or path
242 242
243 243 # -- Wrappers: modify existing commands --------------------------------
244 244
245 245 def overrideadd(orig, ui, repo, *pats, **opts):
246 246 if opts.get('normal') and opts.get('large'):
247 247 raise util.Abort(_('--normal cannot be used with --large'))
248 248 return orig(ui, repo, *pats, **opts)
249 249
250 250 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
251 251 # The --normal flag short circuits this override
252 252 if opts.get('normal'):
253 253 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
254 254
255 255 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
256 256 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
257 257 ladded)
258 258 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
259 259
260 260 bad.extend(f for f in lbad)
261 261 return bad
262 262
263 263 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos):
264 264 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
265 265 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos)
266 266 return removelargefiles(ui, repo, False, matcher, after=after,
267 267 force=force) or result
268 268
269 269 def overridestatusfn(orig, repo, rev2, **opts):
270 270 try:
271 271 repo._repo.lfstatus = True
272 272 return orig(repo, rev2, **opts)
273 273 finally:
274 274 repo._repo.lfstatus = False
275 275
276 276 def overridestatus(orig, ui, repo, *pats, **opts):
277 277 try:
278 278 repo.lfstatus = True
279 279 return orig(ui, repo, *pats, **opts)
280 280 finally:
281 281 repo.lfstatus = False
282 282
283 283 def overridedirty(orig, repo, ignoreupdate=False):
284 284 try:
285 285 repo._repo.lfstatus = True
286 286 return orig(repo, ignoreupdate)
287 287 finally:
288 288 repo._repo.lfstatus = False
289 289
290 290 def overridelog(orig, ui, repo, *pats, **opts):
291 291 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
292 292 default='relpath'):
293 293 """Matcher that merges root directory with .hglf, suitable for log.
294 294 It is still possible to match .hglf directly.
295 295 For any listed files run log on the standin too.
296 296 matchfn tries both the given filename and with .hglf stripped.
297 297 """
298 298 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
299 299 m, p = copy.copy(matchandpats)
300 300
301 301 if m.always():
302 302 # We want to match everything anyway, so there's no benefit trying
303 303 # to add standins.
304 304 return matchandpats
305 305
306 306 pats = set(p)
307 307 # TODO: handling of patterns in both cases below
308 308 if m._cwd:
309 309 if os.path.isabs(m._cwd):
310 310 # TODO: handle largefile magic when invoked from other cwd
311 311 return matchandpats
312 312 back = (m._cwd.count('/') + 1) * '../'
313 313 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
314 314 else:
315 315 pats.update(lfutil.standin(f) for f in p)
316 316
317 317 for i in range(0, len(m._files)):
318 318 standin = lfutil.standin(m._files[i])
319 # If the "standin" is a directory, append instead of replace to
320 # support naming a directory on the command line with only
321 # largefiles. The original directory is kept to support normal
322 # files.
319 323 if standin in repo[ctx.node()]:
320 324 m._files[i] = standin
321 elif m._files[i] not in repo[ctx.node()]:
325 elif m._files[i] not in repo[ctx.node()] \
326 and repo.wvfs.isdir(standin):
322 327 m._files.append(standin)
323 328 pats.add(standin)
324 329
325 330 m._fmap = set(m._files)
326 331 m._always = False
327 332 origmatchfn = m.matchfn
328 333 def lfmatchfn(f):
329 334 lf = lfutil.splitstandin(f)
330 335 if lf is not None and origmatchfn(lf):
331 336 return True
332 337 r = origmatchfn(f)
333 338 return r
334 339 m.matchfn = lfmatchfn
335 340
336 341 return m, pats
337 342
338 343 # For hg log --patch, the match object is used in two different senses:
339 344 # (1) to determine what revisions should be printed out, and
340 345 # (2) to determine what files to print out diffs for.
341 346 # The magic matchandpats override should be used for case (1) but not for
342 347 # case (2).
343 348 def overridemakelogfilematcher(repo, pats, opts):
344 349 pctx = repo[None]
345 350 match, pats = oldmatchandpats(pctx, pats, opts)
346 351 return lambda rev: match
347 352
348 353 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
349 354 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
350 355 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
351 356
352 357 try:
353 358 return orig(ui, repo, *pats, **opts)
354 359 finally:
355 360 restorematchandpatsfn()
356 361 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
357 362
358 363 def overrideverify(orig, ui, repo, *pats, **opts):
359 364 large = opts.pop('large', False)
360 365 all = opts.pop('lfa', False)
361 366 contents = opts.pop('lfc', False)
362 367
363 368 result = orig(ui, repo, *pats, **opts)
364 369 if large or all or contents:
365 370 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
366 371 return result
367 372
368 373 def overridedebugstate(orig, ui, repo, *pats, **opts):
369 374 large = opts.pop('large', False)
370 375 if large:
371 376 class fakerepo(object):
372 377 dirstate = lfutil.openlfdirstate(ui, repo)
373 378 orig(ui, fakerepo, *pats, **opts)
374 379 else:
375 380 orig(ui, repo, *pats, **opts)
376 381
377 382 # Override needs to refresh standins so that update's normal merge
378 383 # will go through properly. Then the other update hook (overriding repo.update)
379 384 # will get the new files. Filemerge is also overridden so that the merge
380 385 # will merge standins correctly.
381 386 def overrideupdate(orig, ui, repo, *pats, **opts):
382 387 # Need to lock between the standins getting updated and their
383 388 # largefiles getting updated
384 389 wlock = repo.wlock()
385 390 try:
386 391 if opts['check']:
387 392 lfdirstate = lfutil.openlfdirstate(ui, repo)
388 393 unsure, s = lfdirstate.status(
389 394 match_.always(repo.root, repo.getcwd()),
390 395 [], False, False, False)
391 396
392 397 mod = len(s.modified) > 0
393 398 for lfile in unsure:
394 399 standin = lfutil.standin(lfile)
395 400 if repo['.'][standin].data().strip() != \
396 401 lfutil.hashfile(repo.wjoin(lfile)):
397 402 mod = True
398 403 else:
399 404 lfdirstate.normal(lfile)
400 405 lfdirstate.write()
401 406 if mod:
402 407 raise util.Abort(_('uncommitted changes'))
403 408 return orig(ui, repo, *pats, **opts)
404 409 finally:
405 410 wlock.release()
406 411
407 412 # Before starting the manifest merge, merge.updates will call
408 413 # _checkunknownfile to check if there are any files in the merged-in
409 414 # changeset that collide with unknown files in the working copy.
410 415 #
411 416 # The largefiles are seen as unknown, so this prevents us from merging
412 417 # in a file 'foo' if we already have a largefile with the same name.
413 418 #
414 419 # The overridden function filters the unknown files by removing any
415 420 # largefiles. This makes the merge proceed and we can then handle this
416 421 # case further in the overridden calculateupdates function below.
417 422 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
418 423 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
419 424 return False
420 425 return origfn(repo, wctx, mctx, f, f2)
421 426
422 427 # The manifest merge handles conflicts on the manifest level. We want
423 428 # to handle changes in largefile-ness of files at this level too.
424 429 #
425 430 # The strategy is to run the original calculateupdates and then process
426 431 # the action list it outputs. There are two cases we need to deal with:
427 432 #
428 433 # 1. Normal file in p1, largefile in p2. Here the largefile is
429 434 # detected via its standin file, which will enter the working copy
430 435 # with a "get" action. It is not "merge" since the standin is all
431 436 # Mercurial is concerned with at this level -- the link to the
432 437 # existing normal file is not relevant here.
433 438 #
434 439 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
435 440 # since the largefile will be present in the working copy and
436 441 # different from the normal file in p2. Mercurial therefore
437 442 # triggers a merge action.
438 443 #
439 444 # In both cases, we prompt the user and emit new actions to either
440 445 # remove the standin (if the normal file was kept) or to remove the
441 446 # normal file and get the standin (if the largefile was kept). The
442 447 # default prompt answer is to use the largefile version since it was
443 448 # presumably changed on purpose.
444 449 #
445 450 # Finally, the merge.applyupdates function will then take care of
446 451 # writing the files into the working copy and lfcommands.updatelfiles
447 452 # will update the largefiles.
448 453 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
449 454 partial, acceptremote, followcopies):
450 455 overwrite = force and not branchmerge
451 456 actions, diverge, renamedelete = origfn(
452 457 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
453 458 followcopies)
454 459
455 460 if overwrite:
456 461 return actions, diverge, renamedelete
457 462
458 463 # Convert to dictionary with filename as key and action as value.
459 464 lfiles = set()
460 465 for f in actions:
461 466 splitstandin = f and lfutil.splitstandin(f)
462 467 if splitstandin in p1:
463 468 lfiles.add(splitstandin)
464 469 elif lfutil.standin(f) in p1:
465 470 lfiles.add(f)
466 471
467 472 for lfile in lfiles:
468 473 standin = lfutil.standin(lfile)
469 474 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
470 475 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
471 476 if sm in ('g', 'dc') and lm != 'r':
472 477 # Case 1: normal file in the working copy, largefile in
473 478 # the second parent
474 479 usermsg = _('remote turned local normal file %s into a largefile\n'
475 480 'use (l)argefile or keep (n)ormal file?'
476 481 '$$ &Largefile $$ &Normal file') % lfile
477 482 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
478 483 actions[lfile] = ('r', None, 'replaced by standin')
479 484 actions[standin] = ('g', sargs, 'replaces standin')
480 485 else: # keep local normal file
481 486 actions[lfile] = ('k', None, 'replaces standin')
482 487 if branchmerge:
483 488 actions[standin] = ('k', None, 'replaced by non-standin')
484 489 else:
485 490 actions[standin] = ('r', None, 'replaced by non-standin')
486 491 elif lm in ('g', 'dc') and sm != 'r':
487 492 # Case 2: largefile in the working copy, normal file in
488 493 # the second parent
489 494 usermsg = _('remote turned local largefile %s into a normal file\n'
490 495 'keep (l)argefile or use (n)ormal file?'
491 496 '$$ &Largefile $$ &Normal file') % lfile
492 497 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
493 498 if branchmerge:
494 499 # largefile can be restored from standin safely
495 500 actions[lfile] = ('k', None, 'replaced by standin')
496 501 actions[standin] = ('k', None, 'replaces standin')
497 502 else:
498 503 # "lfile" should be marked as "removed" without
499 504 # removal of itself
500 505 actions[lfile] = ('lfmr', None,
501 506 'forget non-standin largefile')
502 507
503 508 # linear-merge should treat this largefile as 're-added'
504 509 actions[standin] = ('a', None, 'keep standin')
505 510 else: # pick remote normal file
506 511 actions[lfile] = ('g', largs, 'replaces standin')
507 512 actions[standin] = ('r', None, 'replaced by non-standin')
508 513
509 514 return actions, diverge, renamedelete
510 515
511 516 def mergerecordupdates(orig, repo, actions, branchmerge):
512 517 if 'lfmr' in actions:
513 518 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
514 519 for lfile, args, msg in actions['lfmr']:
515 520 # this should be executed before 'orig', to execute 'remove'
516 521 # before all other actions
517 522 repo.dirstate.remove(lfile)
518 523 # make sure lfile doesn't get synclfdirstate'd as normal
519 524 lfdirstate.add(lfile)
520 525 lfdirstate.write()
521 526
522 527 return orig(repo, actions, branchmerge)
523 528
524 529
525 530 # Override filemerge to prompt the user about how they wish to merge
526 531 # largefiles. This will handle identical edits without prompting the user.
527 532 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
528 533 if not lfutil.isstandin(orig):
529 534 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
530 535
531 536 ahash = fca.data().strip().lower()
532 537 dhash = fcd.data().strip().lower()
533 538 ohash = fco.data().strip().lower()
534 539 if (ohash != ahash and
535 540 ohash != dhash and
536 541 (dhash == ahash or
537 542 repo.ui.promptchoice(
538 543 _('largefile %s has a merge conflict\nancestor was %s\n'
539 544 'keep (l)ocal %s or\ntake (o)ther %s?'
540 545 '$$ &Local $$ &Other') %
541 546 (lfutil.splitstandin(orig), ahash, dhash, ohash),
542 547 0) == 1)):
543 548 repo.wwrite(fcd.path(), fco.data(), fco.flags())
544 549 return 0
545 550
546 551 # Copy first changes the matchers to match standins instead of
547 552 # largefiles. Then it overrides util.copyfile in that function it
548 553 # checks if the destination largefile already exists. It also keeps a
549 554 # list of copied files so that the largefiles can be copied and the
550 555 # dirstate updated.
551 556 def overridecopy(orig, ui, repo, pats, opts, rename=False):
552 557 # doesn't remove largefile on rename
553 558 if len(pats) < 2:
554 559 # this isn't legal, let the original function deal with it
555 560 return orig(ui, repo, pats, opts, rename)
556 561
557 562 def makestandin(relpath):
558 563 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
559 564 return os.path.join(repo.wjoin(lfutil.standin(path)))
560 565
561 566 fullpats = scmutil.expandpats(pats)
562 567 dest = fullpats[-1]
563 568
564 569 if os.path.isdir(dest):
565 570 if not os.path.isdir(makestandin(dest)):
566 571 os.makedirs(makestandin(dest))
567 572 # This could copy both lfiles and normal files in one command,
568 573 # but we don't want to do that. First replace their matcher to
569 574 # only match normal files and run it, then replace it to just
570 575 # match largefiles and run it again.
571 576 nonormalfiles = False
572 577 nolfiles = False
573 578 installnormalfilesmatchfn(repo[None].manifest())
574 579 try:
575 580 try:
576 581 result = orig(ui, repo, pats, opts, rename)
577 582 except util.Abort, e:
578 583 if str(e) != _('no files to copy'):
579 584 raise e
580 585 else:
581 586 nonormalfiles = True
582 587 result = 0
583 588 finally:
584 589 restorematchfn()
585 590
586 591 # The first rename can cause our current working directory to be removed.
587 592 # In that case there is nothing left to copy/rename so just quit.
588 593 try:
589 594 repo.getcwd()
590 595 except OSError:
591 596 return result
592 597
593 598 try:
594 599 try:
595 600 # When we call orig below it creates the standins but we don't add
596 601 # them to the dir state until later so lock during that time.
597 602 wlock = repo.wlock()
598 603
599 604 manifest = repo[None].manifest()
600 605 def overridematch(ctx, pats=[], opts={}, globbed=False,
601 606 default='relpath'):
602 607 newpats = []
603 608 # The patterns were previously mangled to add the standin
604 609 # directory; we need to remove that now
605 610 for pat in pats:
606 611 if match_.patkind(pat) is None and lfutil.shortname in pat:
607 612 newpats.append(pat.replace(lfutil.shortname, ''))
608 613 else:
609 614 newpats.append(pat)
610 615 match = oldmatch(ctx, newpats, opts, globbed, default)
611 616 m = copy.copy(match)
612 617 lfile = lambda f: lfutil.standin(f) in manifest
613 618 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
614 619 m._fmap = set(m._files)
615 620 origmatchfn = m.matchfn
616 621 m.matchfn = lambda f: (lfutil.isstandin(f) and
617 622 (f in manifest) and
618 623 origmatchfn(lfutil.splitstandin(f)) or
619 624 None)
620 625 return m
621 626 oldmatch = installmatchfn(overridematch)
622 627 listpats = []
623 628 for pat in pats:
624 629 if match_.patkind(pat) is not None:
625 630 listpats.append(pat)
626 631 else:
627 632 listpats.append(makestandin(pat))
628 633
629 634 try:
630 635 origcopyfile = util.copyfile
631 636 copiedfiles = []
632 637 def overridecopyfile(src, dest):
633 638 if (lfutil.shortname in src and
634 639 dest.startswith(repo.wjoin(lfutil.shortname))):
635 640 destlfile = dest.replace(lfutil.shortname, '')
636 641 if not opts['force'] and os.path.exists(destlfile):
637 642 raise IOError('',
638 643 _('destination largefile already exists'))
639 644 copiedfiles.append((src, dest))
640 645 origcopyfile(src, dest)
641 646
642 647 util.copyfile = overridecopyfile
643 648 result += orig(ui, repo, listpats, opts, rename)
644 649 finally:
645 650 util.copyfile = origcopyfile
646 651
647 652 lfdirstate = lfutil.openlfdirstate(ui, repo)
648 653 for (src, dest) in copiedfiles:
649 654 if (lfutil.shortname in src and
650 655 dest.startswith(repo.wjoin(lfutil.shortname))):
651 656 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
652 657 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
653 658 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
654 659 if not os.path.isdir(destlfiledir):
655 660 os.makedirs(destlfiledir)
656 661 if rename:
657 662 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
658 663
659 664 # The file is gone, but this deletes any empty parent
660 665 # directories as a side-effect.
661 666 util.unlinkpath(repo.wjoin(srclfile), True)
662 667 lfdirstate.remove(srclfile)
663 668 else:
664 669 util.copyfile(repo.wjoin(srclfile),
665 670 repo.wjoin(destlfile))
666 671
667 672 lfdirstate.add(destlfile)
668 673 lfdirstate.write()
669 674 except util.Abort, e:
670 675 if str(e) != _('no files to copy'):
671 676 raise e
672 677 else:
673 678 nolfiles = True
674 679 finally:
675 680 restorematchfn()
676 681 wlock.release()
677 682
678 683 if nolfiles and nonormalfiles:
679 684 raise util.Abort(_('no files to copy'))
680 685
681 686 return result
682 687
683 688 # When the user calls revert, we have to be careful to not revert any
684 689 # changes to other largefiles accidentally. This means we have to keep
685 690 # track of the largefiles that are being reverted so we only pull down
686 691 # the necessary largefiles.
687 692 #
688 693 # Standins are only updated (to match the hash of largefiles) before
689 694 # commits. Update the standins then run the original revert, changing
690 695 # the matcher to hit standins instead of largefiles. Based on the
691 696 # resulting standins update the largefiles.
692 697 def overriderevert(orig, ui, repo, *pats, **opts):
693 698 # Because we put the standins in a bad state (by updating them)
694 699 # and then return them to a correct state we need to lock to
695 700 # prevent others from changing them in their incorrect state.
696 701 wlock = repo.wlock()
697 702 try:
698 703 lfdirstate = lfutil.openlfdirstate(ui, repo)
699 704 s = lfutil.lfdirstatestatus(lfdirstate, repo)
700 705 lfdirstate.write()
701 706 for lfile in s.modified:
702 707 lfutil.updatestandin(repo, lfutil.standin(lfile))
703 708 for lfile in s.deleted:
704 709 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
705 710 os.unlink(repo.wjoin(lfutil.standin(lfile)))
706 711
707 712 oldstandins = lfutil.getstandinsstate(repo)
708 713
709 714 def overridematch(ctx, pats=[], opts={}, globbed=False,
710 715 default='relpath'):
711 716 match = oldmatch(ctx, pats, opts, globbed, default)
712 717 m = copy.copy(match)
713 718 def tostandin(f):
714 719 if lfutil.standin(f) in ctx:
715 720 return lfutil.standin(f)
716 721 elif lfutil.standin(f) in repo[None]:
717 722 return None
718 723 return f
719 724 m._files = [tostandin(f) for f in m._files]
720 725 m._files = [f for f in m._files if f is not None]
721 726 m._fmap = set(m._files)
722 727 origmatchfn = m.matchfn
723 728 def matchfn(f):
724 729 if lfutil.isstandin(f):
725 730 return (origmatchfn(lfutil.splitstandin(f)) and
726 731 (f in repo[None] or f in ctx))
727 732 return origmatchfn(f)
728 733 m.matchfn = matchfn
729 734 return m
730 735 oldmatch = installmatchfn(overridematch)
731 736 try:
732 737 orig(ui, repo, *pats, **opts)
733 738 finally:
734 739 restorematchfn()
735 740
736 741 newstandins = lfutil.getstandinsstate(repo)
737 742 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
738 743 # lfdirstate should be 'normallookup'-ed for updated files,
739 744 # because reverting doesn't touch dirstate for 'normal' files
740 745 # when target revision is explicitly specified: in such case,
741 746 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
742 747 # of target (standin) file.
743 748 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
744 749 normallookup=True)
745 750
746 751 finally:
747 752 wlock.release()
748 753
749 754 # after pulling changesets, we need to take some extra care to get
750 755 # largefiles updated remotely
751 756 def overridepull(orig, ui, repo, source=None, **opts):
752 757 revsprepull = len(repo)
753 758 if not source:
754 759 source = 'default'
755 760 repo.lfpullsource = source
756 761 result = orig(ui, repo, source, **opts)
757 762 revspostpull = len(repo)
758 763 lfrevs = opts.get('lfrev', [])
759 764 if opts.get('all_largefiles'):
760 765 lfrevs.append('pulled()')
761 766 if lfrevs and revspostpull > revsprepull:
762 767 numcached = 0
763 768 repo.firstpulled = revsprepull # for pulled() revset expression
764 769 try:
765 770 for rev in scmutil.revrange(repo, lfrevs):
766 771 ui.note(_('pulling largefiles for revision %s\n') % rev)
767 772 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
768 773 numcached += len(cached)
769 774 finally:
770 775 del repo.firstpulled
771 776 ui.status(_("%d largefiles cached\n") % numcached)
772 777 return result
773 778
774 779 def pulledrevsetsymbol(repo, subset, x):
775 780 """``pulled()``
776 781 Changesets that just has been pulled.
777 782
778 783 Only available with largefiles from pull --lfrev expressions.
779 784
780 785 .. container:: verbose
781 786
782 787 Some examples:
783 788
784 789 - pull largefiles for all new changesets::
785 790
786 791 hg pull -lfrev "pulled()"
787 792
788 793 - pull largefiles for all new branch heads::
789 794
790 795 hg pull -lfrev "head(pulled()) and not closed()"
791 796
792 797 """
793 798
794 799 try:
795 800 firstpulled = repo.firstpulled
796 801 except AttributeError:
797 802 raise util.Abort(_("pulled() only available in --lfrev"))
798 803 return revset.baseset([r for r in subset if r >= firstpulled])
799 804
800 805 def overrideclone(orig, ui, source, dest=None, **opts):
801 806 d = dest
802 807 if d is None:
803 808 d = hg.defaultdest(source)
804 809 if opts.get('all_largefiles') and not hg.islocal(d):
805 810 raise util.Abort(_(
806 811 '--all-largefiles is incompatible with non-local destination %s') %
807 812 d)
808 813
809 814 return orig(ui, source, dest, **opts)
810 815
811 816 def hgclone(orig, ui, opts, *args, **kwargs):
812 817 result = orig(ui, opts, *args, **kwargs)
813 818
814 819 if result is not None:
815 820 sourcerepo, destrepo = result
816 821 repo = destrepo.local()
817 822
818 823 # Caching is implicitly limited to 'rev' option, since the dest repo was
819 824 # truncated at that point. The user may expect a download count with
820 825 # this option, so attempt whether or not this is a largefile repo.
821 826 if opts.get('all_largefiles'):
822 827 success, missing = lfcommands.downloadlfiles(ui, repo, None)
823 828
824 829 if missing != 0:
825 830 return None
826 831
827 832 return result
828 833
829 834 def overriderebase(orig, ui, repo, **opts):
830 835 resuming = opts.get('continue')
831 836 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
832 837 repo._lfstatuswriters.append(lambda *msg, **opts: None)
833 838 try:
834 839 return orig(ui, repo, **opts)
835 840 finally:
836 841 repo._lfstatuswriters.pop()
837 842 repo._lfcommithooks.pop()
838 843
839 844 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
840 845 prefix=None, mtime=None, subrepos=None):
841 846 # No need to lock because we are only reading history and
842 847 # largefile caches, neither of which are modified.
843 848 lfcommands.cachelfiles(repo.ui, repo, node)
844 849
845 850 if kind not in archival.archivers:
846 851 raise util.Abort(_("unknown archive type '%s'") % kind)
847 852
848 853 ctx = repo[node]
849 854
850 855 if kind == 'files':
851 856 if prefix:
852 857 raise util.Abort(
853 858 _('cannot give prefix when archiving to files'))
854 859 else:
855 860 prefix = archival.tidyprefix(dest, kind, prefix)
856 861
857 862 def write(name, mode, islink, getdata):
858 863 if matchfn and not matchfn(name):
859 864 return
860 865 data = getdata()
861 866 if decode:
862 867 data = repo.wwritedata(name, data)
863 868 archiver.addfile(prefix + name, mode, islink, data)
864 869
865 870 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
866 871
867 872 if repo.ui.configbool("ui", "archivemeta", True):
868 873 def metadata():
869 874 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
870 875 hex(repo.changelog.node(0)), hex(node), ctx.branch())
871 876
872 877 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
873 878 if repo.tagtype(t) == 'global')
874 879 if not tags:
875 880 repo.ui.pushbuffer()
876 881 opts = {'template': '{latesttag}\n{latesttagdistance}',
877 882 'style': '', 'patch': None, 'git': None}
878 883 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
879 884 ltags, dist = repo.ui.popbuffer().split('\n')
880 885 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
881 886 tags += 'latesttagdistance: %s\n' % dist
882 887
883 888 return base + tags
884 889
885 890 write('.hg_archival.txt', 0644, False, metadata)
886 891
887 892 for f in ctx:
888 893 ff = ctx.flags(f)
889 894 getdata = ctx[f].data
890 895 if lfutil.isstandin(f):
891 896 path = lfutil.findfile(repo, getdata().strip())
892 897 if path is None:
893 898 raise util.Abort(
894 899 _('largefile %s not found in repo store or system cache')
895 900 % lfutil.splitstandin(f))
896 901 f = lfutil.splitstandin(f)
897 902
898 903 def getdatafn():
899 904 fd = None
900 905 try:
901 906 fd = open(path, 'rb')
902 907 return fd.read()
903 908 finally:
904 909 if fd:
905 910 fd.close()
906 911
907 912 getdata = getdatafn
908 913 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
909 914
910 915 if subrepos:
911 916 for subpath in sorted(ctx.substate):
912 917 sub = ctx.sub(subpath)
913 918 submatch = match_.narrowmatcher(subpath, matchfn)
914 919 sub.archive(archiver, prefix, submatch)
915 920
916 921 archiver.done()
917 922
918 923 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
919 924 repo._get(repo._state + ('hg',))
920 925 rev = repo._state[1]
921 926 ctx = repo._repo[rev]
922 927
923 928 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
924 929
925 930 def write(name, mode, islink, getdata):
926 931 # At this point, the standin has been replaced with the largefile name,
927 932 # so the normal matcher works here without the lfutil variants.
928 933 if match and not match(f):
929 934 return
930 935 data = getdata()
931 936
932 937 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
933 938
934 939 for f in ctx:
935 940 ff = ctx.flags(f)
936 941 getdata = ctx[f].data
937 942 if lfutil.isstandin(f):
938 943 path = lfutil.findfile(repo._repo, getdata().strip())
939 944 if path is None:
940 945 raise util.Abort(
941 946 _('largefile %s not found in repo store or system cache')
942 947 % lfutil.splitstandin(f))
943 948 f = lfutil.splitstandin(f)
944 949
945 950 def getdatafn():
946 951 fd = None
947 952 try:
948 953 fd = open(os.path.join(prefix, path), 'rb')
949 954 return fd.read()
950 955 finally:
951 956 if fd:
952 957 fd.close()
953 958
954 959 getdata = getdatafn
955 960
956 961 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
957 962
958 963 for subpath in sorted(ctx.substate):
959 964 sub = ctx.sub(subpath)
960 965 submatch = match_.narrowmatcher(subpath, match)
961 966 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
962 967
963 968 # If a largefile is modified, the change is not reflected in its
964 969 # standin until a commit. cmdutil.bailifchanged() raises an exception
965 970 # if the repo has uncommitted changes. Wrap it to also check if
966 971 # largefiles were changed. This is used by bisect, backout and fetch.
967 972 def overridebailifchanged(orig, repo):
968 973 orig(repo)
969 974 repo.lfstatus = True
970 975 s = repo.status()
971 976 repo.lfstatus = False
972 977 if s.modified or s.added or s.removed or s.deleted:
973 978 raise util.Abort(_('uncommitted changes'))
974 979
975 980 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly):
976 981 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
977 982 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly)
978 983 m = composelargefilematcher(match, repo[None].manifest())
979 984
980 985 try:
981 986 repo.lfstatus = True
982 987 s = repo.status(match=m, clean=True)
983 988 finally:
984 989 repo.lfstatus = False
985 990 forget = sorted(s.modified + s.added + s.deleted + s.clean)
986 991 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
987 992
988 993 for f in forget:
989 994 if lfutil.standin(f) not in repo.dirstate and not \
990 995 repo.wvfs.isdir(lfutil.standin(f)):
991 996 ui.warn(_('not removing %s: file is already untracked\n')
992 997 % m.rel(f))
993 998 bad.append(f)
994 999
995 1000 for f in forget:
996 1001 if ui.verbose or not m.exact(f):
997 1002 ui.status(_('removing %s\n') % m.rel(f))
998 1003
999 1004 # Need to lock because standin files are deleted then removed from the
1000 1005 # repository and we could race in-between.
1001 1006 wlock = repo.wlock()
1002 1007 try:
1003 1008 lfdirstate = lfutil.openlfdirstate(ui, repo)
1004 1009 for f in forget:
1005 1010 if lfdirstate[f] == 'a':
1006 1011 lfdirstate.drop(f)
1007 1012 else:
1008 1013 lfdirstate.remove(f)
1009 1014 lfdirstate.write()
1010 1015 standins = [lfutil.standin(f) for f in forget]
1011 1016 for f in standins:
1012 1017 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1013 1018 rejected = repo[None].forget(standins)
1014 1019 finally:
1015 1020 wlock.release()
1016 1021
1017 1022 bad.extend(f for f in rejected if f in m.files())
1018 1023 forgot.extend(f for f in forget if f not in rejected)
1019 1024 return bad, forgot
1020 1025
1021 1026 def _getoutgoings(repo, other, missing, addfunc):
1022 1027 """get pairs of filename and largefile hash in outgoing revisions
1023 1028 in 'missing'.
1024 1029
1025 1030 largefiles already existing on 'other' repository are ignored.
1026 1031
1027 1032 'addfunc' is invoked with each unique pairs of filename and
1028 1033 largefile hash value.
1029 1034 """
1030 1035 knowns = set()
1031 1036 lfhashes = set()
1032 1037 def dedup(fn, lfhash):
1033 1038 k = (fn, lfhash)
1034 1039 if k not in knowns:
1035 1040 knowns.add(k)
1036 1041 lfhashes.add(lfhash)
1037 1042 lfutil.getlfilestoupload(repo, missing, dedup)
1038 1043 if lfhashes:
1039 1044 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1040 1045 for fn, lfhash in knowns:
1041 1046 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1042 1047 addfunc(fn, lfhash)
1043 1048
1044 1049 def outgoinghook(ui, repo, other, opts, missing):
1045 1050 if opts.pop('large', None):
1046 1051 lfhashes = set()
1047 1052 if ui.debugflag:
1048 1053 toupload = {}
1049 1054 def addfunc(fn, lfhash):
1050 1055 if fn not in toupload:
1051 1056 toupload[fn] = []
1052 1057 toupload[fn].append(lfhash)
1053 1058 lfhashes.add(lfhash)
1054 1059 def showhashes(fn):
1055 1060 for lfhash in sorted(toupload[fn]):
1056 1061 ui.debug(' %s\n' % (lfhash))
1057 1062 else:
1058 1063 toupload = set()
1059 1064 def addfunc(fn, lfhash):
1060 1065 toupload.add(fn)
1061 1066 lfhashes.add(lfhash)
1062 1067 def showhashes(fn):
1063 1068 pass
1064 1069 _getoutgoings(repo, other, missing, addfunc)
1065 1070
1066 1071 if not toupload:
1067 1072 ui.status(_('largefiles: no files to upload\n'))
1068 1073 else:
1069 1074 ui.status(_('largefiles to upload (%d entities):\n')
1070 1075 % (len(lfhashes)))
1071 1076 for file in sorted(toupload):
1072 1077 ui.status(lfutil.splitstandin(file) + '\n')
1073 1078 showhashes(file)
1074 1079 ui.status('\n')
1075 1080
1076 1081 def summaryremotehook(ui, repo, opts, changes):
1077 1082 largeopt = opts.get('large', False)
1078 1083 if changes is None:
1079 1084 if largeopt:
1080 1085 return (False, True) # only outgoing check is needed
1081 1086 else:
1082 1087 return (False, False)
1083 1088 elif largeopt:
1084 1089 url, branch, peer, outgoing = changes[1]
1085 1090 if peer is None:
1086 1091 # i18n: column positioning for "hg summary"
1087 1092 ui.status(_('largefiles: (no remote repo)\n'))
1088 1093 return
1089 1094
1090 1095 toupload = set()
1091 1096 lfhashes = set()
1092 1097 def addfunc(fn, lfhash):
1093 1098 toupload.add(fn)
1094 1099 lfhashes.add(lfhash)
1095 1100 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1096 1101
1097 1102 if not toupload:
1098 1103 # i18n: column positioning for "hg summary"
1099 1104 ui.status(_('largefiles: (no files to upload)\n'))
1100 1105 else:
1101 1106 # i18n: column positioning for "hg summary"
1102 1107 ui.status(_('largefiles: %d entities for %d files to upload\n')
1103 1108 % (len(lfhashes), len(toupload)))
1104 1109
1105 1110 def overridesummary(orig, ui, repo, *pats, **opts):
1106 1111 try:
1107 1112 repo.lfstatus = True
1108 1113 orig(ui, repo, *pats, **opts)
1109 1114 finally:
1110 1115 repo.lfstatus = False
1111 1116
1112 1117 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1113 1118 similarity=None):
1114 1119 if not lfutil.islfilesrepo(repo):
1115 1120 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1116 1121 # Get the list of missing largefiles so we can remove them
1117 1122 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1118 1123 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1119 1124 False, False, False)
1120 1125
1121 1126 # Call into the normal remove code, but the removing of the standin, we want
1122 1127 # to have handled by original addremove. Monkey patching here makes sure
1123 1128 # we don't remove the standin in the largefiles code, preventing a very
1124 1129 # confused state later.
1125 1130 if s.deleted:
1126 1131 m = copy.copy(matcher)
1127 1132
1128 1133 # The m._files and m._map attributes are not changed to the deleted list
1129 1134 # because that affects the m.exact() test, which in turn governs whether
1130 1135 # or not the file name is printed, and how. Simply limit the original
1131 1136 # matches to those in the deleted status list.
1132 1137 matchfn = m.matchfn
1133 1138 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1134 1139
1135 1140 removelargefiles(repo.ui, repo, True, m, **opts)
1136 1141 # Call into the normal add code, and any files that *should* be added as
1137 1142 # largefiles will be
1138 1143 added, bad = addlargefiles(repo.ui, repo, True, matcher, **opts)
1139 1144 # Now that we've handled largefiles, hand off to the original addremove
1140 1145 # function to take care of the rest. Make sure it doesn't do anything with
1141 1146 # largefiles by passing a matcher that will ignore them.
1142 1147 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1143 1148 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1144 1149
1145 1150 # Calling purge with --all will cause the largefiles to be deleted.
1146 1151 # Override repo.status to prevent this from happening.
1147 1152 def overridepurge(orig, ui, repo, *dirs, **opts):
1148 1153 # XXX Monkey patching a repoview will not work. The assigned attribute will
1149 1154 # be set on the unfiltered repo, but we will only lookup attributes in the
1150 1155 # unfiltered repo if the lookup in the repoview object itself fails. As the
1151 1156 # monkey patched method exists on the repoview class the lookup will not
1152 1157 # fail. As a result, the original version will shadow the monkey patched
1153 1158 # one, defeating the monkey patch.
1154 1159 #
1155 1160 # As a work around we use an unfiltered repo here. We should do something
1156 1161 # cleaner instead.
1157 1162 repo = repo.unfiltered()
1158 1163 oldstatus = repo.status
1159 1164 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1160 1165 clean=False, unknown=False, listsubrepos=False):
1161 1166 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1162 1167 listsubrepos)
1163 1168 lfdirstate = lfutil.openlfdirstate(ui, repo)
1164 1169 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1165 1170 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1166 1171 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1167 1172 unknown, ignored, r.clean)
1168 1173 repo.status = overridestatus
1169 1174 orig(ui, repo, *dirs, **opts)
1170 1175 repo.status = oldstatus
1171 1176 def overriderollback(orig, ui, repo, **opts):
1172 1177 wlock = repo.wlock()
1173 1178 try:
1174 1179 before = repo.dirstate.parents()
1175 1180 orphans = set(f for f in repo.dirstate
1176 1181 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1177 1182 result = orig(ui, repo, **opts)
1178 1183 after = repo.dirstate.parents()
1179 1184 if before == after:
1180 1185 return result # no need to restore standins
1181 1186
1182 1187 pctx = repo['.']
1183 1188 for f in repo.dirstate:
1184 1189 if lfutil.isstandin(f):
1185 1190 orphans.discard(f)
1186 1191 if repo.dirstate[f] == 'r':
1187 1192 repo.wvfs.unlinkpath(f, ignoremissing=True)
1188 1193 elif f in pctx:
1189 1194 fctx = pctx[f]
1190 1195 repo.wwrite(f, fctx.data(), fctx.flags())
1191 1196 else:
1192 1197 # content of standin is not so important in 'a',
1193 1198 # 'm' or 'n' (coming from the 2nd parent) cases
1194 1199 lfutil.writestandin(repo, f, '', False)
1195 1200 for standin in orphans:
1196 1201 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1197 1202
1198 1203 lfdirstate = lfutil.openlfdirstate(ui, repo)
1199 1204 orphans = set(lfdirstate)
1200 1205 lfiles = lfutil.listlfiles(repo)
1201 1206 for file in lfiles:
1202 1207 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1203 1208 orphans.discard(file)
1204 1209 for lfile in orphans:
1205 1210 lfdirstate.drop(lfile)
1206 1211 lfdirstate.write()
1207 1212 finally:
1208 1213 wlock.release()
1209 1214 return result
1210 1215
1211 1216 def overridetransplant(orig, ui, repo, *revs, **opts):
1212 1217 resuming = opts.get('continue')
1213 1218 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1214 1219 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1215 1220 try:
1216 1221 result = orig(ui, repo, *revs, **opts)
1217 1222 finally:
1218 1223 repo._lfstatuswriters.pop()
1219 1224 repo._lfcommithooks.pop()
1220 1225 return result
1221 1226
1222 1227 def overridecat(orig, ui, repo, file1, *pats, **opts):
1223 1228 ctx = scmutil.revsingle(repo, opts.get('rev'))
1224 1229 err = 1
1225 1230 notbad = set()
1226 1231 m = scmutil.match(ctx, (file1,) + pats, opts)
1227 1232 origmatchfn = m.matchfn
1228 1233 def lfmatchfn(f):
1229 1234 if origmatchfn(f):
1230 1235 return True
1231 1236 lf = lfutil.splitstandin(f)
1232 1237 if lf is None:
1233 1238 return False
1234 1239 notbad.add(lf)
1235 1240 return origmatchfn(lf)
1236 1241 m.matchfn = lfmatchfn
1237 1242 origbadfn = m.bad
1238 1243 def lfbadfn(f, msg):
1239 1244 if not f in notbad:
1240 1245 origbadfn(f, msg)
1241 1246 m.bad = lfbadfn
1242 1247 for f in ctx.walk(m):
1243 1248 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1244 1249 pathname=f)
1245 1250 lf = lfutil.splitstandin(f)
1246 1251 if lf is None or origmatchfn(f):
1247 1252 # duplicating unreachable code from commands.cat
1248 1253 data = ctx[f].data()
1249 1254 if opts.get('decode'):
1250 1255 data = repo.wwritedata(f, data)
1251 1256 fp.write(data)
1252 1257 else:
1253 1258 hash = lfutil.readstandin(repo, lf, ctx.rev())
1254 1259 if not lfutil.inusercache(repo.ui, hash):
1255 1260 store = basestore._openstore(repo)
1256 1261 success, missing = store.get([(lf, hash)])
1257 1262 if len(success) != 1:
1258 1263 raise util.Abort(
1259 1264 _('largefile %s is not in cache and could not be '
1260 1265 'downloaded') % lf)
1261 1266 path = lfutil.usercachepath(repo.ui, hash)
1262 1267 fpin = open(path, "rb")
1263 1268 for chunk in util.filechunkiter(fpin, 128 * 1024):
1264 1269 fp.write(chunk)
1265 1270 fpin.close()
1266 1271 fp.close()
1267 1272 err = 0
1268 1273 return err
1269 1274
1270 1275 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1271 1276 *args, **kwargs):
1272 1277 wlock = repo.wlock()
1273 1278 try:
1274 1279 # branch | | |
1275 1280 # merge | force | partial | action
1276 1281 # -------+-------+---------+--------------
1277 1282 # x | x | x | linear-merge
1278 1283 # o | x | x | branch-merge
1279 1284 # x | o | x | overwrite (as clean update)
1280 1285 # o | o | x | force-branch-merge (*1)
1281 1286 # x | x | o | (*)
1282 1287 # o | x | o | (*)
1283 1288 # x | o | o | overwrite (as revert)
1284 1289 # o | o | o | (*)
1285 1290 #
1286 1291 # (*) don't care
1287 1292 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1288 1293
1289 1294 linearmerge = not branchmerge and not force and not partial
1290 1295
1291 1296 if linearmerge or (branchmerge and force and not partial):
1292 1297 # update standins for linear-merge or force-branch-merge,
1293 1298 # because largefiles in the working directory may be modified
1294 1299 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1295 1300 unsure, s = lfdirstate.status(match_.always(repo.root,
1296 1301 repo.getcwd()),
1297 1302 [], False, False, False)
1298 1303 pctx = repo['.']
1299 1304 for lfile in unsure + s.modified:
1300 1305 lfileabs = repo.wvfs.join(lfile)
1301 1306 if not os.path.exists(lfileabs):
1302 1307 continue
1303 1308 lfhash = lfutil.hashrepofile(repo, lfile)
1304 1309 standin = lfutil.standin(lfile)
1305 1310 lfutil.writestandin(repo, standin, lfhash,
1306 1311 lfutil.getexecutable(lfileabs))
1307 1312 if (standin in pctx and
1308 1313 lfhash == lfutil.readstandin(repo, lfile, '.')):
1309 1314 lfdirstate.normal(lfile)
1310 1315 for lfile in s.added:
1311 1316 lfutil.updatestandin(repo, lfutil.standin(lfile))
1312 1317 lfdirstate.write()
1313 1318
1314 1319 if linearmerge:
1315 1320 # Only call updatelfiles on the standins that have changed
1316 1321 # to save time
1317 1322 oldstandins = lfutil.getstandinsstate(repo)
1318 1323
1319 1324 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1320 1325
1321 1326 filelist = None
1322 1327 if linearmerge:
1323 1328 newstandins = lfutil.getstandinsstate(repo)
1324 1329 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1325 1330
1326 1331 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1327 1332 normallookup=partial, checked=linearmerge)
1328 1333
1329 1334 return result
1330 1335 finally:
1331 1336 wlock.release()
1332 1337
1333 1338 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1334 1339 result = orig(repo, files, *args, **kwargs)
1335 1340
1336 1341 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1337 1342 if filelist:
1338 1343 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1339 1344 printmessage=False, normallookup=True)
1340 1345
1341 1346 return result
@@ -1,1932 +1,1945 b''
1 1 Log on empty repository: checking consistency
2 2
3 3 $ hg init empty
4 4 $ cd empty
5 5 $ hg log
6 6 $ hg log -r 1
7 7 abort: unknown revision '1'!
8 8 [255]
9 9 $ hg log -r -1:0
10 10 abort: unknown revision '-1'!
11 11 [255]
12 12 $ hg log -r 'branch(name)'
13 13 abort: unknown revision 'name'!
14 14 [255]
15 15 $ hg log -r null -q
16 16 -1:000000000000
17 17
18 18 The g is crafted to have 2 filelog topological heads in a linear
19 19 changeset graph
20 20
21 21 $ hg init a
22 22 $ cd a
23 23 $ echo a > a
24 24 $ echo f > f
25 25 $ hg ci -Ama -d '1 0'
26 26 adding a
27 27 adding f
28 28
29 29 $ hg cp a b
30 30 $ hg cp f g
31 31 $ hg ci -mb -d '2 0'
32 32
33 33 $ mkdir dir
34 34 $ hg mv b dir
35 35 $ echo g >> g
36 36 $ echo f >> f
37 37 $ hg ci -mc -d '3 0'
38 38
39 39 $ hg mv a b
40 40 $ hg cp -f f g
41 41 $ echo a > d
42 42 $ hg add d
43 43 $ hg ci -md -d '4 0'
44 44
45 45 $ hg mv dir/b e
46 46 $ hg ci -me -d '5 0'
47 47
48 Make sure largefiles doesn't interfere with logging a regular file
49 $ hg log a --config extensions.largefiles=
50 changeset: 0:9161b9aeaf16
51 user: test
52 date: Thu Jan 01 00:00:01 1970 +0000
53 summary: a
54
48 55 $ hg log a
49 56 changeset: 0:9161b9aeaf16
50 57 user: test
51 58 date: Thu Jan 01 00:00:01 1970 +0000
52 59 summary: a
53 60
54 61 log on directory
55 62
56 63 $ hg log dir
57 64 changeset: 4:7e4639b4691b
58 65 tag: tip
59 66 user: test
60 67 date: Thu Jan 01 00:00:05 1970 +0000
61 68 summary: e
62 69
63 70 changeset: 2:f8954cd4dc1f
64 71 user: test
65 72 date: Thu Jan 01 00:00:03 1970 +0000
66 73 summary: c
67 74
68 75 $ hg log somethingthatdoesntexist dir
69 76 changeset: 4:7e4639b4691b
70 77 tag: tip
71 78 user: test
72 79 date: Thu Jan 01 00:00:05 1970 +0000
73 80 summary: e
74 81
75 82 changeset: 2:f8954cd4dc1f
76 83 user: test
77 84 date: Thu Jan 01 00:00:03 1970 +0000
78 85 summary: c
79 86
80 87
81 88 -f, non-existent directory
82 89
83 90 $ hg log -f dir
84 91 abort: cannot follow file not in parent revision: "dir"
85 92 [255]
86 93
87 94 -f, directory
88 95
89 96 $ hg up -q 3
90 97 $ hg log -f dir
91 98 changeset: 2:f8954cd4dc1f
92 99 user: test
93 100 date: Thu Jan 01 00:00:03 1970 +0000
94 101 summary: c
95 102
96 103 -f, directory with --patch
97 104
98 105 $ hg log -f dir -p
99 106 changeset: 2:f8954cd4dc1f
100 107 user: test
101 108 date: Thu Jan 01 00:00:03 1970 +0000
102 109 summary: c
103 110
104 111 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
105 112 --- /dev/null* (glob)
106 113 +++ b/dir/b* (glob)
107 114 @@ -0,0 +1,1 @@
108 115 +a
109 116
110 117
111 118 -f, pattern
112 119
113 120 $ hg log -f -I 'dir**' -p
114 121 changeset: 2:f8954cd4dc1f
115 122 user: test
116 123 date: Thu Jan 01 00:00:03 1970 +0000
117 124 summary: c
118 125
119 126 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
120 127 --- /dev/null* (glob)
121 128 +++ b/dir/b* (glob)
122 129 @@ -0,0 +1,1 @@
123 130 +a
124 131
125 132 $ hg up -q 4
126 133
127 134 -f, a wrong style
128 135
129 136 $ hg log -f -l1 --style something
130 137 abort: style 'something' not found
131 138 (available styles: bisect, changelog, compact, default, phases, xml)
132 139 [255]
133 140
134 141 -f, phases style
135 142
136 143
137 144 $ hg log -f -l1 --style phases
138 145 changeset: 4:7e4639b4691b
139 146 tag: tip
140 147 phase: draft
141 148 user: test
142 149 date: Thu Jan 01 00:00:05 1970 +0000
143 150 summary: e
144 151
145 152
146 153 -f, but no args
147 154
148 155 $ hg log -f
149 156 changeset: 4:7e4639b4691b
150 157 tag: tip
151 158 user: test
152 159 date: Thu Jan 01 00:00:05 1970 +0000
153 160 summary: e
154 161
155 162 changeset: 3:2ca5ba701980
156 163 user: test
157 164 date: Thu Jan 01 00:00:04 1970 +0000
158 165 summary: d
159 166
160 167 changeset: 2:f8954cd4dc1f
161 168 user: test
162 169 date: Thu Jan 01 00:00:03 1970 +0000
163 170 summary: c
164 171
165 172 changeset: 1:d89b0a12d229
166 173 user: test
167 174 date: Thu Jan 01 00:00:02 1970 +0000
168 175 summary: b
169 176
170 177 changeset: 0:9161b9aeaf16
171 178 user: test
172 179 date: Thu Jan 01 00:00:01 1970 +0000
173 180 summary: a
174 181
175 182
176 183 one rename
177 184
178 185 $ hg up -q 2
179 186 $ hg log -vf a
180 187 changeset: 0:9161b9aeaf16
181 188 user: test
182 189 date: Thu Jan 01 00:00:01 1970 +0000
183 190 files: a f
184 191 description:
185 192 a
186 193
187 194
188 195
189 196 many renames
190 197
191 198 $ hg up -q tip
192 199 $ hg log -vf e
193 200 changeset: 4:7e4639b4691b
194 201 tag: tip
195 202 user: test
196 203 date: Thu Jan 01 00:00:05 1970 +0000
197 204 files: dir/b e
198 205 description:
199 206 e
200 207
201 208
202 209 changeset: 2:f8954cd4dc1f
203 210 user: test
204 211 date: Thu Jan 01 00:00:03 1970 +0000
205 212 files: b dir/b f g
206 213 description:
207 214 c
208 215
209 216
210 217 changeset: 1:d89b0a12d229
211 218 user: test
212 219 date: Thu Jan 01 00:00:02 1970 +0000
213 220 files: b g
214 221 description:
215 222 b
216 223
217 224
218 225 changeset: 0:9161b9aeaf16
219 226 user: test
220 227 date: Thu Jan 01 00:00:01 1970 +0000
221 228 files: a f
222 229 description:
223 230 a
224 231
225 232
226 233
227 234
228 235 log -pf dir/b
229 236
230 237 $ hg up -q 3
231 238 $ hg log -pf dir/b
232 239 changeset: 2:f8954cd4dc1f
233 240 user: test
234 241 date: Thu Jan 01 00:00:03 1970 +0000
235 242 summary: c
236 243
237 244 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
238 245 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
239 246 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
240 247 @@ -0,0 +1,1 @@
241 248 +a
242 249
243 250 changeset: 1:d89b0a12d229
244 251 user: test
245 252 date: Thu Jan 01 00:00:02 1970 +0000
246 253 summary: b
247 254
248 255 diff -r 9161b9aeaf16 -r d89b0a12d229 b
249 256 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
250 257 +++ b/b Thu Jan 01 00:00:02 1970 +0000
251 258 @@ -0,0 +1,1 @@
252 259 +a
253 260
254 261 changeset: 0:9161b9aeaf16
255 262 user: test
256 263 date: Thu Jan 01 00:00:01 1970 +0000
257 264 summary: a
258 265
259 266 diff -r 000000000000 -r 9161b9aeaf16 a
260 267 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
261 268 +++ b/a Thu Jan 01 00:00:01 1970 +0000
262 269 @@ -0,0 +1,1 @@
263 270 +a
264 271
265 272
266 273 log -pf b inside dir
267 274
268 275 $ hg --cwd=dir log -pf b
269 276 changeset: 2:f8954cd4dc1f
270 277 user: test
271 278 date: Thu Jan 01 00:00:03 1970 +0000
272 279 summary: c
273 280
274 281 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
275 282 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276 283 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
277 284 @@ -0,0 +1,1 @@
278 285 +a
279 286
280 287 changeset: 1:d89b0a12d229
281 288 user: test
282 289 date: Thu Jan 01 00:00:02 1970 +0000
283 290 summary: b
284 291
285 292 diff -r 9161b9aeaf16 -r d89b0a12d229 b
286 293 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
287 294 +++ b/b Thu Jan 01 00:00:02 1970 +0000
288 295 @@ -0,0 +1,1 @@
289 296 +a
290 297
291 298 changeset: 0:9161b9aeaf16
292 299 user: test
293 300 date: Thu Jan 01 00:00:01 1970 +0000
294 301 summary: a
295 302
296 303 diff -r 000000000000 -r 9161b9aeaf16 a
297 304 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
298 305 +++ b/a Thu Jan 01 00:00:01 1970 +0000
299 306 @@ -0,0 +1,1 @@
300 307 +a
301 308
302 309
303 310 log -pf, but no args
304 311
305 312 $ hg log -pf
306 313 changeset: 3:2ca5ba701980
307 314 user: test
308 315 date: Thu Jan 01 00:00:04 1970 +0000
309 316 summary: d
310 317
311 318 diff -r f8954cd4dc1f -r 2ca5ba701980 a
312 319 --- a/a Thu Jan 01 00:00:03 1970 +0000
313 320 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
314 321 @@ -1,1 +0,0 @@
315 322 -a
316 323 diff -r f8954cd4dc1f -r 2ca5ba701980 b
317 324 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
318 325 +++ b/b Thu Jan 01 00:00:04 1970 +0000
319 326 @@ -0,0 +1,1 @@
320 327 +a
321 328 diff -r f8954cd4dc1f -r 2ca5ba701980 d
322 329 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
323 330 +++ b/d Thu Jan 01 00:00:04 1970 +0000
324 331 @@ -0,0 +1,1 @@
325 332 +a
326 333 diff -r f8954cd4dc1f -r 2ca5ba701980 g
327 334 --- a/g Thu Jan 01 00:00:03 1970 +0000
328 335 +++ b/g Thu Jan 01 00:00:04 1970 +0000
329 336 @@ -1,2 +1,2 @@
330 337 f
331 338 -g
332 339 +f
333 340
334 341 changeset: 2:f8954cd4dc1f
335 342 user: test
336 343 date: Thu Jan 01 00:00:03 1970 +0000
337 344 summary: c
338 345
339 346 diff -r d89b0a12d229 -r f8954cd4dc1f b
340 347 --- a/b Thu Jan 01 00:00:02 1970 +0000
341 348 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
342 349 @@ -1,1 +0,0 @@
343 350 -a
344 351 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
345 352 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
346 353 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
347 354 @@ -0,0 +1,1 @@
348 355 +a
349 356 diff -r d89b0a12d229 -r f8954cd4dc1f f
350 357 --- a/f Thu Jan 01 00:00:02 1970 +0000
351 358 +++ b/f Thu Jan 01 00:00:03 1970 +0000
352 359 @@ -1,1 +1,2 @@
353 360 f
354 361 +f
355 362 diff -r d89b0a12d229 -r f8954cd4dc1f g
356 363 --- a/g Thu Jan 01 00:00:02 1970 +0000
357 364 +++ b/g Thu Jan 01 00:00:03 1970 +0000
358 365 @@ -1,1 +1,2 @@
359 366 f
360 367 +g
361 368
362 369 changeset: 1:d89b0a12d229
363 370 user: test
364 371 date: Thu Jan 01 00:00:02 1970 +0000
365 372 summary: b
366 373
367 374 diff -r 9161b9aeaf16 -r d89b0a12d229 b
368 375 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
369 376 +++ b/b Thu Jan 01 00:00:02 1970 +0000
370 377 @@ -0,0 +1,1 @@
371 378 +a
372 379 diff -r 9161b9aeaf16 -r d89b0a12d229 g
373 380 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
374 381 +++ b/g Thu Jan 01 00:00:02 1970 +0000
375 382 @@ -0,0 +1,1 @@
376 383 +f
377 384
378 385 changeset: 0:9161b9aeaf16
379 386 user: test
380 387 date: Thu Jan 01 00:00:01 1970 +0000
381 388 summary: a
382 389
383 390 diff -r 000000000000 -r 9161b9aeaf16 a
384 391 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
385 392 +++ b/a Thu Jan 01 00:00:01 1970 +0000
386 393 @@ -0,0 +1,1 @@
387 394 +a
388 395 diff -r 000000000000 -r 9161b9aeaf16 f
389 396 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
390 397 +++ b/f Thu Jan 01 00:00:01 1970 +0000
391 398 @@ -0,0 +1,1 @@
392 399 +f
393 400
394 401
395 402 log -vf dir/b
396 403
397 404 $ hg log -vf dir/b
398 405 changeset: 2:f8954cd4dc1f
399 406 user: test
400 407 date: Thu Jan 01 00:00:03 1970 +0000
401 408 files: b dir/b f g
402 409 description:
403 410 c
404 411
405 412
406 413 changeset: 1:d89b0a12d229
407 414 user: test
408 415 date: Thu Jan 01 00:00:02 1970 +0000
409 416 files: b g
410 417 description:
411 418 b
412 419
413 420
414 421 changeset: 0:9161b9aeaf16
415 422 user: test
416 423 date: Thu Jan 01 00:00:01 1970 +0000
417 424 files: a f
418 425 description:
419 426 a
420 427
421 428
422 429
423 430
424 431 -f and multiple filelog heads
425 432
426 433 $ hg up -q 2
427 434 $ hg log -f g --template '{rev}\n'
428 435 2
429 436 1
430 437 0
431 438 $ hg up -q tip
432 439 $ hg log -f g --template '{rev}\n'
433 440 3
434 441 2
435 442 0
436 443
437 444
438 445 log copies with --copies
439 446
440 447 $ hg log -vC --template '{rev} {file_copies}\n'
441 448 4 e (dir/b)
442 449 3 b (a)g (f)
443 450 2 dir/b (b)
444 451 1 b (a)g (f)
445 452 0
446 453
447 454 log copies switch without --copies, with old filecopy template
448 455
449 456 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
450 457 4
451 458 3
452 459 2
453 460 1
454 461 0
455 462
456 463 log copies switch with --copies
457 464
458 465 $ hg log -vC --template '{rev} {file_copies_switch}\n'
459 466 4 e (dir/b)
460 467 3 b (a)g (f)
461 468 2 dir/b (b)
462 469 1 b (a)g (f)
463 470 0
464 471
465 472
466 473 log copies with hardcoded style and with --style=default
467 474
468 475 $ hg log -vC -r4
469 476 changeset: 4:7e4639b4691b
470 477 tag: tip
471 478 user: test
472 479 date: Thu Jan 01 00:00:05 1970 +0000
473 480 files: dir/b e
474 481 copies: e (dir/b)
475 482 description:
476 483 e
477 484
478 485
479 486 $ hg log -vC -r4 --style=default
480 487 changeset: 4:7e4639b4691b
481 488 tag: tip
482 489 user: test
483 490 date: Thu Jan 01 00:00:05 1970 +0000
484 491 files: dir/b e
485 492 copies: e (dir/b)
486 493 description:
487 494 e
488 495
489 496
490 497
491 498
492 499 log copies, non-linear manifest
493 500
494 501 $ hg up -C 3
495 502 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
496 503 $ hg mv dir/b e
497 504 $ echo foo > foo
498 505 $ hg ci -Ame2 -d '6 0'
499 506 adding foo
500 507 created new head
501 508 $ hg log -v --template '{rev} {file_copies}\n' -r 5
502 509 5 e (dir/b)
503 510
504 511
505 512 log copies, execute bit set
506 513
507 514 #if execbit
508 515 $ chmod +x e
509 516 $ hg ci -me3 -d '7 0'
510 517 $ hg log -v --template '{rev} {file_copies}\n' -r 6
511 518 6
512 519 #endif
513 520
514 521
515 522 log -p d
516 523
517 524 $ hg log -pv d
518 525 changeset: 3:2ca5ba701980
519 526 user: test
520 527 date: Thu Jan 01 00:00:04 1970 +0000
521 528 files: a b d g
522 529 description:
523 530 d
524 531
525 532
526 533 diff -r f8954cd4dc1f -r 2ca5ba701980 d
527 534 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
528 535 +++ b/d Thu Jan 01 00:00:04 1970 +0000
529 536 @@ -0,0 +1,1 @@
530 537 +a
531 538
532 539
533 540
534 541 log --removed file
535 542
536 543 $ hg log --removed -v a
537 544 changeset: 3:2ca5ba701980
538 545 user: test
539 546 date: Thu Jan 01 00:00:04 1970 +0000
540 547 files: a b d g
541 548 description:
542 549 d
543 550
544 551
545 552 changeset: 0:9161b9aeaf16
546 553 user: test
547 554 date: Thu Jan 01 00:00:01 1970 +0000
548 555 files: a f
549 556 description:
550 557 a
551 558
552 559
553 560
554 561 log --removed revrange file
555 562
556 563 $ hg log --removed -v -r0:2 a
557 564 changeset: 0:9161b9aeaf16
558 565 user: test
559 566 date: Thu Jan 01 00:00:01 1970 +0000
560 567 files: a f
561 568 description:
562 569 a
563 570
564 571
565 572 $ cd ..
566 573
567 574 log --follow tests
568 575
569 576 $ hg init follow
570 577 $ cd follow
571 578
572 579 $ echo base > base
573 580 $ hg ci -Ambase -d '1 0'
574 581 adding base
575 582
576 583 $ echo r1 >> base
577 584 $ hg ci -Amr1 -d '1 0'
578 585 $ echo r2 >> base
579 586 $ hg ci -Amr2 -d '1 0'
580 587
581 588 $ hg up -C 1
582 589 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 590 $ echo b1 > b1
584 591 $ hg ci -Amb1 -d '1 0'
585 592 adding b1
586 593 created new head
587 594
588 595
589 596 log -f
590 597
591 598 $ hg log -f
592 599 changeset: 3:e62f78d544b4
593 600 tag: tip
594 601 parent: 1:3d5bf5654eda
595 602 user: test
596 603 date: Thu Jan 01 00:00:01 1970 +0000
597 604 summary: b1
598 605
599 606 changeset: 1:3d5bf5654eda
600 607 user: test
601 608 date: Thu Jan 01 00:00:01 1970 +0000
602 609 summary: r1
603 610
604 611 changeset: 0:67e992f2c4f3
605 612 user: test
606 613 date: Thu Jan 01 00:00:01 1970 +0000
607 614 summary: base
608 615
609 616
610 617
611 618 log -f -r 1:tip
612 619
613 620 $ hg up -C 0
614 621 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
615 622 $ echo b2 > b2
616 623 $ hg ci -Amb2 -d '1 0'
617 624 adding b2
618 625 created new head
619 626 $ hg log -f -r 1:tip
620 627 changeset: 1:3d5bf5654eda
621 628 user: test
622 629 date: Thu Jan 01 00:00:01 1970 +0000
623 630 summary: r1
624 631
625 632 changeset: 2:60c670bf5b30
626 633 user: test
627 634 date: Thu Jan 01 00:00:01 1970 +0000
628 635 summary: r2
629 636
630 637 changeset: 3:e62f78d544b4
631 638 parent: 1:3d5bf5654eda
632 639 user: test
633 640 date: Thu Jan 01 00:00:01 1970 +0000
634 641 summary: b1
635 642
636 643
637 644
638 645 log -f -r null
639 646
640 647 $ hg log -f -r null
641 648 changeset: -1:000000000000
642 649 user:
643 650 date: Thu Jan 01 00:00:00 1970 +0000
644 651
645 652 $ hg log -f -r null -G
646 653 o changeset: -1:000000000000
647 654 user:
648 655 date: Thu Jan 01 00:00:00 1970 +0000
649 656
650 657
651 658
652 659 log -r . with two parents
653 660
654 661 $ hg up -C 3
655 662 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
656 663 $ hg merge tip
657 664 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
658 665 (branch merge, don't forget to commit)
659 666 $ hg log -r .
660 667 changeset: 3:e62f78d544b4
661 668 parent: 1:3d5bf5654eda
662 669 user: test
663 670 date: Thu Jan 01 00:00:01 1970 +0000
664 671 summary: b1
665 672
666 673
667 674
668 675 log -r . with one parent
669 676
670 677 $ hg ci -mm12 -d '1 0'
671 678 $ hg log -r .
672 679 changeset: 5:302e9dd6890d
673 680 tag: tip
674 681 parent: 3:e62f78d544b4
675 682 parent: 4:ddb82e70d1a1
676 683 user: test
677 684 date: Thu Jan 01 00:00:01 1970 +0000
678 685 summary: m12
679 686
680 687
681 688 $ echo postm >> b1
682 689 $ hg ci -Amb1.1 -d'1 0'
683 690
684 691
685 692 log --follow-first
686 693
687 694 $ hg log --follow-first
688 695 changeset: 6:2404bbcab562
689 696 tag: tip
690 697 user: test
691 698 date: Thu Jan 01 00:00:01 1970 +0000
692 699 summary: b1.1
693 700
694 701 changeset: 5:302e9dd6890d
695 702 parent: 3:e62f78d544b4
696 703 parent: 4:ddb82e70d1a1
697 704 user: test
698 705 date: Thu Jan 01 00:00:01 1970 +0000
699 706 summary: m12
700 707
701 708 changeset: 3:e62f78d544b4
702 709 parent: 1:3d5bf5654eda
703 710 user: test
704 711 date: Thu Jan 01 00:00:01 1970 +0000
705 712 summary: b1
706 713
707 714 changeset: 1:3d5bf5654eda
708 715 user: test
709 716 date: Thu Jan 01 00:00:01 1970 +0000
710 717 summary: r1
711 718
712 719 changeset: 0:67e992f2c4f3
713 720 user: test
714 721 date: Thu Jan 01 00:00:01 1970 +0000
715 722 summary: base
716 723
717 724
718 725
719 726 log -P 2
720 727
721 728 $ hg log -P 2
722 729 changeset: 6:2404bbcab562
723 730 tag: tip
724 731 user: test
725 732 date: Thu Jan 01 00:00:01 1970 +0000
726 733 summary: b1.1
727 734
728 735 changeset: 5:302e9dd6890d
729 736 parent: 3:e62f78d544b4
730 737 parent: 4:ddb82e70d1a1
731 738 user: test
732 739 date: Thu Jan 01 00:00:01 1970 +0000
733 740 summary: m12
734 741
735 742 changeset: 4:ddb82e70d1a1
736 743 parent: 0:67e992f2c4f3
737 744 user: test
738 745 date: Thu Jan 01 00:00:01 1970 +0000
739 746 summary: b2
740 747
741 748 changeset: 3:e62f78d544b4
742 749 parent: 1:3d5bf5654eda
743 750 user: test
744 751 date: Thu Jan 01 00:00:01 1970 +0000
745 752 summary: b1
746 753
747 754
748 755
749 756 log -r tip -p --git
750 757
751 758 $ hg log -r tip -p --git
752 759 changeset: 6:2404bbcab562
753 760 tag: tip
754 761 user: test
755 762 date: Thu Jan 01 00:00:01 1970 +0000
756 763 summary: b1.1
757 764
758 765 diff --git a/b1 b/b1
759 766 --- a/b1
760 767 +++ b/b1
761 768 @@ -1,1 +1,2 @@
762 769 b1
763 770 +postm
764 771
765 772
766 773
767 774 log -r ""
768 775
769 776 $ hg log -r ''
770 777 hg: parse error: empty query
771 778 [255]
772 779
773 780 log -r <some unknown node id>
774 781
775 782 $ hg log -r 1000000000000000000000000000000000000000
776 783 abort: unknown revision '1000000000000000000000000000000000000000'!
777 784 [255]
778 785
779 786 log -k r1
780 787
781 788 $ hg log -k r1
782 789 changeset: 1:3d5bf5654eda
783 790 user: test
784 791 date: Thu Jan 01 00:00:01 1970 +0000
785 792 summary: r1
786 793
787 794 log -p -l2 --color=always
788 795
789 796 $ hg --config extensions.color= --config color.mode=ansi \
790 797 > log -p -l2 --color=always
791 798 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
792 799 tag: tip
793 800 user: test
794 801 date: Thu Jan 01 00:00:01 1970 +0000
795 802 summary: b1.1
796 803
797 804 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
798 805 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
799 806 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
800 807 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
801 808 b1
802 809 \x1b[0;32m+postm\x1b[0m (esc)
803 810
804 811 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
805 812 parent: 3:e62f78d544b4
806 813 parent: 4:ddb82e70d1a1
807 814 user: test
808 815 date: Thu Jan 01 00:00:01 1970 +0000
809 816 summary: m12
810 817
811 818 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
812 819 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
813 820 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
814 821 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
815 822 \x1b[0;32m+b2\x1b[0m (esc)
816 823
817 824
818 825
819 826 log -r tip --stat
820 827
821 828 $ hg log -r tip --stat
822 829 changeset: 6:2404bbcab562
823 830 tag: tip
824 831 user: test
825 832 date: Thu Jan 01 00:00:01 1970 +0000
826 833 summary: b1.1
827 834
828 835 b1 | 1 +
829 836 1 files changed, 1 insertions(+), 0 deletions(-)
830 837
831 838
832 839 $ cd ..
833 840
834 841
835 842 User
836 843
837 844 $ hg init usertest
838 845 $ cd usertest
839 846
840 847 $ echo a > a
841 848 $ hg ci -A -m "a" -u "User One <user1@example.org>"
842 849 adding a
843 850 $ echo b > b
844 851 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
845 852 adding b
846 853
847 854 $ hg log -u "User One <user1@example.org>"
848 855 changeset: 0:29a4c94f1924
849 856 user: User One <user1@example.org>
850 857 date: Thu Jan 01 00:00:00 1970 +0000
851 858 summary: a
852 859
853 860 $ hg log -u "user1" -u "user2"
854 861 changeset: 1:e834b5e69c0e
855 862 tag: tip
856 863 user: User Two <user2@example.org>
857 864 date: Thu Jan 01 00:00:00 1970 +0000
858 865 summary: b
859 866
860 867 changeset: 0:29a4c94f1924
861 868 user: User One <user1@example.org>
862 869 date: Thu Jan 01 00:00:00 1970 +0000
863 870 summary: a
864 871
865 872 $ hg log -u "user3"
866 873
867 874 $ cd ..
868 875
869 876 $ hg init branches
870 877 $ cd branches
871 878
872 879 $ echo a > a
873 880 $ hg ci -A -m "commit on default"
874 881 adding a
875 882 $ hg branch test
876 883 marked working directory as branch test
877 884 (branches are permanent and global, did you want a bookmark?)
878 885 $ echo b > b
879 886 $ hg ci -A -m "commit on test"
880 887 adding b
881 888
882 889 $ hg up default
883 890 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
884 891 $ echo c > c
885 892 $ hg ci -A -m "commit on default"
886 893 adding c
887 894 $ hg up test
888 895 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
889 896 $ echo c > c
890 897 $ hg ci -A -m "commit on test"
891 898 adding c
892 899
893 900
894 901 log -b default
895 902
896 903 $ hg log -b default
897 904 changeset: 2:c3a4f03cc9a7
898 905 parent: 0:24427303d56f
899 906 user: test
900 907 date: Thu Jan 01 00:00:00 1970 +0000
901 908 summary: commit on default
902 909
903 910 changeset: 0:24427303d56f
904 911 user: test
905 912 date: Thu Jan 01 00:00:00 1970 +0000
906 913 summary: commit on default
907 914
908 915
909 916
910 917 log -b test
911 918
912 919 $ hg log -b test
913 920 changeset: 3:f5d8de11c2e2
914 921 branch: test
915 922 tag: tip
916 923 parent: 1:d32277701ccb
917 924 user: test
918 925 date: Thu Jan 01 00:00:00 1970 +0000
919 926 summary: commit on test
920 927
921 928 changeset: 1:d32277701ccb
922 929 branch: test
923 930 user: test
924 931 date: Thu Jan 01 00:00:00 1970 +0000
925 932 summary: commit on test
926 933
927 934
928 935
929 936 log -b dummy
930 937
931 938 $ hg log -b dummy
932 939 abort: unknown revision 'dummy'!
933 940 [255]
934 941
935 942
936 943 log -b .
937 944
938 945 $ hg log -b .
939 946 changeset: 3:f5d8de11c2e2
940 947 branch: test
941 948 tag: tip
942 949 parent: 1:d32277701ccb
943 950 user: test
944 951 date: Thu Jan 01 00:00:00 1970 +0000
945 952 summary: commit on test
946 953
947 954 changeset: 1:d32277701ccb
948 955 branch: test
949 956 user: test
950 957 date: Thu Jan 01 00:00:00 1970 +0000
951 958 summary: commit on test
952 959
953 960
954 961
955 962 log -b default -b test
956 963
957 964 $ hg log -b default -b test
958 965 changeset: 3:f5d8de11c2e2
959 966 branch: test
960 967 tag: tip
961 968 parent: 1:d32277701ccb
962 969 user: test
963 970 date: Thu Jan 01 00:00:00 1970 +0000
964 971 summary: commit on test
965 972
966 973 changeset: 2:c3a4f03cc9a7
967 974 parent: 0:24427303d56f
968 975 user: test
969 976 date: Thu Jan 01 00:00:00 1970 +0000
970 977 summary: commit on default
971 978
972 979 changeset: 1:d32277701ccb
973 980 branch: test
974 981 user: test
975 982 date: Thu Jan 01 00:00:00 1970 +0000
976 983 summary: commit on test
977 984
978 985 changeset: 0:24427303d56f
979 986 user: test
980 987 date: Thu Jan 01 00:00:00 1970 +0000
981 988 summary: commit on default
982 989
983 990
984 991
985 992 log -b default -b .
986 993
987 994 $ hg log -b default -b .
988 995 changeset: 3:f5d8de11c2e2
989 996 branch: test
990 997 tag: tip
991 998 parent: 1:d32277701ccb
992 999 user: test
993 1000 date: Thu Jan 01 00:00:00 1970 +0000
994 1001 summary: commit on test
995 1002
996 1003 changeset: 2:c3a4f03cc9a7
997 1004 parent: 0:24427303d56f
998 1005 user: test
999 1006 date: Thu Jan 01 00:00:00 1970 +0000
1000 1007 summary: commit on default
1001 1008
1002 1009 changeset: 1:d32277701ccb
1003 1010 branch: test
1004 1011 user: test
1005 1012 date: Thu Jan 01 00:00:00 1970 +0000
1006 1013 summary: commit on test
1007 1014
1008 1015 changeset: 0:24427303d56f
1009 1016 user: test
1010 1017 date: Thu Jan 01 00:00:00 1970 +0000
1011 1018 summary: commit on default
1012 1019
1013 1020
1014 1021
1015 1022 log -b . -b test
1016 1023
1017 1024 $ hg log -b . -b test
1018 1025 changeset: 3:f5d8de11c2e2
1019 1026 branch: test
1020 1027 tag: tip
1021 1028 parent: 1:d32277701ccb
1022 1029 user: test
1023 1030 date: Thu Jan 01 00:00:00 1970 +0000
1024 1031 summary: commit on test
1025 1032
1026 1033 changeset: 1:d32277701ccb
1027 1034 branch: test
1028 1035 user: test
1029 1036 date: Thu Jan 01 00:00:00 1970 +0000
1030 1037 summary: commit on test
1031 1038
1032 1039
1033 1040
1034 1041 log -b 2
1035 1042
1036 1043 $ hg log -b 2
1037 1044 changeset: 2:c3a4f03cc9a7
1038 1045 parent: 0:24427303d56f
1039 1046 user: test
1040 1047 date: Thu Jan 01 00:00:00 1970 +0000
1041 1048 summary: commit on default
1042 1049
1043 1050 changeset: 0:24427303d56f
1044 1051 user: test
1045 1052 date: Thu Jan 01 00:00:00 1970 +0000
1046 1053 summary: commit on default
1047 1054
1048 1055 #if gettext
1049 1056
1050 1057 Test that all log names are translated (e.g. branches, bookmarks, tags):
1051 1058
1052 1059 $ hg bookmark babar -r tip
1053 1060
1054 1061 $ HGENCODING=UTF-8 LANGUAGE=de hg log -r tip
1055 1062 \xc3\x84nderung: 3:f5d8de11c2e2 (esc)
1056 1063 Zweig: test
1057 1064 Lesezeichen: babar
1058 1065 Marke: tip
1059 1066 Vorg\xc3\xa4nger: 1:d32277701ccb (esc)
1060 1067 Nutzer: test
1061 1068 Datum: Thu Jan 01 00:00:00 1970 +0000
1062 1069 Zusammenfassung: commit on test
1063 1070
1064 1071 $ hg bookmark -d babar
1065 1072
1066 1073 #endif
1067 1074
1068 1075 log -p --cwd dir (in subdir)
1069 1076
1070 1077 $ mkdir dir
1071 1078 $ hg log -p --cwd dir
1072 1079 changeset: 3:f5d8de11c2e2
1073 1080 branch: test
1074 1081 tag: tip
1075 1082 parent: 1:d32277701ccb
1076 1083 user: test
1077 1084 date: Thu Jan 01 00:00:00 1970 +0000
1078 1085 summary: commit on test
1079 1086
1080 1087 diff -r d32277701ccb -r f5d8de11c2e2 c
1081 1088 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1082 1089 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1083 1090 @@ -0,0 +1,1 @@
1084 1091 +c
1085 1092
1086 1093 changeset: 2:c3a4f03cc9a7
1087 1094 parent: 0:24427303d56f
1088 1095 user: test
1089 1096 date: Thu Jan 01 00:00:00 1970 +0000
1090 1097 summary: commit on default
1091 1098
1092 1099 diff -r 24427303d56f -r c3a4f03cc9a7 c
1093 1100 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1094 1101 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1095 1102 @@ -0,0 +1,1 @@
1096 1103 +c
1097 1104
1098 1105 changeset: 1:d32277701ccb
1099 1106 branch: test
1100 1107 user: test
1101 1108 date: Thu Jan 01 00:00:00 1970 +0000
1102 1109 summary: commit on test
1103 1110
1104 1111 diff -r 24427303d56f -r d32277701ccb b
1105 1112 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1106 1113 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1107 1114 @@ -0,0 +1,1 @@
1108 1115 +b
1109 1116
1110 1117 changeset: 0:24427303d56f
1111 1118 user: test
1112 1119 date: Thu Jan 01 00:00:00 1970 +0000
1113 1120 summary: commit on default
1114 1121
1115 1122 diff -r 000000000000 -r 24427303d56f a
1116 1123 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1117 1124 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1118 1125 @@ -0,0 +1,1 @@
1119 1126 +a
1120 1127
1121 1128
1122 1129
1123 1130 log -p -R repo
1124 1131
1125 1132 $ cd dir
1126 1133 $ hg log -p -R .. ../a
1127 1134 changeset: 0:24427303d56f
1128 1135 user: test
1129 1136 date: Thu Jan 01 00:00:00 1970 +0000
1130 1137 summary: commit on default
1131 1138
1132 1139 diff -r 000000000000 -r 24427303d56f a
1133 1140 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1134 1141 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1135 1142 @@ -0,0 +1,1 @@
1136 1143 +a
1137 1144
1138 1145
1139 1146 $ cd ../..
1140 1147
1141 1148 $ hg init follow2
1142 1149 $ cd follow2
1143 1150
1144 1151 # Build the following history:
1145 1152 # tip - o - x - o - x - x
1146 1153 # \ /
1147 1154 # o - o - o - x
1148 1155 # \ /
1149 1156 # o
1150 1157 #
1151 1158 # Where "o" is a revision containing "foo" and
1152 1159 # "x" is a revision without "foo"
1153 1160
1154 1161 $ touch init
1155 1162 $ hg ci -A -m "init, unrelated"
1156 1163 adding init
1157 1164 $ echo 'foo' > init
1158 1165 $ hg ci -m "change, unrelated"
1159 1166 $ echo 'foo' > foo
1160 1167 $ hg ci -A -m "add unrelated old foo"
1161 1168 adding foo
1162 1169 $ hg rm foo
1163 1170 $ hg ci -m "delete foo, unrelated"
1164 1171 $ echo 'related' > foo
1165 1172 $ hg ci -A -m "add foo, related"
1166 1173 adding foo
1167 1174
1168 1175 $ hg up 0
1169 1176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1170 1177 $ touch branch
1171 1178 $ hg ci -A -m "first branch, unrelated"
1172 1179 adding branch
1173 1180 created new head
1174 1181 $ touch foo
1175 1182 $ hg ci -A -m "create foo, related"
1176 1183 adding foo
1177 1184 $ echo 'change' > foo
1178 1185 $ hg ci -m "change foo, related"
1179 1186
1180 1187 $ hg up 6
1181 1188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1182 1189 $ echo 'change foo in branch' > foo
1183 1190 $ hg ci -m "change foo in branch, related"
1184 1191 created new head
1185 1192 $ hg merge 7
1186 1193 merging foo
1187 1194 warning: conflicts during merge.
1188 1195 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1189 1196 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1190 1197 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1191 1198 [1]
1192 1199 $ echo 'merge 1' > foo
1193 1200 $ hg resolve -m foo
1194 1201 (no more unresolved files)
1195 1202 $ hg ci -m "First merge, related"
1196 1203
1197 1204 $ hg merge 4
1198 1205 merging foo
1199 1206 warning: conflicts during merge.
1200 1207 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
1201 1208 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1202 1209 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1203 1210 [1]
1204 1211 $ echo 'merge 2' > foo
1205 1212 $ hg resolve -m foo
1206 1213 (no more unresolved files)
1207 1214 $ hg ci -m "Last merge, related"
1208 1215
1209 1216 $ hg log --graph
1210 1217 @ changeset: 10:4dae8563d2c5
1211 1218 |\ tag: tip
1212 1219 | | parent: 9:7b35701b003e
1213 1220 | | parent: 4:88176d361b69
1214 1221 | | user: test
1215 1222 | | date: Thu Jan 01 00:00:00 1970 +0000
1216 1223 | | summary: Last merge, related
1217 1224 | |
1218 1225 | o changeset: 9:7b35701b003e
1219 1226 | |\ parent: 8:e5416ad8a855
1220 1227 | | | parent: 7:87fe3144dcfa
1221 1228 | | | user: test
1222 1229 | | | date: Thu Jan 01 00:00:00 1970 +0000
1223 1230 | | | summary: First merge, related
1224 1231 | | |
1225 1232 | | o changeset: 8:e5416ad8a855
1226 1233 | | | parent: 6:dc6c325fe5ee
1227 1234 | | | user: test
1228 1235 | | | date: Thu Jan 01 00:00:00 1970 +0000
1229 1236 | | | summary: change foo in branch, related
1230 1237 | | |
1231 1238 | o | changeset: 7:87fe3144dcfa
1232 1239 | |/ user: test
1233 1240 | | date: Thu Jan 01 00:00:00 1970 +0000
1234 1241 | | summary: change foo, related
1235 1242 | |
1236 1243 | o changeset: 6:dc6c325fe5ee
1237 1244 | | user: test
1238 1245 | | date: Thu Jan 01 00:00:00 1970 +0000
1239 1246 | | summary: create foo, related
1240 1247 | |
1241 1248 | o changeset: 5:73db34516eb9
1242 1249 | | parent: 0:e87515fd044a
1243 1250 | | user: test
1244 1251 | | date: Thu Jan 01 00:00:00 1970 +0000
1245 1252 | | summary: first branch, unrelated
1246 1253 | |
1247 1254 o | changeset: 4:88176d361b69
1248 1255 | | user: test
1249 1256 | | date: Thu Jan 01 00:00:00 1970 +0000
1250 1257 | | summary: add foo, related
1251 1258 | |
1252 1259 o | changeset: 3:dd78ae4afb56
1253 1260 | | user: test
1254 1261 | | date: Thu Jan 01 00:00:00 1970 +0000
1255 1262 | | summary: delete foo, unrelated
1256 1263 | |
1257 1264 o | changeset: 2:c4c64aedf0f7
1258 1265 | | user: test
1259 1266 | | date: Thu Jan 01 00:00:00 1970 +0000
1260 1267 | | summary: add unrelated old foo
1261 1268 | |
1262 1269 o | changeset: 1:e5faa7440653
1263 1270 |/ user: test
1264 1271 | date: Thu Jan 01 00:00:00 1970 +0000
1265 1272 | summary: change, unrelated
1266 1273 |
1267 1274 o changeset: 0:e87515fd044a
1268 1275 user: test
1269 1276 date: Thu Jan 01 00:00:00 1970 +0000
1270 1277 summary: init, unrelated
1271 1278
1272 1279
1273 1280 $ hg --traceback log -f foo
1274 1281 changeset: 10:4dae8563d2c5
1275 1282 tag: tip
1276 1283 parent: 9:7b35701b003e
1277 1284 parent: 4:88176d361b69
1278 1285 user: test
1279 1286 date: Thu Jan 01 00:00:00 1970 +0000
1280 1287 summary: Last merge, related
1281 1288
1282 1289 changeset: 9:7b35701b003e
1283 1290 parent: 8:e5416ad8a855
1284 1291 parent: 7:87fe3144dcfa
1285 1292 user: test
1286 1293 date: Thu Jan 01 00:00:00 1970 +0000
1287 1294 summary: First merge, related
1288 1295
1289 1296 changeset: 8:e5416ad8a855
1290 1297 parent: 6:dc6c325fe5ee
1291 1298 user: test
1292 1299 date: Thu Jan 01 00:00:00 1970 +0000
1293 1300 summary: change foo in branch, related
1294 1301
1295 1302 changeset: 7:87fe3144dcfa
1296 1303 user: test
1297 1304 date: Thu Jan 01 00:00:00 1970 +0000
1298 1305 summary: change foo, related
1299 1306
1300 1307 changeset: 6:dc6c325fe5ee
1301 1308 user: test
1302 1309 date: Thu Jan 01 00:00:00 1970 +0000
1303 1310 summary: create foo, related
1304 1311
1305 1312 changeset: 4:88176d361b69
1306 1313 user: test
1307 1314 date: Thu Jan 01 00:00:00 1970 +0000
1308 1315 summary: add foo, related
1309 1316
1310 1317
1311 1318 Also check when maxrev < lastrevfilelog
1312 1319
1313 1320 $ hg --traceback log -f -r4 foo
1314 1321 changeset: 4:88176d361b69
1315 1322 user: test
1316 1323 date: Thu Jan 01 00:00:00 1970 +0000
1317 1324 summary: add foo, related
1318 1325
1319 1326 $ cd ..
1320 1327
1321 1328 Issue2383: hg log showing _less_ differences than hg diff
1322 1329
1323 1330 $ hg init issue2383
1324 1331 $ cd issue2383
1325 1332
1326 1333 Create a test repo:
1327 1334
1328 1335 $ echo a > a
1329 1336 $ hg ci -Am0
1330 1337 adding a
1331 1338 $ echo b > b
1332 1339 $ hg ci -Am1
1333 1340 adding b
1334 1341 $ hg co 0
1335 1342 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1336 1343 $ echo b > a
1337 1344 $ hg ci -m2
1338 1345 created new head
1339 1346
1340 1347 Merge:
1341 1348
1342 1349 $ hg merge
1343 1350 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1344 1351 (branch merge, don't forget to commit)
1345 1352
1346 1353 Make sure there's a file listed in the merge to trigger the bug:
1347 1354
1348 1355 $ echo c > a
1349 1356 $ hg ci -m3
1350 1357
1351 1358 Two files shown here in diff:
1352 1359
1353 1360 $ hg diff --rev 2:3
1354 1361 diff -r b09be438c43a -r 8e07aafe1edc a
1355 1362 --- a/a Thu Jan 01 00:00:00 1970 +0000
1356 1363 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1357 1364 @@ -1,1 +1,1 @@
1358 1365 -b
1359 1366 +c
1360 1367 diff -r b09be438c43a -r 8e07aafe1edc b
1361 1368 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1362 1369 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1363 1370 @@ -0,0 +1,1 @@
1364 1371 +b
1365 1372
1366 1373 Diff here should be the same:
1367 1374
1368 1375 $ hg log -vpr 3
1369 1376 changeset: 3:8e07aafe1edc
1370 1377 tag: tip
1371 1378 parent: 2:b09be438c43a
1372 1379 parent: 1:925d80f479bb
1373 1380 user: test
1374 1381 date: Thu Jan 01 00:00:00 1970 +0000
1375 1382 files: a
1376 1383 description:
1377 1384 3
1378 1385
1379 1386
1380 1387 diff -r b09be438c43a -r 8e07aafe1edc a
1381 1388 --- a/a Thu Jan 01 00:00:00 1970 +0000
1382 1389 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1383 1390 @@ -1,1 +1,1 @@
1384 1391 -b
1385 1392 +c
1386 1393 diff -r b09be438c43a -r 8e07aafe1edc b
1387 1394 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1388 1395 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1389 1396 @@ -0,0 +1,1 @@
1390 1397 +b
1391 1398
1392 1399 $ cd ..
1393 1400
1394 1401 'hg log -r rev fn' when last(filelog(fn)) != rev
1395 1402
1396 1403 $ hg init simplelog
1397 1404 $ cd simplelog
1398 1405 $ echo f > a
1399 1406 $ hg ci -Am'a' -d '0 0'
1400 1407 adding a
1401 1408 $ echo f >> a
1402 1409 $ hg ci -Am'a bis' -d '1 0'
1403 1410
1404 1411 $ hg log -r0 a
1405 1412 changeset: 0:9f758d63dcde
1406 1413 user: test
1407 1414 date: Thu Jan 01 00:00:00 1970 +0000
1408 1415 summary: a
1409 1416
1410 1417 enable obsolete to test hidden feature
1411 1418
1412 1419 $ cat >> $HGRCPATH << EOF
1413 1420 > [experimental]
1414 1421 > evolution=createmarkers
1415 1422 > EOF
1416 1423
1417 1424 $ hg log --template='{rev}:{node}\n'
1418 1425 1:a765632148dc55d38c35c4f247c618701886cb2f
1419 1426 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1420 1427 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1421 1428 $ hg up null -q
1422 1429 $ hg log --template='{rev}:{node}\n'
1423 1430 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1424 1431 $ hg log --template='{rev}:{node}\n' --hidden
1425 1432 1:a765632148dc55d38c35c4f247c618701886cb2f
1426 1433 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1427 1434 $ hg log -r a
1428 1435 abort: hidden revision 'a'!
1429 1436 (use --hidden to access hidden revisions)
1430 1437 [255]
1431 1438
1432 1439 test that parent prevent a changeset to be hidden
1433 1440
1434 1441 $ hg up 1 -q --hidden
1435 1442 $ hg log --template='{rev}:{node}\n'
1436 1443 1:a765632148dc55d38c35c4f247c618701886cb2f
1437 1444 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1438 1445
1439 1446 test that second parent prevent a changeset to be hidden too
1440 1447
1441 1448 $ hg debugsetparents 0 1 # nothing suitable to merge here
1442 1449 $ hg log --template='{rev}:{node}\n'
1443 1450 1:a765632148dc55d38c35c4f247c618701886cb2f
1444 1451 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1445 1452 $ hg debugsetparents 1
1446 1453 $ hg up -q null
1447 1454
1448 1455 bookmarks prevent a changeset being hidden
1449 1456
1450 1457 $ hg bookmark --hidden -r 1 X
1451 1458 $ hg log --template '{rev}:{node}\n'
1452 1459 1:a765632148dc55d38c35c4f247c618701886cb2f
1453 1460 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1454 1461 $ hg bookmark -d X
1455 1462
1456 1463 divergent bookmarks are not hidden
1457 1464
1458 1465 $ hg bookmark --hidden -r 1 X@foo
1459 1466 $ hg log --template '{rev}:{node}\n'
1460 1467 1:a765632148dc55d38c35c4f247c618701886cb2f
1461 1468 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1462 1469
1463 1470 clear extensions configuration
1464 1471 $ echo '[extensions]' >> $HGRCPATH
1465 1472 $ echo "obs=!" >> $HGRCPATH
1466 1473 $ cd ..
1467 1474
1468 1475 test -u/-k for problematic encoding
1469 1476 # unicode: cp932:
1470 1477 # u30A2 0x83 0x41(= 'A')
1471 1478 # u30C2 0x83 0x61(= 'a')
1472 1479
1473 1480 $ hg init problematicencoding
1474 1481 $ cd problematicencoding
1475 1482
1476 1483 $ python > setup.sh <<EOF
1477 1484 > print u'''
1478 1485 > echo a > text
1479 1486 > hg add text
1480 1487 > hg --encoding utf-8 commit -u '\u30A2' -m none
1481 1488 > echo b > text
1482 1489 > hg --encoding utf-8 commit -u '\u30C2' -m none
1483 1490 > echo c > text
1484 1491 > hg --encoding utf-8 commit -u none -m '\u30A2'
1485 1492 > echo d > text
1486 1493 > hg --encoding utf-8 commit -u none -m '\u30C2'
1487 1494 > '''.encode('utf-8')
1488 1495 > EOF
1489 1496 $ sh < setup.sh
1490 1497
1491 1498 test in problematic encoding
1492 1499 $ python > test.sh <<EOF
1493 1500 > print u'''
1494 1501 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1495 1502 > echo ====
1496 1503 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1497 1504 > echo ====
1498 1505 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1499 1506 > echo ====
1500 1507 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1501 1508 > '''.encode('cp932')
1502 1509 > EOF
1503 1510 $ sh < test.sh
1504 1511 0
1505 1512 ====
1506 1513 1
1507 1514 ====
1508 1515 2
1509 1516 0
1510 1517 ====
1511 1518 3
1512 1519 1
1513 1520
1514 1521 $ cd ..
1515 1522
1516 1523 test hg log on non-existent files and on directories
1517 1524 $ hg init issue1340
1518 1525 $ cd issue1340
1519 1526 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1520 1527 $ echo 1 > d1/f1
1521 1528 $ echo 1 > D2/f1
1522 1529 $ echo 1 > D3.i/f1
1523 1530 $ echo 1 > d4.hg/f1
1524 1531 $ echo 1 > d5.d/f1
1525 1532 $ echo 1 > .d6/f1
1526 1533 $ hg -q add .
1527 1534 $ hg commit -m "a bunch of weird directories"
1528 1535 $ hg log -l1 d1/f1 | grep changeset
1529 1536 changeset: 0:65624cd9070a
1530 1537 $ hg log -l1 f1
1531 1538 $ hg log -l1 . | grep changeset
1532 1539 changeset: 0:65624cd9070a
1533 1540 $ hg log -l1 ./ | grep changeset
1534 1541 changeset: 0:65624cd9070a
1535 1542 $ hg log -l1 d1 | grep changeset
1536 1543 changeset: 0:65624cd9070a
1537 1544 $ hg log -l1 D2 | grep changeset
1538 1545 changeset: 0:65624cd9070a
1539 1546 $ hg log -l1 D2/f1 | grep changeset
1540 1547 changeset: 0:65624cd9070a
1541 1548 $ hg log -l1 D3.i | grep changeset
1542 1549 changeset: 0:65624cd9070a
1543 1550 $ hg log -l1 D3.i/f1 | grep changeset
1544 1551 changeset: 0:65624cd9070a
1545 1552 $ hg log -l1 d4.hg | grep changeset
1546 1553 changeset: 0:65624cd9070a
1547 1554 $ hg log -l1 d4.hg/f1 | grep changeset
1548 1555 changeset: 0:65624cd9070a
1549 1556 $ hg log -l1 d5.d | grep changeset
1550 1557 changeset: 0:65624cd9070a
1551 1558 $ hg log -l1 d5.d/f1 | grep changeset
1552 1559 changeset: 0:65624cd9070a
1553 1560 $ hg log -l1 .d6 | grep changeset
1554 1561 changeset: 0:65624cd9070a
1555 1562 $ hg log -l1 .d6/f1 | grep changeset
1556 1563 changeset: 0:65624cd9070a
1557 1564
1558 1565 issue3772: hg log -r :null showing revision 0 as well
1559 1566
1560 1567 $ hg log -r :null
1561 1568 changeset: 0:65624cd9070a
1562 1569 tag: tip
1563 1570 user: test
1564 1571 date: Thu Jan 01 00:00:00 1970 +0000
1565 1572 summary: a bunch of weird directories
1566 1573
1567 1574 changeset: -1:000000000000
1568 1575 user:
1569 1576 date: Thu Jan 01 00:00:00 1970 +0000
1570 1577
1571 1578 $ hg log -r null:null
1572 1579 changeset: -1:000000000000
1573 1580 user:
1574 1581 date: Thu Jan 01 00:00:00 1970 +0000
1575 1582
1576 1583 Check that adding an arbitrary name shows up in log automatically
1577 1584
1578 1585 $ cat > ../names.py <<EOF
1579 1586 > """A small extension to test adding arbitrary names to a repo"""
1580 1587 > from mercurial.namespaces import namespace
1581 1588 >
1582 1589 > def reposetup(ui, repo):
1583 1590 > foo = {'foo': repo[0].node()}
1584 1591 > names = lambda r: foo.keys()
1585 1592 > namemap = lambda r, name: foo.get(name)
1586 1593 > nodemap = lambda r, node: [name for name, n in foo.iteritems()
1587 1594 > if n == node]
1588 1595 > ns = namespace("bars", templatename="bar", logname="barlog",
1589 1596 > colorname="barcolor", listnames=names, namemap=namemap,
1590 1597 > nodemap=nodemap)
1591 1598 >
1592 1599 > repo.names.addnamespace(ns)
1593 1600 > EOF
1594 1601
1595 1602 $ hg --config extensions.names=../names.py log -r 0
1596 1603 changeset: 0:65624cd9070a
1597 1604 tag: tip
1598 1605 barlog: foo
1599 1606 user: test
1600 1607 date: Thu Jan 01 00:00:00 1970 +0000
1601 1608 summary: a bunch of weird directories
1602 1609
1603 1610 $ hg --config extensions.names=../names.py \
1604 1611 > --config extensions.color= --config color.log.barcolor=red \
1605 1612 > --color=always log -r 0
1606 1613 \x1b[0;33mchangeset: 0:65624cd9070a\x1b[0m (esc)
1607 1614 tag: tip
1608 1615 \x1b[0;31mbarlog: foo\x1b[0m (esc)
1609 1616 user: test
1610 1617 date: Thu Jan 01 00:00:00 1970 +0000
1611 1618 summary: a bunch of weird directories
1612 1619
1613 1620 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
1614 1621 foo
1615 1622
1616 1623 $ cd ..
1617 1624
1618 1625 hg log -f dir across branches
1619 1626
1620 1627 $ hg init acrossbranches
1621 1628 $ cd acrossbranches
1622 1629 $ mkdir d
1623 1630 $ echo a > d/a && hg ci -Aqm a
1624 1631 $ echo b > d/a && hg ci -Aqm b
1625 1632 $ hg up -q 0
1626 1633 $ echo b > d/a && hg ci -Aqm c
1627 1634 $ hg log -f d -T '{desc}' -G
1628 1635 @ c
1629 1636 |
1630 1637 o a
1631 1638
1639 Ensure that largefiles doesn't intefere with following a normal file
1640 $ hg --config extensions.largefiles= log -f d -T '{desc}' -G
1641 @ c
1642 |
1643 o a
1644
1632 1645 $ hg log -f d/a -T '{desc}' -G
1633 1646 @ c
1634 1647 |
1635 1648 o a
1636 1649
1637 1650 $ cd ..
1638 1651
1639 1652 hg log -f with linkrev pointing to another branch
1640 1653 -------------------------------------------------
1641 1654
1642 1655 create history with a filerev whose linkrev points to another branch
1643 1656
1644 1657 $ hg init branchedlinkrev
1645 1658 $ cd branchedlinkrev
1646 1659 $ echo 1 > a
1647 1660 $ hg commit -Am 'content1'
1648 1661 adding a
1649 1662 $ echo 2 > a
1650 1663 $ hg commit -m 'content2'
1651 1664 $ hg up --rev 'desc(content1)'
1652 1665 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1653 1666 $ echo unrelated > unrelated
1654 1667 $ hg commit -Am 'unrelated'
1655 1668 adding unrelated
1656 1669 created new head
1657 1670 $ hg graft -r 'desc(content2)'
1658 1671 grafting 1:2294ae80ad84 "content2"
1659 1672 $ echo 3 > a
1660 1673 $ hg commit -m 'content3'
1661 1674 $ hg log -G
1662 1675 @ changeset: 4:50b9b36e9c5d
1663 1676 | tag: tip
1664 1677 | user: test
1665 1678 | date: Thu Jan 01 00:00:00 1970 +0000
1666 1679 | summary: content3
1667 1680 |
1668 1681 o changeset: 3:15b2327059e5
1669 1682 | user: test
1670 1683 | date: Thu Jan 01 00:00:00 1970 +0000
1671 1684 | summary: content2
1672 1685 |
1673 1686 o changeset: 2:2029acd1168c
1674 1687 | parent: 0:ae0a3c9f9e95
1675 1688 | user: test
1676 1689 | date: Thu Jan 01 00:00:00 1970 +0000
1677 1690 | summary: unrelated
1678 1691 |
1679 1692 | o changeset: 1:2294ae80ad84
1680 1693 |/ user: test
1681 1694 | date: Thu Jan 01 00:00:00 1970 +0000
1682 1695 | summary: content2
1683 1696 |
1684 1697 o changeset: 0:ae0a3c9f9e95
1685 1698 user: test
1686 1699 date: Thu Jan 01 00:00:00 1970 +0000
1687 1700 summary: content1
1688 1701
1689 1702
1690 1703 log -f on the file should list the graft result.
1691 1704
1692 1705 $ hg log -Gf a
1693 1706 @ changeset: 4:50b9b36e9c5d
1694 1707 | tag: tip
1695 1708 | user: test
1696 1709 | date: Thu Jan 01 00:00:00 1970 +0000
1697 1710 | summary: content3
1698 1711 |
1699 1712 o changeset: 3:15b2327059e5
1700 1713 | user: test
1701 1714 | date: Thu Jan 01 00:00:00 1970 +0000
1702 1715 | summary: content2
1703 1716 |
1704 1717 o changeset: 0:ae0a3c9f9e95
1705 1718 user: test
1706 1719 date: Thu Jan 01 00:00:00 1970 +0000
1707 1720 summary: content1
1708 1721
1709 1722
1710 1723 plain log lists the original version
1711 1724 (XXX we should probably list both)
1712 1725
1713 1726 $ hg log -G a
1714 1727 @ changeset: 4:50b9b36e9c5d
1715 1728 | tag: tip
1716 1729 | user: test
1717 1730 | date: Thu Jan 01 00:00:00 1970 +0000
1718 1731 | summary: content3
1719 1732 |
1720 1733 | o changeset: 1:2294ae80ad84
1721 1734 |/ user: test
1722 1735 | date: Thu Jan 01 00:00:00 1970 +0000
1723 1736 | summary: content2
1724 1737 |
1725 1738 o changeset: 0:ae0a3c9f9e95
1726 1739 user: test
1727 1740 date: Thu Jan 01 00:00:00 1970 +0000
1728 1741 summary: content1
1729 1742
1730 1743
1731 1744 hg log -f from the grafted changeset
1732 1745 (The bootstrap should properly take the topology in account)
1733 1746
1734 1747 $ hg up 'desc(content3)^'
1735 1748 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1736 1749 $ hg log -Gf a
1737 1750 @ changeset: 3:15b2327059e5
1738 1751 | user: test
1739 1752 | date: Thu Jan 01 00:00:00 1970 +0000
1740 1753 | summary: content2
1741 1754 |
1742 1755 o changeset: 0:ae0a3c9f9e95
1743 1756 user: test
1744 1757 date: Thu Jan 01 00:00:00 1970 +0000
1745 1758 summary: content1
1746 1759
1747 1760
1748 1761 Test that we use the first non-hidden changeset in that case.
1749 1762
1750 1763 (hide the changeset)
1751 1764
1752 1765 $ hg log -T '{node}\n' -r 1
1753 1766 2294ae80ad8447bc78383182eeac50cb049df623
1754 1767 $ hg debugobsolete 2294ae80ad8447bc78383182eeac50cb049df623
1755 1768 $ hg log -G
1756 1769 o changeset: 4:50b9b36e9c5d
1757 1770 | tag: tip
1758 1771 | user: test
1759 1772 | date: Thu Jan 01 00:00:00 1970 +0000
1760 1773 | summary: content3
1761 1774 |
1762 1775 @ changeset: 3:15b2327059e5
1763 1776 | user: test
1764 1777 | date: Thu Jan 01 00:00:00 1970 +0000
1765 1778 | summary: content2
1766 1779 |
1767 1780 o changeset: 2:2029acd1168c
1768 1781 | parent: 0:ae0a3c9f9e95
1769 1782 | user: test
1770 1783 | date: Thu Jan 01 00:00:00 1970 +0000
1771 1784 | summary: unrelated
1772 1785 |
1773 1786 o changeset: 0:ae0a3c9f9e95
1774 1787 user: test
1775 1788 date: Thu Jan 01 00:00:00 1970 +0000
1776 1789 summary: content1
1777 1790
1778 1791
1779 1792 Check that log on the file does not drop the file revision.
1780 1793
1781 1794 $ hg log -G a
1782 1795 o changeset: 4:50b9b36e9c5d
1783 1796 | tag: tip
1784 1797 | user: test
1785 1798 | date: Thu Jan 01 00:00:00 1970 +0000
1786 1799 | summary: content3
1787 1800 |
1788 1801 @ changeset: 3:15b2327059e5
1789 1802 | user: test
1790 1803 | date: Thu Jan 01 00:00:00 1970 +0000
1791 1804 | summary: content2
1792 1805 |
1793 1806 o changeset: 0:ae0a3c9f9e95
1794 1807 user: test
1795 1808 date: Thu Jan 01 00:00:00 1970 +0000
1796 1809 summary: content1
1797 1810
1798 1811
1799 1812 Even when a head revision is linkrev-shadowed.
1800 1813
1801 1814 $ hg log -T '{node}\n' -r 4
1802 1815 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1803 1816 $ hg debugobsolete 50b9b36e9c5df2c6fc6dcefa8ad0da929e84aed2
1804 1817 $ hg log -G a
1805 1818 @ changeset: 3:15b2327059e5
1806 1819 | tag: tip
1807 1820 | user: test
1808 1821 | date: Thu Jan 01 00:00:00 1970 +0000
1809 1822 | summary: content2
1810 1823 |
1811 1824 o changeset: 0:ae0a3c9f9e95
1812 1825 user: test
1813 1826 date: Thu Jan 01 00:00:00 1970 +0000
1814 1827 summary: content1
1815 1828
1816 1829
1817 1830 $ cd ..
1818 1831
1819 1832 Even when the file revision is missing from some head:
1820 1833
1821 1834 $ hg init issue4490
1822 1835 $ cd issue4490
1823 1836 $ echo '[experimental]' >> .hg/hgrc
1824 1837 $ echo 'evolution=createmarkers' >> .hg/hgrc
1825 1838 $ echo a > a
1826 1839 $ hg ci -Am0
1827 1840 adding a
1828 1841 $ echo b > b
1829 1842 $ hg ci -Am1
1830 1843 adding b
1831 1844 $ echo B > b
1832 1845 $ hg ci --amend -m 1
1833 1846 $ hg up 0
1834 1847 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1835 1848 $ echo c > c
1836 1849 $ hg ci -Am2
1837 1850 adding c
1838 1851 created new head
1839 1852 $ hg up 'head() and not .'
1840 1853 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1841 1854 $ hg log -G
1842 1855 o changeset: 4:db815d6d32e6
1843 1856 | tag: tip
1844 1857 | parent: 0:f7b1eb17ad24
1845 1858 | user: test
1846 1859 | date: Thu Jan 01 00:00:00 1970 +0000
1847 1860 | summary: 2
1848 1861 |
1849 1862 | @ changeset: 3:9bc8ce7f9356
1850 1863 |/ parent: 0:f7b1eb17ad24
1851 1864 | user: test
1852 1865 | date: Thu Jan 01 00:00:00 1970 +0000
1853 1866 | summary: 1
1854 1867 |
1855 1868 o changeset: 0:f7b1eb17ad24
1856 1869 user: test
1857 1870 date: Thu Jan 01 00:00:00 1970 +0000
1858 1871 summary: 0
1859 1872
1860 1873 $ hg log -f -G b
1861 1874 @ changeset: 3:9bc8ce7f9356
1862 1875 | parent: 0:f7b1eb17ad24
1863 1876 | user: test
1864 1877 | date: Thu Jan 01 00:00:00 1970 +0000
1865 1878 | summary: 1
1866 1879 |
1867 1880 $ hg log -G b
1868 1881 @ changeset: 3:9bc8ce7f9356
1869 1882 | parent: 0:f7b1eb17ad24
1870 1883 | user: test
1871 1884 | date: Thu Jan 01 00:00:00 1970 +0000
1872 1885 | summary: 1
1873 1886 |
1874 1887 $ cd ..
1875 1888
1876 1889 Check proper report when the manifest changes but not the file issue4499
1877 1890 ------------------------------------------------------------------------
1878 1891
1879 1892 $ hg init issue4499
1880 1893 $ cd issue4499
1881 1894 $ for f in A B C D F E G H I J K L M N O P Q R S T U; do
1882 1895 > echo 1 > $f;
1883 1896 > hg add $f;
1884 1897 > done
1885 1898 $ hg commit -m 'A1B1C1'
1886 1899 $ echo 2 > A
1887 1900 $ echo 2 > B
1888 1901 $ echo 2 > C
1889 1902 $ hg commit -m 'A2B2C2'
1890 1903 $ hg up 0
1891 1904 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1892 1905 $ echo 3 > A
1893 1906 $ echo 2 > B
1894 1907 $ echo 2 > C
1895 1908 $ hg commit -m 'A3B2C2'
1896 1909 created new head
1897 1910
1898 1911 $ hg log -G
1899 1912 @ changeset: 2:fe5fc3d0eb17
1900 1913 | tag: tip
1901 1914 | parent: 0:abf4f0e38563
1902 1915 | user: test
1903 1916 | date: Thu Jan 01 00:00:00 1970 +0000
1904 1917 | summary: A3B2C2
1905 1918 |
1906 1919 | o changeset: 1:07dcc6b312c0
1907 1920 |/ user: test
1908 1921 | date: Thu Jan 01 00:00:00 1970 +0000
1909 1922 | summary: A2B2C2
1910 1923 |
1911 1924 o changeset: 0:abf4f0e38563
1912 1925 user: test
1913 1926 date: Thu Jan 01 00:00:00 1970 +0000
1914 1927 summary: A1B1C1
1915 1928
1916 1929
1917 1930 Log -f on B should reports current changesets
1918 1931
1919 1932 $ hg log -fG B
1920 1933 @ changeset: 2:fe5fc3d0eb17
1921 1934 | tag: tip
1922 1935 | parent: 0:abf4f0e38563
1923 1936 | user: test
1924 1937 | date: Thu Jan 01 00:00:00 1970 +0000
1925 1938 | summary: A3B2C2
1926 1939 |
1927 1940 o changeset: 0:abf4f0e38563
1928 1941 user: test
1929 1942 date: Thu Jan 01 00:00:00 1970 +0000
1930 1943 summary: A1B1C1
1931 1944
1932 1945 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now