blob: d342c4f6c84bea0548d0d4382454ec3b5c09bc86 [file] [log] [blame]
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: <common root>
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.