merge with self.
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -125,12 +125,22 @@ def walkchangerevs(ui, repo, pats, opts)
files, matchfn, anypats = matchpats(repo, pats, opts)
- follow = opts.get('follow')
+ follow = opts.get('follow') or opts.get('follow_first')
if repo.changelog.count() == 0:
return [], False, matchfn
- revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
+ if follow:
+ p = repo.dirstate.parents()[0]
+ if p == nullid:
+ ui.warn(_('No working directory revision; defaulting to tip\n'))
+ start = 'tip'
+ else:
+ start = repo.changelog.rev(p)
+ defrange = '%s:0' % start
+ else:
+ defrange = 'tip:0'
+ revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
wanted = {}
slowpath = anypats
fncache = {}
@@ -206,10 +216,55 @@ def walkchangerevs(ui, repo, pats, opts)
wanted[rev] = 1
def iterate():
+ class followfilter:
+ def __init__(self, onlyfirst=False):
+ self.startrev = -1
+ self.roots = []
+ self.onlyfirst = onlyfirst
+
+ def match(self, rev):
+ def realparents(rev):
+ if self.onlyfirst:
+ return repo.changelog.parentrevs(rev)[0:1]
+ else:
+ return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
+
+ if self.startrev == -1:
+ self.startrev = rev
+ return True
+
+ if rev > self.startrev:
+ # forward: all descendants
+ if not self.roots:
+ self.roots.append(self.startrev)
+ for parent in realparents(rev):
+ if parent in self.roots:
+ self.roots.append(rev)
+ return True
+ else:
+ # backwards: all parents
+ if not self.roots:
+ self.roots.extend(realparents(self.startrev))
+ if rev in self.roots:
+ self.roots.remove(rev)
+ self.roots.extend(realparents(rev))
+ return True
+
+ return False
+
+ if follow and not files:
+ ff = followfilter(onlyfirst=opts.get('follow_first'))
+ def want(rev):
+ if rev not in wanted:
+ return False
+ return ff.match(rev)
+ else:
+ def want(rev):
+ return rev in wanted
+
for i, window in increasing_windows(0, len(revs)):
yield 'window', revs[0] < revs[-1], revs[-1]
- nrevs = [rev for rev in revs[i:i+window]
- if rev in wanted]
+ nrevs = [rev for rev in revs[i:i+window] if want(rev)]
srevs = list(nrevs)
srevs.sort()
for rev in srevs:
@@ -1972,8 +2027,14 @@ def log(ui, repo, *pats, **opts):
project.
File history is shown without following rename or copy history of
- files. Use -f/--follow to follow history across renames and
- copies.
+ files. Use -f/--follow with a file name to follow history across
+ renames and copies. --follow without a file name will only show
+ ancestors or descendants of the starting revision. --follow-first
+ only follows the first parent of merge revisions.
+
+ If no revision range is specified, the default is tip:0 unless
+ --follow is set, in which case the working directory parent is
+ used as the starting revision.
By default this command outputs: changeset id and hash, tags,
non-trivial parents, user, date and time, and a summary for each
@@ -3087,7 +3148,9 @@ table = {
(log,
[('b', 'branches', None, _('show branches')),
('f', 'follow', None,
- _('follow file history across copies and renames')),
+ _('follow changeset history, or file history across copies and renames')),
+ ('', 'follow-first', None,
+ _('only follow the first parent of merge changesets')),
('k', 'keyword', [], _('search for a keyword')),
('l', 'limit', '', _('limit number of changes displayed')),
('r', 'rev', [], _('show the specified revision or range')),
--- a/tests/test-log
+++ b/tests/test-log
@@ -28,3 +28,38 @@ echo % one rename
hg log -vf a
echo % many renames
hg log -vf e
+
+# log --follow tests
+hg init ../follow
+cd ../follow
+echo base > base
+hg ci -Ambase -d '1 0'
+
+echo r1 >> base
+hg ci -Amr1 -d '1 0'
+echo r2 >> base
+hg ci -Amr2 -d '1 0'
+
+hg up -C 1
+echo b1 > b1
+hg ci -Amb1 -d '1 0'
+
+echo % log -f
+hg log -f
+
+hg up -C 0
+echo b2 > b2
+hg ci -Amb2 -d '1 0'
+
+echo % log -f -r 1:tip
+hg log -f -r 1:tip
+
+hg up -C 3
+hg merge tip
+hg ci -mm12 -d '1 0'
+
+echo postm >> b1
+hg ci -Amb1.1 -d'1 0'
+
+echo % log --follow-first
+hg log --follow-first
--- a/tests/test-log.out
+++ b/tests/test-log.out
@@ -76,3 +76,76 @@ description:
a
+adding base
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+adding b1
+% log -f
+changeset: 3:e62f78d544b4
+tag: tip
+parent: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1
+
+changeset: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: r1
+
+changeset: 0:67e992f2c4f3
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: base
+
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding b2
+% log -f -r 1:tip
+changeset: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: r1
+
+changeset: 2:60c670bf5b30
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: r2
+
+changeset: 3:e62f78d544b4
+parent: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1
+
+2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% log --follow-first
+changeset: 6:2404bbcab562
+tag: tip
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1.1
+
+changeset: 5:302e9dd6890d
+parent: 3:e62f78d544b4
+parent: 4:ddb82e70d1a1
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: m12
+
+changeset: 3:e62f78d544b4
+parent: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1
+
+changeset: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: r1
+
+changeset: 0:67e992f2c4f3
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: base
+