You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@subversion.apache.org by Vincent Lefevre <vi...@vinc17.net> on 2019/11/18 09:44:04 UTC

"svn diff -c" behavior on file copy from an old revision

I have the following issue with svn 1.10.6:

Assume that I committed "file1" at revision 1, did some unrelated
change at revision 2, and for revision 3, copied "file1@1" to "file2"
with "svn copy"[*] and did some changes in file2 before the commit.

[*] The revision older than the latest one is what happens when one
does a "svn copy" directly from the working copy without an update
first.

If I do "svn diff -r 1:3 file2", then I get the changes that have been
introduced between file1 and file2. But if I do "svn diff -c 3 file2",
which is equivalent to "svn diff -r 2:3 file2", then I get the whole
file2 content, as if file2 were an entirely new file.

I'm wondering whether this is the expected behavior. In any case,
this behavior is rather unintuitive and rather useless. I think there
should be an easy way to get the changes introduced by a commit.

Note: "svn cat -r... file2" or "svn cat -r... file2@3" also shows a
similar behavior:
  -r1: one gets file1@1
  -r2: "Unable to find repository location for..." error
  -r3: one gets file2@3

-- 
Vincent Lefèvre <vi...@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

Re: "svn diff -c" behavior on file copy from an old revision

Posted by Vincent Lefevre <vi...@vinc17.net>.
On 2019-11-21 15:09:05 +0100, Vincent Lefevre wrote:
> Exactly, but the reason is not that file1 was unchanged in r2.
> It is because that file1@1 is the latest ancestor or file2@3.
                                                    ^^
to be read: "the latest ancestor of file2@3". Sorry for the typo.

-- 
Vincent Lefèvre <vi...@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

Re: "svn diff -c" behavior on file copy from an old revision

Posted by Johan Corveleyn <jc...@gmail.com>.
On Thu, Nov 21, 2019 at 3:09 PM Vincent Lefevre <vi...@vinc17.net> wrote:
> On 2019-11-20 15:21:22 +0100, Johan Corveleyn wrote:
> > Vincent Lefevre also wrote:
> > >> Note: "svn cat -r... file2" or "svn cat -r... file2@3" also shows a
> > >> similar behavior:
> > >>   -r1: one gets file1@1
> > >>   -r2: "Unable to find repository location for..." error
> > >>   -r3: one gets file2@3
> >
> > Hm, it might be related, but I don't see this as exactly the same
> > problem. IMHO this is normal and correct behavior.
>
> I think that, as -c is documented, this is the same issue: "-c M" is a
> shorthand for "-r N:M" with N = M−1. Thus
>
>   svn diff -c3 file2
>
> is equivalent to
>
>   svn diff -r2:3 file2@BASE
>
> Here, BASE is assumed to be 3 (or equivalent). Thus one should get the
> difference between the contents corresponding to
>
>   svn cat -r2 file2@3
>
> and
>
>   svn cat -r3 file2@3
>
> > Indeed, in r2 there was no file2.
>
> This is not really what is described here:
>
>   http://svnbook.red-bean.com/en/1.6/svn.advanced.pegrevs.html
>
> OPERATIVE-REV is older than PEG-REV. Thus
>
> 1. Locate item in the revision identified by PEG-REV. There can be
>    only one such object.
>
> → This is file2.
>
> 2. Trace the object's history backwards (through any possible renames)
>    to its ancestor in the revision OPERATIVE-REV.
>
> → As I understand it, the history is as followed.
>
> There is file2 at revision 3, which is a copy of file1 from revision 1.
> At revision 1, this is file1. The renamed (and modification) occurred
> at revision 3, thus I would say that revision 2 did not introduce a
> change of the file, i.e. this is like file1@1. If the file is assumed
> to be nonexistent, then this would mean that in the history line, it
> has been removed, then re-added; this does not make sense to me, as
> there was no such operation in the history.
>
> > In r1 there was a predecessor of file2@3, namely file1@1. You could
> > argue that in r2 it should show the contents of file1@1 (which were
> > incidentally unchanged in r2).
>
> Exactly, but the reason is not that file1 was unchanged in r2.
> It is because that file1@1 is the latest ancestor or file2@3.
>
> > But what if file1 would have been changed in r2 (yet file2@3 was a
> > copy of file1@1), what would you expect svn to show?
>
> Obviously file1@1, as file1@2 is *not* an ancestor of file2@3.
> Just like file1@3 will not affect file2@3.
>
> Remember, we are looking at the (backward) *history* of file2@3.
>
> > Or what if file1 was deleted in r2?
>
> Ditto, file1@1.
>
> > I guess the same questions can be asked for 'svn diff -c 3' (what if
> > file1 had a different content in r2, or was deleted in r2?). Yet in
> > that case I intuitively expect "diff -c3" to take the copy-source into
> > account, no matter if it has made a jump through history. As I argued
> > in [3] above, it seems 'svnlook' can do this with its --diff-copy-from
> > option ... (which I happen to like for generating diffs in post-commit
> > emails).
>
> My above interpretation of the history would have the advantage to
> make it consistent with the current specification of "diff -c".

Ah, okay. Thanks for explaining. I can follow that.
So I agree this is probably the same issue, in that there is a similar
"bug in semantics".

If both commands ('svn cat -r2 file2@3' and 'svn diff -c3 file2', with
file2='svn copy file1@1') would use the IMHO very reasonable semantics
that you explain above, that would make sense to me.

As I said before in this thread, 'svnlook --diff-copy-from' seems to
be able to do it, so I think there is no purely technical reason why
it can't be done either.

-- 
Johan

Re: "svn diff -c" behavior on file copy from an old revision

Posted by Vincent Lefevre <vi...@vinc17.net>.
On 2019-11-20 15:21:22 +0100, Johan Corveleyn wrote:
> Vincent Lefevre also wrote:
> >> Note: "svn cat -r... file2" or "svn cat -r... file2@3" also shows a
> >> similar behavior:
> >>   -r1: one gets file1@1
> >>   -r2: "Unable to find repository location for..." error
> >>   -r3: one gets file2@3
> 
> Hm, it might be related, but I don't see this as exactly the same
> problem. IMHO this is normal and correct behavior.

I think that, as -c is documented, this is the same issue: "-c M" is a
shorthand for "-r N:M" with N = M−1. Thus

  svn diff -c3 file2

is equivalent to

  svn diff -r2:3 file2@BASE

Here, BASE is assumed to be 3 (or equivalent). Thus one should get the
difference between the contents corresponding to

  svn cat -r2 file2@3

and

  svn cat -r3 file2@3

> Indeed, in r2 there was no file2.

This is not really what is described here:

  http://svnbook.red-bean.com/en/1.6/svn.advanced.pegrevs.html

OPERATIVE-REV is older than PEG-REV. Thus

1. Locate item in the revision identified by PEG-REV. There can be
   only one such object.

→ This is file2.

2. Trace the object's history backwards (through any possible renames)
   to its ancestor in the revision OPERATIVE-REV.

→ As I understand it, the history is as followed.

There is file2 at revision 3, which is a copy of file1 from revision 1.
At revision 1, this is file1. The renamed (and modification) occurred
at revision 3, thus I would say that revision 2 did not introduce a
change of the file, i.e. this is like file1@1. If the file is assumed
to be nonexistent, then this would mean that in the history line, it
has been removed, then re-added; this does not make sense to me, as
there was no such operation in the history.

> In r1 there was a predecessor of file2@3, namely file1@1. You could
> argue that in r2 it should show the contents of file1@1 (which were
> incidentally unchanged in r2).

Exactly, but the reason is not that file1 was unchanged in r2.
It is because that file1@1 is the latest ancestor or file2@3.

> But what if file1 would have been changed in r2 (yet file2@3 was a
> copy of file1@1), what would you expect svn to show?

Obviously file1@1, as file1@2 is *not* an ancestor of file2@3.
Just like file1@3 will not affect file2@3.

Remember, we are looking at the (backward) *history* of file2@3.

> Or what if file1 was deleted in r2?

Ditto, file1@1.

> I guess the same questions can be asked for 'svn diff -c 3' (what if
> file1 had a different content in r2, or was deleted in r2?). Yet in
> that case I intuitively expect "diff -c3" to take the copy-source into
> account, no matter if it has made a jump through history. As I argued
> in [3] above, it seems 'svnlook' can do this with its --diff-copy-from
> option ... (which I happen to like for generating diffs in post-commit
> emails).

My above interpretation of the history would have the advantage to
make it consistent with the current specification of "diff -c".

-- 
Vincent Lefèvre <vi...@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

Re: "svn diff -c" behavior on file copy from an old revision

Posted by Johan Corveleyn <jc...@gmail.com>.
On Tue, Nov 19, 2019 at 4:53 PM Nathan Hartman <ha...@gmail.com> wrote:
>
> On Mon, Nov 18, 2019 at 4:44 AM Vincent Lefevre <vi...@vinc17.net> wrote:
>>
>> I have the following issue with svn 1.10.6:
>>
>> Assume that I committed "file1" at revision 1, did some unrelated
>> change at revision 2, and for revision 3, copied "file1@1" to "file2"
>> with "svn copy"[*] and did some changes in file2 before the commit.
>>
>> [*] The revision older than the latest one is what happens when one
>> does a "svn copy" directly from the working copy without an update
>> first.
>>
>> If I do "svn diff -r 1:3 file2", then I get the changes that have been
>> introduced between file1 and file2. But if I do "svn diff -c 3 file2",
>> which is equivalent to "svn diff -r 2:3 file2", then I get the whole
>> file2 content, as if file2 were an entirely new file.
>>
>> I'm wondering whether this is the expected behavior. In any case,
>> this behavior is rather unintuitive and rather useless. I think there
>> should be an easy way to get the changes introduced by a commit.

[ snipped note ... not sure this is the same problem, see below. ]

>
>
> Hello Vincent,
>
> Thank you for reporting this.
>
> I think it is the expected behavior because file2 does not exist in revision 2 and by using '-c 3' (equivalent to -r 2:3) you're restricting the revisions that are included in the differencing; as it does not follow the copy source farther back than revision 2, the file is considered a new file.
>
> In contrast, with -r 1:3, since the revisions are not restricted (or at least not as restricted; revision 1 is now included in the differencing), it follows the copy backwards to revision 1 and shows only the differences.
>
> I agree it would be nice if it could show only the changes in the copy, but then a command like 'diff -r 2:3' would be ambiguous... How would it know if you want it to trace history beyond the range specified, or if you want it to respect the -r 2:3 limit?
>
> Thoughts?

This issue is _ancient_ :-).

FWIW: I agree with you, Vincent. I expect the same behavior as you do.
But this has been discussed at length before, and so far no one has
managed to (find consensus to) change this, or to even invent a new
option to get the behavior you and I find intuitive.

For some background, see this thread from dev@ in 2013 [1]:
    1.6 vs. 1.8: strange behavior of 'svn diff -cN WC-FILE' if the
file was created in rev N by copying

In my last post in that thread I tried the "but this is inconsistent /
unpredictable" card, to no avail [2]:
    "Maybe I gave the wrong impression, but I'm not trying to completely
     redefine the behavior of 'diff -c'. However the current behavior, when
     looking at a moved file, is unpredictable: it depends on whether or
     not the move source's revision was exactly 1 revision before the
     move-commit. That unpredictability is not good."

Somewhere in that thread I also dropped a pointer to an earlier thread
in which I observed (in passing) that this was a difference between
'svn' and 'svnlook' [3].
    "So it seems that detecting copies with their sources is broken in
'svn diff'"

[1] https://svn.haxx.se/dev/archive-2013-06/0588.shtml
[2] https://svn.haxx.se/dev/archive-2013-06/0705.shtml
[3] https://svn.haxx.se/dev/archive-2012-11/0480.shtml


Vincent Lefevre also wrote:
>> Note: "svn cat -r... file2" or "svn cat -r... file2@3" also shows a
>> similar behavior:
>>   -r1: one gets file1@1
>>   -r2: "Unable to find repository location for..." error
>>   -r3: one gets file2@3

Hm, it might be related, but I don't see this as exactly the same
problem. IMHO this is normal and correct behavior.

Indeed, in r2 there was no file2. In r1 there was a predecessor of
file2@3, namely file1@1. You could argue that in r2 it should show the
contents of file1@1 (which were incidentally unchanged in r2). But
what if file1 would have been changed in r2 (yet file2@3 was a copy of
file1@1), what would you expect svn to show? Or what if file1 was
deleted in r2?

I guess the same questions can be asked for 'svn diff -c 3' (what if
file1 had a different content in r2, or was deleted in r2?). Yet in
that case I intuitively expect "diff -c3" to take the copy-source into
account, no matter if it has made a jump through history. As I argued
in [3] above, it seems 'svnlook' can do this with its --diff-copy-from
option ... (which I happen to like for generating diffs in post-commit
emails).

-- 
Johan

Re: "svn diff -c" behavior on file copy from an old revision

Posted by Nathan Hartman <ha...@gmail.com>.
On Mon, Nov 18, 2019 at 4:44 AM Vincent Lefevre <vi...@vinc17.net>
wrote:

> I have the following issue with svn 1.10.6:
>
> Assume that I committed "file1" at revision 1, did some unrelated
> change at revision 2, and for revision 3, copied "file1@1" to "file2"
> with "svn copy"[*] and did some changes in file2 before the commit.
>
> [*] The revision older than the latest one is what happens when one
> does a "svn copy" directly from the working copy without an update
> first.
>
> If I do "svn diff -r 1:3 file2", then I get the changes that have been
> introduced between file1 and file2. But if I do "svn diff -c 3 file2",
> which is equivalent to "svn diff -r 2:3 file2", then I get the whole
> file2 content, as if file2 were an entirely new file.
>
> I'm wondering whether this is the expected behavior. In any case,
> this behavior is rather unintuitive and rather useless. I think there
> should be an easy way to get the changes introduced by a commit.
>
> Note: "svn cat -r... file2" or "svn cat -r... file2@3" also shows a
> similar behavior:
>   -r1: one gets file1@1
>   -r2: "Unable to find repository location for..." error
>   -r3: one gets file2@3
>

Hello Vincent,

Thank you for reporting this.

I think it is the expected behavior because file2 does not exist in
revision 2 and by using '-c 3' (equivalent to -r 2:3) you're restricting
the revisions that are included in the differencing; as it does not follow
the copy source farther back than revision 2, the file is considered a new
file.

In contrast, with -r 1:3, since the revisions are not restricted (or at
least not as restricted; revision 1 is now included in the differencing),
it follows the copy backwards to revision 1 and shows only the differences.

I agree it would be nice if it could show only the changes in the copy, but
then a command like 'diff -r 2:3' would be ambiguous... How would it know
if you want it to trace history beyond the range specified, or if you want
it to respect the -r 2:3 limit?

Thoughts?

Thanks again for writing.

Nathan