How to get previous revision file content

Hello !
I have a SVNLogEntry list and need to read every file, it content, previous revision content and compare them. There is file path entryPath.getPath() (i.e. /branches/4_1_X/test.java) then I call SvnOperationFactory
logOperation.setSingleTarget(SvnTarget.fromURL(
SVNURL.parseURIEncoded(repositoryRoot + path)
));
logOperation.run and get affected revisions.

It’s ok BUT there is problem when some file was copied/moved from other path/branch. I have file path (i.e. /branches/4_1_X/test.java) and try to get it content from previous revision on other branch (i.e. /branches/3_4_X/test.java).
In TortoiseSVN it’s very simple - in log messages I can select any file, right click on it and “show log”. I need to do it similar way in svnkit.

I will be grateful for any help.
Pawel

Hello Pawel,
if I understand your question correctly, you could have a look at low level (SVNRepository-based) API. Then SVNRepository#getLocationSegments method will return previous paths and revisions for the path specified taking copying information into account.

But I think you can even avoid low-level API if you understand a concept of “peg revisions” and “operative revisions”. Here’s a good article about them.

For example, if you have

/branches/4_1_X/test.java

at r4 copied from r3 of

/branches/3_4_X/test.java

Then if can use methods that accept both peg and operative revisions: you can specify “/branches/4_1_X/test.java” as the path, r4 as the “peg” revision. Then if you use r3 as “operative” revision, SVN and SVNKit will automatically use /branches/3_4_X/test.java:3 for that method.

I would recommend you to have a look at implementation of “jsvn log --diff” functionality of SVNKit:

https://svn.svnkit.com/repos/svnkit/trunk/svnkit-cli/src/main/java/org/tmatesoft/svn/cli/svn/SVNLogCommand.java

If you look at doDiff(…) method (line 454): it accepts a log entry and produces a diff. To do so it uses the revision of the log entry as the peg revision and the previous revision as the operative revision and this is enough to take the fact of copying into accout.

If I understand, “svn log --difff” is exactly what you’re trying to implement, so SVNLogCommand#doDiff is the best example for you.

Dear Dmitry,

thank you very much for help.

You understood me correctly – I need to collect data about changes done in commit. I’ve wrote some piece of code to gather LogEntries in specified range (dates or revisions). Next I go through ChangedPaths, get current revision file content, search for previous revision, get it content and compare them using java-diff-utils.

Everything works correctly until a file wasn’t moved from branch to branch.

I’ve tried your solution with SVNLogCommand, copied doDiff method and call it similar way:

SVNClientManager diffClientManager = SVNClientManager.newInstance(svnOperationFactory);
SVNDiffClient client = diffClientManager.getDiffClient();
client.setShowCopiesAsAdds(false);
SVNPath target = new SVNPath(entryPath.getPath(), true);
doDiff(client, logEntry, target, SVNDepth.INFINITY);

Unfortunately I got exception :
svn: E200007: Runner for ‘org.tmatesoft.svn.core.wc2.SvnDiff’ command have not been found; probably not yet implement in this API.

I’m using SvnKit in 1.10.4 version.

Where I’m wrong?

Thanks,
Pawel

Hello again,
I’ve tried your first solution and seems to be ok for me.

Thanks for all help,
Best regards,
Pawel

Hello Pawel,
I would like to say a couple of words about the error you see.
doDiff() is implemented via SvnOperationFactory API. It creates ‘SvnDiff’ operation that has 2 runners:

  • SvnNgDiff for working copy format of version =>1.7 and remote operations
  • SvnOldDiff for working copy format of version <= 1.6

When you run SvnDiff operation, SVNKit tries to find a runner for it taking SvnNgDiff#isApplicable and SvnOldDiff#isApplicable into account. For some reasons it cannot find the runner for your situation because both runners are not isApplicable(). Probably this is because you create SVNPath for the path (instead of URL) and this is interpreted as a file on the filesystem. But if you want to run diff for a remote file, you should use URLs. But I can’t reproduce the problem.

In either case I don’t recommend SVNClientManager/SVNDiffClient API, prefer newer SvnOperationFactory API (which is equivalent but a bit better).