[PATCH V2] (was Re: [PATCH STABLE] log --follow shouldn't depend on the working dir context)

Christian Boos cboos at edgewall.org
Tue Jun 12 16:34:09 CDT 2012


On 6/12/2012 2:39 PM, Patrick Mézard wrote:
> Le 11/06/12 22:39, Christian Boos a écrit :
>> Hello,
>>
>> I noticed that the change 60101427d618 (released in Mercurial 2.1.1)
>> introduced a check for "log --follow", verifying that the file examined
>> is present in the parent context, so that revisions in the filelog
>> can be followed from the appropriate starting point.
>>
>> See http://www.selenic.com/hg/rev/60101427d618 for details.
>>
>> This is all well and good except for the change's notion of parent
>> context: it uses the working dir context for that!
>> This breaks a number of things, like in my case the mercurial plugin
>> for Trac which can operate on repositories having the null rev as the
>> working dir revision. I'm sure it can also break other tools, like the
>> hg command server in the same situation, and it even breaks "hg log" itself if you try something like:
>>
>>    "hg log --follow file_only_in_branch_B -r branch_B"
>>
>> when you're not on branch_B.
>>
>> After discussing the matter with Patrick on IRC this morning,
>> he agreed this was indeed a problem and suggested the following fix.
>
> To clarify a bit, I agreed the lack of "peg-revision" is a long standing issue with log command when specifying file names, and threw this fix before vanishing away.
>
> I do not like this fix because this is just a hack. Say file "foo" exists in revision r1 but not in revision r2, the following will now work:
>
>    hg log --follow foo -r 'r1:r2'
>
> but not this:
>
>    hg log --follow foo -r 'r2:r1'
>
> So the query output content depends on the revision order. This is surprising, only the output order should depend on the revision order.
>

Note that there is a precedent for that in "hg log --follow -r REV",
i.e. when no file is specified. There you can also have a very
different result depending on the revision order given in the range.
Consider:

$ hg glog --template="\t{branch} {rev}\n"
@       A 5
|
| o     B 4
| |
o |     A 3
| |
| o     B 2
| |
| o     B 1
|
o       A 0

$ hg log --follow --template '{branch} {rev}\n' -r 4:0
B 4
B 2
B 1

$ hg log --follow --template '{branch} {rev}\n' -r 0:4
A 0
A 3

 From a user perspective I think that the usage pattern is similar, the
start revision determines which "branch" is picked, the changelog
branch in the above example, the filelog branch in case of --follow
file.

On the opposite, if you had a dedicated option like --pathrev as you
suggested, users would have to deal with two similar notions of "start
revisions", and it might be tricky to explain the subtle difference
between them. And even if the difference is plain clear, I'm not sure
if there are many use cases where you would them to be different,
except when you'd like to reverse the display order as in your example.
IMO, having an extra option is not a clear win, it's certainly more
precise but comes at the price of added user interface complexity.

That being said, I let you decide what's more appropriate to do, what I
really care about is that there's a fix for:

> ... "foo" is implicitely defined as "foo" in revision ".".

and *any* way to specify the parent context for the file would be fine
for me.

> What you want is a way to say: "I want information about the thing called 'foo' defined in revision X over the revision range Y". Subversion supports this like:
>
>    svn log -rY foo at X
>
> We need a way to specify X, with a silly option like --pathrev if we cannot find a better one. Then we have to resolve this name for each revision in Y, which usually reduces to resolving the name in each "head" of Y. The problem is it is cheap to find the names of "foo" in ancestors of X, more expensive to do so in descendants of X. The second problem is it means refactoring walkchangerevs() to achieve this while we really want to replace it with a version or another of graphlog.getlogrevs().
>

So if you really prefer that approach, fine, I've reworked the patch in
that direction. Btw, I picked --file-rev instead of --pathrev as I
think it better hints that it is related to the "--follow file" mode.

The log options help looks now like the following:

options:

  -f --follow              follow changeset history, or file history across
                           copies and renames
     --file-rev REV        parent revision containing the followed file
                           (default: .)
  ...

The term "parent revision" comes from the current error message
"cannot follow file not in parent revision".

I've also tweaked the log command help accordingly.

-- Christian


# HG changeset patch
# User Christian Boos <cboos at edgewall.org>
# Date 1339531876 -7200
# Branch stable
# Node ID a219b8888e61547713ddda1a1840c8e70e5b9bb1
# Parent  15159abc5ab68050e9a19cc1c74240a937dd1a85
log: add --file-rev option to complement --follow file

The parent revision used for locating the topological head
of interest in the filelog of the followed file was always
the working dir parent revision, per 60101427d618.

That default can be problematic sometimes, for example
in a repository with no checkout (working dir parent is
null). In that situation, if the parent revision isn't
specified with --file-rev, --follow file will always fail
with the "cannot follow file not in parent revision" error.

Also, the change enable tools which expected to be able to
use walkchangerevs without a working copy to use the 'follow'
option again, provided they now also specify 'file_rev'.

diff -r 15159abc5ab6 -r a219b8888e61 mercurial/cmdutil.py
--- a/mercurial/cmdutil.py	Wed Jun 06 21:17:20 2012 -0500
+++ b/mercurial/cmdutil.py	Tue Jun 12 22:11:16 2012 +0200
@@ -1047,7 +1047,7 @@

              return reversed(revs)
          def iterfiles():
-            pctx = repo['.']
+            pctx = repo[opts.get('file_rev') or '.']
              for filename in match.files():
                  if follow:
                      if filename not in pctx:
diff -r 15159abc5ab6 -r a219b8888e61 mercurial/commands.py
--- a/mercurial/commands.py	Wed Jun 06 21:17:20 2012 -0500
+++ b/mercurial/commands.py	Tue Jun 12 22:11:16 2012 +0200
@@ -3849,6 +3849,8 @@
  @command('^log|history',
      [('f', 'follow', None,
       _('follow changeset history, or file history across copies and 
renames')),
+    ('', 'file-rev', '.',
+     _('parent revision containing the followed file'), _('REV')),
      ('', 'follow-first', None,
       _('only follow the first parent of merge changesets (DEPRECATED)')),
      ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
@@ -3881,8 +3883,10 @@

      File history is shown without following rename or copy history of
      files. Use -f/--follow with a filename to follow history across
-    renames and copies. --follow without a filename will only show
-    ancestors or descendants of the starting revision.
+    renames and copies. In this mode, use --file-rev to specify the
+    parent revision containing the file, when the working directory
+    parent is not appropriate for that. --follow without a filename
+    will only show ancestors or descendants of the starting revision.

      By default this command prints revision number and changeset id,
      tags, non-trivial parents, user, date and time, and a summary for
diff -r 15159abc5ab6 -r a219b8888e61 tests/test-debugcomplete.t
--- a/tests/test-debugcomplete.t	Wed Jun 06 21:17:20 2012 -0500
+++ b/tests/test-debugcomplete.t	Tue Jun 12 22:11:16 2012 +0200
@@ -198,7 +198,7 @@
    export: output, switch-parent, rev, text, git, nodates
    forget: include, exclude
    init: ssh, remotecmd, insecure
-  log: follow, follow-first, date, copies, keyword, rev, removed, 
only-merges, user, only-branch, branch, prune, hidden, patch, git, 
limit, no-merges, stat, style, template, include, exclude
+  log: follow, file-rev, follow-first, date, copies, keyword, rev, 
removed, only-merges, user, only-branch, branch, prune, hidden, patch, 
git, limit, no-merges, stat, style, template, include, exclude
    merge: force, rev, preview, tool
    phase: public, draft, secret, force, rev
    pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
diff -r 15159abc5ab6 -r a219b8888e61 tests/test-log.t
--- a/tests/test-log.t	Wed Jun 06 21:17:20 2012 -0500
+++ b/tests/test-log.t	Tue Jun 12 22:11:16 2012 +0200
@@ -191,6 +191,23 @@



+-f and multile filelog heads, independent of working dir revision
+
+  $ hg up -q null
+  $ hg log -f g --template '{rev}\n' --file-rev 2
+  2
+  1
+  0
+  $ hg log -f g --template '{rev}\n' --file-rev tip
+  3
+  2
+  0
+  $ hg log -f g --template '{rev}\n' --file-rev tip -r 2:0
+  2
+  0
+  $ hg log -f g --template '{rev}\n' --file-rev tip -r 0:2
+  0
+  2

  -f and multiple filelog heads



More information about the Mercurial-devel mailing list