# HG changeset patch # User Patrick Mezard # Date 2012-02-25 21:11:36 # Node ID 9178d284b880efde10eca117cbdeeffd2c6d055c # Parent db75321c7a0e351d94d27779342c88daa7f5d4a0 graphlog: implement --follow with file arguments diff --git a/hgext/graphlog.py b/hgext/graphlog.py --- a/hgext/graphlog.py +++ b/hgext/graphlog.py @@ -241,9 +241,6 @@ def check_unsupported_flags(pats, opts): if op in opts and opts[op]: raise util.Abort(_("-G/--graph option is incompatible with --%s") % op.replace("_", "-")) - if pats and opts.get('follow'): - raise util.Abort(_("-G/--graph option is incompatible with --follow " - "with file argument")) def revset(repo, pats, opts): """Return revset str built of revisions, log options and file patterns. @@ -256,6 +253,7 @@ def revset(repo, pats, opts): 'date': ('date(%(val)r)', None), 'branch': ('branch(%(val)r)', ' or '), '_patslog': ('filelog(%(val)r)', ' or '), + '_patsfollow': ('follow(%(val)r)', ' or '), 'keyword': ('keyword(%(val)r)', ' or '), 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), 'user': ('user(%(val)r)', ' or '), @@ -268,22 +266,35 @@ def revset(repo, pats, opts): if 'branch' in opts and 'only_branch' in opts: opts['branch'] = opts['branch'] + opts.pop('only_branch') + follow = opts.get('follow') + if 'follow' in opts: + del opts['follow'] # pats/include/exclude are passed to match.match() directly in # _matchfile() revset but walkchangerevs() builds its matcher with # scmutil.match(). The difference is input pats are globbed on # platforms without shell expansion (windows). - match, pats = scmutil.matchandpats(repo[None], pats, opts) + pctx = repo[None] + match, pats = scmutil.matchandpats(pctx, pats, opts) slowpath = match.anypats() or (match.files() and opts.get('removed')) if not slowpath: for f in match.files(): + if follow and f not in pctx: + raise util.Abort(_('cannot follow file not in parent ' + 'revision: "%s"') % f) filelog = repo.file(f) if not len(filelog): # A zero count may be a directory or deleted file, so # try to find matching entries on the slow path. + if follow: + raise util.Abort( + _('cannot follow nonexistent file: "%s"') % f) slowpath = True if slowpath: # See cmdutil.walkchangerevs() slow path. # + if follow: + raise util.Abort(_('can only follow copies/renames for explicit ' + 'filenames')) # pats/include/exclude cannot be represented as separate # revset expressions as their filtering logic applies at file # level. For instance "-I a -X a" matches a revision touching @@ -298,7 +309,13 @@ def revset(repo, pats, opts): matchargs = ','.join(('%r' % p) for p in matchargs) opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs] else: - opts['_patslog'] = list(pats) + if follow: + if pats: + opts['_patsfollow'] = list(pats) + else: + opts['follow'] = True + else: + opts['_patslog'] = list(pats) revset = [] for op, val in opts.iteritems(): diff --git a/tests/test-glog.t b/tests/test-glog.t --- a/tests/test-glog.t +++ b/tests/test-glog.t @@ -1454,8 +1454,6 @@ glog always reorders nodes which explain ('group', ('group', ('or', ('or', ('func', ('symbol', 'branch'), ('string', 'default')), ('func', ('symbol', 'branch'), ('string', 'branch'))), ('func', ('symbol', 'branch'), ('string', 'branch'))))) $ testlog -k expand -k merge ('group', ('group', ('or', ('func', ('symbol', 'keyword'), ('string', 'expand')), ('func', ('symbol', 'keyword'), ('string', 'merge'))))) - $ hg log -G --follow --template 'nodetag {rev}\n' | grep nodetag | wc -l - \s*36 (re) $ hg log -G --removed --template 'nodetag {rev}\n' | grep nodetag | wc -l \s*0 (re) $ hg log -G --only-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l @@ -1492,27 +1490,30 @@ glog always reorders nodes which explain [255] $ testlog --prune 31 --prune 32 ('group', ('group', ('and', ('not', ('group', ('or', ('string', '31'), ('func', ('symbol', 'ancestors'), ('string', '31'))))), ('not', ('group', ('or', ('string', '32'), ('func', ('symbol', 'ancestors'), ('string', '32')))))))) - $ hg log -G --follow a - abort: -G/--graph option is incompatible with --follow with file argument - [255] - -Dedicated repo for --follow and paths filtering +Dedicated repo for --follow and paths filtering. The g is crafted to +have 2 filelog topological heads in a linear changeset graph. $ cd .. $ hg init follow $ cd follow $ echo a > a $ echo aa > aa + $ echo f > f $ hg ci -Am "add a" adding a adding aa + adding f $ hg cp a b + $ hg cp f g $ hg ci -m "copy a b" $ mkdir dir $ hg mv b dir + $ echo g >> g + $ echo f >> f $ hg ci -m "mv b dir/b" $ hg mv a b + $ hg cp -f f g $ echo a > d $ hg add d $ hg ci -m "mv a b; add d" @@ -1555,3 +1556,65 @@ Test glob expansion of pats > testlog a*; > fi; ('group', ('group', ('func', ('symbol', 'filelog'), ('string', 'aa')))) + +Test --follow on a directory + + $ testlog -f dir + abort: cannot follow file not in parent revision: "dir" + abort: cannot follow file not in parent revision: "dir" + abort: cannot follow file not in parent revision: "dir" + +Test --follow on file not in parent revision + + $ testlog -f a + abort: cannot follow file not in parent revision: "a" + abort: cannot follow file not in parent revision: "a" + abort: cannot follow file not in parent revision: "a" + +Test --follow and patterns + + $ testlog -f 'glob:*' + abort: can only follow copies/renames for explicit filenames + abort: can only follow copies/renames for explicit filenames + abort: can only follow copies/renames for explicit filenames + +Test --follow on a single rename + + $ hg up -q 2 + $ testlog -f a + ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'a')))) + +Test --follow and multiple renames + + $ hg up -q tip + $ testlog -f e + ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'e')))) + +Test --follow and multiple filelog heads + + $ hg up -q 2 + $ testlog -f g + ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g')))) + $ cat log.nodes + nodetag 2 + nodetag 1 + nodetag 0 + $ hg up -q tip + $ testlog -f g + ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g')))) + $ cat log.nodes + nodetag 3 + nodetag 2 + nodetag 0 + +Test --follow and multiple files + + $ testlog -f g e + ('group', ('group', ('or', ('func', ('symbol', 'follow'), ('string', 'g')), ('func', ('symbol', 'follow'), ('string', 'e'))))) + $ cat log.nodes + nodetag 4 + nodetag 3 + nodetag 2 + nodetag 1 + nodetag 0 +