mercurial/cmdutil.py
changeset 35686 b25fa5da4ca2
parent 35685 659dfbd852e2
child 35687 67893a516272
equal deleted inserted replaced
35685:659dfbd852e2 35686:b25fa5da4ca2
  2369             else:
  2369             else:
  2370                 slowpath = False
  2370                 slowpath = False
  2371 
  2371 
  2372     return match, pats, slowpath
  2372     return match, pats, slowpath
  2373 
  2373 
       
  2374 def _fileancestors(repo, revs, match, followfirst):
       
  2375     fctxs = []
       
  2376     for r in revs:
       
  2377         ctx = repo[r]
       
  2378         fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
       
  2379     return dagop.filerevancestors(fctxs, followfirst=followfirst)
       
  2380 
  2374 def _makefollowlogfilematcher(repo, files, followfirst):
  2381 def _makefollowlogfilematcher(repo, files, followfirst):
  2375     # When displaying a revision with --patch --follow FILE, we have
  2382     # When displaying a revision with --patch --follow FILE, we have
  2376     # to know which file of the revision must be diffed. With
  2383     # to know which file of the revision must be diffed. With
  2377     # --follow, we want the names of the ancestors of FILE in the
  2384     # --follow, we want the names of the ancestors of FILE in the
  2378     # revision, stored in "fcache". "fcache" is populated by
  2385     # revision, stored in "fcache". "fcache" is populated by
  2404     return None
  2411     return None
  2405 
  2412 
  2406 _opt2logrevset = {
  2413 _opt2logrevset = {
  2407     'no_merges':        ('not merge()', None),
  2414     'no_merges':        ('not merge()', None),
  2408     'only_merges':      ('merge()', None),
  2415     'only_merges':      ('merge()', None),
  2409     '_ancestors':       ('ancestors(%r)', None),
       
  2410     '_fancestors':      ('_firstancestors(%r)', None),
       
  2411     '_matchfiles':      (None, '_matchfiles(%ps)'),
  2416     '_matchfiles':      (None, '_matchfiles(%ps)'),
  2412     'date':             ('date(%s)', None),
  2417     'date':             ('date(%s)', None),
  2413     'branch':           ('branch(%s)', '%lr'),
  2418     'branch':           ('branch(%s)', '%lr'),
  2414     '_patslog':         ('filelog(%s)', '%lr'),
  2419     '_patslog':         ('filelog(%s)', '%lr'),
  2415     '_patsfollow':      ('follow(%s)', '%lr'),
       
  2416     '_patsfollowfirst': ('_followfirst(%s)', '%lr'),
       
  2417     'keyword':          ('keyword(%s)', '%lr'),
  2420     'keyword':          ('keyword(%s)', '%lr'),
  2418     'prune':            ('ancestors(%s)', 'not %lr'),
  2421     'prune':            ('ancestors(%s)', 'not %lr'),
  2419     'user':             ('user(%s)', '%lr'),
  2422     'user':             ('user(%s)', '%lr'),
  2420 }
  2423 }
  2421 
  2424 
  2427     the files to be detailed when displaying the revision.
  2430     the files to be detailed when displaying the revision.
  2428     """
  2431     """
  2429     opts = dict(opts)
  2432     opts = dict(opts)
  2430     # follow or not follow?
  2433     # follow or not follow?
  2431     follow = opts.get('follow') or opts.get('follow_first')
  2434     follow = opts.get('follow') or opts.get('follow_first')
  2432     if opts.get('follow_first'):
       
  2433         followfirst = 1
       
  2434     else:
       
  2435         followfirst = 0
       
  2436 
  2435 
  2437     # branch and only_branch are really aliases and must be handled at
  2436     # branch and only_branch are really aliases and must be handled at
  2438     # the same time
  2437     # the same time
  2439     opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
  2438     opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
  2440     opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
  2439     opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
  2441 
       
  2442     fpats = ('_patsfollow', '_patsfollowfirst')
       
  2443     fnopats = ('_ancestors', '_fancestors')
       
  2444 
  2440 
  2445     if slowpath:
  2441     if slowpath:
  2446         # See walkchangerevs() slow path.
  2442         # See walkchangerevs() slow path.
  2447         #
  2443         #
  2448         # pats/include/exclude cannot be represented as separate
  2444         # pats/include/exclude cannot be represented as separate
  2457         for p in opts.get('include', []):
  2453         for p in opts.get('include', []):
  2458             matchargs.append('i:' + p)
  2454             matchargs.append('i:' + p)
  2459         for p in opts.get('exclude', []):
  2455         for p in opts.get('exclude', []):
  2460             matchargs.append('x:' + p)
  2456             matchargs.append('x:' + p)
  2461         opts['_matchfiles'] = matchargs
  2457         opts['_matchfiles'] = matchargs
  2462         if follow:
  2458     elif not follow:
  2463             opts[fnopats[followfirst]] = '.'
  2459         opts['_patslog'] = list(pats)
  2464     else:
       
  2465         if follow:
       
  2466             if pats:
       
  2467                 # follow() revset interprets its file argument as a
       
  2468                 # manifest entry, so use match.files(), not pats.
       
  2469                 opts[fpats[followfirst]] = list(match.files())
       
  2470             else:
       
  2471                 op = fnopats[followfirst]
       
  2472                 opts[op] = '.'
       
  2473         else:
       
  2474             opts['_patslog'] = list(pats)
       
  2475 
  2460 
  2476     filematcher = None
  2461     filematcher = None
  2477     if opts.get('patch') or opts.get('stat'):
  2462     if opts.get('patch') or opts.get('stat'):
  2478         # When following files, track renames via a special matcher.
  2463         # When following files, track renames via a special matcher.
  2479         # If we're forced to take the slowpath it means we're following
  2464         # If we're forced to take the slowpath it means we're following
  2480         # at least one pattern/directory, so don't bother with rename tracking.
  2465         # at least one pattern/directory, so don't bother with rename tracking.
  2481         if follow and not match.always() and not slowpath:
  2466         if follow and not match.always() and not slowpath:
  2482             # _makefollowlogfilematcher expects its files argument to be
  2467             # _makefollowlogfilematcher expects its files argument to be
  2483             # relative to the repo root, so use match.files(), not pats.
  2468             # relative to the repo root, so use match.files(), not pats.
  2484             filematcher = _makefollowlogfilematcher(repo, match.files(),
  2469             filematcher = _makefollowlogfilematcher(repo, match.files(),
  2485                                                     followfirst)
  2470                                                     opts.get('follow_first'))
  2486         else:
  2471         else:
  2487             filematcher = _makenofollowlogfilematcher(repo, pats, opts)
  2472             filematcher = _makenofollowlogfilematcher(repo, pats, opts)
  2488             if filematcher is None:
  2473             if filematcher is None:
  2489                 filematcher = lambda rev: match
  2474                 filematcher = lambda rev: match
  2490 
  2475 
  2509     else:
  2494     else:
  2510         expr = None
  2495         expr = None
  2511     return expr, filematcher
  2496     return expr, filematcher
  2512 
  2497 
  2513 def _logrevs(repo, opts):
  2498 def _logrevs(repo, opts):
       
  2499     """Return the initial set of revisions to be filtered or followed"""
  2514     follow = opts.get('follow') or opts.get('follow_first')
  2500     follow = opts.get('follow') or opts.get('follow_first')
  2515     if opts.get('rev'):
  2501     if opts.get('rev'):
  2516         revs = scmutil.revrange(repo, opts['rev'])
  2502         revs = scmutil.revrange(repo, opts['rev'])
  2517     elif follow and repo.dirstate.p1() == nullid:
  2503     elif follow and repo.dirstate.p1() == nullid:
  2518         revs = smartset.baseset()
  2504         revs = smartset.baseset()
  2519     elif follow:
  2505     elif follow:
  2520         revs = repo.revs('reverse(:.)')
  2506         revs = repo.revs('.')
  2521     else:
  2507     else:
  2522         revs = smartset.spanset(repo)
  2508         revs = smartset.spanset(repo)
  2523         revs.reverse()
  2509         revs.reverse()
  2524     return revs
  2510     return revs
  2525 
  2511 
  2539     limit = loglimit(opts)
  2525     limit = loglimit(opts)
  2540     revs = _logrevs(repo, opts)
  2526     revs = _logrevs(repo, opts)
  2541     if not revs:
  2527     if not revs:
  2542         return smartset.baseset(), None
  2528         return smartset.baseset(), None
  2543     match, pats, slowpath = _makelogmatcher(repo, pats, opts)
  2529     match, pats, slowpath = _makelogmatcher(repo, pats, opts)
  2544     if opts.get('rev') and follow:
  2530     if follow:
  2545         revs = dagop.revancestors(repo, revs, followfirst=followfirst)
  2531         if opts.get('rev') or slowpath or not pats:
       
  2532             revs = dagop.revancestors(repo, revs, followfirst=followfirst)
       
  2533         else:
       
  2534             revs = _fileancestors(repo, revs, match, followfirst)
  2546         revs.reverse()
  2535         revs.reverse()
  2547     expr, filematcher = _makelogrevset(repo, match, pats, slowpath, opts)
  2536     expr, filematcher = _makelogrevset(repo, match, pats, slowpath, opts)
  2548     if opts.get('graph') and opts.get('rev'):
  2537     if opts.get('graph') and opts.get('rev'):
  2549         # User-specified revs might be unsorted, but don't sort before
  2538         # User-specified revs might be unsorted, but don't sort before
  2550         # _makelogrevset because it might depend on the order of revs
  2539         # _makelogrevset because it might depend on the order of revs