Commit from Multiple Working Copies 1) Expected behavior When committing files, listing their paths, no matter whether they belong to the same work copy or not, if they all live in the same repository, they should be committed successfully. 2) Actual behavior Currently, the code "condenses" all target paths, which means it tries to find a common root for them, and then it tries to lock that common root. If the common root is not a working copy, locking the common root fails and the commit is simply aborted ("svn: is not a working copy"). Multiple commit targets will only be committed successfully if all they all belong to the same working copy. 3) Suggested behaviour There are three possible solutions, listed in order of difficulty. A Make svn_client_commit4() do multiple commits, one for each target working copy. Essentially: svn commit wc1; svn commit wc2; ...; svn commit wcN; This solution has many drawbacks, but is the easiest one to implement. Most people won't like it and it will probably never end up in a Subversion release. The solution will be discarded anyway later when commit functionality is rebased on WC-NG. B Try to change the current commit code into passing around a list of access batons, and make it create truly atomic commits from multiple working copies as people would expect. This solution is much more involved than A. People might like it, and it could even end up in a release if WC-NG continues to progress at the current slow speed. The solution will be discarded or amended later when commit functionality is rebased on WC-NG. C Start working on WC-NG instead of doing this in wc-1. A lot of things are still left to do before svn commit will even start using WC-NG code. So the goal will change from "allow commit from multiple working copies" to "help get WC-NG ready so that, one day, we can have truly atomic commits from multiple working copies". Since this problem is being worked on as part of Summer of Code, and the student has no prior experience with the Subversion code base, it is reasonable to solve the problem in multiple steps, implementing solution A first, and then extend that to solution B, or jump straight to solution C. Below, we describe how solution A will be implemented. Because solution A will make more than one commit, we'll have to make svn_client_commit4() return an array of svn_commit_info_t objects, one for each commit made, instead of just a single svn_commit_info_t object. Because this changes the public API, we need to bump the function's revision to 5: svn_client_commit5(). This API change will be reverted in case solution B or solution C gets implemented, or in case solution A gets discarded before release. 1. We receive a list of targets to commit. In subversion\svn\commit-cmd.c the function svn_error_t * svn_cl__commit(apr_getopt_t *os, void *baton, apr_pool_t *pool) receives the targest list first. Then, in E:\subversion\subversion\libsvn_client\commit.c the function svn_error_t * svn_client_commit4(svn_commit_info_t **commit_info_p, const apr_array_header_t *targets, svn_depth_t depth, svn_boolean_t keep_locks, svn_boolean_t keep_changelists, const apr_array_header_t *changelists, const apr_hash_t *revprop_table, svn_client_ctx_t *ctx, apr_pool_t *pool) uses the targest list to do a commit. 2. If targets are not from the same working copy, we do the following instead of aborting the commit: If locking the common root failed: For each target path we got: For each working copy root we already know (initially we don't know any working copy roots): Check if the current target path is below the working copy root. If it is, put it into this root's group ("commit packet") and continue with the next target path. If we end up here, no suitable working copy root was found for the current target path. Walk the current target path downwards, starting from the common root (the root which we could not lock, in the code this is often called the "base_dir"). Try to lock the current directory at each step. If locking succeeds, we have found a new WC root! Store its access baton in the set of known working copy roots. Put the current target path into the group of the root we just found. Here we use a struct to store each "commit packet": typedef struct { /* Working copy root of a wc */ const char *base_dir; /* Targets under base_dir */ apr_array_header_t *targets; svn_wc_adm_access_t *base_dir_access; } commit_packet_t; It would be a local variable of the function svn_client_commit5(), because it is used only in the function. And it is allocated from pool. Now run a commit for each working copy root we found. This is done just like before when the code only knew about a single root, but it's done for each root in turn.