Author: julianfoad Date: Thu Apr 16 09:27:18 2015 New Revision: 1674030 URL: http://svn.apache.org/r1674030 Log: On the 'move-tracking-2' branch: Implement merging of subbranches (just for edit-vs-edit cases, so far), and add a test that merges subbranches.
* subversion/svnmover/svnmover.c (merge_subbranch): New. (branch_merge_subtree_r): Merge subbranches. Notify start and end of merging this branch. Simplify a bit of notification code. * subversion/tests/cmdline/svnmover_tests.py (subbranches1): New test. (test_list): Run it. Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c?rev=1674030&r1=1674029&r2=1674030&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original) +++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Thu Apr 16 09:27:18 2015 @@ -659,6 +659,80 @@ element_merge(svn_branch_el_rev_content_ *conflict_p = conflict; } +static svn_error_t * +branch_merge_subtree_r(svn_editor3_t *editor, + const svn_branch_el_rev_id_t *src, + const svn_branch_el_rev_id_t *tgt, + const svn_branch_el_rev_id_t *yca, + apr_pool_t *scratch_pool); + +/* Merge the subbranch of {SRC, TGT, YCA} found at EID. + */ +static svn_error_t * +merge_subbranch(svn_editor3_t *editor, + const svn_branch_el_rev_id_t *src, + const svn_branch_el_rev_id_t *tgt, + const svn_branch_el_rev_id_t *yca, + int eid, + apr_pool_t *scratch_pool) +{ + svn_branch_instance_t *src_subbranch + = svn_branch_get_subbranch_at_eid(src->branch, eid, scratch_pool); + svn_branch_instance_t *tgt_subbranch + = svn_branch_get_subbranch_at_eid(tgt->branch, eid, scratch_pool); + svn_branch_instance_t *yca_subbranch + = svn_branch_get_subbranch_at_eid(yca->branch, eid, scratch_pool); + svn_branch_el_rev_id_t *subbr_src = NULL; + svn_branch_el_rev_id_t *subbr_tgt = NULL; + svn_branch_el_rev_id_t *subbr_yca = NULL; + + if (src_subbranch) + subbr_src = svn_branch_el_rev_id_create( + src_subbranch, src_subbranch->sibling_defn->root_eid, + src->rev, scratch_pool); + if (tgt_subbranch) + subbr_tgt = svn_branch_el_rev_id_create( + tgt_subbranch, tgt_subbranch->sibling_defn->root_eid, + tgt->rev, scratch_pool); + if (yca_subbranch) + subbr_yca = svn_branch_el_rev_id_create( + yca_subbranch, yca_subbranch->sibling_defn->root_eid, + yca->rev, scratch_pool); + + if (subbr_src && subbr_tgt && subbr_yca) /* ?edit vs. ?edit */ + { + /* subbranch possibly changed in source => merge */ + SVN_ERR(branch_merge_subtree_r(editor, subbr_src, subbr_tgt, subbr_yca, + scratch_pool)); + } + else if (subbr_src && subbr_yca) /* ?edit vs. delete */ + { + /* ### possible conflict (edit vs. delete) */ + } + else if (subbr_tgt && subbr_yca) /* delete vs. ?edit */ + { + /* ### possible conflict (delete vs. edit) */ + } + else if (subbr_src && subbr_tgt) /* double add */ + { + /* ### conflict */ + } + else if (subbr_src) /* added on source branch */ + { + /* ### add it on target */ + } + else if (subbr_tgt) /* added on target branch */ + { + /* nothing to do */ + } + else if (subbr_yca) /* double delete */ + { + /* ### conflict? policy option? */ + } + + return SVN_NO_ERROR; +} + /* Merge ... * * Merge any sub-branches in the same way, recursively. @@ -688,6 +762,8 @@ branch_merge_subtree_r(svn_editor3_t *ed yca->rev, yca->branch->sibling_defn->bsid, yca->eid)); + notify("merging into branch %s", + svn_branch_instance_get_id(tgt->branch, scratch_pool)); /* for (eid, diff1) in element_differences(YCA, FROM): diff2 = element_diff(eid, YCA, TO) @@ -729,6 +805,9 @@ branch_merge_subtree_r(svn_editor3_t *ed TGT, YCA) exists, but we choose to skip it when SRC == YCA. */ if (! e_yca_src) { + /* Still may need to merge a subbranch here */ + SVN_ERR(merge_subbranch(editor, src, tgt, yca, eid, scratch_pool)); + continue; } @@ -755,6 +834,8 @@ branch_merge_subtree_r(svn_editor3_t *ed SVN_ERR(svn_editor3_alter(editor, tgt->rev, tgt->branch, eid, result->parent_eid, result->name, result->content)); + + SVN_ERR(merge_subbranch(editor, src, tgt, yca, eid, scratch_pool)); } else if (e_tgt) { @@ -768,12 +849,9 @@ branch_merge_subtree_r(svn_editor3_t *ed svn_branch_instance_t *subbranch = svn_branch_get_subbranch_at_eid(src->branch, eid, scratch_pool); - if (subbranch) - notify("A e%d %s%s", - eid, result->name, - subbranch_str(src->branch, eid, scratch_pool)); - else - notify("A e%d %s", eid, result->name); + notify("A e%d %s%s", + eid, result->name, + subbranch_str(src->branch, eid, scratch_pool)); /* In BRANCH, create an instance of the element EID with new content. * @@ -798,6 +876,9 @@ branch_merge_subtree_r(svn_editor3_t *ed } } + notify("merging into branch %s -- finished", + svn_branch_instance_get_id(tgt->branch, scratch_pool)); + if (had_conflict) { return svn_error_createf(SVN_ERR_BRANCHING, NULL, @@ -808,8 +889,6 @@ branch_merge_subtree_r(svn_editor3_t *ed SVN_DBG(("merge completed: no conflicts")); } - /* ### TODO: subbranches */ - return SVN_NO_ERROR; } Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py?rev=1674030&r1=1674029&r2=1674030&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py Thu Apr 16 09:27:18 2015 @@ -992,6 +992,52 @@ def restructure_repo_projects_ttb_to_ttb ### It's all very well to see that the dirs and files now appear at the ### right places, but what should we test to ensure the history is intact? +# Brane's example on IRC 2015-04-14 +# "e.g., in our tree, libsvn_fs_x is a branch of libsvn_fs_fs; are we still +# allowed to merge branches/foo to trunk, and will the merge correctly reflect +# changes in these two sub-branches, and will a subsequent merge from fs_fs to +# fs_x produce sane results?" +def subbranches1(sbox): + "subbranches1" + sbox_build_svnmover(sbox, content=initial_content_in_trunk) + repo_url = sbox.repo_url + head = 1 + + # create content in a trunk subtree 'libsvn_fs_fs' + test_svnmover2(sbox, 'trunk', None, + 'mv lib libsvn_fs_fs', + 'put', mk_file(sbox, 'file.c'), 'libsvn_fs_fs/file.c') + # branch 'trunk/libsvn_fs_fs' to 'trunk/libsvn_fs_x' + test_svnmover2(sbox, 'trunk', None, + 'branch libsvn_fs_fs libsvn_fs_x') + # branch 'trunk' to 'branches/foo' + test_svnmover2(sbox, '', None, + 'branch trunk branches/foo') + + # make edits in 'branches/foo' and its subbranch + test_svnmover2(sbox, 'branches/foo', None, + 'mkdir docs', + 'mv libsvn_fs_fs/file.c libsvn_fs_fs/file2.c') + test_svnmover2(sbox, 'branches/foo/libsvn_fs_x', None, + 'mkdir reps', + 'mv file.c reps/file.c') + + # merge 'branches/foo' to 'trunk' + test_svnmover2(sbox, '', + reported_br_diff('trunk', 'trunk') + + reported_add('docs') + + reported_move('libsvn_fs_fs/file.c', 'libsvn_fs_fs/file2.c') + + reported_br_diff('trunk/libsvn_fs_x', 'trunk/libsvn_fs_x') + + reported_add('reps') + + reported_move('file.c', 'reps/file.c'), + 'merge branches/foo trunk trunk@4') + + # merge 'trunk/libsvn_fs_fs' to 'trunk/libsvn_fs_x' + test_svnmover2(sbox, '', + reported_br_diff('trunk/libsvn_fs_x', 'trunk/libsvn_fs_x') + + reported_move('reps/file.c', 'reps/file2.c'), + 'merge trunk/libsvn_fs_fs trunk/libsvn_fs_x trunk/libsvn_fs_fs@4') + ###################################################################### @@ -1007,6 +1053,7 @@ test_list = [ None, move_branch_within_same_parent_branch, restructure_repo_ttb_projects_to_projects_ttb, restructure_repo_projects_ttb_to_ttb_projects, + subbranches1, ] if __name__ == '__main__':