[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: 1.6 vs. 1.8: strange behavior of 'svn diff -cN WC-FILE' if the file was created in rev N by copying

From: Ben Reser <ben_at_reser.org>
Date: Tue, 25 Jun 2013 22:26:08 +0200

On Tue, Jun 25, 2013 at 8:33 PM, Tobias Bading <tbading_at_web.de> wrote:
> I think I can already hear Emacs developers of both VC camps, the Bazaar'ians and the Git'ians, laughing together in harmony in the distance... ;-)
> No disrespect & thank you for the hint, but shouldn't a version control system be able to answer the question "what's changed?" without making you jump through hoops?

Yes Git has better behavior here (not sure about Bazaar). Git also
has a way to represent tree modifications in their diff format. The
problem here is that Subversion's diff isn't really tree versioning
aware. This goes back to the fact that when Subversion was written
there wasn't a format for representing tree deltas. Git's format has
become somewhat of a standard (though even it isn't really sufficient
for us). We still don't have a good format for this that's cross VC
and the Subversion project never felt like it wanted to take it upon
itself to just ship something that couldn't interoperate with others.
There were efforts to agree on a format across VC systems, but it was
not possible to agree. We probably should have in retrospect just
developed a format. Git however, had no choice because their
fundamental purpose was to manage passing patches around. Unified
diff couldn't solve this problem so they solved it on their own.
Subversion being based on a centralized repository didn't have the
same requirements of being able to represent every change with diff,
so our output favors interoperability with the patch command.

Back to your issue. Since Subversion can't represent the copy as part
of the diff it tries to do the interoperable thing which is to
represent the addition of a new file (from a copy) as an addition.
Simply using a revision range isn't exactly what is changing the
output you're getting. You can't just use -rM:N where M < N-1, M
*MUST* be the revision you copied from. When you specify this then
the base of the diff ends up being the file you copied from since
Subversion follows the copy and you get the result you want. A great
way to see this is to simply add another unrelated file in r1 in your
example script and change your diffs to use -c4 and -r1:4. Your copy
now comes from r2 and you'll see the same output for both -c4 and
-r1:4, where as -r2:4 provides the output you want.

From the perspective of someone who is wanting to see the change done
in the repository with diff then I can see your point. From the point
of view of someone that wants to send the diff to someone to apply
with the patch command that isn't necessarily using Subversion or even
the same repository, the way things work now properly are better.

Fortunately, the problem I mention above where sending tree changes
with the delta should be solved with the --git option to diff (the git
people can laugh some more that the solution to your problem should be
to pass that option). However, if you use it you'll have the same
issues that you have already. Simply because the --git option hasn't
really been fully finished being implemented. Subversion doesn't have
proper move tracking or even really move heuristics yet, so it can't
represent moves. However, it does have fully knowledge of the copy
and in this case I would consider it a bug that the --git option does
not return the the git extended header as "copy from ..." instead of
"new file" as it does now and then provide a diff off the copy.

While I understand your interpretation I don't think we are likely to
change the default output of diff to behave this way. I can see an
argument for an option to diff to tell it to use the base of copies as
where they were copied from, but I'm not sure if that's really useful
when you'd end up not seeing where it was copied from in the diff. So
IMHO the correct solution to this is to fix the --git option and
change your vc-svn.el module to pass that flag.

That doesn't help you much right now, but I think that's the right
solution. The other solutions people have suggested, using log to
find the copy from and then setting the range right won't help you
with vc-svn.el because if there are multiple files copied from
different revs, it will be impossible to get the base correct on all
of them.

Side note for anyone wondering: Git doesn't track copies, however,
when the copy is in the same change then it will always find it. So
even without the humorously named --find-copies-harder the equivalent
case in Git will always behave as Tobias expects. However, you can
end up with similar issues with git when the copy isn't so easy to
find (and then you have to start using -C or --find-copies-harder to
get the output you expect).
Received on 2013-06-25 22:26:46 CEST

This is an archived mail posted to the Subversion Dev mailing list.