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=1710565&r1=1710564&r2=1710565&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original) +++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Mon Oct 26 11:06:50 2015 @@ -1218,783 +1218,6 @@ list_all_branches(svn_branch_txn_t *txn, return SVN_NO_ERROR; } -/* Options to control how strict the merge is about detecting conflicts. - * - * The options affect cases that, depending on the user's preference, could - * either be considered a conflict or be merged to a deterministic result. - * - * The set of options is flexible and may be extended in future. - */ -typedef struct merge_conflict_policy_t -{ - /* Whether to merge delete-vs-delete */ - svn_boolean_t merge_double_delete; - /* Whether to merge add-vs-add (with same parent/name/payload) */ - svn_boolean_t merge_double_add; - /* Whether to merge reparent-vs-reparent (with same parent) */ - svn_boolean_t merge_double_reparent; - /* Whether to merge rename-vs-rename (with same name) */ - svn_boolean_t merge_double_rename; - /* Whether to merge modify-vs-modify (with same payload) */ - svn_boolean_t merge_double_modify; - /* Possible additional controls: */ - /* merge (parent, name, props, text) independently or as a group */ - /* merge (parent, name) independently or as a group */ - /* merge (props, text) independently or as a group */ -} merge_conflict_policy_t; - -/* An element-merge conflict description. - */ -typedef struct element_merge3_conflict_t -{ - svn_element_content_t *yca; - svn_element_content_t *side1; - svn_element_content_t *side2; -} element_merge3_conflict_t; - -static element_merge3_conflict_t * -element_merge3_conflict_create(svn_element_content_t *yca, - svn_element_content_t *side1, - svn_element_content_t *side2, - apr_pool_t *result_pool) -{ - element_merge3_conflict_t *c = apr_pcalloc(result_pool, sizeof(*c)); - - c->yca = yca; - c->side1 = side1; - c->side2 = side2; - return c; -} - -/* A name-clash conflict description. - */ -typedef struct name_clash_conflict_t -{ - int parent_eid; - const char *name; - /* All EIDs that conflict with each other: hash of (eid -> irrelevant). */ - apr_hash_t *elements; -} name_clash_conflict_t; - -static name_clash_conflict_t * -name_clash_conflict_create(int parent_eid, - const char *name, - apr_pool_t *result_pool) -{ - name_clash_conflict_t *c = apr_pcalloc(result_pool, sizeof(*c)); - - c->parent_eid = parent_eid; - c->name = apr_pstrdup(result_pool, name); - c->elements = apr_hash_make(result_pool); - return c; -} - -/* An orphan conflict description. - */ -typedef struct orphan_conflict_t -{ - svn_element_content_t *element; -} orphan_conflict_t; - -static orphan_conflict_t * -orphan_conflict_create(svn_element_content_t *element, - apr_pool_t *result_pool) -{ - orphan_conflict_t *c = apr_pcalloc(result_pool, sizeof(*c)); - - c->element = element; - return c; -} - -typedef struct conflict_storage_t -{ - /* Single-element conflicts */ - /* (eid -> element_merge3_conflict_t) */ - apr_hash_t *single_element_conflicts; - - /* Name-clash conflicts */ - /* ("%{parent_eid}d/%{name}s" -> name_clash_conflict_t) */ - apr_hash_t *name_clash_conflicts; - - /* Orphan conflicts */ - /* (eid -> orphan_conflict_t) */ - apr_hash_t *orphan_conflicts; -} conflict_storage_t; - -/* */ -static conflict_storage_t * -conflict_storage_create(apr_pool_t *result_pool) -{ - conflict_storage_t *c = apr_pcalloc(result_pool, sizeof(*c)); - - return c; -} - -/* */ -static const char * -brief_eid_and_name_or_nil(svn_element_content_t *e, - apr_pool_t *result_pool) -{ - return e ? apr_psprintf(result_pool, "%d/%s", e->parent_eid, e->name) - : "<nil>"; - - return SVN_NO_ERROR; -} - -/* */ -static svn_error_t * -display_conflicts(conflict_storage_t *conflict_storage, - const char *prefix, - apr_pool_t *scratch_pool) -{ - apr_hash_index_t *hi; - - for (hi = apr_hash_first(scratch_pool, - conflict_storage->single_element_conflicts); - hi; hi = apr_hash_next(hi)) - { - int eid = svn_int_hash_this_key(hi); - element_merge3_conflict_t *c = apr_hash_this_val(hi); - - printf("%ssingle-element conflict: e%d: yca=%s, side1=%s, side2=%s\n", - prefix, eid, - brief_eid_and_name_or_nil(c->yca, scratch_pool), - brief_eid_and_name_or_nil(c->side1, scratch_pool), - brief_eid_and_name_or_nil(c->side2, scratch_pool)); - } - for (hi = apr_hash_first(scratch_pool, - conflict_storage->name_clash_conflicts); - hi; hi = apr_hash_next(hi)) - { - /*const char *key = apr_hash_this_key(hi);*/ - name_clash_conflict_t *c = apr_hash_this_val(hi); - apr_hash_index_t *hi2; - - printf("%sname-clash conflict: peid %d, name '%s', %d elements\n", - prefix, c->parent_eid, c->name, apr_hash_count(c->elements)); - for (hi2 = apr_hash_first(scratch_pool, c->elements); - hi2; hi2 = apr_hash_next(hi2)) - { - int eid = svn_int_hash_this_key(hi2); - - printf("%s element %d\n", prefix, eid); - } - } - for (hi = apr_hash_first(scratch_pool, - conflict_storage->orphan_conflicts); - hi; hi = apr_hash_next(hi)) - { - int eid = svn_int_hash_this_key(hi); - orphan_conflict_t *c = apr_hash_this_val(hi); - - printf("%sorphan conflict: element %d/%s: peid %d does not exist\n", - prefix, eid, c->element->name, c->element->parent_eid); - } - return SVN_NO_ERROR; -} - -/* Merge the payload for one element. - * - * If there is no conflict, set *CONFLICT_P to FALSE and *RESULT_P to the - * merged element; otherwise set *CONFLICT_P to TRUE and *RESULT_P to NULL. - * Note that *RESULT_P can be null, indicating a deletion. - * - * This handles any case where at least one of (SIDE1, SIDE2, YCA) exists. - * - * Allocate the result in RESULT_POOL and/or as pointers to the inputs. - */ -static void -payload_merge(svn_element_payload_t **result_p, - svn_boolean_t *conflict_p, - int eid, - svn_element_payload_t *side1, - svn_element_payload_t *side2, - svn_element_payload_t *yca, - const merge_conflict_policy_t *policy, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_boolean_t conflict = FALSE; - svn_element_payload_t *result = NULL; - - if (yca && side1 && side2) - { - if (svn_element_payload_equal(side1, yca, scratch_pool)) - { - result = side2; - } - else if (svn_element_payload_equal(side2, yca, scratch_pool)) - { - result = side1; - } - else if (policy->merge_double_modify - && svn_element_payload_equal(side1, side2, scratch_pool)) - { - SVN_DBG(("e%d double modify: ... -> { ... | ... }", - eid)); - result = side1; - } - else - { - /* ### Need not conflict if can merge props and text separately. */ - - SVN_DBG(("e%d conflict: payload: ... -> { ... | ... }", - eid)); - conflict = TRUE; - } - } - - *result_p = result; - *conflict_p = conflict; -} - -/* Merge the content for one element. - * - * If there is no conflict, set *CONFLICT_P to FALSE and *RESULT_P to the - * merged element; otherwise set *CONFLICT_P to TRUE and *RESULT_P to NULL. - * Note that *RESULT_P can be null, indicating a deletion. - * - * This handles any case where at least one of (SIDE1, SIDE2, YCA) exists. - * - * Allocate the result in RESULT_POOL and/or as pointers to the inputs. - */ -static void -element_merge(svn_element_content_t **result_p, - element_merge3_conflict_t **conflict_p, - int eid, - svn_element_content_t *side1, - svn_element_content_t *side2, - svn_element_content_t *yca, - const merge_conflict_policy_t *policy, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_boolean_t same1 = svn_element_content_equal(yca, side1, scratch_pool); - svn_boolean_t same2 = svn_element_content_equal(yca, side2, scratch_pool); - svn_boolean_t conflict = FALSE; - svn_element_content_t *result = NULL; - - if (same1) - { - result = side2; - } - else if (same2) - { - result = side1; - } - else if (yca && side1 && side2) - { - /* All three sides are different, and all exist */ - result = apr_pmemdup(result_pool, yca, sizeof(*result)); - - /* merge the parent-eid */ - if (side1->parent_eid == yca->parent_eid) - { - result->parent_eid = side2->parent_eid; - } - else if (side2->parent_eid == yca->parent_eid) - { - result->parent_eid = side1->parent_eid; - } - else if (policy->merge_double_reparent - && side1->parent_eid == side2->parent_eid) - { - SVN_DBG(("e%d double reparent: e%d -> { e%d | e%d }", - eid, yca->parent_eid, side1->parent_eid, side2->parent_eid)); - result->parent_eid = side1->parent_eid; - } - else - { - SVN_DBG(("e%d conflict: parent: e%d -> { e%d | e%d }", - eid, yca->parent_eid, side1->parent_eid, side2->parent_eid)); - conflict = TRUE; - } - - /* merge the name */ - if (strcmp(side1->name, yca->name) == 0) - { - result->name = side2->name; - } - else if (strcmp(side2->name, yca->name) == 0) - { - result->name = side1->name; - } - else if (policy->merge_double_rename - && strcmp(side1->name, side2->name) == 0) - { - SVN_DBG(("e%d double rename: %s -> { %s | %s }", - eid, yca->name, side1->name, side2->name)); - result->name = side1->name; - } - else - { - SVN_DBG(("e%d conflict: name: %s -> { %s | %s }", - eid, yca->name, side1->name, side2->name)); - conflict = TRUE; - } - - /* merge the payload */ - { - svn_boolean_t payload_conflict; - - payload_merge(&result->payload, &payload_conflict, - eid, side1->payload, side2->payload, yca->payload, - policy, result_pool, scratch_pool); - if (payload_conflict) - conflict = TRUE; - } - } - else if (! side1 && ! side2) - { - /* Double delete (as we assume at least one of YCA/SIDE1/SIDE2 exists) */ - if (policy->merge_double_delete) - { - SVN_DBG(("e%d double delete", - eid)); - result = side1; - } - else - { - SVN_DBG(("e%d conflict: delete vs. delete", - eid)); - conflict = TRUE; - } - } - else if (side1 && side2) - { - /* Double add (as we already handled the case where YCA also exists) */ - /* May be allowed for equal content of a normal element (not subbranch) */ - if (policy->merge_double_add - && !side1->payload->is_subbranch_root - && !side2->payload->is_subbranch_root - && svn_element_content_equal(side1, side2, scratch_pool)) - { - SVN_DBG(("e%d double add", - eid)); - result = side1; - } - else - { - SVN_DBG(("e%d conflict: add vs. add (%s)", - eid, - svn_element_content_equal(side1, side2, scratch_pool) - ? "same content" : "different content")); - conflict = TRUE; - } - } - else - { - /* The remaining cases must be delete vs. modify */ - SVN_DBG(("e%d conflict: delete vs. modify: %d -> { %d | %d }", - eid, !!yca, !!side1, !!side2)); - conflict = TRUE; - } - - *result_p = result; - *conflict_p - = conflict ? element_merge3_conflict_create(yca, side1, side2, - result_pool) : NULL; -} - -static svn_error_t * -branch_merge_subtree_r(svn_branch_txn_t *edit_txn, - conflict_storage_t **conflict_storage_p, - 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 *result_pool, - apr_pool_t *scratch_pool); - -/* Merge the subbranch of {SRC, TGT, YCA} found at EID. - */ -static svn_error_t * -merge_subbranch(svn_branch_txn_t *edit_txn, - 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_state_t *src_subbranch - = svn_branch_get_subbranch_at_eid(src->branch, eid, scratch_pool); - svn_branch_state_t *tgt_subbranch - = svn_branch_get_subbranch_at_eid(tgt->branch, eid, scratch_pool); - svn_branch_state_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, svn_branch_root_eid(src_subbranch), - src->rev, scratch_pool); - if (tgt_subbranch) - subbr_tgt = svn_branch_el_rev_id_create( - tgt_subbranch, svn_branch_root_eid(tgt_subbranch), - tgt->rev, scratch_pool); - if (yca_subbranch) - subbr_yca = svn_branch_el_rev_id_create( - yca_subbranch, svn_branch_root_eid(yca_subbranch), - yca->rev, scratch_pool); - - if (subbr_src && subbr_tgt && subbr_yca) /* ?edit vs. ?edit */ - { - conflict_storage_t *conflict_storage; - - /* subbranch possibly changed in source => merge */ - SVN_ERR(branch_merge_subtree_r(edit_txn, - &conflict_storage, - subbr_src, subbr_tgt, subbr_yca, - scratch_pool, scratch_pool)); - /* ### store this branch's conflict_storage somewhere ... */ - } - 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 */ - { - const char *new_branch_id - = svn_branch_id_nest(svn_branch_get_id(tgt->branch, scratch_pool), - eid, scratch_pool); - svn_branch_rev_bid_eid_t *from - = svn_branch_rev_bid_eid_create(src_subbranch->txn->rev, - svn_branch_get_id(src_subbranch, - scratch_pool), - svn_branch_root_eid(src_subbranch), - scratch_pool); - - SVN_ERR(svn_branch_txn_branch(edit_txn, NULL /*new_branch_id_p*/, from, - new_branch_id, scratch_pool, scratch_pool)); - } - else if (subbr_tgt) /* added on target branch */ - { - /* nothing to do */ - } - else if (subbr_yca) /* double delete */ - { - /* ### conflict? policy option? */ - } - - return SVN_NO_ERROR; -} - -/* */ -static int -sort_compare_items_by_peid_and_name(const svn_sort__item_t *a, - const svn_sort__item_t *b) -{ - svn_element_content_t *element_a = a->value; - svn_element_content_t *element_b = b->value; - - if (element_a->parent_eid != element_b->parent_eid) - return element_a->parent_eid - element_b->parent_eid; - return strcmp(element_a->name, element_b->name); -} - -/* Return all (key -> name_clash_conflict_t) name clash conflicts in BRANCH. - */ -static svn_error_t * -detect_clashes(apr_hash_t **clashes_p, - svn_branch_state_t *branch, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_hash_t *clashes = apr_hash_make(result_pool); - SVN_ITER_T(svn_element_content_t) *pi; - int prev_eid = -1; - svn_element_content_t *prev_element = NULL; - - for (SVN_HASH_ITER_SORTED(pi, svn_branch_get_elements(branch), - sort_compare_items_by_peid_and_name, scratch_pool)) - { - int eid = *(const int *)(pi->key); - svn_element_content_t *element = pi->val; - - if (prev_element - && element->parent_eid == prev_element->parent_eid - && strcmp(element->name, prev_element->name) == 0) - { - const char *key = apr_psprintf(result_pool, "%d/%s", - element->parent_eid, element->name); - name_clash_conflict_t *c; - - c = svn_hash_gets(clashes, key); - if (!c) - { - c = name_clash_conflict_create( - element->parent_eid, element->name, - result_pool); - svn_hash_sets(clashes, key, c); - } - svn_int_hash_set(c->elements, eid, &c); - svn_int_hash_set(c->elements, prev_eid, &c); - } - prev_eid = eid; - prev_element = element; - } - - *clashes_p = clashes; - return SVN_NO_ERROR; -} - -/* Return all (eid -> orphan_conflict_t) orphan conflicts in BRANCH. - */ -static svn_error_t * -detect_orphans(apr_hash_t **orphans_p, - svn_branch_state_t *branch, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_hash_t *orphans = apr_hash_make(result_pool); - SVN_ITER_T(svn_element_content_t) *pi; - const svn_element_tree_t *elements = svn_branch_get_element_tree(branch); - - for (SVN_HASH_ITER(pi, scratch_pool, elements->e_map)) - { - int eid = *(const int *)(pi->key); - svn_element_content_t *element = pi->val; - - if (eid != elements->root_eid - && ! svn_element_tree_get(elements, element->parent_eid)) - { - orphan_conflict_t *c; - - c = orphan_conflict_create(element, result_pool); - svn_int_hash_set(orphans, eid, c); - - notify(" orphan: %d/%s: peid %d does not exist", - eid, element->name, element->parent_eid); - } - } - - *orphans_p = orphans; - return SVN_NO_ERROR; -} - -/* Merge ... - * - * Merge any sub-branches in the same way, recursively. - */ -static svn_error_t * -branch_merge_subtree_r(svn_branch_txn_t *edit_txn, - conflict_storage_t **conflict_storage_p, - 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 *result_pool, - apr_pool_t *scratch_pool) -{ - svn_branch_subtree_t *s_src, *s_tgt, *s_yca; - apr_hash_t *diff_yca_src, *diff_yca_tgt; - apr_hash_t *e_conflicts = apr_hash_make(scratch_pool); - conflict_storage_t *conflict_storage = conflict_storage_create(result_pool); - SVN_ITER_T(svn_element_content_t *) *pi; - apr_hash_t *all_elements; - const merge_conflict_policy_t policy = { TRUE, TRUE, TRUE, TRUE, TRUE }; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - - SVN_ERR_ASSERT(src->eid == tgt->eid); - SVN_ERR_ASSERT(src->eid == yca->eid); - - SVN_DBG(("merge src: r%2ld %s e%3d", - src->rev, - svn_branch_get_id(src->branch, scratch_pool), src->eid)); - SVN_DBG(("merge tgt: r%2ld %s e%3d", - tgt->rev, - svn_branch_get_id(tgt->branch, scratch_pool), tgt->eid)); - SVN_DBG(("merge yca: r%2ld %s e%3d", - yca->rev, - svn_branch_get_id(yca->branch, scratch_pool), yca->eid)); - - notify_v("merging into branch %s", - svn_branch_get_id(tgt->branch, scratch_pool)); - /* - for (eid, diff1) in element_differences(YCA, FROM): - diff2 = element_diff(eid, YCA, TO) - if diff1 and diff2: - result := element_merge(diff1, diff2) - elif diff1: - result := diff1.right - # else no change - */ - s_src = svn_branch_get_subtree(src->branch, src->eid, scratch_pool); - s_tgt = svn_branch_get_subtree(tgt->branch, tgt->eid, scratch_pool); - s_yca = svn_branch_get_subtree(yca->branch, yca->eid, scratch_pool); - SVN_ERR(element_differences(&diff_yca_src, - s_yca->tree, s_src->tree, - scratch_pool, scratch_pool)); - /* ### We only need to query for YCA:TO differences in elements that are - different in YCA:FROM, but right now we ask for all differences. */ - SVN_ERR(element_differences(&diff_yca_tgt, - s_yca->tree, s_tgt->tree, - scratch_pool, scratch_pool)); - - all_elements = apr_hash_overlay(scratch_pool, - svn_branch_get_elements(src->branch), - svn_branch_get_elements(tgt->branch)); - all_elements = apr_hash_overlay(scratch_pool, - svn_branch_get_elements(yca->branch), - all_elements); - for (SVN_HASH_ITER_SORTED(pi, all_elements, - sort_compare_items_by_eid, scratch_pool)) - { - int eid = *(const int *)(pi->key); - svn_element_content_t **e_yca_src - = svn_int_hash_get(diff_yca_src, eid); - svn_element_content_t **e_yca_tgt - = svn_int_hash_get(diff_yca_tgt, eid); - svn_element_content_t *e_yca; - svn_element_content_t *e_src; - svn_element_content_t *e_tgt; - svn_element_content_t *result; - element_merge3_conflict_t *conflict; - - svn_pool_clear(iterpool); - - /* If an element hasn't changed in the source branch, there is - no need to do anything with it in the target branch. We could - use element_merge() for any case where at least one of (SRC, - TGT, YCA) exists, but we choose to skip it when SRC == YCA. */ - if (! e_yca_src) - { - /* Still need to merge any subbranch linked to this element. - There were no changes to the link element but that doesn't - mean there were no changes to the linked branch. */ - SVN_ERR(merge_subbranch(edit_txn, src, tgt, yca, eid, iterpool)); - - continue; - } - - e_yca = e_yca_src[0]; - e_src = e_yca_src[1]; - e_tgt = e_yca_tgt ? e_yca_tgt[1] : e_yca_src[0]; - - element_merge(&result, &conflict, - eid, e_src, e_tgt, e_yca, - &policy, - scratch_pool, scratch_pool); - - if (conflict) - { - notify_v("! e%d <conflict>", eid); - svn_int_hash_set(e_conflicts, eid, conflict); - } - else if (e_tgt && result) - { - notify_v("M/V e%d %s%s", - eid, result->name, - subbranch_str(tgt->branch, eid, iterpool)); - - SVN_ERR(svn_branch_state_alter_one(tgt->branch, eid, - result->parent_eid, result->name, - result->payload, iterpool)); - - SVN_ERR(merge_subbranch(edit_txn, src, tgt, yca, eid, iterpool)); - } - else if (e_tgt) - { - notify_v("D e%d %s%s", - eid, e_yca->name, - subbranch_str(yca->branch, eid, iterpool)); - SVN_ERR(svn_branch_state_delete_one(tgt->branch, eid, iterpool)); - - /* ### If this is a subbranch-root element being deleted, shouldn't - we see if there were any changes to be merged in the subbranch, - and raise a delete-vs-edit conflict if so? */ - } - else if (result) - { - notify_v("A e%d %s%s", - eid, result->name, - subbranch_str(src->branch, eid, iterpool)); - - /* In BRANCH, create an instance of the element EID with new content. - * - * Translated to old language, this means create a new node-copy - * copied (branched) from the source-right version of the merge - * (which is not specified here, but will need to be), - * which may be in this branch or in another branch. - */ - SVN_ERR(svn_branch_state_alter_one(tgt->branch, eid, - result->parent_eid, result->name, - result->payload, iterpool)); - - SVN_ERR(merge_subbranch(edit_txn, src, tgt, yca, eid, iterpool)); - } - } - svn_pool_destroy(iterpool); - - /* Detect clashes. - ### TODO: Detect clashes, cycles and orphans; and report full conflict - info (including the relevant incoming changes) for each - kind of conflict. If there are no conflicts, flatten the - merge result into a tree. */ - conflict_storage->single_element_conflicts = e_conflicts; - SVN_ERR(detect_clashes(&conflict_storage->name_clash_conflicts, - tgt->branch, - result_pool, scratch_pool)); - SVN_ERR(detect_orphans(&conflict_storage->orphan_conflicts, - tgt->branch, - result_pool, scratch_pool)); - - notify_v("merging into branch %s -- finished", - svn_branch_get_id(tgt->branch, scratch_pool)); - - *conflict_storage_p = conflict_storage; - return SVN_NO_ERROR; -} - -/* Merge SRC into TGT, using the common ancestor YCA. - * - * Merge the two sets of changes: YCA -> SRC and YCA -> TGT, applying - * the result to the transaction at TGT. - * - * If conflicts arise, just fail. - * - * SRC, TGT and YCA must be existing and corresponding (same EID) elements. - * - * None of SRC, TGT and YCA is a subbranch root element. - * - * Nested subbranches will also be merged. - */ -static svn_error_t * -svn_branch_merge(svn_branch_txn_t *edit_txn, - conflict_storage_t **conflict_storage_p, - svn_branch_el_rev_id_t *src, - svn_branch_el_rev_id_t *tgt, - svn_branch_el_rev_id_t *yca, - apr_pool_t *scratch_pool) -{ - /*SVN_ERR(verify_exists_in_branch(from, scratch_pool));*/ - /*SVN_ERR(verify_exists_in_branch(to, scratch_pool));*/ - /*SVN_ERR(verify_exists_in_branch(yca, scratch_pool));*/ - if (src->eid != tgt->eid || src->eid != yca->eid) - return svn_error_createf(SVN_ERR_BRANCHING, NULL, - _("Merge branches must all be same element " - "(from: e%d, to: e%d, yca: e%d)"), - src->eid, tgt->eid, yca->eid); - /*SVN_ERR(verify_not_subbranch_root(from, scratch_pool));*/ - /*SVN_ERR(verify_not_subbranch_root(to, scratch_pool));*/ - /*SVN_ERR(verify_not_subbranch_root(yca, scratch_pool));*/ - - SVN_ERR(branch_merge_subtree_r(edit_txn, - conflict_storage_p, - src, tgt, yca, - scratch_pool, scratch_pool)); - - return SVN_NO_ERROR; -} - /* Switch the WC to revision BASE_REVISION (SVN_INVALID_REVNUM means HEAD) * and branch BRANCH_ID. * @@ -2048,14 +1271,15 @@ do_switch(svnmover_wc_t *wc, tgt = svn_branch_el_rev_id_create(wc->working->branch, svn_branch_root_eid(wc->working->branch), SVN_INVALID_REVNUM, scratch_pool); - SVN_ERR(svn_branch_merge(wc->edit_txn, &conflicts, - src, tgt, yca, scratch_pool)); + SVN_ERR(svnmover_branch_merge(wc->edit_txn, &conflicts, + src, tgt, yca, scratch_pool)); if (apr_hash_count(conflicts->single_element_conflicts) || apr_hash_count(conflicts->name_clash_conflicts) || apr_hash_count(conflicts->orphan_conflicts)) { - SVN_ERR(display_conflicts(conflicts, "switch: ", scratch_pool)); + SVN_ERR(svnmover_display_conflicts(conflicts, "switch: ", + scratch_pool)); return svn_error_createf( SVN_ERR_BRANCHING, NULL, _("Switch failed because of conflicts: " @@ -3578,18 +2802,19 @@ execute(svnmover_wc_t *wc, VERIFY_EID_EXISTS("merge", 0); VERIFY_EID_EXISTS("merge", 1); VERIFY_EID_EXISTS("merge", 2); - SVN_ERR(svn_branch_merge(wc->edit_txn, - &conflicts, - arg[0]->el_rev /*from*/, - arg[1]->el_rev /*to*/, - arg[2]->el_rev /*yca*/, - iterpool)); + SVN_ERR(svnmover_branch_merge(wc->edit_txn, + &conflicts, + arg[0]->el_rev /*from*/, + arg[1]->el_rev /*to*/, + arg[2]->el_rev /*yca*/, + iterpool)); if (apr_hash_count(conflicts->single_element_conflicts) || apr_hash_count(conflicts->name_clash_conflicts) || apr_hash_count(conflicts->orphan_conflicts)) { - SVN_ERR(display_conflicts(conflicts, "merge: ", iterpool)); + SVN_ERR(svnmover_display_conflicts(conflicts, "merge: ", + iterpool)); return svn_error_createf( SVN_ERR_BRANCHING, NULL, _("Merge failed because of conflicts: "
Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnmover/svnmover.h?rev=1710565&r1=1710564&r2=1710565&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.h (original) +++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.h Mon Oct 26 11:06:50 2015 @@ -65,6 +65,49 @@ typedef struct svnmover_wc_t } svnmover_wc_t; +/* */ +typedef struct conflict_storage_t +{ + /* Single-element conflicts */ + /* (eid -> element_merge3_conflict_t) */ + apr_hash_t *single_element_conflicts; + + /* Name-clash conflicts */ + /* ("%{parent_eid}d/%{name}s" -> name_clash_conflict_t) */ + apr_hash_t *name_clash_conflicts; + + /* Orphan conflicts */ + /* (eid -> orphan_conflict_t) */ + apr_hash_t *orphan_conflicts; +} conflict_storage_t; + +/* Merge SRC into TGT, using the common ancestor YCA. + * + * Merge the two sets of changes: YCA -> SRC and YCA -> TGT, applying + * the result to the transaction at TGT. + * + * If conflicts arise, just fail. + * + * SRC, TGT and YCA must be existing and corresponding (same EID) elements. + * + * None of SRC, TGT and YCA is a subbranch root element. + * + * Nested subbranches will also be merged. + */ +svn_error_t * +svnmover_branch_merge(svn_branch_txn_t *edit_txn, + conflict_storage_t **conflict_storage_p, + svn_branch_el_rev_id_t *src, + svn_branch_el_rev_id_t *tgt, + svn_branch_el_rev_id_t *yca, + apr_pool_t *scratch_pool); + +/* */ +svn_error_t * +svnmover_display_conflicts(conflict_storage_t *conflict_storage, + const char *prefix, + apr_pool_t *scratch_pool); + #ifdef __cplusplus }
