##// END OF EJS Templates
graphlog: implement --follow with file arguments
Patrick Mezard -
r16173:9178d284 default
parent child Browse files
Show More
@@ -241,9 +241,6 b' def check_unsupported_flags(pats, opts):'
241 if op in opts and opts[op]:
241 if op in opts and opts[op]:
242 raise util.Abort(_("-G/--graph option is incompatible with --%s")
242 raise util.Abort(_("-G/--graph option is incompatible with --%s")
243 % op.replace("_", "-"))
243 % op.replace("_", "-"))
244 if pats and opts.get('follow'):
245 raise util.Abort(_("-G/--graph option is incompatible with --follow "
246 "with file argument"))
247
244
248 def revset(repo, pats, opts):
245 def revset(repo, pats, opts):
249 """Return revset str built of revisions, log options and file patterns.
246 """Return revset str built of revisions, log options and file patterns.
@@ -256,6 +253,7 b' def revset(repo, pats, opts):'
256 'date': ('date(%(val)r)', None),
253 'date': ('date(%(val)r)', None),
257 'branch': ('branch(%(val)r)', ' or '),
254 'branch': ('branch(%(val)r)', ' or '),
258 '_patslog': ('filelog(%(val)r)', ' or '),
255 '_patslog': ('filelog(%(val)r)', ' or '),
256 '_patsfollow': ('follow(%(val)r)', ' or '),
259 'keyword': ('keyword(%(val)r)', ' or '),
257 'keyword': ('keyword(%(val)r)', ' or '),
260 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
258 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
261 'user': ('user(%(val)r)', ' or '),
259 'user': ('user(%(val)r)', ' or '),
@@ -268,22 +266,35 b' def revset(repo, pats, opts):'
268 if 'branch' in opts and 'only_branch' in opts:
266 if 'branch' in opts and 'only_branch' in opts:
269 opts['branch'] = opts['branch'] + opts.pop('only_branch')
267 opts['branch'] = opts['branch'] + opts.pop('only_branch')
270
268
269 follow = opts.get('follow')
270 if 'follow' in opts:
271 del opts['follow']
271 # pats/include/exclude are passed to match.match() directly in
272 # pats/include/exclude are passed to match.match() directly in
272 # _matchfile() revset but walkchangerevs() builds its matcher with
273 # _matchfile() revset but walkchangerevs() builds its matcher with
273 # scmutil.match(). The difference is input pats are globbed on
274 # scmutil.match(). The difference is input pats are globbed on
274 # platforms without shell expansion (windows).
275 # platforms without shell expansion (windows).
275 match, pats = scmutil.matchandpats(repo[None], pats, opts)
276 pctx = repo[None]
277 match, pats = scmutil.matchandpats(pctx, pats, opts)
276 slowpath = match.anypats() or (match.files() and opts.get('removed'))
278 slowpath = match.anypats() or (match.files() and opts.get('removed'))
277 if not slowpath:
279 if not slowpath:
278 for f in match.files():
280 for f in match.files():
281 if follow and f not in pctx:
282 raise util.Abort(_('cannot follow file not in parent '
283 'revision: "%s"') % f)
279 filelog = repo.file(f)
284 filelog = repo.file(f)
280 if not len(filelog):
285 if not len(filelog):
281 # A zero count may be a directory or deleted file, so
286 # A zero count may be a directory or deleted file, so
282 # try to find matching entries on the slow path.
287 # try to find matching entries on the slow path.
288 if follow:
289 raise util.Abort(
290 _('cannot follow nonexistent file: "%s"') % f)
283 slowpath = True
291 slowpath = True
284 if slowpath:
292 if slowpath:
285 # See cmdutil.walkchangerevs() slow path.
293 # See cmdutil.walkchangerevs() slow path.
286 #
294 #
295 if follow:
296 raise util.Abort(_('can only follow copies/renames for explicit '
297 'filenames'))
287 # pats/include/exclude cannot be represented as separate
298 # pats/include/exclude cannot be represented as separate
288 # revset expressions as their filtering logic applies at file
299 # revset expressions as their filtering logic applies at file
289 # level. For instance "-I a -X a" matches a revision touching
300 # level. For instance "-I a -X a" matches a revision touching
@@ -298,7 +309,13 b' def revset(repo, pats, opts):'
298 matchargs = ','.join(('%r' % p) for p in matchargs)
309 matchargs = ','.join(('%r' % p) for p in matchargs)
299 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs]
310 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs]
300 else:
311 else:
301 opts['_patslog'] = list(pats)
312 if follow:
313 if pats:
314 opts['_patsfollow'] = list(pats)
315 else:
316 opts['follow'] = True
317 else:
318 opts['_patslog'] = list(pats)
302
319
303 revset = []
320 revset = []
304 for op, val in opts.iteritems():
321 for op, val in opts.iteritems():
@@ -1454,8 +1454,6 b' glog always reorders nodes which explain'
1454 ('group', ('group', ('or', ('or', ('func', ('symbol', 'branch'), ('string', 'default')), ('func', ('symbol', 'branch'), ('string', 'branch'))), ('func', ('symbol', 'branch'), ('string', 'branch')))))
1454 ('group', ('group', ('or', ('or', ('func', ('symbol', 'branch'), ('string', 'default')), ('func', ('symbol', 'branch'), ('string', 'branch'))), ('func', ('symbol', 'branch'), ('string', 'branch')))))
1455 $ testlog -k expand -k merge
1455 $ testlog -k expand -k merge
1456 ('group', ('group', ('or', ('func', ('symbol', 'keyword'), ('string', 'expand')), ('func', ('symbol', 'keyword'), ('string', 'merge')))))
1456 ('group', ('group', ('or', ('func', ('symbol', 'keyword'), ('string', 'expand')), ('func', ('symbol', 'keyword'), ('string', 'merge')))))
1457 $ hg log -G --follow --template 'nodetag {rev}\n' | grep nodetag | wc -l
1458 \s*36 (re)
1459 $ hg log -G --removed --template 'nodetag {rev}\n' | grep nodetag | wc -l
1457 $ hg log -G --removed --template 'nodetag {rev}\n' | grep nodetag | wc -l
1460 \s*0 (re)
1458 \s*0 (re)
1461 $ hg log -G --only-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l
1459 $ hg log -G --only-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l
@@ -1492,27 +1490,30 b' glog always reorders nodes which explain'
1492 [255]
1490 [255]
1493 $ testlog --prune 31 --prune 32
1491 $ testlog --prune 31 --prune 32
1494 ('group', ('group', ('and', ('not', ('group', ('or', ('string', '31'), ('func', ('symbol', 'ancestors'), ('string', '31'))))), ('not', ('group', ('or', ('string', '32'), ('func', ('symbol', 'ancestors'), ('string', '32'))))))))
1492 ('group', ('group', ('and', ('not', ('group', ('or', ('string', '31'), ('func', ('symbol', 'ancestors'), ('string', '31'))))), ('not', ('group', ('or', ('string', '32'), ('func', ('symbol', 'ancestors'), ('string', '32'))))))))
1495 $ hg log -G --follow a
1496 abort: -G/--graph option is incompatible with --follow with file argument
1497 [255]
1498
1493
1499
1494 Dedicated repo for --follow and paths filtering. The g is crafted to
1500 Dedicated repo for --follow and paths filtering
1495 have 2 filelog topological heads in a linear changeset graph.
1501
1496
1502 $ cd ..
1497 $ cd ..
1503 $ hg init follow
1498 $ hg init follow
1504 $ cd follow
1499 $ cd follow
1505 $ echo a > a
1500 $ echo a > a
1506 $ echo aa > aa
1501 $ echo aa > aa
1502 $ echo f > f
1507 $ hg ci -Am "add a"
1503 $ hg ci -Am "add a"
1508 adding a
1504 adding a
1509 adding aa
1505 adding aa
1506 adding f
1510 $ hg cp a b
1507 $ hg cp a b
1508 $ hg cp f g
1511 $ hg ci -m "copy a b"
1509 $ hg ci -m "copy a b"
1512 $ mkdir dir
1510 $ mkdir dir
1513 $ hg mv b dir
1511 $ hg mv b dir
1512 $ echo g >> g
1513 $ echo f >> f
1514 $ hg ci -m "mv b dir/b"
1514 $ hg ci -m "mv b dir/b"
1515 $ hg mv a b
1515 $ hg mv a b
1516 $ hg cp -f f g
1516 $ echo a > d
1517 $ echo a > d
1517 $ hg add d
1518 $ hg add d
1518 $ hg ci -m "mv a b; add d"
1519 $ hg ci -m "mv a b; add d"
@@ -1555,3 +1556,65 b' Test glob expansion of pats'
1555 > testlog a*;
1556 > testlog a*;
1556 > fi;
1557 > fi;
1557 ('group', ('group', ('func', ('symbol', 'filelog'), ('string', 'aa'))))
1558 ('group', ('group', ('func', ('symbol', 'filelog'), ('string', 'aa'))))
1559
1560 Test --follow on a directory
1561
1562 $ testlog -f dir
1563 abort: cannot follow file not in parent revision: "dir"
1564 abort: cannot follow file not in parent revision: "dir"
1565 abort: cannot follow file not in parent revision: "dir"
1566
1567 Test --follow on file not in parent revision
1568
1569 $ testlog -f a
1570 abort: cannot follow file not in parent revision: "a"
1571 abort: cannot follow file not in parent revision: "a"
1572 abort: cannot follow file not in parent revision: "a"
1573
1574 Test --follow and patterns
1575
1576 $ testlog -f 'glob:*'
1577 abort: can only follow copies/renames for explicit filenames
1578 abort: can only follow copies/renames for explicit filenames
1579 abort: can only follow copies/renames for explicit filenames
1580
1581 Test --follow on a single rename
1582
1583 $ hg up -q 2
1584 $ testlog -f a
1585 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'a'))))
1586
1587 Test --follow and multiple renames
1588
1589 $ hg up -q tip
1590 $ testlog -f e
1591 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'e'))))
1592
1593 Test --follow and multiple filelog heads
1594
1595 $ hg up -q 2
1596 $ testlog -f g
1597 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g'))))
1598 $ cat log.nodes
1599 nodetag 2
1600 nodetag 1
1601 nodetag 0
1602 $ hg up -q tip
1603 $ testlog -f g
1604 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g'))))
1605 $ cat log.nodes
1606 nodetag 3
1607 nodetag 2
1608 nodetag 0
1609
1610 Test --follow and multiple files
1611
1612 $ testlog -f g e
1613 ('group', ('group', ('or', ('func', ('symbol', 'follow'), ('string', 'g')), ('func', ('symbol', 'follow'), ('string', 'e')))))
1614 $ cat log.nodes
1615 nodetag 4
1616 nodetag 3
1617 nodetag 2
1618 nodetag 1
1619 nodetag 0
1620
General Comments 0
You need to be logged in to leave comments. Login now