Line
Link Here
|
0 |
-- subversion/libsvn_client/merge.c |
0 |
++ subversion/libsvn_client/merge.c |
Lines 1311-1322
Link Here
|
1311 |
} notification_receiver_baton_t; |
1311 |
} notification_receiver_baton_t; |
1312 |
|
1312 |
|
1313 |
|
1313 |
|
1314 |
/* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for PATH. |
1314 |
/* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for PATH. If |
|
|
1315 |
PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO |
1316 |
where child->path == PATH is considered PATH's ancestor. If FALSE, |
1317 |
then child->path must be a proper ancestor of PATH. |
1318 |
|
1315 |
CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first |
1319 |
CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first |
1316 |
order of path. Nearest ancestor's index from |
1320 |
order of path. Nearest ancestor's index from |
1317 |
CHILDREN_WITH_MERGEINFO is returned. */ |
1321 |
CHILDREN_WITH_MERGEINFO is returned. */ |
1318 |
static int |
1322 |
static int |
1319 |
find_nearest_ancestor(apr_array_header_t *children_with_mergeinfo, |
1323 |
find_nearest_ancestor(apr_array_header_t *children_with_mergeinfo, |
|
|
1324 |
svn_boolean_t path_is_own_ancestor, |
1320 |
const char *path) |
1325 |
const char *path) |
1321 |
{ |
1326 |
{ |
1322 |
int i; |
1327 |
int i; |
Lines 1332-1339
Link Here
|
1332 |
{ |
1337 |
{ |
1333 |
svn_client__merge_path_t *child = |
1338 |
svn_client__merge_path_t *child = |
1334 |
APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); |
1339 |
APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); |
1335 |
if (svn_path_is_ancestor(child->path, path)) |
1340 |
if (svn_path_is_ancestor(child->path, path) |
1336 |
ancestor_index = i; |
1341 |
&& (svn_path_compare_paths(child->path, path) != 0 |
|
|
1342 |
|| path_is_own_ancestor)) |
1343 |
ancestor_index = i; |
1337 |
} |
1344 |
} |
1338 |
return ancestor_index; |
1345 |
return ancestor_index; |
1339 |
} |
1346 |
} |
Lines 1371-1379
Link Here
|
1371 |
/* See if this is an operative directory merge. */ |
1378 |
/* See if this is an operative directory merge. */ |
1372 |
if (!(notify_b->is_single_file_merge) && is_operative_notification) |
1379 |
if (!(notify_b->is_single_file_merge) && is_operative_notification) |
1373 |
{ |
1380 |
{ |
|
|
1381 |
/* Find NOTIFY->PATH's nearest ancestor in |
1382 |
NOTIFY->CHILDREN_WITH_MERGEINFO. Normally we consider a child in |
1383 |
NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an |
1384 |
ancestor of PATH, but if this is a deletion of PATH then the |
1385 |
notification must be for a proper ancestor of PATH. This ensures |
1386 |
we don't get notifications like: |
1387 |
|
1388 |
--- Merging rX into 'PARENT/CHILD' |
1389 |
D PARENT/CHILD |
1390 |
|
1391 |
But rather: |
1392 |
|
1393 |
--- Merging rX into 'PARENT' |
1394 |
D PARENT/CHILD |
1395 |
*/ |
1374 |
int new_nearest_ancestor_index = |
1396 |
int new_nearest_ancestor_index = |
1375 |
find_nearest_ancestor(notify_b->children_with_mergeinfo, |
1397 |
find_nearest_ancestor( |
1376 |
notify->path); |
1398 |
notify_b->children_with_mergeinfo, |
|
|
1399 |
notify->action == svn_wc_notify_update_delete ? FALSE : TRUE, |
1400 |
notify->path); |
1401 |
|
1377 |
if (new_nearest_ancestor_index != notify_b->cur_ancestor_index) |
1402 |
if (new_nearest_ancestor_index != notify_b->cur_ancestor_index) |
1378 |
{ |
1403 |
{ |
1379 |
svn_client__merge_path_t *child = |
1404 |
svn_client__merge_path_t *child = |
Lines 1853-1859
Link Here
|
1853 |
const char *child_repos_path; |
1878 |
const char *child_repos_path; |
1854 |
const svn_wc_entry_t *child_entry; |
1879 |
const svn_wc_entry_t *child_entry; |
1855 |
const char *child_url1, *child_url2; |
1880 |
const char *child_url1, *child_url2; |
1856 |
svn_mergeinfo_t implicit_mergeinfo; |
|
|
1857 |
svn_client__merge_path_t *child = |
1881 |
svn_client__merge_path_t *child = |
1858 |
APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); |
1882 |
APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); |
1859 |
|
1883 |
|
Lines 1875-1881
Link Here
|
1875 |
FALSE, iterpool)); |
1899 |
FALSE, iterpool)); |
1876 |
|
1900 |
|
1877 |
SVN_ERR(get_full_mergeinfo(&(child->pre_merge_mergeinfo), |
1901 |
SVN_ERR(get_full_mergeinfo(&(child->pre_merge_mergeinfo), |
1878 |
&implicit_mergeinfo, child_entry, |
1902 |
&(child->implicit_mergeinfo), child_entry, |
1879 |
&(child->indirect_mergeinfo), |
1903 |
&(child->indirect_mergeinfo), |
1880 |
svn_mergeinfo_inherited, NULL, child->path, |
1904 |
svn_mergeinfo_inherited, NULL, child->path, |
1881 |
MAX(revision1, revision2), |
1905 |
MAX(revision1, revision2), |
Lines 1888-1894
Link Here
|
1888 |
child_url2, revision2, |
1912 |
child_url2, revision2, |
1889 |
inheritable, |
1913 |
inheritable, |
1890 |
child->pre_merge_mergeinfo, |
1914 |
child->pre_merge_mergeinfo, |
1891 |
implicit_mergeinfo, |
1915 |
child->implicit_mergeinfo, |
1892 |
ra_session, child_entry, merge_b->ctx, |
1916 |
ra_session, child_entry, merge_b->ctx, |
1893 |
pool)); |
1917 |
pool)); |
1894 |
} |
1918 |
} |
Lines 1925-1932
Link Here
|
1925 |
/*** Other Helper Functions ***/ |
1949 |
/*** Other Helper Functions ***/ |
1926 |
|
1950 |
|
1927 |
|
1951 |
|
1928 |
/* Create mergeinfo describing the merge of RANGE into our target, accounting |
1952 |
/* Create mergeinfo describing the merge of RANGELIST into TARGET_WCPATH, |
1929 |
for paths unaffected by the merge due to skips or conflicts from |
1953 |
accounting for paths unaffected by the merge due to skips or conflicts from |
1930 |
NOTIFY_B. For 'immediates' merge it sets an inheritable mergeinfo |
1954 |
NOTIFY_B. For 'immediates' merge it sets an inheritable mergeinfo |
1931 |
corresponding to current merge on merge target. For 'files' merge it sets |
1955 |
corresponding to current merge on merge target. For 'files' merge it sets |
1932 |
an inheritable mergeinfo corrsponding to current merge on merged files. |
1956 |
an inheritable mergeinfo corrsponding to current merge on merged files. |
Lines 1934-1952
Link Here
|
1934 |
TARGET_MISSING_CHILD should be true, otherwise it is false.*/ |
1958 |
TARGET_MISSING_CHILD should be true, otherwise it is false.*/ |
1935 |
static svn_error_t * |
1959 |
static svn_error_t * |
1936 |
determine_merges_performed(apr_hash_t **merges, const char *target_wcpath, |
1960 |
determine_merges_performed(apr_hash_t **merges, const char *target_wcpath, |
1937 |
svn_merge_range_t *range, |
1961 |
apr_array_header_t *rangelist, |
1938 |
svn_depth_t depth, |
1962 |
svn_depth_t depth, |
1939 |
svn_wc_adm_access_t *adm_access, |
1963 |
svn_wc_adm_access_t *adm_access, |
1940 |
notification_receiver_baton_t *notify_b, |
1964 |
notification_receiver_baton_t *notify_b, |
1941 |
merge_cmd_baton_t *merge_b, |
1965 |
merge_cmd_baton_t *merge_b, |
1942 |
apr_pool_t *pool) |
1966 |
apr_pool_t *pool) |
1943 |
{ |
1967 |
{ |
1944 |
apr_array_header_t *rangelist = apr_array_make(pool, 1, sizeof(range)); |
|
|
1945 |
apr_size_t nbr_skips = (notify_b->skipped_paths != NULL ? |
1968 |
apr_size_t nbr_skips = (notify_b->skipped_paths != NULL ? |
1946 |
apr_hash_count(notify_b->skipped_paths) : 0); |
1969 |
apr_hash_count(notify_b->skipped_paths) : 0); |
1947 |
|
1970 |
|
1948 |
*merges = apr_hash_make(pool); |
1971 |
*merges = apr_hash_make(pool); |
1949 |
APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = range; |
|
|
1950 |
apr_hash_set(*merges, target_wcpath, APR_HASH_KEY_STRING, rangelist); |
1972 |
apr_hash_set(*merges, target_wcpath, APR_HASH_KEY_STRING, rangelist); |
1951 |
if (nbr_skips > 0) |
1973 |
if (nbr_skips > 0) |
1952 |
{ |
1974 |
{ |
Lines 1978-1984
Link Here
|
1978 |
### see issue #2915. */ |
2000 |
### see issue #2915. */ |
1979 |
apr_hash_set(*merges, (const char *) skipped_path, |
2001 |
apr_hash_set(*merges, (const char *) skipped_path, |
1980 |
APR_HASH_KEY_STRING, |
2002 |
APR_HASH_KEY_STRING, |
1981 |
apr_array_make(pool, 0, sizeof(range))); |
2003 |
apr_array_make(pool, 0, sizeof(svn_merge_range_t))); |
1982 |
|
2004 |
|
1983 |
if (nbr_skips < notify_b->nbr_notifications) |
2005 |
if (nbr_skips < notify_b->nbr_notifications) |
1984 |
/* ### Use RANGELIST as the mergeinfo for all children of |
2006 |
/* ### Use RANGELIST as the mergeinfo for all children of |
Lines 1996-2005
Link Here
|
1996 |
hi = apr_hash_next(hi)) |
2018 |
hi = apr_hash_next(hi)) |
1997 |
{ |
2019 |
{ |
1998 |
const svn_wc_entry_t *child_entry; |
2020 |
const svn_wc_entry_t *child_entry; |
1999 |
svn_merge_range_t *child_merge_range; |
|
|
2000 |
apr_array_header_t *rangelist_of_child = NULL; |
2021 |
apr_array_header_t *rangelist_of_child = NULL; |
2001 |
apr_hash_this(hi, &merged_path, NULL, NULL); |
2022 |
apr_hash_this(hi, &merged_path, NULL, NULL); |
2002 |
child_merge_range = svn_merge_range_dup(range, pool); |
|
|
2003 |
SVN_ERR(svn_wc__entry_versioned(&child_entry, |
2023 |
SVN_ERR(svn_wc__entry_versioned(&child_entry, |
2004 |
merged_path, |
2024 |
merged_path, |
2005 |
adm_access, FALSE, |
2025 |
adm_access, FALSE, |
Lines 2014-2027
Link Here
|
2014 |
1. Merge target directory if depth is immediates. |
2034 |
1. Merge target directory if depth is immediates. |
2015 |
2. If merge is on a file and requested depth is 'files'. |
2035 |
2. If merge is on a file and requested depth is 'files'. |
2016 |
*/ |
2036 |
*/ |
2017 |
child_merge_range->inheritable = TRUE; |
2037 |
int i; |
2018 |
rangelist_of_child = apr_array_make(pool, 1, sizeof(range)); |
2038 |
rangelist_of_child = svn_rangelist_dup(rangelist, pool); |
|
|
2039 |
for (i = 0; i < rangelist_of_child->nelts; i++) |
2040 |
{ |
2041 |
svn_merge_range_t *rng = |
2042 |
APR_ARRAY_IDX(rangelist_of_child, i, svn_merge_range_t *); |
2043 |
rng->inheritable = TRUE; |
2044 |
} |
2019 |
} |
2045 |
} |
2020 |
if (rangelist_of_child) |
2046 |
if (rangelist_of_child) |
2021 |
{ |
2047 |
{ |
2022 |
APR_ARRAY_PUSH(rangelist_of_child, svn_merge_range_t *) = |
|
|
2023 |
child_merge_range; |
2024 |
|
2025 |
apr_hash_set(*merges, (const char *)merged_path, |
2048 |
apr_hash_set(*merges, (const char *)merged_path, |
2026 |
APR_HASH_KEY_STRING, rangelist_of_child); |
2049 |
APR_HASH_KEY_STRING, rangelist_of_child); |
2027 |
} |
2050 |
} |
Lines 2510-2525
Link Here
|
2510 |
} |
2533 |
} |
2511 |
} |
2534 |
} |
2512 |
|
2535 |
|
2513 |
/* For each child of CHILDREN_WITH_MERGEINFO create a new remaining_ranges |
2536 |
/* Helper for do_directory_merge(). |
2514 |
by removing the first item from the original range list and overwrite the |
2537 |
|
2515 |
original remaining_ranges with this new list. |
2538 |
Remove the first remaining revision range for each child in |
2516 |
All the allocations are persistent from a POOL. |
2539 |
CHILDREN_WITH_MERGEINFO *iff* that child was already merged. END_REV is the |
2517 |
TODO, we should have remaining_ranges in reverse order to avoid recreating |
2540 |
ending revision of the most recently merged range, i.e. the same end_rev |
2518 |
the remaining_ranges every time instead of one 'pop' operation. */ |
2541 |
passed to drive_merge_report_editor() by do_directory_merge(). If a |
|
|
2542 |
range is removed from a child's remaining_ranges array, allocate the new |
2543 |
remaining_ranges array in POOL. |
2544 |
|
2545 |
### TODO: We should have remaining_ranges in reverse order to avoid |
2546 |
### recreating and reallocationg the remaining_ranges every time we want |
2547 |
### to remove the first range. If the ranges were reversed we could simply |
2548 |
### pop the last element in the array. */ |
2519 |
static void |
2549 |
static void |
2520 |
remove_first_range_from_remaining_ranges( |
2550 |
remove_first_range_from_remaining_ranges(svn_revnum_t end_rev, |
2521 |
apr_array_header_t *children_with_mergeinfo, |
2551 |
apr_array_header_t |
2522 |
apr_pool_t *pool) |
2552 |
*children_with_mergeinfo, |
|
|
2553 |
apr_pool_t *pool) |
2523 |
{ |
2554 |
{ |
2524 |
int i, j; |
2555 |
int i, j; |
2525 |
for (i = 0; i < children_with_mergeinfo->nelts; i++) |
2556 |
for (i = 0; i < children_with_mergeinfo->nelts; i++) |
Lines 2531-2547
Link Here
|
2531 |
continue; |
2562 |
continue; |
2532 |
if (child->remaining_ranges->nelts > 0) |
2563 |
if (child->remaining_ranges->nelts > 0) |
2533 |
{ |
2564 |
{ |
2534 |
apr_array_header_t *orig_remaining_ranges = child->remaining_ranges; |
2565 |
svn_merge_range_t *first_range = |
2535 |
child->remaining_ranges = |
2566 |
APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); |
2536 |
apr_array_make(pool, (child->remaining_ranges->nelts - 1), |
2567 |
if (first_range->end == end_rev) |
2537 |
sizeof(svn_merge_range_t *)); |
|
|
2538 |
for (j = 1; j < orig_remaining_ranges->nelts; j++) |
2539 |
{ |
2568 |
{ |
2540 |
svn_merge_range_t *range = APR_ARRAY_IDX(orig_remaining_ranges, |
2569 |
apr_array_header_t *orig_remaining_ranges = |
2541 |
j, |
2570 |
child->remaining_ranges; |
2542 |
svn_merge_range_t *); |
2571 |
child->remaining_ranges = |
2543 |
APR_ARRAY_PUSH(child->remaining_ranges, svn_merge_range_t *) |
2572 |
apr_array_make(pool, (child->remaining_ranges->nelts - 1), |
2544 |
= range; |
2573 |
sizeof(svn_merge_range_t *)); |
|
|
2574 |
for (j = 1; j < orig_remaining_ranges->nelts; j++) |
2575 |
{ |
2576 |
svn_merge_range_t *range = |
2577 |
APR_ARRAY_IDX(orig_remaining_ranges, |
2578 |
j, |
2579 |
svn_merge_range_t *); |
2580 |
APR_ARRAY_PUSH(child->remaining_ranges, |
2581 |
svn_merge_range_t *) = range; |
2582 |
} |
2545 |
} |
2583 |
} |
2546 |
} |
2584 |
} |
2547 |
} |
2585 |
} |
Lines 3455-3460
Link Here
|
3455 |
} |
3493 |
} |
3456 |
|
3494 |
|
3457 |
|
3495 |
|
|
|
3496 |
/* Implements the svn_log_entry_receiver_t interface. */ |
3497 |
static svn_error_t * |
3498 |
log_changed_revs(void *baton, |
3499 |
svn_log_entry_t *log_entry, |
3500 |
apr_pool_t *pool) |
3501 |
{ |
3502 |
apr_array_header_t *revs = baton; |
3503 |
svn_revnum_t *revision = apr_palloc(revs->pool, sizeof(*revision)); |
3504 |
*revision = log_entry->revision; |
3505 |
APR_ARRAY_PUSH(revs, svn_revnum_t *) = revision; |
3506 |
return SVN_NO_ERROR; |
3507 |
} |
3508 |
|
3509 |
|
3510 |
/* Set *OPERATIVE_RANGES_P to an array of svn_merge_range_t * merge |
3511 |
range objects copied wholesale from RANGES which have the property |
3512 |
that in some revision within that range the object identified by |
3513 |
RA_SESSION was modified (if by "modified" we mean "'svn log' would |
3514 |
return that revision). *OPERATIVE_RANGES_P is allocated from the |
3515 |
same pool as RANGES, and the ranges within it are shared with |
3516 |
RANGES, too. Use POOL for temporary allocations. */ |
3517 |
static svn_error_t * |
3518 |
remove_noop_merge_ranges(apr_array_header_t **operative_ranges_p, |
3519 |
svn_ra_session_t *ra_session, |
3520 |
apr_array_header_t *ranges, |
3521 |
apr_pool_t *pool) |
3522 |
{ |
3523 |
int i; |
3524 |
svn_revnum_t oldest_rev = SVN_INVALID_REVNUM; |
3525 |
svn_revnum_t youngest_rev = SVN_INVALID_REVNUM; |
3526 |
apr_array_header_t *changed_revs = |
3527 |
apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t *)); |
3528 |
apr_array_header_t *operative_ranges = |
3529 |
apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size); |
3530 |
apr_array_header_t *log_targets = |
3531 |
apr_array_make(pool, 1, sizeof(const char *)); |
3532 |
APR_ARRAY_PUSH(log_targets, const char *) = ""; |
3533 |
|
3534 |
/* Find the revision extremes of the RANGES we have. */ |
3535 |
for (i = 0; i < ranges->nelts; i++) |
3536 |
{ |
3537 |
svn_merge_range_t *r = APR_ARRAY_IDX(ranges, i, svn_merge_range_t *); |
3538 |
svn_revnum_t max_rev = MAX(r->start, r->end); |
3539 |
svn_revnum_t min_rev = MIN(r->start, r->end) + 1; |
3540 |
|
3541 |
if ((! SVN_IS_VALID_REVNUM(youngest_rev)) || (max_rev > youngest_rev)) |
3542 |
youngest_rev = max_rev; |
3543 |
if ((! SVN_IS_VALID_REVNUM(oldest_rev)) || (min_rev < oldest_rev)) |
3544 |
oldest_rev = min_rev; |
3545 |
} |
3546 |
|
3547 |
/* Get logs across those ranges, recording which revisions hold |
3548 |
changes to our object's history. */ |
3549 |
SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev, |
3550 |
oldest_rev, 0, FALSE, FALSE, FALSE, |
3551 |
apr_array_make(pool, 0, sizeof(const char *)), |
3552 |
log_changed_revs, changed_revs, pool)); |
3553 |
|
3554 |
/* Now, copy from RANGES to *OPERATIVE_RANGES, filtering out ranges |
3555 |
that aren't operative (by virtue of not having any revisions |
3556 |
represented in the CHANGED_REVS array). */ |
3557 |
for (i = 0; i < ranges->nelts; i++) |
3558 |
{ |
3559 |
svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i, svn_merge_range_t *); |
3560 |
int j; |
3561 |
|
3562 |
for (j = 0; j < changed_revs->nelts; j++) |
3563 |
{ |
3564 |
svn_revnum_t *changed_rev = |
3565 |
APR_ARRAY_IDX(changed_revs, j, svn_revnum_t *); |
3566 |
if ((*changed_rev > MIN(range->start, range->end)) |
3567 |
&& (*changed_rev <= MAX(range->start, range->end))) |
3568 |
{ |
3569 |
APR_ARRAY_PUSH(operative_ranges, svn_merge_range_t *) = range; |
3570 |
break; |
3571 |
} |
3572 |
} |
3573 |
} |
3574 |
*operative_ranges_p = operative_ranges; |
3575 |
return SVN_NO_ERROR; |
3576 |
} |
3577 |
|
3578 |
|
3458 |
/*-----------------------------------------------------------------------*/ |
3579 |
/*-----------------------------------------------------------------------*/ |
3459 |
|
3580 |
|
3460 |
/*** Merge Source Normalization ***/ |
3581 |
/*** Merge Source Normalization ***/ |
Lines 3859-3864
Link Here
|
3859 |
|
3980 |
|
3860 |
/*** Merge Workhorse Functions ***/ |
3981 |
/*** Merge Workhorse Functions ***/ |
3861 |
|
3982 |
|
|
|
3983 |
/* Helper for do_directory_merge() and do_file_merge() which filters out a |
3984 |
path's own natural history from the mergeinfo describing a merge. |
3985 |
|
3986 |
Given the natural history IMPLICIT_MERGEINFO of some wc merge target path, |
3987 |
the repository relative merge source path SOURCE_REL_PATH, and the |
3988 |
requested merge range REQUESTED_RANGE from SOURCE_REL_PATH, remove any |
3989 |
portion of REQUESTED_RANGE which is already described in |
3990 |
IMPLICIT_MERGEINFO. Store the result in *FILTERED_RANGELIST. |
3991 |
|
3992 |
*FILTERED_RANGELIST is allocated in POOL. */ |
3993 |
static svn_error_t * |
3994 |
filter_natural_history_from_mergeinfo(apr_array_header_t **filtered_rangelist, |
3995 |
const char *source_rel_path, |
3996 |
svn_mergeinfo_t implicit_mergeinfo, |
3997 |
svn_merge_range_t *requested_range, |
3998 |
apr_pool_t *pool) |
3999 |
{ |
4000 |
/* Make the REQUESTED_RANGE into a rangelist. */ |
4001 |
apr_array_header_t *requested_rangelist = |
4002 |
apr_array_make(pool, 0, sizeof(svn_merge_range_t *)); |
4003 |
APR_ARRAY_PUSH(requested_rangelist, svn_merge_range_t *) = |
4004 |
svn_merge_range_dup(requested_range, pool); |
4005 |
|
4006 |
*filtered_rangelist = NULL; |
4007 |
|
4008 |
/* If the IMPLICIT_MERGEINFO already describes ranges associated |
4009 |
with SOURCE_REL_PATH then filter those ranges out. */ |
4010 |
if (implicit_mergeinfo) |
4011 |
{ |
4012 |
apr_array_header_t *implied_rangelist = |
4013 |
apr_hash_get(implicit_mergeinfo, source_rel_path, |
4014 |
APR_HASH_KEY_STRING); |
4015 |
|
4016 |
if (implied_rangelist) |
4017 |
SVN_ERR(svn_rangelist_remove(filtered_rangelist, |
4018 |
implied_rangelist, |
4019 |
requested_rangelist, |
4020 |
FALSE, pool)); |
4021 |
} |
4022 |
|
4023 |
/* If no filtering was performed the filtered rangelist is |
4024 |
simply the requested rangelist.*/ |
4025 |
if (! (*filtered_rangelist)) |
4026 |
*filtered_rangelist = requested_rangelist; |
4027 |
|
4028 |
return SVN_NO_ERROR; |
4029 |
} |
4030 |
|
3862 |
/* The single-file, simplified version of do_directory_merge(), which see for |
4031 |
/* The single-file, simplified version of do_directory_merge(), which see for |
3863 |
parameter descriptions. |
4032 |
parameter descriptions. |
3864 |
|
4033 |
|
Lines 3868-3873
Link Here
|
3868 |
merge source are historically related (ancestors, uncles, second |
4037 |
merge source are historically related (ancestors, uncles, second |
3869 |
cousins thrice removed, etc...). (This is used to simulate the |
4038 |
cousins thrice removed, etc...). (This is used to simulate the |
3870 |
history checks that the repository logic does in the directory case.) |
4039 |
history checks that the repository logic does in the directory case.) |
|
|
4040 |
|
4041 |
Note: MERGE_B->RA_SESSION1 must be associated with URL1 and |
4042 |
MERGE_B->RA_SESSION2 with URL2. |
3871 |
*/ |
4043 |
*/ |
3872 |
static svn_error_t * |
4044 |
static svn_error_t * |
3873 |
do_file_merge(const char *url1, |
4045 |
do_file_merge(const char *url1, |
Lines 3900-3905
Link Here
|
3900 |
svn_boolean_t is_rollback = (revision1 > revision2); |
4072 |
svn_boolean_t is_rollback = (revision1 > revision2); |
3901 |
const char *primary_url = is_rollback ? url1 : url2; |
4073 |
const char *primary_url = is_rollback ? url1 : url2; |
3902 |
svn_boolean_t honor_mergeinfo, record_mergeinfo; |
4074 |
svn_boolean_t honor_mergeinfo, record_mergeinfo; |
|
|
4075 |
svn_mergeinfo_t implicit_mergeinfo; |
3903 |
|
4076 |
|
3904 |
mergeinfo_behavior(&honor_mergeinfo, &record_mergeinfo, merge_b); |
4077 |
mergeinfo_behavior(&honor_mergeinfo, &record_mergeinfo, merge_b); |
3905 |
|
4078 |
|
Lines 3922-3953
Link Here
|
3922 |
if (honor_mergeinfo) |
4095 |
if (honor_mergeinfo) |
3923 |
{ |
4096 |
{ |
3924 |
const char *source_root_url; |
4097 |
const char *source_root_url; |
3925 |
svn_mergeinfo_t implicit_mergeinfo; |
4098 |
|
3926 |
|
|
|
3927 |
|
3928 |
SVN_ERR(svn_ra_get_repos_root2(merge_b->ra_session1, |
4099 |
SVN_ERR(svn_ra_get_repos_root2(merge_b->ra_session1, |
3929 |
&source_root_url, pool)); |
4100 |
&source_root_url, pool)); |
3930 |
SVN_ERR(svn_client__path_relative_to_root(&mergeinfo_path, primary_url, |
4101 |
SVN_ERR(svn_client__path_relative_to_root(&mergeinfo_path, primary_url, |
3931 |
source_root_url, TRUE, NULL, |
4102 |
source_root_url, TRUE, NULL, |
3932 |
NULL, pool)); |
4103 |
NULL, pool)); |
3933 |
|
4104 |
|
|
|
4105 |
/* Fetch mergeinfo (temporarily reparenting ra_session1 to |
4106 |
working copy target URL). */ |
4107 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, entry->url, pool)); |
4108 |
SVN_ERR(get_full_mergeinfo(&target_mergeinfo, &implicit_mergeinfo, |
4109 |
entry, &indirect, svn_mergeinfo_inherited, |
4110 |
merge_b->ra_session1, target_wcpath, |
4111 |
MAX(revision1, revision2), |
4112 |
MIN(revision1, revision2), |
4113 |
adm_access, ctx, pool)); |
4114 |
|
4115 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, url1, pool)); |
4116 |
|
3934 |
/* Calculate remaining merges unless this is a record only merge. |
4117 |
/* Calculate remaining merges unless this is a record only merge. |
3935 |
In that case the remaining range is the whole range described |
4118 |
In that case the remaining range is the whole range described |
3936 |
by REVISION1:REVISION2. */ |
4119 |
by REVISION1:REVISION2. */ |
3937 |
if (!merge_b->record_only) |
4120 |
if (!merge_b->record_only) |
3938 |
{ |
4121 |
{ |
3939 |
/* Fetch mergeinfo (temporarily reparenting ra_session1 to |
|
|
3940 |
working copy target URL). */ |
3941 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, entry->url, pool)); |
3942 |
SVN_ERR(get_full_mergeinfo(&target_mergeinfo, &implicit_mergeinfo, |
3943 |
entry, &indirect, svn_mergeinfo_inherited, |
3944 |
merge_b->ra_session1, target_wcpath, |
3945 |
MAX(revision1, revision2), |
3946 |
MIN(revision1, revision2), |
3947 |
adm_access, ctx, pool)); |
3948 |
|
3949 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, url1, pool)); |
3950 |
|
3951 |
SVN_ERR(calculate_remaining_ranges(&remaining_ranges, |
4122 |
SVN_ERR(calculate_remaining_ranges(&remaining_ranges, |
3952 |
source_root_url, |
4123 |
source_root_url, |
3953 |
url1, revision1, url2, revision2, |
4124 |
url1, revision1, url2, revision2, |
Lines 3969-3984
Link Here
|
3969 |
|
4140 |
|
3970 |
if (!merge_b->record_only) |
4141 |
if (!merge_b->record_only) |
3971 |
{ |
4142 |
{ |
3972 |
for (i = 0; i < remaining_ranges->nelts; i++) |
4143 |
apr_array_header_t *ranges_to_merge = remaining_ranges; |
|
|
4144 |
|
4145 |
/* If we have ancestrally related sources and more than one |
4146 |
range to merge, eliminate no-op ranges before going through |
4147 |
the effort of downloading the many copies of the file |
4148 |
required to do these merges (two copies per range). */ |
4149 |
if (merge_b->sources_ancestral && (remaining_ranges->nelts > 1)) |
3973 |
{ |
4150 |
{ |
|
|
4151 |
const char *old_sess_url = NULL; |
4152 |
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, |
4153 |
merge_b->ra_session1, |
4154 |
primary_url, subpool)); |
4155 |
SVN_ERR(remove_noop_merge_ranges(&ranges_to_merge, |
4156 |
merge_b->ra_session1, |
4157 |
remaining_ranges, subpool)); |
4158 |
if (old_sess_url) |
4159 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess_url, |
4160 |
subpool)); |
4161 |
svn_pool_clear(subpool); |
4162 |
} |
4163 |
|
4164 |
for (i = 0; i < ranges_to_merge->nelts; i++) |
4165 |
{ |
3974 |
svn_wc_notify_t *n; |
4166 |
svn_wc_notify_t *n; |
3975 |
svn_boolean_t header_sent = FALSE; |
4167 |
svn_boolean_t header_sent = FALSE; |
3976 |
svn_error_t *err = SVN_NO_ERROR; |
4168 |
svn_error_t *err = SVN_NO_ERROR; |
|
|
4169 |
svn_ra_session_t *ra_session1, *ra_session2; |
3977 |
|
4170 |
|
3978 |
/* When using this merge range, account for the exclusivity of |
4171 |
/* When using this merge range, account for the exclusivity of |
3979 |
its low value (which is indicated by this operation being a |
4172 |
its low value (which is indicated by this operation being a |
3980 |
merge vs. revert). */ |
4173 |
merge vs. revert). */ |
3981 |
svn_merge_range_t *r = APR_ARRAY_IDX(remaining_ranges, i, |
4174 |
svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, i, |
3982 |
svn_merge_range_t *); |
4175 |
svn_merge_range_t *); |
3983 |
|
4176 |
|
3984 |
svn_pool_clear(subpool); |
4177 |
svn_pool_clear(subpool); |
Lines 3991-4002
Link Here
|
3991 |
if (merge_b->sources_ancestral) |
4184 |
if (merge_b->sources_ancestral) |
3992 |
n->merge_range = r; |
4185 |
n->merge_range = r; |
3993 |
|
4186 |
|
|
|
4187 |
/* Issue #3174: If we are honoring mergeinfo, then URL1, URL2, |
4188 |
REVISION1, and REVISION2 meet the conditions described in |
4189 |
'MERGEINFO MERGE SOURCE NORMALIZATION'. This means that |
4190 |
URL1@REVISION1 may be the copy source of URL2@REVISION2. |
4191 |
If this is the case, then URL1 != URL2. Since |
4192 |
MERGE_B->RA_SESSION1 is always opened with URL1, the only time |
4193 |
we can safely call single_file_merge_get_file() with that RA |
4194 |
session is for REVISION1 (or REVISION2 if this is a reverse |
4195 |
merge). */ |
4196 |
ra_session1 = merge_b->ra_session1; |
4197 |
ra_session2 = merge_b->ra_session2; |
4198 |
if (honor_mergeinfo && strcmp(url1, url2) != 0) |
4199 |
{ |
4200 |
if (!is_rollback && r->start != revision1) |
4201 |
ra_session1 = ra_session2; /* Use URL2's RA session. */ |
4202 |
else if (is_rollback && r->end != revision2) |
4203 |
ra_session2 = ra_session1; /* Use URL1's RA session. */ |
4204 |
} |
4205 |
|
3994 |
/* While we currently don't allow it, in theory we could be |
4206 |
/* While we currently don't allow it, in theory we could be |
3995 |
fetching two fulltexts from two different repositories here. */ |
4207 |
fetching two fulltexts from two different repositories here. */ |
3996 |
SVN_ERR(single_file_merge_get_file(&tmpfile1, merge_b->ra_session1, |
4208 |
SVN_ERR(single_file_merge_get_file(&tmpfile1, ra_session1, |
3997 |
&props1, r->start, target_wcpath, |
4209 |
&props1, r->start, target_wcpath, |
3998 |
subpool)); |
4210 |
subpool)); |
3999 |
SVN_ERR(single_file_merge_get_file(&tmpfile2, merge_b->ra_session2, |
4211 |
SVN_ERR(single_file_merge_get_file(&tmpfile2, ra_session2, |
4000 |
&props2, r->end, target_wcpath, |
4212 |
&props2, r->end, target_wcpath, |
4001 |
subpool)); |
4213 |
subpool)); |
4002 |
|
4214 |
|
Lines 4078-4084
Link Here
|
4078 |
return err; |
4290 |
return err; |
4079 |
svn_error_clear(err); |
4291 |
svn_error_clear(err); |
4080 |
|
4292 |
|
4081 |
if ((i < (remaining_ranges->nelts - 1)) |
4293 |
if ((i < (ranges_to_merge->nelts - 1)) |
4082 |
&& is_path_conflicted_by_merge(merge_b)) |
4294 |
&& is_path_conflicted_by_merge(merge_b)) |
4083 |
{ |
4295 |
{ |
4084 |
conflicted_range = r; |
4296 |
conflicted_range = r; |
Lines 4088-4111
Link Here
|
4088 |
} /* !merge_b->record_only */ |
4300 |
} /* !merge_b->record_only */ |
4089 |
|
4301 |
|
4090 |
/* Record updated WC mergeinfo to account for our new merges, minus |
4302 |
/* Record updated WC mergeinfo to account for our new merges, minus |
4091 |
any unresolved conflicts and skips. */ |
4303 |
any unresolved conflicts and skips. We use the original |
|
|
4304 |
REMAINING_RANGES here instead of the possibly-pared-down |
4305 |
RANGES_TO_MERGE because we want to record all the requested |
4306 |
merge ranges, include the noop ones. */ |
4092 |
if (record_mergeinfo && remaining_ranges->nelts) |
4307 |
if (record_mergeinfo && remaining_ranges->nelts) |
4093 |
{ |
4308 |
{ |
4094 |
apr_hash_t *merges; |
4309 |
apr_hash_t *merges; |
4095 |
SVN_ERR(determine_merges_performed(&merges, target_wcpath, |
4310 |
apr_array_header_t *filtered_rangelist; |
4096 |
&range, svn_depth_infinity, |
4311 |
|
4097 |
adm_access, notify_b, merge_b, |
4312 |
/* Filter any ranges from TARGET_WCPATH's own history, there is no |
4098 |
subpool)); |
4313 |
need to record this explicitly in mergeinfo, it is already part |
4099 |
/* If merge target has indirect mergeinfo set it before |
4314 |
of TARGET_WCPATH's natural history (implicit mergeinfo). */ |
4100 |
recording the first merge range. */ |
4315 |
SVN_ERR(filter_natural_history_from_mergeinfo(&filtered_rangelist, |
4101 |
if (indirect) |
4316 |
mergeinfo_path, |
4102 |
SVN_ERR(svn_client__record_wc_mergeinfo(target_wcpath, |
4317 |
implicit_mergeinfo, |
4103 |
target_mergeinfo, |
4318 |
&range, subpool)); |
4104 |
adm_access, subpool)); |
4319 |
|
|
|
4320 |
if (filtered_rangelist->nelts) |
4321 |
{ |
4322 |
SVN_ERR(determine_merges_performed(&merges, target_wcpath, |
4323 |
filtered_rangelist, |
4324 |
svn_depth_infinity, |
4325 |
adm_access, notify_b, |
4326 |
merge_b, subpool)); |
4327 |
/* If merge target has indirect mergeinfo set it before |
4328 |
recording the first merge range. */ |
4329 |
if (indirect) |
4330 |
SVN_ERR(svn_client__record_wc_mergeinfo(target_wcpath, |
4331 |
target_mergeinfo, |
4332 |
adm_access, subpool)); |
4105 |
|
4333 |
|
4106 |
SVN_ERR(update_wc_mergeinfo(target_wcpath, entry, mergeinfo_path, |
4334 |
SVN_ERR(update_wc_mergeinfo(target_wcpath, entry, mergeinfo_path, |
4107 |
merges, is_rollback, adm_access, |
4335 |
merges, is_rollback, adm_access, |
4108 |
ctx, subpool)); |
4336 |
ctx, subpool)); |
|
|
4337 |
} |
4109 |
} |
4338 |
} |
4110 |
|
4339 |
|
4111 |
svn_pool_destroy(subpool); |
4340 |
svn_pool_destroy(subpool); |
Lines 4258-4263
Link Here
|
4258 |
ra_session, mergeinfo_path, |
4487 |
ra_session, mergeinfo_path, |
4259 |
adm_access, merge_b)); |
4488 |
adm_access, merge_b)); |
4260 |
|
4489 |
|
|
|
4490 |
/* Always start with a range which describes our most inclusive merge. */ |
4491 |
range.start = revision1; |
4492 |
range.end = revision2; |
4493 |
range.inheritable = inheritable; |
4494 |
|
4261 |
if (honor_mergeinfo && !merge_b->record_only) |
4495 |
if (honor_mergeinfo && !merge_b->record_only) |
4262 |
{ |
4496 |
{ |
4263 |
svn_revnum_t start_rev, end_rev; |
4497 |
svn_revnum_t start_rev, end_rev; |
Lines 4267-4385
Link Here
|
4267 |
end revisions. */ |
4501 |
end revisions. */ |
4268 |
start_rev = get_most_inclusive_start_rev(children_with_mergeinfo, |
4502 |
start_rev = get_most_inclusive_start_rev(children_with_mergeinfo, |
4269 |
is_rollback); |
4503 |
is_rollback); |
4270 |
if (start_rev == SVN_INVALID_REVNUM) |
4504 |
|
4271 |
start_rev = revision1; |
4505 |
/* Is there anything to merge? */ |
|
|
4506 |
if (SVN_IS_VALID_REVNUM(start_rev)) |
4507 |
{ |
4508 |
range.start = start_rev; |
4509 |
end_rev = get_youngest_end_rev(children_with_mergeinfo, is_rollback); |
4272 |
|
4510 |
|
4273 |
end_rev = get_youngest_end_rev(children_with_mergeinfo, is_rollback); |
4511 |
/* Build a range which describes our most inclusive merge. */ |
|
|
4512 |
range.start = start_rev; |
4274 |
|
4513 |
|
4275 |
/* Build a range which describes our most inclusive merge. */ |
4514 |
/* While END_REV is valid, do the following: |
4276 |
range.start = start_rev; |
|
|
4277 |
range.end = revision2; |
4278 |
range.inheritable = inheritable; |
4279 |
|
4515 |
|
4280 |
/* While END_REV is valid, do the following: |
4516 |
1. slice each remaining ranges around this 'end_rev'. |
|
|
4517 |
2. starting with START_REV, call |
4518 |
drive_merge_report_editor() on MERGE_B->target for |
4519 |
start_rev:end_rev. |
4520 |
3. remove the first item from each remaining range. |
4521 |
4. set START_REV=END_REV and pick the next END_REV. |
4522 |
5. lather, rinse, repeat. |
4523 |
*/ |
4524 |
iterpool = svn_pool_create(pool); |
4525 |
while (end_rev != SVN_INVALID_REVNUM) |
4526 |
{ |
4527 |
svn_revnum_t next_end_rev; |
4528 |
const char *real_url1 = url1, *real_url2 = url2; |
4529 |
const char *old_sess1_url = NULL, *old_sess2_url = NULL; |
4281 |
|
4530 |
|
4282 |
1. slice each remaining ranges around this 'end_rev'. |
4531 |
svn_pool_clear(iterpool); |
4283 |
2. starting with START_REV, call |
|
|
4284 |
drive_merge_report_editor() on MERGE_B->target for |
4285 |
start_rev:end_rev. |
4286 |
3. remove the first item from each remaining range. |
4287 |
4. set START_REV=END_REV and pick the next END_REV. |
4288 |
5. lather, rinse, repeat. |
4289 |
*/ |
4290 |
iterpool = svn_pool_create(pool); |
4291 |
while (end_rev != SVN_INVALID_REVNUM) |
4292 |
{ |
4293 |
svn_revnum_t next_end_rev; |
4294 |
const char *real_url1 = url1, *real_url2 = url2; |
4295 |
const char *old_sess1_url = NULL, *old_sess2_url = NULL; |
4296 |
|
4532 |
|
4297 |
svn_pool_clear(iterpool); |
4533 |
/* Use persistent pool while playing with remaining_ranges. */ |
|
|
4534 |
slice_remaining_ranges(children_with_mergeinfo, is_rollback, |
4535 |
end_rev, pool); |
4536 |
notify_b->cur_ancestor_index = -1; |
4298 |
|
4537 |
|
4299 |
/* Use persistent pool while playing with remaining_ranges. */ |
4538 |
/* URL1@REVISION1 is a real location; URL2@REVISION2 is a |
4300 |
slice_remaining_ranges(children_with_mergeinfo, is_rollback, |
4539 |
real location -- that much we know (thanks to the merge |
4301 |
end_rev, pool); |
4540 |
source normalization code). But for revisions between |
4302 |
notify_b->cur_ancestor_index = -1; |
4541 |
them, the URLs might differ. Here are the rules: |
4303 |
|
4542 |
|
4304 |
/* URL1@REVISION1 is a real location; URL2@REVISION2 is a |
4543 |
* If URL1 == URL2, then all URLs between REVISION1 and |
4305 |
real location -- that much we know (thanks to the merge |
4544 |
REVISION2 also match URL1/URL2. |
4306 |
source normalization code). But for revisions between |
|
|
4307 |
them, the URLs might differ. Here are the rules: |
4308 |
|
4545 |
|
4309 |
* If URL1 == URL2, then all URLs between REVISION1 and |
4546 |
* If URL1 != URL2, then: |
4310 |
REVISION2 also match URL1/URL2. |
|
|
4311 |
|
4547 |
|
4312 |
* If URL1 != URL2, then: |
4548 |
* If REVISION1 < REVISION2, only REVISION1 maps to |
|
|
4549 |
URL1. The revisions between REVISION1+1 and |
4550 |
REVISION2 (inclusive) map to URL2. |
4313 |
|
4551 |
|
4314 |
* If REVISION1 < REVISION2, only REVISION1 maps to |
4552 |
* If REVISION1 > REVISION2, Only REVISION2 maps to |
4315 |
URL1. The revisions between REVISION1+1 and |
4553 |
URL2. The revisions between REVISION1 and |
4316 |
REVISION2 (inclusive) map to URL2. |
4554 |
REVISION2+1 (inclusive) map to URL1. |
4317 |
|
4555 |
|
4318 |
* If REVISION1 > REVISION2, Only REVISION2 maps to |
4556 |
We need to adjust our URLs accordingly, here. |
4319 |
URL2. The revisions between REVISION1 and |
4557 |
*/ |
4320 |
REVISION2+1 (inclusive) map to URL1. |
4558 |
if (! same_urls) |
4321 |
|
|
|
4322 |
We need to adjust our URLs accordingly, here. |
4323 |
*/ |
4324 |
if (! same_urls) |
4325 |
{ |
4326 |
if (is_rollback && (end_rev != revision2)) |
4327 |
{ |
4559 |
{ |
4328 |
real_url2 = url1; |
4560 |
if (is_rollback && (end_rev != revision2)) |
4329 |
SVN_ERR(svn_client__ensure_ra_session_url |
4561 |
{ |
4330 |
(&old_sess2_url, merge_b->ra_session2, |
4562 |
real_url2 = url1; |
4331 |
real_url2, iterpool)); |
4563 |
SVN_ERR(svn_client__ensure_ra_session_url |
|
|
4564 |
(&old_sess2_url, merge_b->ra_session2, |
4565 |
real_url2, iterpool)); |
4566 |
} |
4567 |
if ((! is_rollback) && (start_rev != revision1)) |
4568 |
{ |
4569 |
real_url1 = url2; |
4570 |
SVN_ERR(svn_client__ensure_ra_session_url |
4571 |
(&old_sess1_url, merge_b->ra_session1, |
4572 |
real_url1, iterpool)); |
4573 |
} |
4332 |
} |
4574 |
} |
4333 |
if ((! is_rollback) && (start_rev != revision1)) |
4575 |
SVN_ERR(drive_merge_report_editor(merge_b->target, |
|
|
4576 |
real_url1, start_rev, |
4577 |
real_url2, end_rev, |
4578 |
children_with_mergeinfo, |
4579 |
is_rollback, |
4580 |
depth, notify_b, adm_access, |
4581 |
&merge_callbacks, merge_b, |
4582 |
iterpool)); |
4583 |
if (old_sess1_url) |
4584 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, |
4585 |
old_sess1_url, iterpool)); |
4586 |
if (old_sess2_url) |
4587 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session2, |
4588 |
old_sess2_url, iterpool)); |
4589 |
|
4590 |
/* Prepare for the next iteration (if any). */ |
4591 |
remove_first_range_from_remaining_ranges( |
4592 |
end_rev, children_with_mergeinfo, pool); |
4593 |
next_end_rev = get_youngest_end_rev(children_with_mergeinfo, |
4594 |
is_rollback); |
4595 |
if ((next_end_rev != SVN_INVALID_REVNUM) |
4596 |
&& is_path_conflicted_by_merge(merge_b)) |
4334 |
{ |
4597 |
{ |
4335 |
real_url1 = url2; |
4598 |
svn_merge_range_t conflicted_range; |
4336 |
SVN_ERR(svn_client__ensure_ra_session_url |
4599 |
conflicted_range.start = start_rev; |
4337 |
(&old_sess1_url, merge_b->ra_session1, |
4600 |
conflicted_range.end = end_rev; |
4338 |
real_url1, iterpool)); |
4601 |
err = make_merge_conflict_error(merge_b->target, |
|
|
4602 |
&conflicted_range, pool); |
4603 |
range.end = end_rev; |
4604 |
break; |
4339 |
} |
4605 |
} |
|
|
4606 |
start_rev = end_rev; |
4607 |
end_rev = next_end_rev; |
4340 |
} |
4608 |
} |
4341 |
SVN_ERR(drive_merge_report_editor(merge_b->target, |
4609 |
svn_pool_destroy(iterpool); |
4342 |
real_url1, start_rev, real_url2, |
|
|
4343 |
end_rev, children_with_mergeinfo, |
4344 |
is_rollback, |
4345 |
depth, notify_b, adm_access, |
4346 |
&merge_callbacks, merge_b, |
4347 |
iterpool)); |
4348 |
if (old_sess1_url) |
4349 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session1, |
4350 |
old_sess1_url, iterpool)); |
4351 |
if (old_sess2_url) |
4352 |
SVN_ERR(svn_ra_reparent(merge_b->ra_session2, |
4353 |
old_sess2_url, iterpool)); |
4354 |
|
4355 |
/* Prepare for the next iteration (if any). */ |
4356 |
remove_first_range_from_remaining_ranges(children_with_mergeinfo, |
4357 |
pool); |
4358 |
next_end_rev = get_youngest_end_rev(children_with_mergeinfo, |
4359 |
is_rollback); |
4360 |
if ((next_end_rev != SVN_INVALID_REVNUM) |
4361 |
&& is_path_conflicted_by_merge(merge_b)) |
4362 |
{ |
4363 |
svn_merge_range_t conflicted_range; |
4364 |
conflicted_range.start = start_rev; |
4365 |
conflicted_range.end = end_rev; |
4366 |
err = make_merge_conflict_error(merge_b->target, |
4367 |
&conflicted_range, pool); |
4368 |
range.end = end_rev; |
4369 |
break; |
4370 |
} |
4371 |
start_rev = end_rev; |
4372 |
end_rev = next_end_rev; |
4373 |
} |
4610 |
} |
4374 |
svn_pool_destroy(iterpool); |
|
|
4375 |
} |
4611 |
} |
4376 |
else |
4612 |
else |
4377 |
{ |
4613 |
{ |
4378 |
/* Build a range which describes our most inclusive merge. */ |
|
|
4379 |
range.start = revision1; |
4380 |
range.end = revision2; |
4381 |
range.inheritable = inheritable; |
4382 |
|
4383 |
if (!merge_b->record_only) |
4614 |
if (!merge_b->record_only) |
4384 |
{ |
4615 |
{ |
4385 |
/* Reset cur_ancestor_index to -1 so that subsequent cherry |
4616 |
/* Reset cur_ancestor_index to -1 so that subsequent cherry |
Lines 4405-4410
Link Here
|
4405 |
iterpool = svn_pool_create(pool); |
4636 |
iterpool = svn_pool_create(pool); |
4406 |
if (record_mergeinfo) |
4637 |
if (record_mergeinfo) |
4407 |
{ |
4638 |
{ |
|
|
4639 |
apr_array_header_t *filtered_rangelist; |
4640 |
svn_client__merge_path_t *merge_target = |
4641 |
APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *); |
4642 |
|
4408 |
/* Update the WC mergeinfo here to account for our new |
4643 |
/* Update the WC mergeinfo here to account for our new |
4409 |
merges, minus any unresolved conflicts and skips. */ |
4644 |
merges, minus any unresolved conflicts and skips. */ |
4410 |
apr_hash_t *merges; |
4645 |
apr_hash_t *merges; |
Lines 4414-4428
Link Here
|
4414 |
calculate the merges performed. */ |
4649 |
calculate the merges performed. */ |
4415 |
remove_absent_children(merge_b->target, |
4650 |
remove_absent_children(merge_b->target, |
4416 |
children_with_mergeinfo, notify_b); |
4651 |
children_with_mergeinfo, notify_b); |
4417 |
SVN_ERR(determine_merges_performed(&merges, merge_b->target, &range, |
4652 |
|
4418 |
depth, adm_access, notify_b, merge_b, |
4653 |
/* Filter any ranges from MERGE_B->TARGET's own history, there is no |
4419 |
iterpool)); |
4654 |
need to record this explicitly in mergeinfo, it is already part of |
4420 |
SVN_ERR(record_mergeinfo_on_merged_children(depth, adm_access, notify_b, |
4655 |
MERGE_B->TARGET's natural history (implicit mergeinfo). */ |
4421 |
merge_b, iterpool)); |
4656 |
SVN_ERR(filter_natural_history_from_mergeinfo( |
4422 |
SVN_ERR(update_wc_mergeinfo(merge_b->target, parent_entry, |
4657 |
&filtered_rangelist, mergeinfo_path, merge_target->implicit_mergeinfo, |
4423 |
mergeinfo_path, merges, |
4658 |
&range, iterpool)); |
4424 |
is_rollback, adm_access, merge_b->ctx, |
4659 |
|
4425 |
iterpool)); |
4660 |
if (filtered_rangelist->nelts) |
|
|
4661 |
{ |
4662 |
SVN_ERR(determine_merges_performed(&merges, merge_b->target, |
4663 |
filtered_rangelist, depth, |
4664 |
adm_access, notify_b, |
4665 |
merge_b, iterpool)); |
4666 |
|
4667 |
SVN_ERR(record_mergeinfo_on_merged_children(depth, adm_access, |
4668 |
notify_b, merge_b, |
4669 |
iterpool)); |
4670 |
SVN_ERR(update_wc_mergeinfo(merge_b->target, parent_entry, |
4671 |
mergeinfo_path, merges, |
4672 |
is_rollback, adm_access, merge_b->ctx, |
4673 |
iterpool)); |
4674 |
} |
4675 |
|
4426 |
for (i = 0; i < children_with_mergeinfo->nelts; i++) |
4676 |
for (i = 0; i < children_with_mergeinfo->nelts; i++) |
4427 |
{ |
4677 |
{ |
4428 |
const char *child_repos_path; |
4678 |
const char *child_repos_path; |
Lines 4430-4436
Link Here
|
4430 |
const svn_wc_entry_t *child_entry; |
4680 |
const svn_wc_entry_t *child_entry; |
4431 |
apr_array_header_t *child_merge_rangelist; |
4681 |
apr_array_header_t *child_merge_rangelist; |
4432 |
apr_hash_t *child_merges; |
4682 |
apr_hash_t *child_merges; |
4433 |
svn_merge_range_t *child_merge_range; |
|
|
4434 |
svn_client__merge_path_t *child = |
4683 |
svn_client__merge_path_t *child = |
4435 |
APR_ARRAY_IDX(children_with_mergeinfo, i, |
4684 |
APR_ARRAY_IDX(children_with_mergeinfo, i, |
4436 |
svn_client__merge_path_t *); |
4685 |
svn_client__merge_path_t *); |
Lines 4449-4467
Link Here
|
4449 |
adm_access, FALSE, iterpool)); |
4698 |
adm_access, FALSE, iterpool)); |
4450 |
|
4699 |
|
4451 |
child_merges = apr_hash_make(iterpool); |
4700 |
child_merges = apr_hash_make(iterpool); |
4452 |
child_merge_range = svn_merge_range_dup(&range, iterpool); |
4701 |
|
4453 |
if (child_entry->kind == svn_node_file) |
4702 |
/* As we did above for the merge target, filter any ranges from |
4454 |
child_merge_range->inheritable = TRUE; |
4703 |
each child's natural history before setting mergeinfo. */ |
|
|
4704 |
SVN_ERR(filter_natural_history_from_mergeinfo( |
4705 |
&child_merge_rangelist, child_merge_src_canon_path, |
4706 |
child->implicit_mergeinfo, &range, iterpool)); |
4707 |
|
4708 |
if (child_merge_rangelist->nelts == 0) |
4709 |
continue; |
4455 |
else |
4710 |
else |
4456 |
child_merge_range->inheritable = |
4711 |
{ |
4457 |
(!(child->missing_child) |
4712 |
int j; |
4458 |
&& (depth == svn_depth_infinity |
4713 |
for (j = 0; j < child_merge_rangelist->nelts; j++) |
|
|
4714 |
{ |
4715 |
svn_merge_range_t *rng = |
4716 |
APR_ARRAY_IDX(child_merge_rangelist, j, |
4717 |
svn_merge_range_t *); |
4718 |
if (child_entry->kind == svn_node_file) |
4719 |
rng->inheritable = TRUE; |
4720 |
else |
4721 |
rng->inheritable = (!(child->missing_child) |
4722 |
&& (depth == svn_depth_infinity |
4459 |
|| depth == svn_depth_immediates)); |
4723 |
|| depth == svn_depth_immediates)); |
4460 |
child_merge_rangelist = |
4724 |
} |
4461 |
apr_array_make(iterpool, 1, |
4725 |
} |
4462 |
sizeof(child_merge_range)); |
|
|
4463 |
APR_ARRAY_PUSH(child_merge_rangelist, |
4464 |
svn_merge_range_t *) = child_merge_range; |
4465 |
apr_hash_set(child_merges, child->path, APR_HASH_KEY_STRING, |
4726 |
apr_hash_set(child_merges, child->path, APR_HASH_KEY_STRING, |
4466 |
child_merge_rangelist); |
4727 |
child_merge_rangelist); |
4467 |
/* If merge target has indirect mergeinfo set it before |
4728 |
/* If merge target has indirect mergeinfo set it before |
Lines 4489-4498
Link Here
|
4489 |
merge_b, |
4750 |
merge_b, |
4490 |
children_with_mergeinfo, |
4751 |
children_with_mergeinfo, |
4491 |
i, iterpool)); |
4752 |
i, iterpool)); |
|
|
4753 |
|
4754 |
/* Elide explicit subtree mergeinfo. */ |
4492 |
if (i > 0) |
4755 |
if (i > 0) |
4493 |
SVN_ERR(svn_client__elide_mergeinfo(child->path, merge_b->target, |
4756 |
{ |
4494 |
child_entry, adm_access, |
4757 |
svn_boolean_t in_switched_subtree = FALSE; |
4495 |
merge_b->ctx, iterpool)); |
4758 |
|
|
|
4759 |
if (child->switched) |
4760 |
in_switched_subtree = TRUE; |
4761 |
else if (i > 1) |
4762 |
{ |
4763 |
/* Check if CHILD is part of a switched subtree */ |
4764 |
svn_client__merge_path_t *parent; |
4765 |
int j = i - 1; |
4766 |
for (; j > 0; j--) |
4767 |
{ |
4768 |
parent = APR_ARRAY_IDX(children_with_mergeinfo, j, |
4769 |
svn_client__merge_path_t *); |
4770 |
if (parent |
4771 |
&& parent->switched |
4772 |
&& svn_path_is_ancestor(parent->path, child->path)) |
4773 |
{ |
4774 |
in_switched_subtree = TRUE; |
4775 |
break; |
4776 |
} |
4777 |
} |
4778 |
} |
4779 |
|
4780 |
/* Allow mergeinfo on switched subtrees to elide to the |
4781 |
repository. Otherwise limit elision to the merge target |
4782 |
for now. do_directory_merge() will eventually try to |
4783 |
elide that when the merge is complete. */ |
4784 |
SVN_ERR(svn_client__elide_mergeinfo( |
4785 |
child->path, |
4786 |
in_switched_subtree ? NULL : merge_b->target, |
4787 |
child_entry, adm_access, merge_b->ctx, iterpool)); |
4788 |
} |
4496 |
} /* (i = 0; i < children_with_mergeinfo->nelts; i++) */ |
4789 |
} /* (i = 0; i < children_with_mergeinfo->nelts; i++) */ |
4497 |
|
4790 |
|
4498 |
/* If a path has an immediate parent with non-inheritable mergeinfo at |
4791 |
/* If a path has an immediate parent with non-inheritable mergeinfo at |
4499 |
-- subversion/libsvn_client/mergeinfo.c |
4792 |
++ subversion/libsvn_client/mergeinfo.c |
Lines 164-177
Link Here
|
164 |
SVN_ERR(svn_client__parse_mergeinfo(&wc_mergeinfo, entry, wcpath, |
164 |
SVN_ERR(svn_client__parse_mergeinfo(&wc_mergeinfo, entry, wcpath, |
165 |
pristine, adm_access, ctx, |
165 |
pristine, adm_access, ctx, |
166 |
pool)); |
166 |
pool)); |
167 |
|
|
|
168 |
/* If WCPATH is switched, don't look any higher for inherited |
169 |
mergeinfo. */ |
170 |
SVN_ERR(svn_wc__path_switched(wcpath, &switched, entry, pool)); |
171 |
if (switched) |
172 |
break; |
173 |
} |
167 |
} |
174 |
|
168 |
|
|
|
169 |
/* If WCPATH is switched, don't look any higher for inherited |
170 |
mergeinfo. */ |
171 |
SVN_ERR(svn_wc__path_switched(wcpath, &switched, entry, pool)); |
172 |
if (switched) |
173 |
break; |
174 |
|
175 |
/* Subsequent svn_wc_adm_access_t need to be opened with |
175 |
/* Subsequent svn_wc_adm_access_t need to be opened with |
176 |
an absolute path so we can walk up and out of the WC |
176 |
an absolute path so we can walk up and out of the WC |
177 |
if necessary. If we are using LIMIT_PATH it needs to |
177 |
if necessary. If we are using LIMIT_PATH it needs to |
Lines 725-781
Link Here
|
725 |
{ |
725 |
{ |
726 |
svn_mergeinfo_t target_mergeinfo; |
726 |
svn_mergeinfo_t target_mergeinfo; |
727 |
svn_mergeinfo_t mergeinfo = NULL; |
727 |
svn_mergeinfo_t mergeinfo = NULL; |
728 |
svn_boolean_t inherited, switched; |
728 |
svn_boolean_t inherited; |
729 |
const char *walk_path; |
729 |
const char *walk_path; |
730 |
|
730 |
|
731 |
/* Check for second easy out: TARGET_WCPATH is switched. */ |
731 |
/* Get the TARGET_WCPATH's explicit mergeinfo. */ |
732 |
SVN_ERR(svn_wc__path_switched(target_wcpath, &switched, entry, pool)); |
732 |
SVN_ERR(svn_client__get_wc_mergeinfo(&target_mergeinfo, &inherited, |
733 |
if (!switched) |
733 |
FALSE, svn_mergeinfo_inherited, |
734 |
{ |
734 |
entry, target_wcpath, |
735 |
/* Get the TARGET_WCPATH's explicit mergeinfo. */ |
735 |
wc_elision_limit_path |
736 |
SVN_ERR(svn_client__get_wc_mergeinfo(&target_mergeinfo, &inherited, |
736 |
? wc_elision_limit_path |
737 |
FALSE, svn_mergeinfo_inherited, |
737 |
: NULL, |
738 |
entry, target_wcpath, |
738 |
&walk_path, adm_access, |
739 |
wc_elision_limit_path |
739 |
ctx, pool)); |
740 |
? wc_elision_limit_path |
|
|
741 |
: NULL, |
742 |
&walk_path, adm_access, |
743 |
ctx, pool)); |
744 |
|
740 |
|
745 |
/* If TARGET_WCPATH has no explicit mergeinfo, there's nothing to |
741 |
/* If TARGET_WCPATH has no explicit mergeinfo, there's nothing to |
746 |
elide, we're done. */ |
742 |
elide, we're done. */ |
747 |
if (inherited || target_mergeinfo == NULL) |
743 |
if (inherited || target_mergeinfo == NULL) |
748 |
return SVN_NO_ERROR; |
744 |
return SVN_NO_ERROR; |
749 |
|
745 |
|
750 |
/* Get TARGET_WCPATH's inherited mergeinfo from the WC. */ |
746 |
/* Get TARGET_WCPATH's inherited mergeinfo from the WC. */ |
751 |
SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, &inherited, FALSE, |
747 |
SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, &inherited, FALSE, |
752 |
svn_mergeinfo_nearest_ancestor, |
748 |
svn_mergeinfo_nearest_ancestor, |
753 |
entry, target_wcpath, |
749 |
entry, target_wcpath, |
754 |
wc_elision_limit_path |
750 |
wc_elision_limit_path |
755 |
? wc_elision_limit_path |
751 |
? wc_elision_limit_path |
756 |
: NULL, |
752 |
: NULL, |
757 |
&walk_path, adm_access, |
753 |
&walk_path, adm_access, |
758 |
ctx, pool)); |
754 |
ctx, pool)); |
759 |
|
755 |
|
760 |
/* If TARGET_WCPATH inherited no mergeinfo from the WC and we are |
756 |
/* If TARGET_WCPATH inherited no mergeinfo from the WC and we are |
761 |
not limiting our search to the working copy then check if it |
757 |
not limiting our search to the working copy then check if it |
762 |
inherits any from the repos. */ |
758 |
inherits any from the repos. */ |
763 |
if (!mergeinfo && !wc_elision_limit_path) |
759 |
if (!mergeinfo && !wc_elision_limit_path) |
764 |
{ |
760 |
{ |
765 |
SVN_ERR(svn_client__get_wc_or_repos_mergeinfo |
761 |
SVN_ERR(svn_client__get_wc_or_repos_mergeinfo |
766 |
(&mergeinfo, entry, &inherited, TRUE, |
762 |
(&mergeinfo, entry, &inherited, TRUE, |
767 |
svn_mergeinfo_nearest_ancestor, |
763 |
svn_mergeinfo_nearest_ancestor, |
768 |
NULL, target_wcpath, adm_access, ctx, pool)); |
764 |
NULL, target_wcpath, adm_access, ctx, pool)); |
769 |
} |
765 |
} |
770 |
|
766 |
|
771 |
/* If there is nowhere to elide TARGET_WCPATH's mergeinfo to and |
767 |
/* If there is nowhere to elide TARGET_WCPATH's mergeinfo to and |
772 |
the elision is limited, then we are done.*/ |
768 |
the elision is limited, then we are done.*/ |
773 |
if (!mergeinfo && wc_elision_limit_path) |
769 |
if (!mergeinfo && wc_elision_limit_path) |
774 |
return SVN_NO_ERROR; |
770 |
return SVN_NO_ERROR; |
775 |
|
771 |
|
776 |
SVN_ERR(elide_mergeinfo(mergeinfo, target_mergeinfo, target_wcpath, |
772 |
SVN_ERR(elide_mergeinfo(mergeinfo, target_mergeinfo, target_wcpath, |
777 |
NULL, adm_access, pool)); |
773 |
NULL, adm_access, pool)); |
778 |
} |
|
|
779 |
} |
774 |
} |
780 |
return SVN_NO_ERROR; |
775 |
return SVN_NO_ERROR; |
781 |
} |
776 |
} |
782 |
-- subversion/libsvn_client/mergeinfo.h |
777 |
++ subversion/libsvn_client/mergeinfo.h |
Lines 51-56
Link Here
|
51 |
apr_array_header_t *remaining_ranges; /* Per path remaining ranges list. */ |
51 |
apr_array_header_t *remaining_ranges; /* Per path remaining ranges list. */ |
52 |
svn_mergeinfo_t pre_merge_mergeinfo; /* mergeinfo on a path prior to a |
52 |
svn_mergeinfo_t pre_merge_mergeinfo; /* mergeinfo on a path prior to a |
53 |
merge.*/ |
53 |
merge.*/ |
|
|
54 |
svn_mergeinfo_t implicit_mergeinfo; /* Implicit mergeinfo on a path prior |
55 |
to a merge.*/ |
54 |
svn_boolean_t indirect_mergeinfo; |
56 |
svn_boolean_t indirect_mergeinfo; |
55 |
svn_boolean_t scheduled_for_deletion; /* PATH is scheduled for deletion. */ |
57 |
svn_boolean_t scheduled_for_deletion; /* PATH is scheduled for deletion. */ |
56 |
} svn_client__merge_path_t; |
58 |
} svn_client__merge_path_t; |
Lines 72-78
Link Here
|
72 |
inherited mergeinfo for WCPATH is retrieved. |
74 |
inherited mergeinfo for WCPATH is retrieved. |
73 |
|
75 |
|
74 |
Don't look for inherited mergeinfo any higher than LIMIT_PATH |
76 |
Don't look for inherited mergeinfo any higher than LIMIT_PATH |
75 |
(ignored if NULL). |
77 |
(ignored if NULL) or beyond any switched path. |
76 |
|
78 |
|
77 |
Set *WALKED_PATH to the path climbed from WCPATH to find inherited |
79 |
Set *WALKED_PATH to the path climbed from WCPATH to find inherited |
78 |
mergeinfo, or "" if none was found. (ignored if NULL). */ |
80 |
mergeinfo, or "" if none was found. (ignored if NULL). */ |
Lines 196-205
Link Here
|
196 |
copy (or possibly repository) ancestor with equivalent mergeinfo. |
198 |
copy (or possibly repository) ancestor with equivalent mergeinfo. |
197 |
|
199 |
|
198 |
If WC_ELISION_LIMIT_PATH is NULL check up to the root of the working copy |
200 |
If WC_ELISION_LIMIT_PATH is NULL check up to the root of the working copy |
199 |
for an elision destination, if none is found check the repository, |
201 |
or the nearest switched parent for an elision destination, if none is found |
200 |
otherwise check as far as WC_ELISION_LIMIT_PATH within the working copy. |
202 |
check the repository, otherwise check as far as WC_ELISION_LIMIT_PATH |
201 |
TARGET_PATH and WC_ELISION_LIMIT_PATH, if it exists, must both be absolute |
203 |
within the working copy. TARGET_PATH and WC_ELISION_LIMIT_PATH, if it |
202 |
or relative to the working directory. |
204 |
exists, must both be absolute or relative to the working directory. |
203 |
|
205 |
|
204 |
Elision occurs if: |
206 |
Elision occurs if: |
205 |
|
207 |
|
206 |
-- subversion/libsvn_wc/merge.c |
208 |
++ subversion/libsvn_wc/merge.c |
Lines 624-632
Link Here
|
624 |
} |
624 |
} |
625 |
else |
625 |
else |
626 |
{ |
626 |
{ |
627 |
svn_boolean_t same; |
627 |
svn_boolean_t same, special; |
|
|
628 |
/* If 'special', then use the detranslated form of the |
629 |
target file. This is so we don't try to follow symlinks, |
630 |
but the same treatment is probably also appropriate for |
631 |
whatever special file types we may invent in the future. */ |
632 |
SVN_ERR(svn_wc__get_special(&special, merge_target, |
633 |
adm_access, pool)); |
628 |
SVN_ERR(svn_io_files_contents_same_p(&same, result_target, |
634 |
SVN_ERR(svn_io_files_contents_same_p(&same, result_target, |
629 |
merge_target, pool)); |
635 |
(special ? |
|
|
636 |
tmp_target : |
637 |
merge_target), |
638 |
pool)); |
630 |
|
639 |
|
631 |
*merge_outcome = same ? svn_wc_merge_unchanged : svn_wc_merge_merged; |
640 |
*merge_outcome = same ? svn_wc_merge_unchanged : svn_wc_merge_merged; |
632 |
} |
641 |
} |