Here on this page we will publish different user qeustions and answers to them that a visitor may find interesting for himself.

Q: I'm encountering performance issues refreshing a working copy accessed through a symbolic link.

For example I have a symbolic link named 'myProjects' in my home directory which links to /media/projects. When I use the command 'svn status myProjects/projectName' the operation is a lot slower than when I use 'svn status /media/projects/projectName'. Is this a known issue, can it be resolved?

A: This is a known problem specific for older versions of SVNKit. In older versions SVNKit used expensive native program calls (ls) to resolve symbolic links. In case some of the working copy directory parents are symbolic links, such calls are performed for every file in the working copy (because their absolute and canonical path differs and there is no way to say whether a file is a symbolic link or not, but calling ls command for it). However since relatively younger versions SVNKit has been using the JNA library to fulfill some native operations which can not be implemented in native Java, and symbolic links are among them. If you are using the latest version of SVNKit and experiencing such a trouble, it may mean that SVNKit can not find the JNA library and falls back to using expensive Process.exec() calls (ls program). Please, check that JNA is present on your classpath along with SVNKit.

If you prefer to use an older version of SVNKit however, there are two workarounds for this problem:

1. Put your working copy or refer to it by it's "real" path, not by the one that includes symbolic link, that is what you already doing.

2. Disable versioned symbolic links support in SVNKit. To do that set the following System property:


(above is an option that you should add to the command line you're using to start your application)

at runtime you may call:

   1 SVNFileType.setSymlinkSupportEnabled(false);

Q: Can the current SVNKit version be forced to create pre-1.5 format working copies?

My problem is I need to support the older working copy format (pre svn 1.5.0) and I assumed the new SVNKit automatically generates (and upgrades) working copies to this latest format. I thought the most recent 1.2.x release would do the trick.

A: Yes, you can configure SVNKit to use the pre-1.5 WC format by putting the following code somewhere in the startup function:

   1     SVNAdminAreaFactory.setSelector(new ISVNAdminAreaFactorySelector() {
   2         public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws                
   3                                                                                            SVNException  {
   4             Collection enabledFactories = new TreeSet();
   5             for (Iterator factoriesIter = factories.iterator(); factoriesIter.hasNext(); ) {
   6                 SVNAdminAreaFactory factory = (SVNAdminAreaFactory);
   7                 int version = factory.getSupportedVersion();
   8                 if (version == SVNAdminAreaFactory.WC_FORMAT_13 || version == SVNAdminAreaFactory.WC_FORMAT_14) {
   9                     enabledFactories.add(factory);
  10                 }
  11              }
  12              return enabledFactories;
  13          }
  14     });

As you can see in this code snippet ISVNAdminAreaFactorySelector gives you an ability to switch off the 1.5 fromat admin area factory.

There is also a system property svnkit.upgradeWC, when set to false it will disable upgrade of existing working copies to the new format, but it still will be used for new directories, so first option (providing custom interface implementation) is preferable.

Since 1.2.0 version SVNKit provides an ability to downgrade working copy format. The following code snippet shows a way to achieve that:

   1     SVNClientManager clientManager = SVNClientManager.newInstance();
   2     SVNWCClient wcClient = clientManager.getWCClient();
   3     File wc = new File("/path/to/working/copy");
   4     wcClient.doSetWCFormat(wc, SVNAdminAreaFactory.WC_FORMAT_14);

Q: I wonder if the methods of SVNRepository (like checkout() an update()) are atomic?

Is it possible (not probable) that another SVN client commit changes just while (not before or after) I am checking out or updating through these methods ?

A: SVNKit commit operations are atomic. That means that if you have two or more different clients committing (no matter whether they are all SVNKit clients or only one of them), they will be synchronized on the back end. In case of svn:// and http:// protocols commit finalizations are handled by the server itself (svnserve or mod_dav_svn), SVNKit client only sends necessary data and commands to the server, but the final step - writing to the repository - is undertaken by the server as you call ISVNEditor.closeEdit(). In case of the file:/// protocol SVNKit behaves like Subversion - it gets a write lock on a repository before making a transaction immutable the same way Subversion does it.

When updating via svn:// or http://: on the back end it is handled by the server itself, SVNKit receives data and commands to update, but what is happening on the back end, SVNKit doesn't matter (if something is wrong it's up to the server to deal with it). file:/// protocol update is implemented in a similar manner as in Subversion - it's a read operation and does not need any locks. Once it got the revision to update against it doesn't matter whether any commits are being performed: commits can create new repository files, but can not modify or delete existing ones, - you know each revision creates a new rev file in an FSFS repository. So your update will be absolutely consistent, although it doesn't mean that you will always get the latest revision when updating to HEAD revision - it may occur that after you started an update against a HEAD revision, someone started a new commit. But I believe it's true for Subversion, too.

So, the answer to your question is yes, it's possible and it's ok.

Q: In case of heavy editing through calls of the editor's methods it is possible, that another SVN client took a commit meanwhile?

I am concerned about the use of the SVNCommitEditor object: In case of heavy editing through calls of the editor's methods it is possible, that another SVN client took a commit meanwhile? Does this cause trouble for the editor itself? I think a final (and atomic) commit is done by the editor through the call of its .closeEdit() method, not during the editing, or isn't it? To which revision does this refer, the HEAD revision at initialization of the editor or the HEAD revision at the .closeEdit() call?

A: No, it doesn't cause any trouble for the editor itself. Until a call to ISVNEditor.closeEdit() is made each transaction lives in it's own directory on the back end. And even if someone committed a new revision after you started your transaction but before you finished it, when you call ISVNEditor.closeEdit() SVNKit (in file:///) tries to merge all changes committed ever since. And if it sees that someone has changed the same files it aborts, notifying a user with an exception. However if it succeeds to merge all changes committed since the transaction was started a new revision it results to will also contain all previous modifications. It means it "refers" to the real HEAD revision, which may be equal or greater than transaction start point revision. That is a new transaction will be absolutely consistent. In other protocols the picture is the same but this work is handled by the server itself.

Q: Is there any way to distinguish svn moves from svn copies using the low level API?

A: Yes, there is. Here is a short example demonstrating how to do that:

   1 public class Tests {
   3     public static void main(String[] args) {
   4         try {
   5             DAVRepositoryFactory.setup();
   6             SVNRepositoryFactoryImpl.setup();
   7             FSRepositoryFactory.setup();
   8             String url = args[0];
   9             SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
  11             repository.log(null, 0, -1, true, false, -1, false, null, new ISVNLogEntryHandler() {
  13                 public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
  14                     Map changedPaths = logEntry.getChangedPaths();
  15                     for (Iterator changedPathsIter = changedPaths.keySet().iterator(); changedPathsIter.hasNext();) {
  16                         String changedPath = (String);
  17                         SVNLogEntryPath logEntryPath = (SVNLogEntryPath) changedPaths.get(changedPath);
  19                         if (logEntryPath.getType() == SVNLogEntryPath.TYPE_ADDED && logEntryPath.getCopyPath() != null) {
  20                             SVNLogEntryPath copySourcePath = (SVNLogEntryPath) changedPaths.get(logEntryPath.getCopyPath());
  21                             if (copySourcePath != null && copySourcePath.getType() == SVNLogEntryPath.TYPE_DELETED) {
  22                                 System.out.println("Path " + changedPath + " was moved from " + 
  23                                         logEntryPath.getCopyPath() + " in revision " + logEntry.getRevision());
  25                             }
  26                         }
  27                     }
  28                 }
  29             });
  31             System.exit(0);
  32         } catch (Exception e) {
  33             e.printStackTrace();
  34         }
  35     }
  36 }    

Q: Do you have an idea how to get the revision numbers and the corresponding dates of a file?

A: Here is a short example demonstrating how to do that with the low-level API:

   1 public class Tests {
   3     public static void main(String[] args) {
   4         try {
   5             DAVRepositoryFactory.setup();
   6             SVNRepositoryFactoryImpl.setup();
   7             FSRepositoryFactory.setup();
   9             String url = args[0];
  10             String filePathRelativeToURL = args[1];
  11             SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
  13             final Map fileRevisionsToDates = new HashMap();
  14             repository.getFileRevisions(filePathRelativeToURL, 0, -1, false, new ISVNFileRevisionHandler() {
  15                public void applyTextDelta(String path, String baseChecksum) throws SVNException {
  16                }
  19                public void closeRevision(String token) throws SVNException {
  20                }
  22                public void openRevision(SVNFileRevision fileRevision) throws SVNException {
  23                    fileRevisionsToDates.put(new Long(fileRevision.getRevision()), 
  24                            fileRevision.getRevisionProperties().getStringValue(SVNRevisionProperty.DATE));
  25                }
  27                public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
  28                    return null;
  29                }
  31                public void textDeltaEnd(String path) throws SVNException {
  32                }
  33             });
  35             for (Iterator revisionsIter = fileRevisionsToDates.keySet().iterator(); revisionsIter.hasNext();) {
  36                 Long revision = (Long);
  37                 String dateStamp = (String) fileRevisionsToDates.get(revision);
  38                 System.out.println("file revision: " + revision + ", date stamp: " + dateStamp);
  39             }
  41             System.exit(0);
  42         } catch (Exception e) {
  43             e.printStackTrace();
  44         }
  45     }
  46 }    

Q: What is the difference between the two "standalone" downloads - one_with_jna and one_with_no_jna?

A: SVNKit uses JNA library to optionally perform certain low-level file system operations using native OS calls. In particular, JNA is used to improve performance of operations related to symbolic links. Also, it enables credentials encryption on Windows (to store and read encrypted cached credentials to and from SVN_CONFIG/auth/ files).

The reason we provide a distribution without JNA library included is that JNA library is LGPL licensed and some of the users would like to have an ability to download SVNKit with no LGPL components included.

Q: What is Trilead library for?

A: Trilead library is used to establish SSH connections, i.e. to support working with repository over svn+ssh protocol.

Q: Is it possible to create a repository on a remote svn server?

I know it is possible to use SVNKit to create a brand-new repository on the local system like this:

   1      try {
   2          String tgtPath = "C:/repos/root/path";
   3          SVNURL tgtURL = SVNRepositoryFactory.createLocalRepository( new File( tgtPath ), true , false );
   4      } catch ( SVNException e ) {
   5          //handle exception
   6      }

But is it possible to create a repository on a remote system?

A: In general it is possible if, for example, you have SSH access to the remote computer and could run the svnadmin or jsvnadmin program on the remote side. Or you may write a servlet that will run on the server side and handle repository creation request - use SVNKit to create local repository on the server computer.

Otherwise, Subversion server (svnserve, apache modules) doesn't support such a feature (a command to create a brand-new repository on the server side), and so SVNKit by itself couldn't help with that task.

Q: How to merge without specifying revisions (making use of the merge-tracking feature)?

How would I merge all changes from one branch to another without specifying revisions (except maybe HEAD)? What I want is the equivalent of the following (assuming SVN 1.5 and SVNKit 1.2):

svn merge http://localhost/MyProject/trunk c:\myWorkingCopy

A: To get the same results as the command that you're asking about would give, you should call:

   1   SVNDiffClient.doMerge(SVNURL url1, SVNRevision pegRevision,
   2                         Collection rangesToMerge, File dstPath,
   3                         SVNDepth depth, boolean useAncestry,
   4                         boolean force, boolean dryRun,
   5                         boolean recordOnly)

in the following way:

   1     SVNRevisionRange range = new SVNRevisionRange(SVNRevision.create(1), SVNRevision.HEAD);
   3     diffClient.doMerge(SVNURL.parseURIEncoded("http://localhost/MyProject/trunk"), SVNRevision.HEAD, 
   4                        Collections.singleton(range), new File("c:\\myWorkingCopy"),SVNDepth.UNKNOWN, 
   5                        true, false, false, false); 

Q: What could be a possible reason for the 'svn: Malformed reply from SOCKS server' error ?

I've tried various of the sample code snippets from the wiki, but the application hangs for a couple of minutes and then reports "error while listing entries: svn: Malformed reply from SOCKS server".

Has anyone got a solution to this problem please? I googled a bit and it seems this may be an issue with Java itself and using a proxy.

A: The second part of the error message (that follows "svn:") is an error message taken from an IOException instance that was thrown when a socket connection was attempted to be established.

Java may use browser settings by default. Try either changing JVM settings in Java control panel or disabling proxy in your default web browser. In case this resolves the problem, then the reason of the error is most probably not SVNKit-related.

Q: How to prevent users from updating revision properties when specifying read-only URLs?

I'm able to update a revision property even when specifying a URL which is read-only for me. How can I change this behaviour?

A: In case you use a path-based authentication and a certain user has read-only access to some parts of a repository and write access to other parts (paths), that user still could change revision properties in the repository - this is how the Subversion server works.

To disallow certain users changing revision properties you may check a user name in the pre-revprop-change hook. You may find more information on hooks at

I.e. you may check a user name in the pre-revprop-change hook script and exit with an error code other than 0 to disable revision property changes for those users.

Q: Problem on Windows Vista, connecting a repository through the svn protocol: org.tmatesoft.svn.core.SVNException: svn: connection refused by the server

I'm running a Subversion server (svnserve) on Windows Vista. When I try to connect to it through the svn:// protocol with SVNKit using a URL that starts with svn://localhost, I get the error "Conncetion refused by the server". However if I do the same thing with a native svn client or TortoiseSVN, everything works fine. Also if I use ip address in the URL instead of localhost, SVNKit also connects to the repository. What am I doing wrong?

A: This can be a hosts problem. With some jdk's localhost resolves to an IPv6 address instead of IPv4. Try adding ' localhost' line to your hosts file which on Windows Vista can be found under C:\Windows\System32\drivers\etc\.

Q: Recursive repository properties fetch\list operation is slow. Is it possible to make it work faster?

Trying to get entries and their properties from a repository recursively I found that it was extremely slow.

I am using the HTTP connection.

   1     repository.getDir(path, revision, properties, handler);
   2     repository.getFile(path, revision, properties, null);

Is there another way to retrieve entries\entry properties with better performance?

A: When one needs to get entry contents or properties in a single operation, then it makes sense to use SVNRepository.status(...) call.

Instead of fetching properties recursively with getDir/getFile calls, you may try using SVNRepository.status method to get properties for all files in repository:

   1     final long rev = repos.getLatestRevision();
   2     ISVNReporterBaton reporter = new ISVNReporterBaton() {
   3         public void report(ISVNReporter reporter) throws SVNException {
   4             reporter.setPath("", null, rev, true);
   5             reporter.finishReport();
   6         }
   7     };
   9     ISVNEditor editor = new ISVNEditor() {
  10         public void addDir(...) {
  11             //save info about the directory here
  12         }
  14         public void addFile(...) {
  15             //save info about the file here
  16         }
  18         public void changeDirProperty(...) {
  19             //save current (added) directory property here
  20         }
  22         public void changeFileProperty(...){
  23             //save current (added) file property here
  24         }
  26         ....
  27     };
  29     repos.status(rev, null, true, reporter, editor);

Status operation above does the same as checkout, but doesn't send file contents, only properties that you may collect in changeFile/DirProperty methods. Above approach will provide better performance, especially when working with remote repositories - single "connection" will be established, instead of one for each getFile/getDir calls. It may not provide as much improvement for "file" protocol, but there should be some.

Look at the full example code here.

SVNKit_FAQ (last edited 2012-01-03 18:09:05 by ip-109-80-120-205)