You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/08/23 18:28:32 UTC
svn commit: r988188 - in /subversion/trunk/subversion:
libsvn_client/cmdline.c libsvn_client/merge.c tests/cmdline/merge_tests.py
Author: stsp
Date: Mon Aug 23 16:28:31 2010
New Revision: 988188
URL: http://svn.apache.org/viewvc?rev=988188&view=rev
Log:
Allow locally added files and directories as merge targets.
See this thread for related discussion:
Date: Wed, 4 Aug 2010 16:29:51 +0200
From: Stefan Sperling
To: dev@
Subject: merging into locally added files
Message-ID: <20...@ted.stsp.name>
http://mail-archives.apache.org/mod_mbox/subversion-dev/201008.mbox/%3C20100804142951.GE30031@ted.stsp.name%3E
* subversion/libsvn_client/cmdline.c
(check_root_url_of_target): Tolerate a "bad revision" error when
attempting to query the URL of the merge target. Locally added targets
don't have a URL yet.
* subversion/libsvn_client/merge.c
(get_full_mergeinfo): Tolerate targets which have no location in the
repository yet. Return empty implicit mergeinfo for such targets.
* subversion/tests/cmdline/merge_tests.py
(merge_into_locally_added_file, merge_into_locally_added_directory,
test_list): New tests.
Modified:
subversion/trunk/subversion/libsvn_client/cmdline.c
subversion/trunk/subversion/libsvn_client/merge.c
subversion/trunk/subversion/tests/cmdline/merge_tests.py
Modified: subversion/trunk/subversion/libsvn_client/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/cmdline.c?rev=988188&r1=988187&r2=988188&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/cmdline.c (original)
+++ subversion/trunk/subversion/libsvn_client/cmdline.c Mon Aug 23 16:28:31 2010
@@ -125,11 +125,14 @@ check_root_url_of_target(const char **ro
* If the target itself is a URL to a repository that does not exist,
* that's fine, too. The callers will deal with this argument in an
* appropriate manter if it does not make any sense.
+ *
+ * Also tolerate locally added targets ("bad revision" error).
*/
if ((err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
|| (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
|| (err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
- || (err->apr_err == SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED))
+ || (err->apr_err == SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED)
+ || (err->apr_err == SVN_ERR_CLIENT_BAD_REVISION))
{
svn_error_clear(err);
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=988188&r1=988187&r2=988188&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Mon Aug 23 16:28:31 2010
@@ -3367,6 +3367,7 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
svn_revnum_t target_rev;
svn_opt_revision_t peg_revision;
apr_pool_t *sesspool = NULL;
+ svn_error_t *err;
/* Assert that we have sane input. */
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start)
@@ -3374,9 +3375,26 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
&& (start > end));
peg_revision.kind = svn_opt_revision_working;
- SVN_ERR(svn_client__derive_location(&url, &target_rev, target_abspath,
- &peg_revision, ra_session,
- ctx, result_pool, scratch_pool));
+ err = svn_client__derive_location(&url, &target_rev, target_abspath,
+ &peg_revision, ra_session,
+ ctx, result_pool, scratch_pool);
+
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED)
+ {
+ /* We've been asked to operate on a target which has no location
+ * in the repository. Either it's unversioned (but attempts to
+ * merge into unversioned targets should not get as far as here),
+ * or it is locally added, in which case the target's implicit
+ * mergeinfo is empty. */
+ svn_error_clear(err);
+ *implicit_mergeinfo = apr_hash_make(result_pool);
+ return SVN_NO_ERROR;
+ }
+ else
+ return svn_error_return(err);
+ }
if (target_rev <= end)
{
Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=988188&r1=988187&r2=988188&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Mon Aug 23 16:28:31 2010
@@ -15764,6 +15764,113 @@ def copy_causes_phantom_eol_conflict(sbo
expected_skip,
None, None, None, None, None, 1, 1)
+
+#----------------------------------------------------------------------
+def merge_into_locally_added_file(sbox):
+ "merge into locally added file"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Some paths we'll care about
+ pi_path = sbox.ospath("A/D/G/pi")
+ new_path = sbox.ospath("A/D/G/new")
+
+ shutil.copy(pi_path, new_path)
+ svntest.main.file_append(pi_path, "foo\n")
+ sbox.simple_commit(); # r2
+
+ sbox.simple_add(new_path)
+
+ expected_output = wc.State(wc_dir, {
+ 'A/D/G/new' : Item(status='G '),
+ })
+ expected_mergeinfo_output = wc.State(wc_dir, {
+ 'A/D/G/new' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(wc_dir, {})
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({ 'A/D/G/new' : Item(status='A ', wc_rev=0)})
+ expected_status.tweak('A/D/G/pi', wc_rev=2)
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('A/D/G/pi', contents="This is the file 'pi'.\nfoo\n")
+ expected_disk.add({'A/D/G/new' : Item("This is the file 'pi'.\nfoo\n",
+ props={SVN_PROP_MERGEINFO : '/A/D/G/pi:2'})})
+ expected_skip = wc.State(wc_dir, {})
+
+ svntest.actions.run_and_verify_merge(wc_dir, '1', '2',
+ sbox.repo_url + '/A/D/G/pi', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None,
+ True, True, new_path)
+ sbox.simple_commit()
+
+#----------------------------------------------------------------------
+def merge_into_locally_added_directory(sbox):
+ "merge into locally added directory"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Some paths we'll care about
+ G_path = sbox.ospath("A/D/G")
+ pi_path = sbox.ospath("A/D/G/pi")
+ new_dir_path = sbox.ospath("A/D/new_dir")
+
+ svntest.main.file_append(pi_path, "foo\n")
+ sbox.simple_commit(); # r2
+
+ os.mkdir(new_dir_path)
+ svntest.main.file_append(os.path.join(new_dir_path, 'pi'),
+ "This is the file 'pi'.\n")
+ svntest.main.file_append(os.path.join(new_dir_path, 'rho'),
+ "This is the file 'rho'.\n")
+ svntest.main.file_append(os.path.join(new_dir_path, 'tau'),
+ "This is the file 'tau'.\n")
+ sbox.simple_add(new_dir_path)
+
+ expected_output = wc.State(wc_dir, {
+ 'A/D/new_dir/pi' : Item(status='G '),
+ })
+ expected_mergeinfo_output = wc.State(wc_dir, {
+ 'A/D/new_dir' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(wc_dir, {})
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({ 'A/D/new_dir' : Item(status='A ', wc_rev=0)})
+ expected_status.add({ 'A/D/new_dir/pi' : Item(status='A ', wc_rev=0)})
+ expected_status.add({ 'A/D/new_dir/rho' : Item(status='A ', wc_rev=0)})
+ expected_status.add({ 'A/D/new_dir/tau' : Item(status='A ', wc_rev=0)})
+ expected_status.tweak('A/D/G/pi', wc_rev=2)
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('A/D/G/pi', contents="This is the file 'pi'.\nfoo\n")
+ expected_disk.add({'A/D/new_dir' :
+ Item(props={SVN_PROP_MERGEINFO : '/A/D/G:2'})})
+ expected_disk.add({'A/D/new_dir/pi' :
+ Item(contents="This is the file 'pi'.\nfoo\n")})
+ expected_disk.add({'A/D/new_dir/rho' :
+ Item(contents="This is the file 'rho'.\n")})
+ expected_disk.add({'A/D/new_dir/tau' :
+ Item(contents="This is the file 'tau'.\n")})
+ expected_skip = wc.State(wc_dir, {})
+
+ svntest.actions.run_and_verify_merge(wc_dir, '1', '2',
+ sbox.repo_url + '/A/D/G', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None,
+ True, True, new_dir_path)
+ sbox.simple_commit()
+
########################################################################
# Run the tests
@@ -15951,6 +16058,8 @@ test_list = [ None,
immediate_depth_merge_creates_minimal_subtree_mergeinfo,
record_only_merge_creates_self_referential_mergeinfo,
copy_causes_phantom_eol_conflict,
+ merge_into_locally_added_file,
+ merge_into_locally_added_directory,
]
if __name__ == '__main__':