1/* 2 * merge.c: merging 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24/* ==================================================================== */ 25 26 27 28/*** Includes ***/ 29 30#include <assert.h> 31#include <apr_strings.h> 32#include <apr_tables.h> 33#include <apr_hash.h> 34#include "svn_types.h" 35#include "svn_hash.h" 36#include "svn_wc.h" 37#include "svn_delta.h" 38#include "svn_diff.h" 39#include "svn_mergeinfo.h" 40#include "svn_client.h" 41#include "svn_string.h" 42#include "svn_error.h" 43#include "svn_dirent_uri.h" 44#include "svn_path.h" 45#include "svn_io.h" 46#include "svn_utf.h" 47#include "svn_pools.h" 48#include "svn_config.h" 49#include "svn_props.h" 50#include "svn_time.h" 51#include "svn_sorts.h" 52#include "svn_subst.h" 53#include "svn_ra.h" 54#include "client.h" 55#include "mergeinfo.h" 56 57#include "private/svn_fspath.h" 58#include "private/svn_mergeinfo_private.h" 59#include "private/svn_client_private.h" 60#include "private/svn_sorts_private.h" 61#include "private/svn_subr_private.h" 62#include "private/svn_wc_private.h" 63 64#include "svn_private_config.h" 65 66 67/*-----------------------------------------------------------------------*/ 68 69/* MERGEINFO MERGE SOURCE NORMALIZATION 70 * 71 * Nearly any helper function herein that accepts two URL/revision 72 * pairs (or equivalent struct merge_source_t) expects one of two things 73 * to be true: 74 * 75 * 1. that mergeinfo is not being recorded at all for this 76 * operation, or 77 * 78 * 2. that the pairs represent two locations along a single line 79 * of version history such that there are no copies in the 80 * history of the object between the locations when treating 81 * the oldest of the two locations as non-inclusive. In other 82 * words, if there is a copy at all between them, there is only 83 * one copy and its source was the oldest of the two locations. 84 * 85 * We use svn_ra_get_location_segments() to split a given range of 86 * revisions across an object's history into several which obey these 87 * rules. For example, an extract from the log of Subversion's own 88 * /subversion/tags/1.4.5 directory shows the following copies between 89 * r859500 and r866500 (omitting the '/subversion' prefix for clarity): 90 * 91 * r859598: 92 * A /branches/1.4.x (from /trunk:859597) 93 * 94 * r865417: 95 * A /tags/1.4.4 (from /branches/1.4.x:865262) 96 * # Notice that this copy leaves a gap between 865262 and 865417. 97 * 98 * r866420: 99 * A /branches/1.4.5 (from /tags/1.4.4:866419) 100 * 101 * r866425: 102 * D /branches/1.4.5 103 * A /tags/1.4.5 (from /branches/1.4.5:866424) 104 * 105 * In graphical form: 106 * 107 * 859500 859597 865262 866419 866424 866500 108 * . . . . . . 109 * trunk ------------------------------------------------ 110 * \ . . . 111 * branches/1.4.x A------------------------------------- 112 * . \______ . . 113 * . \ . . 114 * tags/1.4.4 . A----------------------- 115 * . . \ . 116 * branches/1.4.5 . . A------D 117 * . . . \. 118 * tags/1.4.5 . . . A--------- 119 * . . . . 120 * 859598 865417 866420 866425 121 * 122 * A merge of the difference between r859500 and r866500 of this directory 123 * gets split into sequential merges of the following location pairs. 124 * 125 * 859500 859597 865262 865416 866419 866424 866500 126 * . . . . . . . 127 * trunk (======] . . . . . 128 * . . . . . 129 * trunk ( . . . . . 130 * branches/1.4.x ======] . . . . 131 * . . . . 132 * branches/1.4.x ( . . . . 133 * tags/1.4.4 =============] . . 134 * implicit_src_gap (======] . . . 135 * . . . 136 * tags/1.4.4 ( . . 137 * branches/1.4.5 ======] . 138 * . . 139 * branches/1.4.5 ( . 140 * tags/1.4.5 ======] 141 * 142 * which are represented in merge_source_t as: 143 * 144 * [/trunk:859500, /trunk:859597] 145 * (recorded in svn:mergeinfo as /trunk:859501-859597) 146 * 147 * [/trunk:859597, /branches/1.4.x:865262] 148 * (recorded in svn:mergeinfo as /branches/1.4.x:859598-865262) 149 * 150 * [/branches/1.4.x:865262, /tags/1.4.4@866419] 151 * (recorded in svn:mergeinfo as /tags/1.4.4:865263-866419) 152 * (and there is a gap, the revision range [865262, 865416]) 153 * 154 * [/tags/1.4.4@866419, /branches/1.4.5@866424] 155 * (recorded in svn:mergeinfo as /branches/1.4.5:866420-866424) 156 * 157 * [/branches/1.4.5@866424, /tags/1.4.5@866500] 158 * (recorded in svn:mergeinfo as /tags/1.4.5:866425-866500) 159 * 160 * Our helper functions would then operate on one of these location 161 * pairs at a time. 162 */ 163 164/* WHICH SVN_CLIENT_MERGE* API DO I WANT? 165 * 166 * libsvn_client has three public merge APIs; they are all wrappers 167 * around the do_merge engine. Which one to use depends on the number 168 * of URLs passed as arguments and whether or not specific merge 169 * ranges (-c/-r) are specified. 170 * 171 * 1 URL 2 URLs 172 * +----+--------------------------------+---------------------+ 173 * | -c | mergeinfo-driven | | 174 * | or | cherrypicking | | 175 * | -r | (svn_client_merge_peg) | | 176 * |----+--------------------------------+ | 177 * | | mergeinfo-driven | unsupported | 178 * | | 'cherry harvest', i.e. merge | | 179 * | | all revisions from URL that | | 180 * | no | have not already been merged | | 181 * | -c | (svn_client_merge_peg) | | 182 * | or +--------------------------------+---------------------+ 183 * | -r | mergeinfo-driven | mergeinfo-writing | 184 * | | whole-branch | diff-and-apply | 185 * | | heuristic merge | (svn_client_merge) | 186 * | | (svn_client_merge_reintegrate) | | 187 * +----+--------------------------------+---------------------+ 188 * 189 * 190 */ 191 192/* THE CHILDREN_WITH_MERGEINFO ARRAY 193 * 194 * Many of the helper functions in this file pass around an 195 * apr_array_header_t *CHILDREN_WITH_MERGEINFO. This is a depth first 196 * sorted array filled with svn_client__merge_path_t * describing the 197 * merge target and any of its subtrees which have explicit mergeinfo 198 * or otherwise need special attention during a merge. 199 * 200 * During mergeinfo unaware merges, CHILDREN_WITH_MERGEINFO contains 201 * contains only one element (added by do_mergeinfo_unaware_dir_merge) 202 * describing a contiguous range to be merged to the WC merge target. 203 * 204 * During mergeinfo aware merges CHILDREN_WITH_MERGEINFO is created 205 * by get_mergeinfo_paths() and outside of that function and its helpers 206 * should always meet the criteria dictated in get_mergeinfo_paths()'s doc 207 * string. The elements of CHILDREN_WITH_MERGEINFO should never be NULL. 208 * 209 * For clarification on mergeinfo aware vs. mergeinfo unaware merges, see 210 * the doc string for HONOR_MERGEINFO(). 211 */ 212 213 214/*-----------------------------------------------------------------------*/ 215 216/*** Repos-Diff Editor Callbacks ***/ 217 218struct merge_cmd_baton_t; 219 220struct notify_begin_state_t 221{ 222 /* Cache of which abspath was last notified. */ 223 const char *last_abspath; 224 225 /* Reference to the main merge baton */ 226 struct merge_cmd_baton_t *merge_b; 227 228 /* the wrapped notification callback */ 229 svn_wc_notify_func2_t notify_func2; 230 void *notify_baton2; 231}; 232 233typedef struct merge_cmd_baton_t { 234 svn_boolean_t force_delete; /* Delete a file/dir even if modified */ 235 svn_boolean_t dry_run; 236 svn_boolean_t record_only; /* Whether to merge only mergeinfo 237 differences. */ 238 svn_boolean_t same_repos; /* Whether the merge source repository 239 is the same repository as the 240 target. Defaults to FALSE if DRY_RUN 241 is TRUE.*/ 242 svn_boolean_t mergeinfo_capable; /* Whether the merge source server 243 is capable of Merge Tracking. */ 244 svn_boolean_t ignore_mergeinfo; /* Don't honor mergeinfo; see 245 doc string of do_merge(). FALSE if 246 MERGE_SOURCE->ancestral is FALSE. */ 247 svn_boolean_t diff_ignore_ancestry; /* Diff unrelated nodes as if related; see 248 doc string of do_merge(). FALSE if 249 MERGE_SOURCE->ancestral is FALSE. */ 250 svn_boolean_t reintegrate_merge; /* Whether this is a --reintegrate 251 merge or not. */ 252 const merge_target_t *target; /* Description of merge target node */ 253 254 /* The left and right URLs and revs. The value of this field changes to 255 reflect the merge_source_t *currently* being merged by do_merge(). */ 256 merge_source_t merge_source; 257 258 /* Rangelist containing single range which describes the gap, if any, 259 in the natural history of the merge source currently being processed. 260 See https://issues.apache.org/jira/browse/SVN-3432. 261 Updated during each call to do_directory_merge(). May be NULL if there 262 is no gap. */ 263 svn_rangelist_t *implicit_src_gap; 264 265 /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global 266 comment) or a similar list for single-file-merges */ 267 apr_array_header_t *children_with_mergeinfo; 268 269 svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */ 270 271 /* The list of any paths which remained in conflict after a 272 resolution attempt was made. We track this in-memory, rather 273 than just using WC entry state, since the latter doesn't help us 274 when in dry_run mode. 275 ### And because we only want to resolve conflicts that were 276 generated by this merge, not pre-existing ones? */ 277 apr_hash_t *conflicted_paths; 278 279 /* A list of absolute paths which had no explicit mergeinfo prior to the 280 merge but got explicit mergeinfo added by the merge. This is populated 281 by merge_change_props() and is allocated in POOL so it is subject to the 282 lifetime limitations of POOL. Is NULL if no paths are found which 283 meet the criteria or DRY_RUN is true. */ 284 apr_hash_t *paths_with_new_mergeinfo; 285 286 /* A list of absolute paths whose mergeinfo doesn't need updating after 287 the merge. This can be caused by the removal of mergeinfo by the merge 288 or by deleting the node itself. This is populated by merge_change_props() 289 and the delete callbacks and is allocated in POOL so it is subject to the 290 lifetime limitations of POOL. Is NULL if no paths are found which 291 meet the criteria or DRY_RUN is true. */ 292 apr_hash_t *paths_with_deleted_mergeinfo; 293 294 /* The list of absolute skipped paths, which should be examined and 295 cleared after each invocation of the callback. The paths 296 are absolute. Is NULL if MERGE_B->MERGE_SOURCE->ancestral and 297 MERGE_B->REINTEGRATE_MERGE are both false. */ 298 apr_hash_t *skipped_abspaths; 299 300 /* The list of absolute merged paths. Unused if MERGE_B->MERGE_SOURCE->ancestral 301 and MERGE_B->REINTEGRATE_MERGE are both false. */ 302 apr_hash_t *merged_abspaths; 303 304 /* A hash of (const char *) absolute WC paths mapped to the same which 305 represent the roots of subtrees added by the merge. */ 306 apr_hash_t *added_abspaths; 307 308 /* A list of tree conflict victim absolute paths which may be NULL. */ 309 apr_hash_t *tree_conflicted_abspaths; 310 311 /* The diff3_cmd in ctx->config, if any, else null. We could just 312 extract this as needed, but since more than one caller uses it, 313 we just set it up when this baton is created. */ 314 const char *diff3_cmd; 315 const apr_array_header_t *merge_options; 316 317 /* Array of file extension patterns to preserve as extensions in 318 generated conflict files. */ 319 const apr_array_header_t *ext_patterns; 320 321 /* RA sessions used throughout a merge operation. Opened/re-parented 322 as needed. 323 324 NOTE: During the actual merge editor drive, RA_SESSION1 is used 325 for the primary editing and RA_SESSION2 for fetching additional 326 information -- as necessary -- from the repository. So during 327 this phase of the merge, you *must not* reparent RA_SESSION1; use 328 (temporarily reparenting if you must) RA_SESSION2 instead. */ 329 svn_ra_session_t *ra_session1; 330 svn_ra_session_t *ra_session2; 331 332 /* During the merge, *USE_SLEEP is set to TRUE if a sleep will be required 333 afterwards to ensure timestamp integrity, or unchanged if not. */ 334 svn_boolean_t *use_sleep; 335 336 /* Pool which has a lifetime limited to one iteration over a given 337 merge source, i.e. it is cleared on every call to do_directory_merge() 338 or do_file_merge() in do_merge(). */ 339 apr_pool_t *pool; 340 341 /* Our notification callback, that adds a 'begin' notification */ 342 svn_wc_notify_func2_t notify_func; 343 void *notify_baton; 344 struct notify_begin_state_t notify_begin; 345 346} merge_cmd_baton_t; 347 348 349/* Return TRUE iff we should be taking account of mergeinfo in deciding what 350 changes to merge, for the merge described by MERGE_B. Specifically, that 351 is if the merge source server is capable of merge tracking, the left-side 352 merge source is an ancestor of the right-side (or vice-versa), the merge 353 source is in the same repository as the merge target, and we are not 354 ignoring mergeinfo. */ 355static svn_boolean_t 356HONOR_MERGEINFO(const merge_cmd_baton_t *merge_b) 357{ 358 return (merge_b->mergeinfo_capable 359 && merge_b->merge_source.ancestral 360 && merge_b->same_repos 361 && (!merge_b->ignore_mergeinfo)); 362} 363 364 365/* Return TRUE iff we should be recording mergeinfo for the merge described 366 by MERGE_B. Specifically, that is if we are honoring mergeinfo and the 367 merge is not a dry run. */ 368static svn_boolean_t 369RECORD_MERGEINFO(const merge_cmd_baton_t *merge_b) 370{ 371 return (HONOR_MERGEINFO(merge_b) 372 && !merge_b->dry_run); 373} 374 375 376/*-----------------------------------------------------------------------*/ 377 378/*** Utilities ***/ 379 380/* Return TRUE iff the session URL of RA_SESSION is equal to URL. Useful in 381 * asserting preconditions. */ 382static svn_boolean_t 383session_url_is(svn_ra_session_t *ra_session, 384 const char *url, 385 apr_pool_t *scratch_pool) 386{ 387 const char *session_url; 388 svn_error_t *err 389 = svn_ra_get_session_url(ra_session, &session_url, scratch_pool); 390 391 SVN_ERR_ASSERT_NO_RETURN(! err); 392 return strcmp(url, session_url) == 0; 393} 394 395/* Return a new merge_source_t structure, allocated in RESULT_POOL, 396 * initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */ 397static merge_source_t * 398merge_source_create(const svn_client__pathrev_t *loc1, 399 const svn_client__pathrev_t *loc2, 400 svn_boolean_t ancestral, 401 apr_pool_t *result_pool) 402{ 403 merge_source_t *s 404 = apr_palloc(result_pool, sizeof(*s)); 405 406 s->loc1 = svn_client__pathrev_dup(loc1, result_pool); 407 s->loc2 = svn_client__pathrev_dup(loc2, result_pool); 408 s->ancestral = ancestral; 409 return s; 410} 411 412/* Return a deep copy of SOURCE, allocated in RESULT_POOL. */ 413static merge_source_t * 414merge_source_dup(const merge_source_t *source, 415 apr_pool_t *result_pool) 416{ 417 merge_source_t *s = apr_palloc(result_pool, sizeof(*s)); 418 419 s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool); 420 s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool); 421 s->ancestral = source->ancestral; 422 return s; 423} 424 425/* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository 426 of LOCAL_ABSPATH. Use SCRATCH_POOL for temporary allocations. */ 427static svn_error_t * 428check_repos_match(const merge_target_t *target, 429 const char *local_abspath, 430 const char *url, 431 apr_pool_t *scratch_pool) 432{ 433 if (!svn_uri__is_ancestor(target->loc.repos_root_url, url)) 434 return svn_error_createf( 435 SVN_ERR_UNSUPPORTED_FEATURE, NULL, 436 _("URL '%s' of '%s' is not in repository '%s'"), 437 url, svn_dirent_local_style(local_abspath, scratch_pool), 438 target->loc.repos_root_url); 439 440 return SVN_NO_ERROR; 441} 442 443/* Return TRUE iff the repository of LOCATION1 is the same as 444 * that of LOCATION2. If STRICT_URLS is true, the URLs must 445 * match (and the UUIDs, just to be sure), otherwise just the UUIDs must 446 * match and the URLs can differ (a common case is http versus https). */ 447static svn_boolean_t 448is_same_repos(const svn_client__pathrev_t *location1, 449 const svn_client__pathrev_t *location2, 450 svn_boolean_t strict_urls) 451{ 452 if (strict_urls) 453 return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0 454 && strcmp(location1->repos_uuid, location2->repos_uuid) == 0); 455 else 456 return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0); 457} 458 459/* If the repository identified of LOCATION1 is not the same as that 460 * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES 461 * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos(). 462 */ 463static svn_error_t * 464check_same_repos(const svn_client__pathrev_t *location1, 465 const char *path1, 466 const svn_client__pathrev_t *location2, 467 const char *path2, 468 svn_boolean_t strict_urls, 469 apr_pool_t *scratch_pool) 470{ 471 if (! is_same_repos(location1, location2, strict_urls)) 472 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, 473 _("'%s' must be from the same repository as " 474 "'%s'"), path1, path2); 475 return SVN_NO_ERROR; 476} 477 478/* Store LOCAL_ABSPATH in PATH_HASH after duplicating it into the pool 479 containing PATH_HASH. */ 480static APR_INLINE void 481store_path(apr_hash_t *path_hash, const char *local_abspath) 482{ 483 const char *dup_path = apr_pstrdup(apr_hash_pool_get(path_hash), 484 local_abspath); 485 486 svn_hash_sets(path_hash, dup_path, dup_path); 487} 488 489/* Store LOCAL_ABSPATH in *PATH_HASH_P after duplicating it into the pool 490 containing *PATH_HASH_P. If *PATH_HASH_P is NULL, then first set 491 *PATH_HASH_P to a new hash allocated from POOL. */ 492static APR_INLINE void 493alloc_and_store_path(apr_hash_t **path_hash_p, 494 const char *local_abspath, 495 apr_pool_t *pool) 496{ 497 if (! *path_hash_p) 498 *path_hash_p = apr_hash_make(pool); 499 store_path(*path_hash_p, local_abspath); 500} 501 502/* Return whether any WC path was put in conflict by the merge 503 operation corresponding to MERGE_B. */ 504static APR_INLINE svn_boolean_t 505is_path_conflicted_by_merge(merge_cmd_baton_t *merge_b) 506{ 507 return (merge_b->conflicted_paths && 508 apr_hash_count(merge_b->conflicted_paths) > 0); 509} 510 511/* Return a state indicating whether the WC metadata matches the 512 * node kind on disk of the local path LOCAL_ABSPATH. 513 * Use MERGE_B to determine the dry-run details; particularly, if a dry run 514 * noted that it deleted this path, assume matching node kinds (as if both 515 * kinds were svn_node_none). 516 * 517 * - Return svn_wc_notify_state_inapplicable if the node kind matches. 518 * - Return 'obstructed' if there is a node on disk where none or a 519 * different kind is expected, or if the disk node cannot be read. 520 * - Return 'missing' if there is no node on disk but one is expected. 521 * Also return 'missing' for server-excluded nodes (not here due to 522 * authz or other reasons determined by the server). 523 * 524 * Optionally return a bit more info for interested users. 525 **/ 526static svn_error_t * 527perform_obstruction_check(svn_wc_notify_state_t *obstruction_state, 528 svn_boolean_t *deleted, 529 svn_boolean_t *excluded, 530 svn_node_kind_t *kind, 531 svn_depth_t *parent_depth, 532 const merge_cmd_baton_t *merge_b, 533 const char *local_abspath, 534 apr_pool_t *scratch_pool) 535{ 536 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx; 537 svn_node_kind_t wc_kind; 538 svn_boolean_t check_root; 539 540 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 541 542 *obstruction_state = svn_wc_notify_state_inapplicable; 543 544 if (deleted) 545 *deleted = FALSE; 546 if (kind) 547 *kind = svn_node_none; 548 549 if (kind == NULL) 550 kind = &wc_kind; 551 552 check_root = ! strcmp(local_abspath, merge_b->target->abspath); 553 554 SVN_ERR(svn_wc__check_for_obstructions(obstruction_state, 555 kind, 556 deleted, 557 excluded, 558 parent_depth, 559 wc_ctx, local_abspath, 560 check_root, 561 scratch_pool)); 562 return SVN_NO_ERROR; 563} 564 565/* Create *LEFT and *RIGHT conflict versions for conflict victim 566 * at VICTIM_ABSPATH, with merge-left node kind MERGE_LEFT_NODE_KIND 567 * and merge-right node kind MERGE_RIGHT_NODE_KIND, using information 568 * obtained from MERGE_SOURCE and TARGET. 569 * Allocate returned conflict versions in RESULT_POOL. */ 570static svn_error_t * 571make_conflict_versions(const svn_wc_conflict_version_t **left, 572 const svn_wc_conflict_version_t **right, 573 const char *victim_abspath, 574 svn_node_kind_t merge_left_node_kind, 575 svn_node_kind_t merge_right_node_kind, 576 const merge_source_t *merge_source, 577 const merge_target_t *target, 578 apr_pool_t *result_pool, 579 apr_pool_t *scratch_pool) 580{ 581 const char *child = svn_dirent_skip_ancestor(target->abspath, 582 victim_abspath); 583 const char *left_relpath, *right_relpath; 584 585 SVN_ERR_ASSERT(child != NULL); 586 left_relpath = svn_client__pathrev_relpath(merge_source->loc1, 587 scratch_pool); 588 right_relpath = svn_client__pathrev_relpath(merge_source->loc2, 589 scratch_pool); 590 591 *left = svn_wc_conflict_version_create2( 592 merge_source->loc1->repos_root_url, 593 merge_source->loc1->repos_uuid, 594 svn_relpath_join(left_relpath, child, scratch_pool), 595 merge_source->loc1->rev, 596 merge_left_node_kind, result_pool); 597 598 *right = svn_wc_conflict_version_create2( 599 merge_source->loc2->repos_root_url, 600 merge_source->loc2->repos_uuid, 601 svn_relpath_join(right_relpath, child, scratch_pool), 602 merge_source->loc2->rev, 603 merge_right_node_kind, result_pool); 604 605 return SVN_NO_ERROR; 606} 607 608/* Helper for filter_self_referential_mergeinfo() 609 610 *MERGEINFO is a non-empty, non-null collection of mergeinfo. 611 612 Remove all mergeinfo from *MERGEINFO that describes revision ranges 613 greater than REVISION. Put a copy of any removed mergeinfo, allocated 614 in POOL, into *YOUNGER_MERGEINFO. 615 616 If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set 617 to NULL. If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is 618 set to NULL. 619 */ 620static svn_error_t* 621split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo, 622 svn_mergeinfo_t *mergeinfo, 623 svn_revnum_t revision, 624 apr_pool_t *pool) 625{ 626 apr_hash_index_t *hi; 627 apr_pool_t *iterpool = svn_pool_create(pool); 628 629 *younger_mergeinfo = NULL; 630 for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi)) 631 { 632 int i; 633 const char *merge_source_path = apr_hash_this_key(hi); 634 svn_rangelist_t *rangelist = apr_hash_this_val(hi); 635 636 svn_pool_clear(iterpool); 637 638 for (i = 0; i < rangelist->nelts; i++) 639 { 640 svn_merge_range_t *range = 641 APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 642 if (range->end <= revision) 643 { 644 /* This entirely of this range is as old or older than 645 REVISION, so leave it in *MERGEINFO. */ 646 continue; 647 } 648 else 649 { 650 /* Since the rangelists in svn_mergeinfo_t's are sorted in 651 increasing order we know that part or all of *this* range 652 and *all* of the remaining ranges in *RANGELIST are younger 653 than REVISION. Remove the younger rangelists from 654 *MERGEINFO and put them in *YOUNGER_MERGEINFO. */ 655 int j; 656 svn_rangelist_t *younger_rangelist = 657 apr_array_make(pool, 1, sizeof(svn_merge_range_t *)); 658 659 for (j = i; j < rangelist->nelts; j++) 660 { 661 svn_merge_range_t *younger_range = svn_merge_range_dup( 662 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool); 663 664 /* REVISION might intersect with the first range where 665 range->end > REVISION. If that is the case then split 666 the current range into two, putting the younger half 667 into *YOUNGER_MERGEINFO and leaving the older half in 668 *MERGEINFO. */ 669 if (j == i && range->start + 1 <= revision) 670 younger_range->start = range->end = revision; 671 672 APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) = 673 younger_range; 674 } 675 676 /* So far we've only been manipulating rangelists, now we 677 actually create *YOUNGER_MERGEINFO and then remove the older 678 ranges from *MERGEINFO */ 679 if (!(*younger_mergeinfo)) 680 *younger_mergeinfo = apr_hash_make(pool); 681 svn_hash_sets(*younger_mergeinfo, merge_source_path, 682 younger_rangelist); 683 SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo, 684 *mergeinfo, TRUE, pool, iterpool)); 685 break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */ 686 } 687 } 688 } 689 690 svn_pool_destroy(iterpool); 691 692 return SVN_NO_ERROR; 693} 694 695 696/* Make a copy of PROPCHANGES (array of svn_prop_t) into *TRIMMED_PROPCHANGES, 697 omitting any svn:mergeinfo changes. */ 698static svn_error_t * 699omit_mergeinfo_changes(apr_array_header_t **trimmed_propchanges, 700 const apr_array_header_t *propchanges, 701 apr_pool_t *result_pool) 702{ 703 int i; 704 705 *trimmed_propchanges = apr_array_make(result_pool, 706 propchanges->nelts, 707 sizeof(svn_prop_t)); 708 709 for (i = 0; i < propchanges->nelts; ++i) 710 { 711 const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t); 712 713 /* If this property is not svn:mergeinfo, then copy it. */ 714 if (strcmp(change->name, SVN_PROP_MERGEINFO) != 0) 715 APR_ARRAY_PUSH(*trimmed_propchanges, svn_prop_t) = *change; 716 } 717 718 return SVN_NO_ERROR; 719} 720 721 722/* Helper for merge_props_changed(). 723 724 *PROPS is an array of svn_prop_t structures representing regular properties 725 to be added to the working copy TARGET_ABSPATH. 726 727 The merge source and target are assumed to be in the same repository. 728 729 Filter out mergeinfo property additions to TARGET_ABSPATH when 730 those additions refer to the same line of history as TARGET_ABSPATH as 731 described below. 732 733 Examine the added mergeinfo, looking at each range (or single rev) 734 of each source path. If a source_path/range refers to the same line of 735 history as TARGET_ABSPATH (pegged at its base revision), then filter out 736 that range. If the entire rangelist for a given path is filtered then 737 filter out the path as well. 738 739 RA_SESSION is an open RA session to the repository 740 in which both the source and target live, else RA_SESSION is not used. It 741 may be temporarily reparented as needed by this function. 742 743 Use CTX for any further client operations. 744 745 If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated 746 in POOL) of incoming *PROPS minus the filtered mergeinfo. */ 747static svn_error_t * 748filter_self_referential_mergeinfo(apr_array_header_t **props, 749 const char *target_abspath, 750 svn_ra_session_t *ra_session, 751 svn_client_ctx_t *ctx, 752 apr_pool_t *pool) 753{ 754 apr_array_header_t *adjusted_props; 755 int i; 756 apr_pool_t *iterpool; 757 svn_boolean_t is_copy; 758 const char *repos_relpath; 759 svn_client__pathrev_t target_base; 760 761 /* If PATH itself has been added there is no need to filter. */ 762 SVN_ERR(svn_wc__node_get_origin(&is_copy, &target_base.rev, &repos_relpath, 763 &target_base.repos_root_url, 764 &target_base.repos_uuid, NULL, NULL, 765 ctx->wc_ctx, target_abspath, FALSE, 766 pool, pool)); 767 768 if (is_copy || !repos_relpath) 769 return SVN_NO_ERROR; /* A copy or a local addition */ 770 771 target_base.url = svn_path_url_add_component2(target_base.repos_root_url, 772 repos_relpath, pool); 773 774 adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t)); 775 iterpool = svn_pool_create(pool); 776 for (i = 0; i < (*props)->nelts; ++i) 777 { 778 svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t); 779 780 svn_mergeinfo_t mergeinfo, younger_mergeinfo; 781 svn_mergeinfo_t filtered_mergeinfo = NULL; 782 svn_mergeinfo_t filtered_younger_mergeinfo = NULL; 783 svn_error_t *err; 784 785 /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal) 786 or empty mergeinfo it does not require any special handling. There 787 is nothing to filter out of empty mergeinfo and the concept of 788 filtering doesn't apply if we are trying to remove mergeinfo 789 entirely. */ 790 if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0) 791 || (! prop->value) /* Removal of mergeinfo */ 792 || (! prop->value->len)) /* Empty mergeinfo */ 793 { 794 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop; 795 continue; 796 } 797 798 svn_pool_clear(iterpool); 799 800 /* Non-empty mergeinfo; filter self-referential mergeinfo out. */ 801 802 /* Parse the incoming mergeinfo to allow easier manipulation. */ 803 err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool); 804 805 if (err) 806 { 807 /* Issue #3896: If we can't parse it, we certainly can't 808 filter it. */ 809 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 810 { 811 svn_error_clear(err); 812 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop; 813 continue; 814 } 815 else 816 { 817 return svn_error_trace(err); 818 } 819 } 820 821 /* The working copy target PATH is at BASE_REVISION. Divide the 822 incoming mergeinfo into two groups. One where all revision ranges 823 are as old or older than BASE_REVISION and one where all revision 824 ranges are younger. 825 826 Note: You may be wondering why we do this. 827 828 For the incoming mergeinfo "older" than target's base revision we 829 can filter out self-referential mergeinfo efficiently using 830 svn_client__get_history_as_mergeinfo(). We simply look at PATH's 831 natural history as mergeinfo and remove that from any incoming 832 mergeinfo. 833 834 For mergeinfo "younger" than the base revision we can't use 835 svn_ra_get_location_segments() to look into PATH's future 836 history. Instead we must use svn_client__repos_locations() and 837 look at each incoming source/range individually and see if PATH 838 at its base revision and PATH at the start of the incoming range 839 exist on the same line of history. If they do then we can filter 840 out the incoming range. But since we have to do this for each 841 range there is a substantial performance penalty to pay if the 842 incoming ranges are not contiguous, i.e. we call 843 svn_client__repos_locations for each discrete range and incur 844 the cost of a roundtrip communication with the repository. */ 845 SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo, 846 &mergeinfo, 847 target_base.rev, 848 iterpool)); 849 850 /* Filter self-referential mergeinfo from younger_mergeinfo. */ 851 if (younger_mergeinfo) 852 { 853 apr_hash_index_t *hi; 854 const char *merge_source_root_url; 855 856 SVN_ERR(svn_ra_get_repos_root2(ra_session, 857 &merge_source_root_url, iterpool)); 858 859 for (hi = apr_hash_first(iterpool, younger_mergeinfo); 860 hi; hi = apr_hash_next(hi)) 861 { 862 int j; 863 const char *source_path = apr_hash_this_key(hi); 864 svn_rangelist_t *rangelist = apr_hash_this_val(hi); 865 const char *merge_source_url; 866 svn_rangelist_t *adjusted_rangelist = 867 apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *)); 868 869 merge_source_url = 870 svn_path_url_add_component2(merge_source_root_url, 871 source_path + 1, iterpool); 872 873 for (j = 0; j < rangelist->nelts; j++) 874 { 875 svn_error_t *err2; 876 svn_client__pathrev_t *start_loc; 877 svn_merge_range_t *range = 878 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *); 879 880 /* Because the merge source normalization code 881 ensures mergeinfo refers to real locations on 882 the same line of history, there's no need to 883 look at the whole range, just the start. */ 884 885 /* Check if PATH@BASE_REVISION exists at 886 RANGE->START on the same line of history. 887 (start+1 because RANGE->start is not inclusive.) */ 888 err2 = svn_client__repos_location(&start_loc, ra_session, 889 &target_base, 890 range->start + 1, 891 ctx, iterpool, iterpool); 892 if (err2) 893 { 894 if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES 895 || err2->apr_err == SVN_ERR_FS_NOT_FOUND 896 || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION) 897 { 898 /* PATH@BASE_REVISION didn't exist at 899 RANGE->START + 1 or is unrelated to the 900 resource PATH@RANGE->START. Some of the 901 requested revisions may not even exist in 902 the repository; a real possibility since 903 mergeinfo is hand editable. In all of these 904 cases clear and ignore the error and don't 905 do any filtering. 906 907 Note: In this last case it is possible that 908 we will allow self-referential mergeinfo to 909 be applied, but fixing it here is potentially 910 very costly in terms of finding what part of 911 a range is actually valid. Simply allowing 912 the merge to proceed without filtering the 913 offending range seems the least worst 914 option. */ 915 svn_error_clear(err2); 916 err2 = NULL; 917 APR_ARRAY_PUSH(adjusted_rangelist, 918 svn_merge_range_t *) = range; 919 } 920 else 921 { 922 return svn_error_trace(err2); 923 } 924 } 925 else 926 { 927 /* PATH@BASE_REVISION exists on the same 928 line of history at RANGE->START and RANGE->END. 929 Now check that PATH@BASE_REVISION's path 930 names at RANGE->START and RANGE->END are the same. 931 If the names are not the same then the mergeinfo 932 describing PATH@RANGE->START through 933 PATH@RANGE->END actually belong to some other 934 line of history and we want to record this 935 mergeinfo, not filter it. */ 936 if (strcmp(start_loc->url, merge_source_url) != 0) 937 { 938 APR_ARRAY_PUSH(adjusted_rangelist, 939 svn_merge_range_t *) = range; 940 } 941 } 942 /* else no need to add, this mergeinfo is 943 all on the same line of history. */ 944 } /* for (j = 0; j < rangelist->nelts; j++) */ 945 946 /* Add any rangelists for source_path that are not 947 self-referential. */ 948 if (adjusted_rangelist->nelts) 949 { 950 if (!filtered_younger_mergeinfo) 951 filtered_younger_mergeinfo = apr_hash_make(iterpool); 952 svn_hash_sets(filtered_younger_mergeinfo, source_path, 953 adjusted_rangelist); 954 } 955 956 } /* Iteration over each merge source in younger_mergeinfo. */ 957 } /* if (younger_mergeinfo) */ 958 959 /* Filter self-referential mergeinfo from "older" mergeinfo. */ 960 if (mergeinfo) 961 { 962 svn_mergeinfo_t implicit_mergeinfo; 963 964 SVN_ERR(svn_client__get_history_as_mergeinfo( 965 &implicit_mergeinfo, NULL, 966 &target_base, target_base.rev, SVN_INVALID_REVNUM, 967 ra_session, ctx, iterpool)); 968 969 /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */ 970 SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo, 971 implicit_mergeinfo, 972 mergeinfo, TRUE, iterpool, iterpool)); 973 } 974 975 /* Combine whatever older and younger filtered mergeinfo exists 976 into filtered_mergeinfo. */ 977 if (filtered_mergeinfo && filtered_younger_mergeinfo) 978 SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo, 979 filtered_younger_mergeinfo, iterpool, 980 iterpool)); 981 else if (filtered_younger_mergeinfo) 982 filtered_mergeinfo = filtered_younger_mergeinfo; 983 984 /* If there is any incoming mergeinfo remaining after filtering 985 then put it in adjusted_props. */ 986 if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo)) 987 { 988 /* Convert filtered_mergeinfo to a svn_prop_t and put it 989 back in the array. */ 990 svn_string_t *filtered_mergeinfo_str; 991 svn_prop_t *adjusted_prop = apr_pcalloc(pool, 992 sizeof(*adjusted_prop)); 993 SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str, 994 filtered_mergeinfo, 995 pool)); 996 adjusted_prop->name = SVN_PROP_MERGEINFO; 997 adjusted_prop->value = filtered_mergeinfo_str; 998 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop; 999 } 1000 } 1001 svn_pool_destroy(iterpool); 1002 1003 *props = adjusted_props; 1004 return SVN_NO_ERROR; 1005} 1006 1007/* Prepare a set of property changes PROPCHANGES to be used for a merge 1008 operation on LOCAL_ABSPATH. 1009 1010 Remove all non-regular prop-changes (entry-props and WC-props). 1011 Remove all non-mergeinfo prop-changes if it's a record-only merge. 1012 Remove self-referential mergeinfo (### in some cases...) 1013 Remove foreign-repository mergeinfo (### in some cases...) 1014 1015 Store the resulting property changes in *PROP_UPDATES. 1016 Store information on where mergeinfo is updated in MERGE_B. 1017 1018 Used for both file and directory property merges. */ 1019static svn_error_t * 1020prepare_merge_props_changed(const apr_array_header_t **prop_updates, 1021 const char *local_abspath, 1022 const apr_array_header_t *propchanges, 1023 merge_cmd_baton_t *merge_b, 1024 apr_pool_t *result_pool, 1025 apr_pool_t *scratch_pool) 1026{ 1027 apr_array_header_t *props; 1028 1029 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 1030 1031 /* We only want to merge "regular" version properties: by 1032 definition, 'svn merge' shouldn't touch any data within .svn/ */ 1033 SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, 1034 result_pool)); 1035 1036 /* If we are only applying mergeinfo changes then we need to do 1037 additional filtering of PROPS so it contains only mergeinfo changes. */ 1038 if (merge_b->record_only && props->nelts) 1039 { 1040 apr_array_header_t *mergeinfo_props = 1041 apr_array_make(result_pool, 1, sizeof(svn_prop_t)); 1042 int i; 1043 1044 for (i = 0; i < props->nelts; i++) 1045 { 1046 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); 1047 1048 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0) 1049 { 1050 APR_ARRAY_PUSH(mergeinfo_props, svn_prop_t) = *prop; 1051 break; 1052 } 1053 } 1054 props = mergeinfo_props; 1055 } 1056 1057 if (props->nelts) 1058 { 1059 /* Issue #3383: We don't want mergeinfo from a foreign repos. 1060 1061 If this is a merge from a foreign repository we must strip all 1062 incoming mergeinfo (including mergeinfo deletions). */ 1063 if (! merge_b->same_repos) 1064 SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool)); 1065 1066 /* If this is a forward merge then don't add new mergeinfo to 1067 PATH that is already part of PATH's own history, see 1068 http://svn.haxx.se/dev/archive-2008-09/0006.shtml. If the 1069 merge sources are not ancestral then there is no concept of a 1070 'forward' or 'reverse' merge and we filter unconditionally. */ 1071 if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev 1072 || !merge_b->merge_source.ancestral) 1073 { 1074 if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge) 1075 SVN_ERR(filter_self_referential_mergeinfo(&props, 1076 local_abspath, 1077 merge_b->ra_session2, 1078 merge_b->ctx, 1079 result_pool)); 1080 } 1081 } 1082 *prop_updates = props; 1083 1084 /* Make a record in BATON if we find a PATH where mergeinfo is added 1085 where none existed previously or PATH is having its existing 1086 mergeinfo deleted. */ 1087 if (props->nelts) 1088 { 1089 int i; 1090 1091 for (i = 0; i < props->nelts; ++i) 1092 { 1093 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); 1094 1095 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0) 1096 { 1097 /* Does LOCAL_ABSPATH have any pristine mergeinfo? */ 1098 svn_boolean_t has_pristine_mergeinfo = FALSE; 1099 apr_hash_t *pristine_props; 1100 1101 SVN_ERR(svn_wc_get_pristine_props(&pristine_props, 1102 merge_b->ctx->wc_ctx, 1103 local_abspath, 1104 scratch_pool, 1105 scratch_pool)); 1106 1107 if (pristine_props 1108 && svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO)) 1109 has_pristine_mergeinfo = TRUE; 1110 1111 if (!has_pristine_mergeinfo && prop->value) 1112 { 1113 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 1114 local_abspath, merge_b->pool); 1115 } 1116 else if (has_pristine_mergeinfo && !prop->value) 1117 { 1118 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 1119 local_abspath, merge_b->pool); 1120 } 1121 } 1122 } 1123 } 1124 1125 return SVN_NO_ERROR; 1126} 1127 1128#define CONFLICT_REASON_NONE ((svn_wc_conflict_reason_t)-1) 1129#define CONFLICT_REASON_SKIP ((svn_wc_conflict_reason_t)-2) 1130#define CONFLICT_REASON_SKIP_WC ((svn_wc_conflict_reason_t)-3) 1131 1132/* Baton used for testing trees for being editted while performing tree 1133 conflict detection for incoming deletes */ 1134struct dir_delete_baton_t 1135{ 1136 /* Reference to dir baton of directory that is the root of the deletion */ 1137 struct merge_dir_baton_t *del_root; 1138 1139 /* Boolean indicating that some edit is found. Allows avoiding more work */ 1140 svn_boolean_t found_edit; 1141 1142 /* A list of paths that are compared. Kept up to date until FOUND_EDIT is 1143 set to TRUE */ 1144 apr_hash_t *compared_abspaths; 1145}; 1146 1147/* Baton for the merge_dir_*() functions. Initialized in merge_dir_opened() */ 1148struct merge_dir_baton_t 1149{ 1150 /* Reference to the parent baton, unless the parent is the anchor, in which 1151 case PARENT_BATON is NULL */ 1152 struct merge_dir_baton_t *parent_baton; 1153 1154 /* The pool containing this baton. Use for RESULT_POOL for storing in this 1155 baton */ 1156 apr_pool_t *pool; 1157 1158 /* This directory doesn't have a representation in the working copy, so any 1159 operation on it will be skipped and possibly cause a tree conflict on the 1160 shadow root */ 1161 svn_boolean_t shadowed; 1162 1163 /* This node or one of its descendants received operational changes from the 1164 merge. If this node is the shadow root its tree conflict status has been 1165 applied */ 1166 svn_boolean_t edited; 1167 1168 /* If a tree conflict will be installed once edited, it's reason. If a skip 1169 should be produced its reason. Otherwise CONFLICT_REASON_NONE for no tree 1170 conflict. 1171 1172 Special values: 1173 CONFLICT_REASON_SKIP: 1174 The node will be skipped with content and property state as stored in 1175 SKIP_REASON. 1176 1177 CONFLICT_REASON_SKIP_WC: 1178 The node will be skipped as an obstructing working copy. 1179 */ 1180 svn_wc_conflict_reason_t tree_conflict_reason; 1181 svn_wc_conflict_action_t tree_conflict_action; 1182 svn_node_kind_t tree_conflict_local_node_kind; 1183 svn_node_kind_t tree_conflict_merge_left_node_kind; 1184 svn_node_kind_t tree_conflict_merge_right_node_kind; 1185 1186 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to 1187 add to the notification */ 1188 svn_wc_notify_state_t skip_reason; 1189 1190 /* TRUE if the node was added by this merge. Otherwise FALSE */ 1191 svn_boolean_t added; 1192 svn_boolean_t add_is_replace; /* Add is second part of replace */ 1193 1194 /* TRUE if we are taking over an existing directory as addition, otherwise 1195 FALSE. */ 1196 svn_boolean_t add_existing; 1197 1198 /* NULL, or an hashtable mapping const char * local_abspaths to 1199 const char *kind mapping, containing deleted nodes that still need a delete 1200 notification (which may be a replaced notification if the node is not just 1201 deleted) */ 1202 apr_hash_t *pending_deletes; 1203 1204 /* NULL, or an hashtable mapping const char * LOCAL_ABSPATHs to 1205 a const svn_wc_conflict_description2_t * instance, describing the just 1206 installed conflict */ 1207 apr_hash_t *new_tree_conflicts; 1208 1209 /* If not NULL, a reference to the information of the delete test that is 1210 currently in progress. Allocated in the root-directory baton, referenced 1211 from all descendants */ 1212 struct dir_delete_baton_t *delete_state; 1213}; 1214 1215/* Baton for the merge_dir_*() functions. Initialized in merge_file_opened() */ 1216struct merge_file_baton_t 1217{ 1218 /* Reference to the parent baton, unless the parent is the anchor, in which 1219 case PARENT_BATON is NULL */ 1220 struct merge_dir_baton_t *parent_baton; 1221 1222 /* This file doesn't have a representation in the working copy, so any 1223 operation on it will be skipped and possibly cause a tree conflict 1224 on the shadow root */ 1225 svn_boolean_t shadowed; 1226 1227 /* This node received operational changes from the merge. If this node 1228 is the shadow root its tree conflict status has been applied */ 1229 svn_boolean_t edited; 1230 1231 /* If a tree conflict will be installed once edited, it's reason. If a skip 1232 should be produced its reason. Some special values are defined. See the 1233 merge_dir_baton_t for an explanation. */ 1234 svn_wc_conflict_reason_t tree_conflict_reason; 1235 svn_wc_conflict_action_t tree_conflict_action; 1236 svn_node_kind_t tree_conflict_local_node_kind; 1237 svn_node_kind_t tree_conflict_merge_left_node_kind; 1238 svn_node_kind_t tree_conflict_merge_right_node_kind; 1239 1240 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to 1241 add to the notification */ 1242 svn_wc_notify_state_t skip_reason; 1243 1244 /* TRUE if the node was added by this merge. Otherwise FALSE */ 1245 svn_boolean_t added; 1246 svn_boolean_t add_is_replace; /* Add is second part of replace */ 1247}; 1248 1249/* Record the skip for future processing and (later) produce the 1250 skip notification */ 1251static svn_error_t * 1252record_skip(merge_cmd_baton_t *merge_b, 1253 const char *local_abspath, 1254 svn_node_kind_t kind, 1255 svn_wc_notify_action_t action, 1256 svn_wc_notify_state_t state, 1257 struct merge_dir_baton_t *pdb, 1258 apr_pool_t *scratch_pool) 1259{ 1260 if (merge_b->record_only) 1261 return SVN_NO_ERROR; /* ### Why? - Legacy compatibility */ 1262 1263 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1264 && !(pdb && pdb->shadowed)) 1265 { 1266 store_path(merge_b->skipped_abspaths, local_abspath); 1267 } 1268 1269 if (merge_b->notify_func) 1270 { 1271 svn_wc_notify_t *notify; 1272 1273 notify = svn_wc_create_notify(local_abspath, action, scratch_pool); 1274 notify->kind = kind; 1275 notify->content_state = notify->prop_state = state; 1276 1277 merge_b->notify_func(merge_b->notify_baton, notify, 1278 scratch_pool); 1279 } 1280 return SVN_NO_ERROR; 1281} 1282 1283/* Forward declaration */ 1284static svn_client__merge_path_t * 1285find_nearest_ancestor_with_intersecting_ranges( 1286 svn_revnum_t *start, 1287 svn_revnum_t *end, 1288 const apr_array_header_t *children_with_mergeinfo, 1289 svn_boolean_t path_is_own_ancestor, 1290 const char *local_abspath); 1291 1292/* Record a tree conflict in the WC, unless this is a dry run or a record- 1293 * only merge, or if a tree conflict is already flagged for the VICTIM_PATH. 1294 * (The latter can happen if a merge-tracking-aware merge is doing multiple 1295 * editor drives because of a gap in the range of eligible revisions.) 1296 * 1297 * The tree conflict, with its victim specified by VICTIM_PATH, is 1298 * assumed to have happened during a merge using merge baton MERGE_B. 1299 * 1300 * ACTION and REASON correspond to the fields 1301 * of the same names in svn_wc_tree_conflict_description_t. 1302 */ 1303static svn_error_t * 1304record_tree_conflict(merge_cmd_baton_t *merge_b, 1305 const char *local_abspath, 1306 struct merge_dir_baton_t *parent_baton, 1307 svn_node_kind_t local_node_kind, 1308 svn_node_kind_t merge_left_node_kind, 1309 svn_node_kind_t merge_right_node_kind, 1310 svn_wc_conflict_action_t action, 1311 svn_wc_conflict_reason_t reason, 1312 const svn_wc_conflict_description2_t *existing_conflict, 1313 svn_boolean_t notify_tc, 1314 apr_pool_t *scratch_pool) 1315{ 1316 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx; 1317 1318 if (merge_b->record_only) 1319 return SVN_NO_ERROR; 1320 1321 if (merge_b->merge_source.ancestral 1322 || merge_b->reintegrate_merge) 1323 { 1324 store_path(merge_b->tree_conflicted_abspaths, local_abspath); 1325 } 1326 1327 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 1328 merge_b->pool); 1329 1330 if (!merge_b->dry_run) 1331 { 1332 svn_wc_conflict_description2_t *conflict; 1333 const svn_wc_conflict_version_t *left; 1334 const svn_wc_conflict_version_t *right; 1335 apr_pool_t *result_pool = parent_baton ? parent_baton->pool 1336 : scratch_pool; 1337 1338 if (reason == svn_wc_conflict_reason_deleted) 1339 { 1340 const char *moved_to_abspath; 1341 1342 SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL, 1343 wc_ctx, local_abspath, 1344 scratch_pool, scratch_pool)); 1345 1346 if (moved_to_abspath) 1347 { 1348 /* Local abspath itself has been moved away. If only a 1349 descendant is moved away, we call the node itself deleted */ 1350 reason = svn_wc_conflict_reason_moved_away; 1351 } 1352 } 1353 else if (reason == svn_wc_conflict_reason_added) 1354 { 1355 const char *moved_from_abspath; 1356 SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL, 1357 wc_ctx, local_abspath, 1358 scratch_pool, scratch_pool)); 1359 if (moved_from_abspath) 1360 reason = svn_wc_conflict_reason_moved_here; 1361 } 1362 1363 if (HONOR_MERGEINFO(merge_b) && merge_b->merge_source.ancestral) 1364 { 1365 struct merge_source_t *source; 1366 svn_client__pathrev_t *loc1; 1367 svn_client__pathrev_t *loc2; 1368 svn_merge_range_t range = 1369 {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE}; 1370 1371 /* We are honoring mergeinfo so do not blindly record 1372 * a conflict describing the merge of 1373 * SOURCE->LOC1->URL@SOURCE->LOC1->REV through 1374 * SOURCE->LOC2->URL@SOURCE->LOC2->REV 1375 * but figure out the actual revision range merged. */ 1376 (void)find_nearest_ancestor_with_intersecting_ranges( 1377 &(range.start), &(range.end), 1378 merge_b->children_with_mergeinfo, 1379 action != svn_wc_conflict_action_delete, 1380 local_abspath); 1381 loc1 = svn_client__pathrev_dup(merge_b->merge_source.loc1, 1382 scratch_pool); 1383 loc2 = svn_client__pathrev_dup(merge_b->merge_source.loc2, 1384 scratch_pool); 1385 loc1->rev = range.start; 1386 loc2->rev = range.end; 1387 source = merge_source_create(loc1, loc2, 1388 merge_b->merge_source.ancestral, 1389 scratch_pool); 1390 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 1391 merge_left_node_kind, 1392 merge_right_node_kind, 1393 source, merge_b->target, 1394 result_pool, scratch_pool)); 1395 } 1396 else 1397 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 1398 merge_left_node_kind, 1399 merge_right_node_kind, 1400 &merge_b->merge_source, merge_b->target, 1401 result_pool, scratch_pool)); 1402 1403 /* Fix up delete of file, add of dir replacement (or other way around) */ 1404 if (existing_conflict != NULL && existing_conflict->src_left_version) 1405 left = existing_conflict->src_left_version; 1406 1407 conflict = svn_wc_conflict_description_create_tree2( 1408 local_abspath, local_node_kind, 1409 svn_wc_operation_merge, 1410 left, right, result_pool); 1411 1412 conflict->action = action; 1413 conflict->reason = reason; 1414 1415 /* May return SVN_ERR_WC_PATH_UNEXPECTED_STATUS */ 1416 if (existing_conflict) 1417 SVN_ERR(svn_wc__del_tree_conflict(wc_ctx, local_abspath, 1418 scratch_pool)); 1419 1420 SVN_ERR(svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict, 1421 scratch_pool)); 1422 1423 if (parent_baton) 1424 { 1425 if (! parent_baton->new_tree_conflicts) 1426 parent_baton->new_tree_conflicts = apr_hash_make(result_pool); 1427 1428 svn_hash_sets(parent_baton->new_tree_conflicts, 1429 apr_pstrdup(result_pool, local_abspath), 1430 conflict); 1431 } 1432 1433 /* ### TODO: Store in parent baton */ 1434 } 1435 1436 /* On a replacement we currently get two tree conflicts */ 1437 if (merge_b->notify_func && notify_tc) 1438 { 1439 svn_wc_notify_t *notify; 1440 1441 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict, 1442 scratch_pool); 1443 notify->kind = local_node_kind; 1444 1445 merge_b->notify_func(merge_b->notify_baton, notify, 1446 scratch_pool); 1447 } 1448 1449 return SVN_NO_ERROR; 1450} 1451 1452/* Record the add for future processing and produce the 1453 update_add notification 1454 */ 1455static svn_error_t * 1456record_update_add(merge_cmd_baton_t *merge_b, 1457 const char *local_abspath, 1458 svn_node_kind_t kind, 1459 svn_boolean_t notify_replaced, 1460 apr_pool_t *scratch_pool) 1461{ 1462 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1463 { 1464 store_path(merge_b->merged_abspaths, local_abspath); 1465 } 1466 1467 if (merge_b->notify_func) 1468 { 1469 svn_wc_notify_t *notify; 1470 svn_wc_notify_action_t action = svn_wc_notify_update_add; 1471 1472 if (notify_replaced) 1473 action = svn_wc_notify_update_replace; 1474 1475 notify = svn_wc_create_notify(local_abspath, action, scratch_pool); 1476 notify->kind = kind; 1477 1478 merge_b->notify_func(merge_b->notify_baton, notify, 1479 scratch_pool); 1480 } 1481 1482 return SVN_NO_ERROR; 1483} 1484 1485/* Record the update for future processing and produce the 1486 update_update notification */ 1487static svn_error_t * 1488record_update_update(merge_cmd_baton_t *merge_b, 1489 const char *local_abspath, 1490 svn_node_kind_t kind, 1491 svn_wc_notify_state_t content_state, 1492 svn_wc_notify_state_t prop_state, 1493 apr_pool_t *scratch_pool) 1494{ 1495 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1496 { 1497 store_path(merge_b->merged_abspaths, local_abspath); 1498 } 1499 1500 if (merge_b->notify_func) 1501 { 1502 svn_wc_notify_t *notify; 1503 1504 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update, 1505 scratch_pool); 1506 notify->kind = kind; 1507 notify->content_state = content_state; 1508 notify->prop_state = prop_state; 1509 1510 merge_b->notify_func(merge_b->notify_baton, notify, 1511 scratch_pool); 1512 } 1513 1514 return SVN_NO_ERROR; 1515} 1516 1517/* Record the delete for future processing and for (later) producing the 1518 update_delete notification */ 1519static svn_error_t * 1520record_update_delete(merge_cmd_baton_t *merge_b, 1521 struct merge_dir_baton_t *parent_db, 1522 const char *local_abspath, 1523 svn_node_kind_t kind, 1524 apr_pool_t *scratch_pool) 1525{ 1526 /* Update the lists of merged, skipped, tree-conflicted and added paths. */ 1527 if (merge_b->merge_source.ancestral 1528 || merge_b->reintegrate_merge) 1529 { 1530 /* Issue #4166: If a previous merge added NOTIFY_ABSPATH, but we 1531 are now deleting it, then remove it from the list of added 1532 paths. */ 1533 svn_hash_sets(merge_b->added_abspaths, local_abspath, NULL); 1534 store_path(merge_b->merged_abspaths, local_abspath); 1535 } 1536 1537 if (parent_db) 1538 { 1539 const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath); 1540 1541 if (!parent_db->pending_deletes) 1542 parent_db->pending_deletes = apr_hash_make(parent_db->pool); 1543 1544 svn_hash_sets(parent_db->pending_deletes, dup_abspath, 1545 svn_node_kind_to_word(kind)); 1546 } 1547 1548 /* Note in children_with_mergeinfo that all paths in this subtree are 1549 * being deleted, to avoid trying to set mergeinfo on them later. */ 1550 if (merge_b->children_with_mergeinfo) 1551 { 1552 int i; 1553 1554 for (i = 0; i < merge_b->children_with_mergeinfo->nelts; i++) 1555 { 1556 svn_client__merge_path_t *child 1557 = APR_ARRAY_IDX(merge_b->children_with_mergeinfo, i, 1558 svn_client__merge_path_t *); 1559 1560 if (svn_dirent_is_ancestor(local_abspath, child->abspath)) 1561 { 1562 SVN_ERR(svn_sort__array_delete2(merge_b->children_with_mergeinfo, i--, 1)); 1563 } 1564 } 1565 } 1566 1567 return SVN_NO_ERROR; 1568} 1569 1570/* Notify the pending 'D'eletes, that were waiting to see if a matching 'A'dd 1571 might make them a 'R'eplace. */ 1572static svn_error_t * 1573handle_pending_notifications(merge_cmd_baton_t *merge_b, 1574 struct merge_dir_baton_t *db, 1575 apr_pool_t *scratch_pool) 1576{ 1577 if (merge_b->notify_func && db->pending_deletes) 1578 { 1579 apr_hash_index_t *hi; 1580 1581 for (hi = apr_hash_first(scratch_pool, db->pending_deletes); 1582 hi; 1583 hi = apr_hash_next(hi)) 1584 { 1585 const char *del_abspath = apr_hash_this_key(hi); 1586 svn_wc_notify_t *notify; 1587 1588 notify = svn_wc_create_notify(del_abspath, 1589 svn_wc_notify_update_delete, 1590 scratch_pool); 1591 notify->kind = svn_node_kind_from_word( 1592 apr_hash_this_val(hi)); 1593 1594 merge_b->notify_func(merge_b->notify_baton, 1595 notify, scratch_pool); 1596 } 1597 1598 db->pending_deletes = NULL; 1599 } 1600 return SVN_NO_ERROR; 1601} 1602 1603/* Helper function for the merge_dir_*() and merge_file_*() functions. 1604 1605 Installs and notifies pre-recorded tree conflicts and skips for 1606 ancestors of operational merges 1607 */ 1608static svn_error_t * 1609mark_dir_edited(merge_cmd_baton_t *merge_b, 1610 struct merge_dir_baton_t *db, 1611 const char *local_abspath, 1612 apr_pool_t *scratch_pool) 1613{ 1614 /* ### Too much common code with mark_file_edited */ 1615 if (db->edited) 1616 return SVN_NO_ERROR; 1617 1618 if (db->parent_baton && !db->parent_baton->edited) 1619 { 1620 const char *dir_abspath = svn_dirent_dirname(local_abspath, 1621 scratch_pool); 1622 1623 SVN_ERR(mark_dir_edited(merge_b, db->parent_baton, dir_abspath, 1624 scratch_pool)); 1625 } 1626 1627 db->edited = TRUE; 1628 1629 if (! db->shadowed) 1630 return SVN_NO_ERROR; /* Easy out */ 1631 1632 if (db->parent_baton 1633 && db->parent_baton->delete_state 1634 && db->tree_conflict_reason != CONFLICT_REASON_NONE) 1635 { 1636 db->parent_baton->delete_state->found_edit = TRUE; 1637 } 1638 else if (db->tree_conflict_reason == CONFLICT_REASON_SKIP 1639 || db->tree_conflict_reason == CONFLICT_REASON_SKIP_WC) 1640 { 1641 /* open_directory() decided not to flag a tree conflict, but 1642 for clarity we produce a skip for this node that 1643 most likely isn't touched by the merge itself */ 1644 1645 if (merge_b->notify_func) 1646 { 1647 svn_wc_notify_t *notify; 1648 1649 notify = svn_wc_create_notify( 1650 local_abspath, 1651 (db->tree_conflict_reason == CONFLICT_REASON_SKIP) 1652 ? svn_wc_notify_skip 1653 : svn_wc_notify_update_skip_obstruction, 1654 scratch_pool); 1655 notify->kind = svn_node_dir; 1656 notify->content_state = notify->prop_state = db->skip_reason; 1657 1658 merge_b->notify_func(merge_b->notify_baton, 1659 notify, 1660 scratch_pool); 1661 } 1662 1663 if (merge_b->merge_source.ancestral 1664 || merge_b->reintegrate_merge) 1665 { 1666 store_path(merge_b->skipped_abspaths, local_abspath); 1667 } 1668 } 1669 else if (db->tree_conflict_reason != CONFLICT_REASON_NONE) 1670 { 1671 /* open_directory() decided that a tree conflict should be raised */ 1672 1673 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton, 1674 db->tree_conflict_local_node_kind, 1675 db->tree_conflict_merge_left_node_kind, 1676 db->tree_conflict_merge_right_node_kind, 1677 db->tree_conflict_action, 1678 db->tree_conflict_reason, 1679 NULL, TRUE, 1680 scratch_pool)); 1681 } 1682 1683 return SVN_NO_ERROR; 1684} 1685 1686/* Helper function for the merge_file_*() functions. 1687 1688 Installs and notifies pre-recorded tree conflicts and skips for 1689 ancestors of operational merges 1690 */ 1691static svn_error_t * 1692mark_file_edited(merge_cmd_baton_t *merge_b, 1693 struct merge_file_baton_t *fb, 1694 const char *local_abspath, 1695 apr_pool_t *scratch_pool) 1696{ 1697 /* ### Too much common code with mark_dir_edited */ 1698 if (fb->edited) 1699 return SVN_NO_ERROR; 1700 1701 if (fb->parent_baton && !fb->parent_baton->edited) 1702 { 1703 const char *dir_abspath = svn_dirent_dirname(local_abspath, 1704 scratch_pool); 1705 1706 SVN_ERR(mark_dir_edited(merge_b, fb->parent_baton, dir_abspath, 1707 scratch_pool)); 1708 } 1709 1710 fb->edited = TRUE; 1711 1712 if (! fb->shadowed) 1713 return SVN_NO_ERROR; /* Easy out */ 1714 1715 if (fb->parent_baton 1716 && fb->parent_baton->delete_state 1717 && fb->tree_conflict_reason != CONFLICT_REASON_NONE) 1718 { 1719 fb->parent_baton->delete_state->found_edit = TRUE; 1720 } 1721 else if (fb->tree_conflict_reason == CONFLICT_REASON_SKIP 1722 || fb->tree_conflict_reason == CONFLICT_REASON_SKIP_WC) 1723 { 1724 /* open_directory() decided not to flag a tree conflict, but 1725 for clarity we produce a skip for this node that 1726 most likely isn't touched by the merge itself */ 1727 1728 if (merge_b->notify_func) 1729 { 1730 svn_wc_notify_t *notify; 1731 1732 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip, 1733 scratch_pool); 1734 notify->kind = svn_node_file; 1735 notify->content_state = notify->prop_state = fb->skip_reason; 1736 1737 merge_b->notify_func(merge_b->notify_baton, 1738 notify, 1739 scratch_pool); 1740 } 1741 1742 if (merge_b->merge_source.ancestral 1743 || merge_b->reintegrate_merge) 1744 { 1745 store_path(merge_b->skipped_abspaths, local_abspath); 1746 } 1747 } 1748 else if (fb->tree_conflict_reason != CONFLICT_REASON_NONE) 1749 { 1750 /* open_file() decided that a tree conflict should be raised */ 1751 1752 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton, 1753 fb->tree_conflict_local_node_kind, 1754 fb->tree_conflict_merge_left_node_kind, 1755 fb->tree_conflict_merge_right_node_kind, 1756 fb->tree_conflict_action, 1757 fb->tree_conflict_reason, 1758 NULL, TRUE, 1759 scratch_pool)); 1760 } 1761 1762 return SVN_NO_ERROR; 1763} 1764 1765/* An svn_diff_tree_processor_t function. 1766 1767 Called before either merge_file_changed(), merge_file_added(), 1768 merge_file_deleted() or merge_file_closed(), unless it sets *SKIP to TRUE. 1769 1770 When *SKIP is TRUE, the diff driver avoids work on getting the details 1771 for the closing callbacks. 1772 */ 1773static svn_error_t * 1774merge_file_opened(void **new_file_baton, 1775 svn_boolean_t *skip, 1776 const char *relpath, 1777 const svn_diff_source_t *left_source, 1778 const svn_diff_source_t *right_source, 1779 const svn_diff_source_t *copyfrom_source, 1780 void *dir_baton, 1781 const struct svn_diff_tree_processor_t *processor, 1782 apr_pool_t *result_pool, 1783 apr_pool_t *scratch_pool) 1784{ 1785 merge_cmd_baton_t *merge_b = processor->baton; 1786 struct merge_dir_baton_t *pdb = dir_baton; 1787 struct merge_file_baton_t *fb; 1788 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 1789 relpath, scratch_pool); 1790 1791 fb = apr_pcalloc(result_pool, sizeof(*fb)); 1792 fb->tree_conflict_reason = CONFLICT_REASON_NONE; 1793 fb->tree_conflict_action = svn_wc_conflict_action_edit; 1794 fb->skip_reason = svn_wc_notify_state_unknown; 1795 1796 if (left_source) 1797 fb->tree_conflict_merge_left_node_kind = svn_node_file; 1798 else 1799 fb->tree_conflict_merge_left_node_kind = svn_node_none; 1800 1801 if (right_source) 1802 fb->tree_conflict_merge_right_node_kind = svn_node_file; 1803 else 1804 fb->tree_conflict_merge_right_node_kind = svn_node_none; 1805 1806 *new_file_baton = fb; 1807 1808 if (pdb) 1809 { 1810 fb->parent_baton = pdb; 1811 fb->shadowed = pdb->shadowed; 1812 fb->skip_reason = pdb->skip_reason; 1813 } 1814 1815 if (fb->shadowed) 1816 { 1817 /* An ancestor is tree conflicted. Nothing to do here. */ 1818 } 1819 else if (left_source != NULL) 1820 { 1821 /* Node is expected to be a file, which will be changed or deleted. */ 1822 svn_boolean_t is_deleted; 1823 svn_boolean_t excluded; 1824 svn_depth_t parent_depth; 1825 1826 if (! right_source) 1827 fb->tree_conflict_action = svn_wc_conflict_action_delete; 1828 1829 { 1830 svn_wc_notify_state_t obstr_state; 1831 1832 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded, 1833 &fb->tree_conflict_local_node_kind, 1834 &parent_depth, 1835 merge_b, local_abspath, 1836 scratch_pool)); 1837 1838 if (obstr_state != svn_wc_notify_state_inapplicable) 1839 { 1840 fb->shadowed = TRUE; 1841 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1842 fb->skip_reason = obstr_state; 1843 return SVN_NO_ERROR; 1844 } 1845 1846 if (is_deleted) 1847 fb->tree_conflict_local_node_kind = svn_node_none; 1848 } 1849 1850 if (fb->tree_conflict_local_node_kind == svn_node_none) 1851 { 1852 fb->shadowed = TRUE; 1853 1854 /* If this is not the merge target and the parent is too shallow to 1855 contain this directory, and the directory is not present 1856 via exclusion or depth filtering, skip it instead of recording 1857 a tree conflict. 1858 1859 Non-inheritable mergeinfo will be recorded, allowing 1860 future merges into non-shallow working copies to merge 1861 changes we missed this time around. */ 1862 if (pdb && (excluded 1863 || (parent_depth != svn_depth_unknown && 1864 parent_depth < svn_depth_files))) 1865 { 1866 fb->shadowed = TRUE; 1867 1868 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1869 fb->skip_reason = svn_wc_notify_state_missing; 1870 return SVN_NO_ERROR; 1871 } 1872 1873 if (is_deleted) 1874 fb->tree_conflict_reason = svn_wc_conflict_reason_deleted; 1875 else 1876 fb->tree_conflict_reason = svn_wc_conflict_reason_missing; 1877 1878 /* ### Similar to directory */ 1879 *skip = TRUE; 1880 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1881 return SVN_NO_ERROR; 1882 /* ### /Similar */ 1883 } 1884 else if (fb->tree_conflict_local_node_kind != svn_node_file) 1885 { 1886 svn_boolean_t added; 1887 fb->shadowed = TRUE; 1888 1889 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx, 1890 local_abspath, scratch_pool)); 1891 1892 fb->tree_conflict_reason = added ? svn_wc_conflict_reason_added 1893 : svn_wc_conflict_reason_obstructed; 1894 1895 /* ### Similar to directory */ 1896 *skip = TRUE; 1897 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1898 return SVN_NO_ERROR; 1899 /* ### /Similar */ 1900 } 1901 1902 if (! right_source) 1903 { 1904 /* We want to delete the directory */ 1905 fb->tree_conflict_action = svn_wc_conflict_action_delete; 1906 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1907 1908 if (fb->shadowed) 1909 { 1910 return SVN_NO_ERROR; /* Already set a tree conflict */ 1911 } 1912 1913 /* Comparison mode to verify for delete tree conflicts? */ 1914 if (pdb && pdb->delete_state 1915 && pdb->delete_state->found_edit) 1916 { 1917 /* Earlier nodes found a conflict. Done. */ 1918 *skip = TRUE; 1919 } 1920 } 1921 } 1922 else 1923 { 1924 const svn_wc_conflict_description2_t *old_tc = NULL; 1925 1926 /* The node doesn't exist pre-merge: We have an addition */ 1927 fb->added = TRUE; 1928 fb->tree_conflict_action = svn_wc_conflict_action_add; 1929 1930 if (pdb && pdb->pending_deletes 1931 && svn_hash_gets(pdb->pending_deletes, local_abspath)) 1932 { 1933 fb->add_is_replace = TRUE; 1934 fb->tree_conflict_action = svn_wc_conflict_action_replace; 1935 1936 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL); 1937 } 1938 1939 if (pdb 1940 && pdb->new_tree_conflicts 1941 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath))) 1942 { 1943 fb->tree_conflict_action = svn_wc_conflict_action_replace; 1944 fb->tree_conflict_reason = old_tc->reason; 1945 1946 /* Update the tree conflict to store that this is a replace */ 1947 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 1948 old_tc->node_kind, 1949 old_tc->src_left_version->node_kind, 1950 svn_node_file, 1951 fb->tree_conflict_action, 1952 fb->tree_conflict_reason, 1953 old_tc, FALSE, 1954 scratch_pool)); 1955 1956 if (old_tc->reason == svn_wc_conflict_reason_deleted 1957 || old_tc->reason == svn_wc_conflict_reason_moved_away) 1958 { 1959 /* Issue #3806: Incoming replacements on local deletes produce 1960 inconsistent result. 1961 1962 In this specific case we can continue applying the add part 1963 of the replacement. */ 1964 } 1965 else 1966 { 1967 *skip = TRUE; 1968 1969 return SVN_NO_ERROR; 1970 } 1971 } 1972 else if (! (merge_b->dry_run 1973 && ((pdb && pdb->added) || fb->add_is_replace))) 1974 { 1975 svn_wc_notify_state_t obstr_state; 1976 svn_boolean_t is_deleted; 1977 1978 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL, 1979 &fb->tree_conflict_local_node_kind, 1980 NULL, merge_b, local_abspath, 1981 scratch_pool)); 1982 1983 if (obstr_state != svn_wc_notify_state_inapplicable) 1984 { 1985 /* Skip the obstruction */ 1986 fb->shadowed = TRUE; 1987 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1988 fb->skip_reason = obstr_state; 1989 } 1990 else if (fb->tree_conflict_local_node_kind != svn_node_none 1991 && !is_deleted) 1992 { 1993 /* Set a tree conflict */ 1994 svn_boolean_t added; 1995 1996 fb->shadowed = TRUE; 1997 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx, 1998 local_abspath, scratch_pool)); 1999 2000 fb->tree_conflict_reason = added ? svn_wc_conflict_reason_added 2001 : svn_wc_conflict_reason_obstructed; 2002 } 2003 } 2004 2005 /* Handle pending conflicts */ 2006 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2007 } 2008 2009 return SVN_NO_ERROR; 2010} 2011 2012/* An svn_diff_tree_processor_t function. 2013 * 2014 * Called after merge_file_opened() when a node receives only text and/or 2015 * property changes between LEFT_SOURCE and RIGHT_SOURCE. 2016 * 2017 * left_file and right_file can be NULL when the file is not modified. 2018 * left_props and right_props are always available. 2019 */ 2020static svn_error_t * 2021merge_file_changed(const char *relpath, 2022 const svn_diff_source_t *left_source, 2023 const svn_diff_source_t *right_source, 2024 const char *left_file, 2025 const char *right_file, 2026 /*const*/ apr_hash_t *left_props, 2027 /*const*/ apr_hash_t *right_props, 2028 svn_boolean_t file_modified, 2029 const apr_array_header_t *prop_changes, 2030 void *file_baton, 2031 const struct svn_diff_tree_processor_t *processor, 2032 apr_pool_t *scratch_pool) 2033{ 2034 merge_cmd_baton_t *merge_b = processor->baton; 2035 struct merge_file_baton_t *fb = file_baton; 2036 svn_client_ctx_t *ctx = merge_b->ctx; 2037 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2038 relpath, scratch_pool); 2039 const svn_wc_conflict_version_t *left; 2040 const svn_wc_conflict_version_t *right; 2041 svn_wc_notify_state_t text_state; 2042 svn_wc_notify_state_t property_state; 2043 2044 SVN_ERR_ASSERT(local_abspath && svn_dirent_is_absolute(local_abspath)); 2045 SVN_ERR_ASSERT(!left_file || svn_dirent_is_absolute(left_file)); 2046 SVN_ERR_ASSERT(!right_file || svn_dirent_is_absolute(right_file)); 2047 2048 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2049 2050 if (fb->shadowed) 2051 { 2052 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 2053 { 2054 /* We haven't notified for this node yet: report a skip */ 2055 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 2056 svn_wc_notify_update_shadowed_update, 2057 fb->skip_reason, fb->parent_baton, 2058 scratch_pool)); 2059 } 2060 2061 return SVN_NO_ERROR; 2062 } 2063 2064 /* This callback is essentially no more than a wrapper around 2065 svn_wc_merge5(). Thank goodness that all the 2066 diff-editor-mechanisms are doing the hard work of getting the 2067 fulltexts! */ 2068 2069 property_state = svn_wc_notify_state_unchanged; 2070 text_state = svn_wc_notify_state_unchanged; 2071 2072 SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath, 2073 prop_changes, merge_b, 2074 scratch_pool, scratch_pool)); 2075 2076 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 2077 svn_node_file, svn_node_file, 2078 &merge_b->merge_source, merge_b->target, 2079 scratch_pool, scratch_pool)); 2080 2081 /* Do property merge now, if we are not going to perform a text merge */ 2082 if ((merge_b->record_only || !left_file) && prop_changes->nelts) 2083 { 2084 SVN_ERR(svn_wc_merge_props3(&property_state, ctx->wc_ctx, local_abspath, 2085 left, right, 2086 left_props, prop_changes, 2087 merge_b->dry_run, 2088 NULL, NULL, 2089 ctx->cancel_func, ctx->cancel_baton, 2090 scratch_pool)); 2091 if (property_state == svn_wc_notify_state_conflicted) 2092 { 2093 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 2094 merge_b->pool); 2095 } 2096 } 2097 2098 /* Easy out: We are only applying mergeinfo differences. */ 2099 if (merge_b->record_only) 2100 { 2101 /* NO-OP */ 2102 } 2103 else if (left_file) 2104 { 2105 svn_boolean_t has_local_mods; 2106 enum svn_wc_merge_outcome_t content_outcome; 2107 const char *target_label; 2108 const char *left_label; 2109 const char *right_label; 2110 const char *path_ext = ""; 2111 2112 if (merge_b->ext_patterns && merge_b->ext_patterns->nelts) 2113 { 2114 svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool); 2115 if (! (*path_ext 2116 && svn_cstring_match_glob_list(path_ext, 2117 merge_b->ext_patterns))) 2118 { 2119 path_ext = ""; 2120 } 2121 } 2122 2123 /* xgettext: the '.working', '.merge-left.r%ld' and 2124 '.merge-right.r%ld' strings are used to tag onto a file 2125 name in case of a merge conflict */ 2126 2127 target_label = apr_psprintf(scratch_pool, _(".working%s%s"), 2128 *path_ext ? "." : "", path_ext); 2129 left_label = apr_psprintf(scratch_pool, 2130 _(".merge-left.r%ld%s%s"), 2131 left_source->revision, 2132 *path_ext ? "." : "", path_ext); 2133 right_label = apr_psprintf(scratch_pool, 2134 _(".merge-right.r%ld%s%s"), 2135 right_source->revision, 2136 *path_ext ? "." : "", path_ext); 2137 2138 SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx, 2139 local_abspath, FALSE, scratch_pool)); 2140 2141 /* Do property merge and text merge in one step so that keyword expansion 2142 takes into account the new property values. */ 2143 SVN_ERR(svn_wc_merge5(&content_outcome, &property_state, ctx->wc_ctx, 2144 left_file, right_file, local_abspath, 2145 left_label, right_label, target_label, 2146 left, right, 2147 merge_b->dry_run, merge_b->diff3_cmd, 2148 merge_b->merge_options, 2149 left_props, prop_changes, 2150 NULL, NULL, 2151 ctx->cancel_func, 2152 ctx->cancel_baton, 2153 scratch_pool)); 2154 2155 if (content_outcome == svn_wc_merge_conflict 2156 || property_state == svn_wc_notify_state_conflicted) 2157 { 2158 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 2159 merge_b->pool); 2160 } 2161 2162 if (content_outcome == svn_wc_merge_conflict) 2163 text_state = svn_wc_notify_state_conflicted; 2164 else if (has_local_mods 2165 && content_outcome != svn_wc_merge_unchanged) 2166 text_state = svn_wc_notify_state_merged; 2167 else if (content_outcome == svn_wc_merge_merged) 2168 text_state = svn_wc_notify_state_changed; 2169 else if (content_outcome == svn_wc_merge_no_merge) 2170 text_state = svn_wc_notify_state_missing; 2171 else /* merge_outcome == svn_wc_merge_unchanged */ 2172 text_state = svn_wc_notify_state_unchanged; 2173 } 2174 2175 if (text_state == svn_wc_notify_state_conflicted 2176 || text_state == svn_wc_notify_state_merged 2177 || text_state == svn_wc_notify_state_changed 2178 || property_state == svn_wc_notify_state_conflicted 2179 || property_state == svn_wc_notify_state_merged 2180 || property_state == svn_wc_notify_state_changed) 2181 { 2182 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file, 2183 text_state, property_state, 2184 scratch_pool)); 2185 } 2186 2187 return SVN_NO_ERROR; 2188} 2189 2190/* An svn_diff_tree_processor_t function. 2191 * 2192 * Called after merge_file_opened() when a node doesn't exist in LEFT_SOURCE, 2193 * but does in RIGHT_SOURCE. 2194 * 2195 * When a node is replaced instead of just added a separate opened+deleted will 2196 * be invoked before the current open+added. 2197 */ 2198static svn_error_t * 2199merge_file_added(const char *relpath, 2200 const svn_diff_source_t *copyfrom_source, 2201 const svn_diff_source_t *right_source, 2202 const char *copyfrom_file, 2203 const char *right_file, 2204 /*const*/ apr_hash_t *copyfrom_props, 2205 /*const*/ apr_hash_t *right_props, 2206 void *file_baton, 2207 const struct svn_diff_tree_processor_t *processor, 2208 apr_pool_t *scratch_pool) 2209{ 2210 merge_cmd_baton_t *merge_b = processor->baton; 2211 struct merge_file_baton_t *fb = file_baton; 2212 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2213 relpath, scratch_pool); 2214 apr_hash_t *pristine_props; 2215 apr_hash_t *new_props; 2216 2217 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 2218 2219 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2220 2221 if (fb->shadowed) 2222 { 2223 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 2224 { 2225 /* We haven't notified for this node yet: report a skip */ 2226 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 2227 svn_wc_notify_update_shadowed_add, 2228 fb->skip_reason, fb->parent_baton, 2229 scratch_pool)); 2230 } 2231 2232 return SVN_NO_ERROR; 2233 } 2234 2235 /* Easy out: We are only applying mergeinfo differences. */ 2236 if (merge_b->record_only) 2237 { 2238 return SVN_NO_ERROR; 2239 } 2240 2241 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 2242 && ( !fb->parent_baton || !fb->parent_baton->added)) 2243 { 2244 /* Store the roots of added subtrees */ 2245 store_path(merge_b->added_abspaths, local_abspath); 2246 } 2247 2248 if (!merge_b->dry_run) 2249 { 2250 const char *copyfrom_url; 2251 svn_revnum_t copyfrom_rev; 2252 svn_stream_t *new_contents, *pristine_contents; 2253 2254 /* If this is a merge from the same repository as our 2255 working copy, we handle adds as add-with-history. 2256 Otherwise, we'll use a pure add. */ 2257 if (merge_b->same_repos) 2258 { 2259 copyfrom_url = svn_path_url_add_component2( 2260 merge_b->merge_source.loc2->url, 2261 relpath, scratch_pool); 2262 copyfrom_rev = right_source->revision; 2263 SVN_ERR(check_repos_match(merge_b->target, local_abspath, 2264 copyfrom_url, scratch_pool)); 2265 SVN_ERR(svn_stream_open_readonly(&pristine_contents, 2266 right_file, 2267 scratch_pool, 2268 scratch_pool)); 2269 new_contents = NULL; /* inherit from new_base_contents */ 2270 2271 pristine_props = right_props; /* Includes last_* information */ 2272 new_props = NULL; /* No local changes */ 2273 2274 if (svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO)) 2275 { 2276 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 2277 local_abspath, merge_b->pool); 2278 } 2279 } 2280 else 2281 { 2282 apr_array_header_t *regular_props; 2283 2284 copyfrom_url = NULL; 2285 copyfrom_rev = SVN_INVALID_REVNUM; 2286 2287 pristine_contents = svn_stream_empty(scratch_pool); 2288 SVN_ERR(svn_stream_open_readonly(&new_contents, right_file, 2289 scratch_pool, scratch_pool)); 2290 2291 pristine_props = apr_hash_make(scratch_pool); /* Local addition */ 2292 2293 /* We don't want any foreign properties */ 2294 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props, 2295 scratch_pool), 2296 NULL, NULL, ®ular_props, 2297 scratch_pool)); 2298 2299 new_props = svn_prop_array_to_hash(regular_props, scratch_pool); 2300 2301 /* Issue #3383: We don't want mergeinfo from a foreign repository. */ 2302 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL); 2303 } 2304 2305 /* Do everything like if we had called 'svn cp PATH1 PATH2'. */ 2306 SVN_ERR(svn_wc_add_repos_file4(merge_b->ctx->wc_ctx, 2307 local_abspath, 2308 pristine_contents, 2309 new_contents, 2310 pristine_props, new_props, 2311 copyfrom_url, copyfrom_rev, 2312 merge_b->ctx->cancel_func, 2313 merge_b->ctx->cancel_baton, 2314 scratch_pool)); 2315 2316 /* Caller must call svn_sleep_for_timestamps() */ 2317 *merge_b->use_sleep = TRUE; 2318 } 2319 2320 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_file, 2321 fb->add_is_replace, scratch_pool)); 2322 2323 return SVN_NO_ERROR; 2324} 2325 2326/* Compare the two sets of properties PROPS1 and PROPS2, ignoring the 2327 * "svn:mergeinfo" property, and noticing only "normal" props. Set *SAME to 2328 * true if the rest of the properties are identical or false if they differ. 2329 */ 2330static svn_error_t * 2331properties_same_p(svn_boolean_t *same, 2332 apr_hash_t *props1, 2333 apr_hash_t *props2, 2334 apr_pool_t *scratch_pool) 2335{ 2336 apr_array_header_t *prop_changes; 2337 int i, diffs; 2338 2339 /* Examine the properties that differ */ 2340 SVN_ERR(svn_prop_diffs(&prop_changes, props1, props2, scratch_pool)); 2341 diffs = 0; 2342 for (i = 0; i < prop_changes->nelts; i++) 2343 { 2344 const char *pname = APR_ARRAY_IDX(prop_changes, i, svn_prop_t).name; 2345 2346 /* Count the properties we're interested in; ignore the rest */ 2347 if (svn_wc_is_normal_prop(pname) 2348 && strcmp(pname, SVN_PROP_MERGEINFO) != 0) 2349 diffs++; 2350 } 2351 *same = (diffs == 0); 2352 return SVN_NO_ERROR; 2353} 2354 2355/* Compare the file OLDER_ABSPATH (together with its normal properties in 2356 * ORIGINAL_PROPS which may also contain WC props and entry props) with the 2357 * versioned file MINE_ABSPATH (together with its versioned properties). 2358 * Set *SAME to true if they are the same or false if they differ, ignoring 2359 * the "svn:mergeinfo" property, and ignoring differences in keyword 2360 * expansion and end-of-line style. */ 2361static svn_error_t * 2362files_same_p(svn_boolean_t *same, 2363 const char *older_abspath, 2364 apr_hash_t *original_props, 2365 const char *mine_abspath, 2366 svn_wc_context_t *wc_ctx, 2367 apr_pool_t *scratch_pool) 2368{ 2369 apr_hash_t *working_props; 2370 2371 SVN_ERR(svn_wc_prop_list2(&working_props, wc_ctx, mine_abspath, 2372 scratch_pool, scratch_pool)); 2373 2374 /* Compare the properties */ 2375 SVN_ERR(properties_same_p(same, original_props, working_props, 2376 scratch_pool)); 2377 if (*same) 2378 { 2379 svn_stream_t *mine_stream; 2380 svn_stream_t *older_stream; 2381 svn_string_t *special = svn_hash_gets(working_props, SVN_PROP_SPECIAL); 2382 svn_string_t *eol_style = svn_hash_gets(working_props, SVN_PROP_EOL_STYLE); 2383 svn_string_t *keywords = svn_hash_gets(working_props, SVN_PROP_KEYWORDS); 2384 2385 /* Compare the file content, translating 'mine' to 'normal' form. */ 2386 if (special != NULL) 2387 SVN_ERR(svn_subst_read_specialfile(&mine_stream, mine_abspath, 2388 scratch_pool, scratch_pool)); 2389 else 2390 SVN_ERR(svn_stream_open_readonly(&mine_stream, mine_abspath, 2391 scratch_pool, scratch_pool)); 2392 2393 if (!special && (eol_style || keywords)) 2394 { 2395 apr_hash_t *kw = NULL; 2396 const char *eol = NULL; 2397 svn_subst_eol_style_t style; 2398 2399 /* We used to use svn_client__get_normalized_stream() here, but 2400 that doesn't work in 100% of the cases because it doesn't 2401 convert EOLs to the repository form; just to '\n'. 2402 */ 2403 2404 if (eol_style) 2405 { 2406 svn_subst_eol_style_from_value(&style, &eol, eol_style->data); 2407 2408 if (style == svn_subst_eol_style_native) 2409 eol = SVN_SUBST_NATIVE_EOL_STR; 2410 else if (style != svn_subst_eol_style_fixed 2411 && style != svn_subst_eol_style_none) 2412 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL); 2413 } 2414 2415 if (keywords) 2416 SVN_ERR(svn_subst_build_keywords3(&kw, keywords->data, "", "", 2417 "", 0, "", scratch_pool)); 2418 2419 mine_stream = svn_subst_stream_translated( 2420 mine_stream, eol, FALSE, kw, FALSE, scratch_pool); 2421 } 2422 2423 SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath, 2424 scratch_pool, scratch_pool)); 2425 2426 SVN_ERR(svn_stream_contents_same2(same, mine_stream, older_stream, 2427 scratch_pool)); 2428 2429 } 2430 2431 return SVN_NO_ERROR; 2432} 2433 2434/* An svn_diff_tree_processor_t function. 2435 * 2436 * Called after merge_file_opened() when a node does exist in LEFT_SOURCE, but 2437 * no longer exists (or is replaced) in RIGHT_SOURCE. 2438 * 2439 * When a node is replaced instead of just added a separate opened+added will 2440 * be invoked after the current open+deleted. 2441 */ 2442static svn_error_t * 2443merge_file_deleted(const char *relpath, 2444 const svn_diff_source_t *left_source, 2445 const char *left_file, 2446 /*const*/ apr_hash_t *left_props, 2447 void *file_baton, 2448 const struct svn_diff_tree_processor_t *processor, 2449 apr_pool_t *scratch_pool) 2450{ 2451 merge_cmd_baton_t *merge_b = processor->baton; 2452 struct merge_file_baton_t *fb = file_baton; 2453 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2454 relpath, scratch_pool); 2455 svn_boolean_t same; 2456 2457 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2458 2459 if (fb->shadowed) 2460 { 2461 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 2462 { 2463 /* We haven't notified for this node yet: report a skip */ 2464 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 2465 svn_wc_notify_update_shadowed_delete, 2466 fb->skip_reason, fb->parent_baton, 2467 scratch_pool)); 2468 } 2469 2470 return SVN_NO_ERROR; 2471 } 2472 2473 /* Easy out: We are only applying mergeinfo differences. */ 2474 if (merge_b->record_only) 2475 { 2476 return SVN_NO_ERROR; 2477 } 2478 2479 /* If the files are identical, attempt deletion */ 2480 if (merge_b->force_delete) 2481 same = TRUE; 2482 else 2483 SVN_ERR(files_same_p(&same, left_file, left_props, 2484 local_abspath, merge_b->ctx->wc_ctx, 2485 scratch_pool)); 2486 2487 if (fb->parent_baton 2488 && fb->parent_baton->delete_state) 2489 { 2490 if (same) 2491 { 2492 /* Note that we checked this file */ 2493 store_path(fb->parent_baton->delete_state->compared_abspaths, 2494 local_abspath); 2495 } 2496 else 2497 { 2498 /* We found some modification. Parent should raise a tree conflict */ 2499 fb->parent_baton->delete_state->found_edit = TRUE; 2500 } 2501 2502 return SVN_NO_ERROR; 2503 } 2504 else if (same) 2505 { 2506 if (!merge_b->dry_run) 2507 SVN_ERR(svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath, 2508 FALSE /* keep_local */, FALSE /* unversioned */, 2509 merge_b->ctx->cancel_func, 2510 merge_b->ctx->cancel_baton, 2511 NULL, NULL /* no notify */, 2512 scratch_pool)); 2513 2514 /* Record that we might have deleted mergeinfo */ 2515 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 2516 local_abspath, merge_b->pool); 2517 2518 /* And notify the deletion */ 2519 SVN_ERR(record_update_delete(merge_b, fb->parent_baton, local_abspath, 2520 svn_node_file, scratch_pool)); 2521 } 2522 else 2523 { 2524 /* The files differ, so raise a conflict instead of deleting */ 2525 2526 /* This is use case 5 described in the paper attached to issue 2527 * #2282. See also notes/tree-conflicts/detection.txt 2528 */ 2529 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton, 2530 svn_node_file, 2531 svn_node_file, 2532 svn_node_none, 2533 svn_wc_conflict_action_delete, 2534 svn_wc_conflict_reason_edited, 2535 NULL, TRUE, 2536 scratch_pool)); 2537 } 2538 2539 return SVN_NO_ERROR; 2540} 2541 2542/* An svn_diff_tree_processor_t function. 2543 2544 Called before either merge_dir_changed(), merge_dir_added(), 2545 merge_dir_deleted() or merge_dir_closed(), unless it sets *SKIP to TRUE. 2546 2547 After this call and before the close call, all descendants will receive 2548 their changes, unless *SKIP_CHILDREN is set to TRUE. 2549 2550 When *SKIP is TRUE, the diff driver avoids work on getting the details 2551 for the closing callbacks. 2552 2553 The SKIP and SKIP_DESCENDANTS work independently. 2554 */ 2555static svn_error_t * 2556merge_dir_opened(void **new_dir_baton, 2557 svn_boolean_t *skip, 2558 svn_boolean_t *skip_children, 2559 const char *relpath, 2560 const svn_diff_source_t *left_source, 2561 const svn_diff_source_t *right_source, 2562 const svn_diff_source_t *copyfrom_source, 2563 void *parent_dir_baton, 2564 const struct svn_diff_tree_processor_t *processor, 2565 apr_pool_t *result_pool, 2566 apr_pool_t *scratch_pool) 2567{ 2568 merge_cmd_baton_t *merge_b = processor->baton; 2569 struct merge_dir_baton_t *db; 2570 struct merge_dir_baton_t *pdb = parent_dir_baton; 2571 2572 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2573 relpath, scratch_pool); 2574 2575 db = apr_pcalloc(result_pool, sizeof(*db)); 2576 db->pool = result_pool; 2577 db->tree_conflict_reason = CONFLICT_REASON_NONE; 2578 db->tree_conflict_action = svn_wc_conflict_action_edit; 2579 db->skip_reason = svn_wc_notify_state_unknown; 2580 2581 *new_dir_baton = db; 2582 2583 if (left_source) 2584 db->tree_conflict_merge_left_node_kind = svn_node_dir; 2585 else 2586 db->tree_conflict_merge_left_node_kind = svn_node_none; 2587 2588 if (right_source) 2589 db->tree_conflict_merge_right_node_kind = svn_node_dir; 2590 else 2591 db->tree_conflict_merge_right_node_kind = svn_node_none; 2592 2593 if (pdb) 2594 { 2595 db->parent_baton = pdb; 2596 db->shadowed = pdb->shadowed; 2597 db->skip_reason = pdb->skip_reason; 2598 } 2599 2600 if (db->shadowed) 2601 { 2602 /* An ancestor is tree conflicted. Nothing to do here. */ 2603 if (! left_source) 2604 db->added = TRUE; 2605 } 2606 else if (left_source != NULL) 2607 { 2608 /* Node is expected to be a directory. */ 2609 svn_boolean_t is_deleted; 2610 svn_boolean_t excluded; 2611 svn_depth_t parent_depth; 2612 2613 if (! right_source) 2614 db->tree_conflict_action = svn_wc_conflict_action_delete; 2615 2616 /* Check for an obstructed or missing node on disk. */ 2617 { 2618 svn_wc_notify_state_t obstr_state; 2619 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded, 2620 &db->tree_conflict_local_node_kind, 2621 &parent_depth, merge_b, 2622 local_abspath, scratch_pool)); 2623 2624 if (obstr_state != svn_wc_notify_state_inapplicable) 2625 { 2626 db->shadowed = TRUE; 2627 2628 if (obstr_state == svn_wc_notify_state_obstructed) 2629 { 2630 svn_boolean_t is_wcroot; 2631 2632 SVN_ERR(svn_wc_check_root(&is_wcroot, NULL, NULL, 2633 merge_b->ctx->wc_ctx, 2634 local_abspath, scratch_pool)); 2635 2636 if (is_wcroot) 2637 { 2638 db->tree_conflict_reason = CONFLICT_REASON_SKIP_WC; 2639 return SVN_NO_ERROR; 2640 } 2641 } 2642 2643 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2644 db->skip_reason = obstr_state; 2645 2646 if (! right_source) 2647 { 2648 *skip = *skip_children = TRUE; 2649 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, 2650 scratch_pool)); 2651 } 2652 2653 return SVN_NO_ERROR; 2654 } 2655 2656 if (is_deleted) 2657 db->tree_conflict_local_node_kind = svn_node_none; 2658 } 2659 2660 if (db->tree_conflict_local_node_kind == svn_node_none) 2661 { 2662 db->shadowed = TRUE; 2663 2664 /* If this is not the merge target and the parent is too shallow to 2665 contain this directory, and the directory is not presen 2666 via exclusion or depth filtering, skip it instead of recording 2667 a tree conflict. 2668 2669 Non-inheritable mergeinfo will be recorded, allowing 2670 future merges into non-shallow working copies to merge 2671 changes we missed this time around. */ 2672 if (pdb && (excluded 2673 || (parent_depth != svn_depth_unknown && 2674 parent_depth < svn_depth_immediates))) 2675 { 2676 db->shadowed = TRUE; 2677 2678 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2679 db->skip_reason = svn_wc_notify_state_missing; 2680 2681 return SVN_NO_ERROR; 2682 } 2683 2684 if (is_deleted) 2685 db->tree_conflict_reason = svn_wc_conflict_reason_deleted; 2686 else 2687 db->tree_conflict_reason = svn_wc_conflict_reason_missing; 2688 2689 /* ### To avoid breaking tests */ 2690 *skip = TRUE; 2691 *skip_children = TRUE; 2692 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2693 return SVN_NO_ERROR; 2694 /* ### /avoid breaking tests */ 2695 } 2696 else if (db->tree_conflict_local_node_kind != svn_node_dir) 2697 { 2698 svn_boolean_t added; 2699 2700 db->shadowed = TRUE; 2701 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx, 2702 local_abspath, scratch_pool)); 2703 2704 db->tree_conflict_reason = added ? svn_wc_conflict_reason_added 2705 : svn_wc_conflict_reason_obstructed; 2706 2707 /* ### To avoid breaking tests */ 2708 *skip = TRUE; 2709 *skip_children = TRUE; 2710 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2711 return SVN_NO_ERROR; 2712 /* ### /avoid breaking tests */ 2713 } 2714 2715 if (! right_source) 2716 { 2717 /* We want to delete the directory */ 2718 /* Mark PB edited now? */ 2719 db->tree_conflict_action = svn_wc_conflict_action_delete; 2720 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2721 2722 if (db->shadowed) 2723 { 2724 *skip_children = TRUE; 2725 return SVN_NO_ERROR; /* Already set a tree conflict */ 2726 } 2727 2728 db->delete_state = (pdb != NULL) ? pdb->delete_state : NULL; 2729 2730 if (db->delete_state && db->delete_state->found_edit) 2731 { 2732 /* A sibling found a conflict. Done. */ 2733 *skip = TRUE; 2734 *skip_children = TRUE; 2735 } 2736 else if (merge_b->force_delete) 2737 { 2738 /* No comparison necessary */ 2739 *skip_children = TRUE; 2740 } 2741 else if (! db->delete_state) 2742 { 2743 /* Start descendant comparison */ 2744 db->delete_state = apr_pcalloc(db->pool, 2745 sizeof(*db->delete_state)); 2746 2747 db->delete_state->del_root = db; 2748 db->delete_state->compared_abspaths = apr_hash_make(db->pool); 2749 } 2750 } 2751 } 2752 else 2753 { 2754 const svn_wc_conflict_description2_t *old_tc = NULL; 2755 2756 /* The node doesn't exist pre-merge: We have an addition */ 2757 db->added = TRUE; 2758 db->tree_conflict_action = svn_wc_conflict_action_add; 2759 2760 if (pdb && pdb->pending_deletes 2761 && svn_hash_gets(pdb->pending_deletes, local_abspath)) 2762 { 2763 db->add_is_replace = TRUE; 2764 db->tree_conflict_action = svn_wc_conflict_action_replace; 2765 2766 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL); 2767 } 2768 2769 if (pdb 2770 && pdb->new_tree_conflicts 2771 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath))) 2772 { 2773 db->tree_conflict_action = svn_wc_conflict_action_replace; 2774 db->tree_conflict_reason = old_tc->reason; 2775 2776 if (old_tc->reason == svn_wc_conflict_reason_deleted 2777 || old_tc->reason == svn_wc_conflict_reason_moved_away) 2778 { 2779 /* Issue #3806: Incoming replacements on local deletes produce 2780 inconsistent result. 2781 2782 In this specific case we can continue applying the add part 2783 of the replacement. */ 2784 } 2785 else 2786 { 2787 *skip = TRUE; 2788 *skip_children = TRUE; 2789 2790 /* Update the tree conflict to store that this is a replace */ 2791 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 2792 old_tc->node_kind, 2793 old_tc->src_left_version->node_kind, 2794 svn_node_dir, 2795 db->tree_conflict_action, 2796 db->tree_conflict_reason, 2797 old_tc, FALSE, 2798 scratch_pool)); 2799 2800 return SVN_NO_ERROR; 2801 } 2802 } 2803 2804 if (! (merge_b->dry_run 2805 && ((pdb && pdb->added) || db->add_is_replace))) 2806 { 2807 svn_wc_notify_state_t obstr_state; 2808 svn_boolean_t is_deleted; 2809 2810 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL, 2811 &db->tree_conflict_local_node_kind, 2812 NULL, merge_b, local_abspath, 2813 scratch_pool)); 2814 2815 /* In this case of adding a directory, we have an exception to the 2816 * usual "skip if it's inconsistent" rule. If the directory exists 2817 * on disk unexpectedly, we simply make it versioned, because we can 2818 * do so without risk of destroying data. Only skip if it is 2819 * versioned but unexpectedly missing from disk, or is unversioned 2820 * but obstructed by a node of the wrong kind. */ 2821 if (obstr_state == svn_wc_notify_state_obstructed 2822 && (is_deleted || 2823 db->tree_conflict_local_node_kind == svn_node_none)) 2824 { 2825 svn_node_kind_t disk_kind; 2826 2827 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, 2828 scratch_pool)); 2829 2830 if (disk_kind == svn_node_dir) 2831 { 2832 obstr_state = svn_wc_notify_state_inapplicable; 2833 db->add_existing = TRUE; /* Take over existing directory */ 2834 } 2835 } 2836 2837 if (obstr_state != svn_wc_notify_state_inapplicable) 2838 { 2839 /* Skip the obstruction */ 2840 db->shadowed = TRUE; 2841 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2842 db->skip_reason = obstr_state; 2843 } 2844 else if (db->tree_conflict_local_node_kind != svn_node_none 2845 && !is_deleted) 2846 { 2847 /* Set a tree conflict */ 2848 svn_boolean_t added; 2849 db->shadowed = TRUE; 2850 2851 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx, 2852 local_abspath, scratch_pool)); 2853 2854 db->tree_conflict_reason = added ? svn_wc_conflict_reason_added 2855 : svn_wc_conflict_reason_obstructed; 2856 } 2857 } 2858 2859 /* Handle pending conflicts */ 2860 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2861 2862 if (db->shadowed) 2863 { 2864 /* Notified and done. Skip children? */ 2865 } 2866 else if (merge_b->record_only) 2867 { 2868 /* Ok, we are done for this node and its descendants */ 2869 *skip = TRUE; 2870 *skip_children = TRUE; 2871 } 2872 else if (! merge_b->dry_run) 2873 { 2874 /* Create the directory on disk, to allow descendants to be added */ 2875 if (! db->add_existing) 2876 SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, 2877 scratch_pool)); 2878 2879 if (old_tc) 2880 { 2881 /* svn_wc_add4 and svn_wc_add_from_disk3 can't add a node 2882 over an existing tree conflict */ 2883 2884 /* ### These functions should take some tree conflict argument 2885 and allow overwriting the tc when one is passed */ 2886 2887 SVN_ERR(svn_wc__del_tree_conflict(merge_b->ctx->wc_ctx, 2888 local_abspath, 2889 scratch_pool)); 2890 } 2891 2892 if (merge_b->same_repos) 2893 { 2894 const char *original_url; 2895 2896 original_url = svn_path_url_add_component2( 2897 merge_b->merge_source.loc2->url, 2898 relpath, scratch_pool); 2899 2900 /* Limitation (aka HACK): 2901 We create a newly added directory with an original URL and 2902 revision as that in the repository, but without its properties 2903 and children. 2904 2905 When the merge is cancelled before the final dir_added(), the 2906 copy won't really represent the in-repository state of the node. 2907 */ 2908 SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath, 2909 svn_depth_infinity, 2910 original_url, 2911 right_source->revision, 2912 merge_b->ctx->cancel_func, 2913 merge_b->ctx->cancel_baton, 2914 NULL, NULL /* no notify! */, 2915 scratch_pool)); 2916 } 2917 else 2918 { 2919 SVN_ERR(svn_wc_add_from_disk3(merge_b->ctx->wc_ctx, local_abspath, 2920 apr_hash_make(scratch_pool), 2921 FALSE /* skip checks */, 2922 NULL, NULL /* no notify! */, 2923 scratch_pool)); 2924 } 2925 2926 if (old_tc != NULL) 2927 { 2928 /* ### Should be atomic with svn_wc_add(4|_from_disk2)() */ 2929 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 2930 old_tc->node_kind, 2931 svn_node_none, 2932 svn_node_dir, 2933 db->tree_conflict_action, 2934 db->tree_conflict_reason, 2935 old_tc, FALSE, 2936 scratch_pool)); 2937 } 2938 } 2939 2940 if (! db->shadowed && !merge_b->record_only) 2941 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_dir, 2942 db->add_is_replace, scratch_pool)); 2943 } 2944 return SVN_NO_ERROR; 2945} 2946 2947/* An svn_diff_tree_processor_t function. 2948 * 2949 * Called after merge_dir_opened() when a node exists in both the left and 2950 * right source, but has its properties changed inbetween. 2951 * 2952 * After the merge_dir_opened() but before the call to this merge_dir_changed() 2953 * function all descendants will have been updated. 2954 */ 2955static svn_error_t * 2956merge_dir_changed(const char *relpath, 2957 const svn_diff_source_t *left_source, 2958 const svn_diff_source_t *right_source, 2959 /*const*/ apr_hash_t *left_props, 2960 /*const*/ apr_hash_t *right_props, 2961 const apr_array_header_t *prop_changes, 2962 void *dir_baton, 2963 const struct svn_diff_tree_processor_t *processor, 2964 apr_pool_t *scratch_pool) 2965{ 2966 merge_cmd_baton_t *merge_b = processor->baton; 2967 struct merge_dir_baton_t *db = dir_baton; 2968 const apr_array_header_t *props; 2969 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2970 relpath, scratch_pool); 2971 2972 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 2973 2974 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2975 2976 if (db->shadowed) 2977 { 2978 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 2979 { 2980 /* We haven't notified for this node yet: report a skip */ 2981 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 2982 svn_wc_notify_update_shadowed_update, 2983 db->skip_reason, db->parent_baton, 2984 scratch_pool)); 2985 } 2986 2987 return SVN_NO_ERROR; 2988 } 2989 2990 SVN_ERR(prepare_merge_props_changed(&props, local_abspath, prop_changes, 2991 merge_b, scratch_pool, scratch_pool)); 2992 2993 if (props->nelts) 2994 { 2995 const svn_wc_conflict_version_t *left; 2996 const svn_wc_conflict_version_t *right; 2997 svn_client_ctx_t *ctx = merge_b->ctx; 2998 svn_wc_notify_state_t prop_state; 2999 3000 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 3001 svn_node_dir, svn_node_dir, 3002 &merge_b->merge_source, 3003 merge_b->target, 3004 scratch_pool, scratch_pool)); 3005 3006 SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath, 3007 left, right, 3008 left_props, props, 3009 merge_b->dry_run, 3010 NULL, NULL, 3011 ctx->cancel_func, ctx->cancel_baton, 3012 scratch_pool)); 3013 3014 if (prop_state == svn_wc_notify_state_conflicted) 3015 { 3016 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 3017 merge_b->pool); 3018 } 3019 3020 if (prop_state == svn_wc_notify_state_conflicted 3021 || prop_state == svn_wc_notify_state_merged 3022 || prop_state == svn_wc_notify_state_changed) 3023 { 3024 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file, 3025 svn_wc_notify_state_inapplicable, 3026 prop_state, scratch_pool)); 3027 } 3028 } 3029 3030 return SVN_NO_ERROR; 3031} 3032 3033 3034/* An svn_diff_tree_processor_t function. 3035 * 3036 * Called after merge_dir_opened() when a node doesn't exist in LEFT_SOURCE, 3037 * but does in RIGHT_SOURCE. After the merge_dir_opened() but before the call 3038 * to this merge_dir_added() function all descendants will have been added. 3039 * 3040 * When a node is replaced instead of just added a separate opened+deleted will 3041 * be invoked before the current open+added. 3042 */ 3043static svn_error_t * 3044merge_dir_added(const char *relpath, 3045 const svn_diff_source_t *copyfrom_source, 3046 const svn_diff_source_t *right_source, 3047 /*const*/ apr_hash_t *copyfrom_props, 3048 /*const*/ apr_hash_t *right_props, 3049 void *dir_baton, 3050 const struct svn_diff_tree_processor_t *processor, 3051 apr_pool_t *scratch_pool) 3052{ 3053 merge_cmd_baton_t *merge_b = processor->baton; 3054 struct merge_dir_baton_t *db = dir_baton; 3055 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 3056 relpath, scratch_pool); 3057 3058 /* For consistency; usually a no-op from _dir_added() */ 3059 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 3060 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 3061 3062 if (db->shadowed) 3063 { 3064 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 3065 { 3066 /* We haven't notified for this node yet: report a skip */ 3067 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 3068 svn_wc_notify_update_shadowed_add, 3069 db->skip_reason, db->parent_baton, 3070 scratch_pool)); 3071 } 3072 3073 return SVN_NO_ERROR; 3074 } 3075 3076 SVN_ERR_ASSERT( 3077 db->edited /* Marked edited from merge_open_dir() */ 3078 && ! merge_b->record_only /* Skip details from merge_open_dir() */ 3079 ); 3080 3081 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 3082 && ( !db->parent_baton || !db->parent_baton->added)) 3083 { 3084 /* Store the roots of added subtrees */ 3085 store_path(merge_b->added_abspaths, local_abspath); 3086 } 3087 3088 if (merge_b->same_repos) 3089 { 3090 /* When the directory was added in merge_dir_added() we didn't update its 3091 pristine properties. Instead we receive the property changes later and 3092 apply them in this function. 3093 3094 If we would apply them as changes (such as before fixing issue #3405), 3095 we would see the unmodified properties as local changes, and the 3096 pristine properties would be out of sync with what the repository 3097 expects for this directory. 3098 3099 Instead of doing that we now simply set the properties as the pristine 3100 properties via a private libsvn_wc api. 3101 */ 3102 3103 const char *copyfrom_url; 3104 svn_revnum_t copyfrom_rev; 3105 const char *parent_abspath; 3106 const char *child; 3107 3108 /* Creating a hash containing regular and entry props */ 3109 apr_hash_t *new_pristine_props = right_props; 3110 3111 parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool); 3112 child = svn_dirent_is_child(merge_b->target->abspath, local_abspath, NULL); 3113 SVN_ERR_ASSERT(child != NULL); 3114 3115 copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2->url, 3116 child, scratch_pool); 3117 copyfrom_rev = right_source->revision; 3118 3119 SVN_ERR(check_repos_match(merge_b->target, parent_abspath, copyfrom_url, 3120 scratch_pool)); 3121 3122 if (!merge_b->dry_run) 3123 { 3124 SVN_ERR(svn_wc__complete_directory_add(merge_b->ctx->wc_ctx, 3125 local_abspath, 3126 new_pristine_props, 3127 copyfrom_url, copyfrom_rev, 3128 scratch_pool)); 3129 } 3130 3131 if (svn_hash_gets(new_pristine_props, SVN_PROP_MERGEINFO)) 3132 { 3133 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 3134 local_abspath, merge_b->pool); 3135 } 3136 } 3137 else 3138 { 3139 apr_array_header_t *regular_props; 3140 apr_hash_t *new_props; 3141 svn_wc_notify_state_t prop_state; 3142 3143 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props, 3144 scratch_pool), 3145 NULL, NULL, ®ular_props, scratch_pool)); 3146 3147 new_props = svn_prop_array_to_hash(regular_props, scratch_pool); 3148 3149 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL); 3150 3151 /* ### What is the easiest way to set new_props on LOCAL_ABSPATH? 3152 3153 ### This doesn't need a merge as we just added the node 3154 ### (or installed a tree conflict and skipped this node)*/ 3155 3156 SVN_ERR(svn_wc_merge_props3(&prop_state, merge_b->ctx->wc_ctx, 3157 local_abspath, 3158 NULL, NULL, 3159 apr_hash_make(scratch_pool), 3160 svn_prop_hash_to_array(new_props, 3161 scratch_pool), 3162 merge_b->dry_run, 3163 NULL, NULL, 3164 merge_b->ctx->cancel_func, 3165 merge_b->ctx->cancel_baton, 3166 scratch_pool)); 3167 if (prop_state == svn_wc_notify_state_conflicted) 3168 { 3169 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 3170 merge_b->pool); 3171 } 3172 } 3173 3174 return SVN_NO_ERROR; 3175} 3176 3177/* Helper for merge_dir_deleted. Implement svn_wc_status_func4_t */ 3178static svn_error_t * 3179verify_touched_by_del_check(void *baton, 3180 const char *local_abspath, 3181 const svn_wc_status3_t *status, 3182 apr_pool_t *scratch_pool) 3183{ 3184 struct dir_delete_baton_t *delb = baton; 3185 3186 if (svn_hash_gets(delb->compared_abspaths, local_abspath)) 3187 return SVN_NO_ERROR; 3188 3189 switch (status->node_status) 3190 { 3191 case svn_wc_status_deleted: 3192 case svn_wc_status_ignored: 3193 case svn_wc_status_none: 3194 return SVN_NO_ERROR; 3195 3196 default: 3197 delb->found_edit = TRUE; 3198 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL); 3199 } 3200} 3201 3202/* An svn_diff_tree_processor_t function. 3203 * 3204 * Called after merge_dir_opened() when a node existed only in the left source. 3205 * 3206 * After the merge_dir_opened() but before the call to this merge_dir_deleted() 3207 * function all descendants that existed in left_source will have been deleted. 3208 * 3209 * If this node is replaced, an _opened() followed by a matching _add() will 3210 * be invoked after this function. 3211 */ 3212static svn_error_t * 3213merge_dir_deleted(const char *relpath, 3214 const svn_diff_source_t *left_source, 3215 /*const*/ apr_hash_t *left_props, 3216 void *dir_baton, 3217 const struct svn_diff_tree_processor_t *processor, 3218 apr_pool_t *scratch_pool) 3219{ 3220 merge_cmd_baton_t *merge_b = processor->baton; 3221 struct merge_dir_baton_t *db = dir_baton; 3222 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 3223 relpath, scratch_pool); 3224 svn_boolean_t same; 3225 apr_hash_t *working_props; 3226 3227 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 3228 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 3229 3230 if (db->shadowed) 3231 { 3232 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 3233 { 3234 /* We haven't notified for this node yet: report a skip */ 3235 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 3236 svn_wc_notify_update_shadowed_delete, 3237 db->skip_reason, db->parent_baton, 3238 scratch_pool)); 3239 } 3240 3241 return SVN_NO_ERROR; 3242 } 3243 3244 /* Easy out: We are only applying mergeinfo differences. */ 3245 if (merge_b->record_only) 3246 { 3247 return SVN_NO_ERROR; 3248 } 3249 3250 SVN_ERR(svn_wc_prop_list2(&working_props, 3251 merge_b->ctx->wc_ctx, local_abspath, 3252 scratch_pool, scratch_pool)); 3253 3254 if (merge_b->force_delete) 3255 { 3256 /* In this legacy mode we just assume that a directory delete 3257 matches any directory. db->delete_state is NULL */ 3258 same = TRUE; 3259 } 3260 else 3261 { 3262 struct dir_delete_baton_t *delb; 3263 3264 /* Compare the properties */ 3265 SVN_ERR(properties_same_p(&same, left_props, working_props, 3266 scratch_pool)); 3267 delb = db->delete_state; 3268 assert(delb != NULL); 3269 3270 if (! same) 3271 { 3272 delb->found_edit = TRUE; 3273 } 3274 else 3275 { 3276 store_path(delb->compared_abspaths, local_abspath); 3277 } 3278 3279 if (delb->del_root != db) 3280 return SVN_NO_ERROR; 3281 3282 if (delb->found_edit) 3283 same = FALSE; 3284 else 3285 { 3286 apr_array_header_t *ignores; 3287 svn_error_t *err; 3288 same = TRUE; 3289 3290 SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, 3291 scratch_pool)); 3292 3293 /* None of the descendants was modified, but maybe there are 3294 descendants we haven't walked? 3295 3296 Note that we aren't interested in changes, as we already verified 3297 changes in the paths touched by the merge. And the existence of 3298 other paths is enough to mark the directory edited */ 3299 err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, 3300 svn_depth_infinity, TRUE /* get-all */, 3301 FALSE /* no-ignore */, 3302 TRUE /* ignore-text-mods */, ignores, 3303 verify_touched_by_del_check, delb, 3304 merge_b->ctx->cancel_func, 3305 merge_b->ctx->cancel_baton, 3306 scratch_pool); 3307 3308 if (err) 3309 { 3310 if (err->apr_err != SVN_ERR_CEASE_INVOCATION) 3311 return svn_error_trace(err); 3312 3313 svn_error_clear(err); 3314 } 3315 3316 same = ! delb->found_edit; 3317 } 3318 } 3319 3320 if (same && !merge_b->dry_run) 3321 { 3322 svn_error_t *err; 3323 3324 err = svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath, 3325 FALSE /* keep_local */, FALSE /* unversioned */, 3326 merge_b->ctx->cancel_func, 3327 merge_b->ctx->cancel_baton, 3328 NULL, NULL /* no notify */, 3329 scratch_pool); 3330 3331 if (err) 3332 { 3333 if (err->apr_err != SVN_ERR_WC_LEFT_LOCAL_MOD) 3334 return svn_error_trace(err); 3335 3336 svn_error_clear(err); 3337 same = FALSE; 3338 } 3339 } 3340 3341 if (! same) 3342 { 3343 /* If the attempt to delete an existing directory failed, 3344 * the directory has local modifications (e.g. locally added 3345 * files, or property changes). Flag a tree conflict. */ 3346 3347 /* This handles use case 5 described in the paper attached to issue 3348 * #2282. See also notes/tree-conflicts/detection.txt 3349 */ 3350 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton, 3351 svn_node_dir, 3352 svn_node_dir, 3353 svn_node_none, 3354 svn_wc_conflict_action_delete, 3355 svn_wc_conflict_reason_edited, 3356 NULL, TRUE, 3357 scratch_pool)); 3358 } 3359 else 3360 { 3361 /* Record that we might have deleted mergeinfo */ 3362 if (working_props 3363 && svn_hash_gets(working_props, SVN_PROP_MERGEINFO)) 3364 { 3365 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 3366 local_abspath, merge_b->pool); 3367 } 3368 3369 SVN_ERR(record_update_delete(merge_b, db->parent_baton, local_abspath, 3370 svn_node_dir, scratch_pool)); 3371 } 3372 3373 return SVN_NO_ERROR; 3374} 3375 3376/* An svn_diff_tree_processor_t function. 3377 * 3378 * Called after merge_dir_opened() when a node itself didn't change between 3379 * the left and right source. 3380 * 3381 * After the merge_dir_opened() but before the call to this merge_dir_closed() 3382 * function all descendants will have been processed. 3383 */ 3384static svn_error_t * 3385merge_dir_closed(const char *relpath, 3386 const svn_diff_source_t *left_source, 3387 const svn_diff_source_t *right_source, 3388 void *dir_baton, 3389 const struct svn_diff_tree_processor_t *processor, 3390 apr_pool_t *scratch_pool) 3391{ 3392 merge_cmd_baton_t *merge_b = processor->baton; 3393 struct merge_dir_baton_t *db = dir_baton; 3394 3395 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 3396 3397 return SVN_NO_ERROR; 3398} 3399 3400/* An svn_diff_tree_processor_t function. 3401 3402 Called when the diff driver wants to report an absent path. 3403 3404 In case of merges this happens when the diff encounters a server-excluded 3405 path. 3406 3407 We register a skipped path, which will make parent mergeinfo non- 3408 inheritable. This ensures that a future merge might see these skipped 3409 changes as eligable for merging. 3410 3411 For legacy reasons we also notify the path as skipped. 3412 */ 3413static svn_error_t * 3414merge_node_absent(const char *relpath, 3415 void *dir_baton, 3416 const svn_diff_tree_processor_t *processor, 3417 apr_pool_t *scratch_pool) 3418{ 3419 merge_cmd_baton_t *merge_b = processor->baton; 3420 struct merge_dir_baton_t *db = dir_baton; 3421 3422 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 3423 relpath, scratch_pool); 3424 3425 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_unknown, 3426 svn_wc_notify_skip, svn_wc_notify_state_missing, 3427 db, scratch_pool)); 3428 3429 return SVN_NO_ERROR; 3430} 3431 3432/* Return a diff processor that will apply the merge to the WC. 3433 */ 3434static svn_diff_tree_processor_t * 3435merge_apply_processor(merge_cmd_baton_t *merge_cmd_baton, 3436 apr_pool_t *result_pool) 3437{ 3438 svn_diff_tree_processor_t *merge_processor; 3439 3440 merge_processor = svn_diff__tree_processor_create(merge_cmd_baton, 3441 result_pool); 3442 3443 merge_processor->dir_opened = merge_dir_opened; 3444 merge_processor->dir_changed = merge_dir_changed; 3445 merge_processor->dir_added = merge_dir_added; 3446 merge_processor->dir_deleted = merge_dir_deleted; 3447 merge_processor->dir_closed = merge_dir_closed; 3448 3449 merge_processor->file_opened = merge_file_opened; 3450 merge_processor->file_changed = merge_file_changed; 3451 merge_processor->file_added = merge_file_added; 3452 merge_processor->file_deleted = merge_file_deleted; 3453 /* Not interested in file_closed() */ 3454 3455 merge_processor->node_absent = merge_node_absent; 3456 3457 return merge_processor; 3458} 3459 3460/* Initialize minimal dir baton to allow calculating 'R'eplace 3461 from 'D'elete + 'A'dd. */ 3462static void * 3463open_dir_for_replace_single_file(apr_pool_t *result_pool) 3464{ 3465 struct merge_dir_baton_t *dir_baton = apr_pcalloc(result_pool, sizeof(*dir_baton)); 3466 3467 dir_baton->pool = result_pool; 3468 dir_baton->tree_conflict_reason = CONFLICT_REASON_NONE; 3469 dir_baton->tree_conflict_action = svn_wc_conflict_action_edit; 3470 dir_baton->skip_reason = svn_wc_notify_state_unknown; 3471 3472 return dir_baton; 3473} 3474 3475/*-----------------------------------------------------------------------*/ 3476 3477/*** Merge Notification ***/ 3478 3479 3480/* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for LOCAL_ABSPATH. If 3481 PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO 3482 where child->abspath == PATH is considered PATH's ancestor. If FALSE, 3483 then child->abspath must be a proper ancestor of PATH. 3484 3485 CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first 3486 order of path. */ 3487static svn_client__merge_path_t * 3488find_nearest_ancestor(const apr_array_header_t *children_with_mergeinfo, 3489 svn_boolean_t path_is_own_ancestor, 3490 const char *local_abspath) 3491{ 3492 int i; 3493 3494 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL); 3495 3496 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--) 3497 { 3498 svn_client__merge_path_t *child = 3499 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 3500 3501 if (svn_dirent_is_ancestor(child->abspath, local_abspath) 3502 && (path_is_own_ancestor 3503 || strcmp(child->abspath, local_abspath) != 0)) 3504 return child; 3505 } 3506 return NULL; 3507} 3508 3509/* Find the highest level path in a merge target (possibly the merge target 3510 itself) to use in a merge notification header. 3511 3512 Return the svn_client__merge_path_t * representing the most distant 3513 ancestor in CHILDREN_WITH_MERGEINFO of LOCAL_ABSPATH where said 3514 ancestor's first remaining ranges element (per the REMAINING_RANGES 3515 member of the ancestor) intersect with the first remaining ranges element 3516 for every intermediate ancestor svn_client__merge_path_t * of 3517 LOCAL_ABSPATH. If no such ancestor is found return NULL. 3518 3519 If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO 3520 represent a forward merge, then set *START to the oldest revision found 3521 in any of the intersecting ancestors and *END to the youngest revision 3522 found. If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO 3523 represent a reverse merge, then set *START to the youngest revision 3524 found and *END to the oldest revision found. If no ancestors are found 3525 then set *START and *END to SVN_INVALID_REVNUM. 3526 3527 If PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO 3528 where child->abspath == PATH is considered PATH's ancestor. If FALSE, 3529 then child->abspath must be a proper ancestor of PATH. 3530 3531 See the CHILDREN_WITH_MERGEINFO ARRAY global comment for more 3532 information. */ 3533static svn_client__merge_path_t * 3534find_nearest_ancestor_with_intersecting_ranges( 3535 svn_revnum_t *start, 3536 svn_revnum_t *end, 3537 const apr_array_header_t *children_with_mergeinfo, 3538 svn_boolean_t path_is_own_ancestor, 3539 const char *local_abspath) 3540{ 3541 int i; 3542 svn_client__merge_path_t *nearest_ancestor = NULL; 3543 3544 *start = SVN_INVALID_REVNUM; 3545 *end = SVN_INVALID_REVNUM; 3546 3547 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL); 3548 3549 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--) 3550 { 3551 svn_client__merge_path_t *child = 3552 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 3553 3554 if (svn_dirent_is_ancestor(child->abspath, local_abspath) 3555 && (path_is_own_ancestor 3556 || strcmp(child->abspath, local_abspath) != 0)) 3557 { 3558 if (nearest_ancestor == NULL) 3559 { 3560 /* Found an ancestor. */ 3561 nearest_ancestor = child; 3562 3563 if (child->remaining_ranges) 3564 { 3565 svn_merge_range_t *r1 = APR_ARRAY_IDX( 3566 child->remaining_ranges, 0, svn_merge_range_t *); 3567 *start = r1->start; 3568 *end = r1->end; 3569 } 3570 else 3571 { 3572 /* If CHILD->REMAINING_RANGES is null then LOCAL_ABSPATH 3573 is inside an absent subtree in the merge target. */ 3574 *start = SVN_INVALID_REVNUM; 3575 *end = SVN_INVALID_REVNUM; 3576 break; 3577 } 3578 } 3579 else 3580 { 3581 /* We'e found another ancestor for LOCAL_ABSPATH. Do its 3582 first remaining range intersect with the previously 3583 found ancestor? */ 3584 svn_merge_range_t *r1 = 3585 APR_ARRAY_IDX(nearest_ancestor->remaining_ranges, 0, 3586 svn_merge_range_t *); 3587 svn_merge_range_t *r2 = 3588 APR_ARRAY_IDX(child->remaining_ranges, 0, 3589 svn_merge_range_t *); 3590 3591 if (r1 && r2) 3592 { 3593 svn_merge_range_t range1; 3594 svn_merge_range_t range2; 3595 svn_boolean_t reverse_merge = r1->start > r2->end; 3596 3597 /* Flip endpoints if this is a reverse merge. */ 3598 if (reverse_merge) 3599 { 3600 range1.start = r1->end; 3601 range1.end = r1->start; 3602 range2.start = r2->end; 3603 range2.end = r2->start; 3604 } 3605 else 3606 { 3607 range1.start = r1->start; 3608 range1.end = r1->end; 3609 range2.start = r2->start; 3610 range2.end = r2->end; 3611 } 3612 3613 if (range1.start < range2.end && range2.start < range1.end) 3614 { 3615 *start = reverse_merge ? 3616 MAX(r1->start, r2->start) : MIN(r1->start, r2->start); 3617 *end = reverse_merge ? 3618 MIN(r1->end, r2->end) : MAX(r1->end, r2->end); 3619 nearest_ancestor = child; 3620 } 3621 } 3622 } 3623 } 3624 } 3625 return nearest_ancestor; 3626} 3627 3628/* Notify that we're starting to record mergeinfo for the merge of the 3629 * revision range RANGE into TARGET_ABSPATH. RANGE should be null if the 3630 * merge sources are not from the same URL. 3631 * 3632 * This calls the client's notification receiver (as found in the client 3633 * context), with a WC abspath. 3634 */ 3635static void 3636notify_mergeinfo_recording(const char *target_abspath, 3637 const svn_merge_range_t *range, 3638 svn_client_ctx_t *ctx, 3639 apr_pool_t *pool) 3640{ 3641 if (ctx->notify_func2) 3642 { 3643 svn_wc_notify_t *n = svn_wc_create_notify( 3644 target_abspath, svn_wc_notify_merge_record_info_begin, pool); 3645 3646 n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL; 3647 ctx->notify_func2(ctx->notify_baton2, n, pool); 3648 } 3649} 3650 3651/* Notify that we're completing the merge into TARGET_ABSPATH. 3652 * 3653 * This calls the client's notification receiver (as found in the client 3654 * context), with a WC abspath. 3655 */ 3656static void 3657notify_merge_completed(const char *target_abspath, 3658 svn_client_ctx_t *ctx, 3659 apr_pool_t *pool) 3660{ 3661 if (ctx->notify_func2) 3662 { 3663 svn_wc_notify_t *n 3664 = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed, 3665 pool); 3666 ctx->notify_func2(ctx->notify_baton2, n, pool); 3667 } 3668} 3669 3670 3671/* Remove merge source gaps from range used for merge notifications. 3672 See https://issues.apache.org/jira/browse/SVN-4138 3673 3674 If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a 3675 single range (see the implicit_src_gap member of merge_cmd_baton_t). 3676 RANGE describes a (possibly reverse) merge. 3677 3678 If IMPLICIT_SRC_GAP is not NULL and it's sole range intersects with 3679 the older revision in *RANGE, then remove IMPLICIT_SRC_GAP's range 3680 from *RANGE. */ 3681static void 3682remove_source_gap(svn_merge_range_t *range, 3683 apr_array_header_t *implicit_src_gap) 3684{ 3685 if (implicit_src_gap) 3686 { 3687 svn_merge_range_t *gap_range = 3688 APR_ARRAY_IDX(implicit_src_gap, 0, svn_merge_range_t *); 3689 if (range->start < range->end) 3690 { 3691 if (gap_range->start == range->start) 3692 range->start = gap_range->end; 3693 } 3694 else /* Reverse merge */ 3695 { 3696 if (gap_range->start == range->end) 3697 range->end = gap_range->end; 3698 } 3699 } 3700} 3701 3702/* Notify that we're starting a merge 3703 * 3704 * This calls the client's notification receiver (as found in the client 3705 * context), with a WC abspath. 3706 */ 3707static void 3708notify_merge_begin(struct notify_begin_state_t *notify_begin_state, 3709 const char *local_abspath, 3710 svn_boolean_t delete_action, 3711 apr_pool_t *scratch_pool) 3712{ 3713 merge_cmd_baton_t *merge_b = notify_begin_state->merge_b; 3714 svn_wc_notify_t *notify; 3715 svn_merge_range_t n_range = 3716 {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE}; 3717 const char *notify_abspath; 3718 3719 if (! notify_begin_state->notify_func2) 3720 return; 3721 3722 /* If our merge sources are ancestors of one another... */ 3723 if (merge_b->merge_source.ancestral) 3724 { 3725 const svn_client__merge_path_t *child; 3726 /* Find LOCAL_ABSPATH's nearest ancestor in 3727 CHILDREN_WITH_MERGEINFO. Normally we consider a child in 3728 CHILDREN_WITH_MERGEINFO representing PATH to be an 3729 ancestor of PATH, but if this is a deletion of PATH then the 3730 notification must be for a proper ancestor of PATH. This ensures 3731 we don't get notifications like: 3732 3733 --- Merging rX into 'PARENT/CHILD' 3734 D PARENT/CHILD 3735 3736 But rather: 3737 3738 --- Merging rX into 'PARENT' 3739 D PARENT/CHILD 3740 */ 3741 3742 child = find_nearest_ancestor_with_intersecting_ranges( 3743 &(n_range.start), &(n_range.end), 3744 merge_b->children_with_mergeinfo, 3745 ! delete_action, local_abspath); 3746 3747 if (!child && delete_action) 3748 { 3749 /* Triggered by file replace in single-file-merge */ 3750 child = find_nearest_ancestor(merge_b->children_with_mergeinfo, 3751 TRUE, local_abspath); 3752 } 3753 3754 assert(child != NULL); /* Should always find the merge anchor */ 3755 3756 if (! child) 3757 return; 3758 3759 if (notify_begin_state->last_abspath != NULL 3760 && strcmp(child->abspath, notify_begin_state->last_abspath) == 0) 3761 { 3762 /* Don't notify the same merge again */ 3763 return; 3764 } 3765 3766 notify_begin_state->last_abspath = child->abspath; 3767 3768 if (child->absent || child->remaining_ranges->nelts == 0 3769 || !SVN_IS_VALID_REVNUM(n_range.start)) 3770 { 3771 /* No valid information for an header */ 3772 return; 3773 } 3774 3775 notify_abspath = child->abspath; 3776 } 3777 else 3778 { 3779 if (notify_begin_state->last_abspath) 3780 return; /* already notified */ 3781 3782 notify_abspath = merge_b->target->abspath; 3783 /* Store something in last_abspath. Any value would do */ 3784 notify_begin_state->last_abspath = merge_b->target->abspath; 3785 } 3786 3787 notify = svn_wc_create_notify(notify_abspath, 3788 merge_b->same_repos 3789 ? svn_wc_notify_merge_begin 3790 : svn_wc_notify_foreign_merge_begin, 3791 scratch_pool); 3792 3793 if (SVN_IS_VALID_REVNUM(n_range.start)) 3794 { 3795 /* If the merge source has a gap, then don't mention 3796 those gap revisions in the notification. */ 3797 remove_source_gap(&n_range, merge_b->implicit_src_gap); 3798 notify->merge_range = &n_range; 3799 } 3800 else 3801 { 3802 notify->merge_range = NULL; 3803 } 3804 3805 notify_begin_state->notify_func2(notify_begin_state->notify_baton2, notify, 3806 scratch_pool); 3807} 3808 3809/* Our notification callback, that adds a 'begin' notification */ 3810static void 3811notify_merging(void *baton, 3812 const svn_wc_notify_t *notify, 3813 apr_pool_t *pool) 3814{ 3815 struct notify_begin_state_t *b = baton; 3816 3817 notify_merge_begin(b, notify->path, 3818 notify->action == svn_wc_notify_update_delete, 3819 pool); 3820 3821 b->notify_func2(b->notify_baton2, notify, pool); 3822} 3823 3824/* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple 3825 * (inheritable) revision range REV1:REV2, according to CONSIDER_INHERITANCE. 3826 * If REV1 is equal to REV2, the result is an empty rangelist, otherwise 3827 * REV1 must be less than REV2. 3828 * 3829 * Note: If CONSIDER_INHERITANCE is FALSE, the effect is to treat any non- 3830 * inheritable input ranges as if they were inheritable. If it is TRUE, the 3831 * effect is to discard any non-inheritable input ranges. Therefore the 3832 * ranges in *OUT_RANGELIST will always be inheritable. */ 3833static svn_error_t * 3834rangelist_intersect_range(svn_rangelist_t **out_rangelist, 3835 const svn_rangelist_t *in_rangelist, 3836 svn_revnum_t rev1, 3837 svn_revnum_t rev2, 3838 svn_boolean_t consider_inheritance, 3839 apr_pool_t *result_pool, 3840 apr_pool_t *scratch_pool) 3841{ 3842 SVN_ERR_ASSERT(rev1 <= rev2); 3843 3844 if (rev1 < rev2) 3845 { 3846 svn_rangelist_t *simple_rangelist = 3847 svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool); 3848 3849 SVN_ERR(svn_rangelist_intersect(out_rangelist, 3850 simple_rangelist, in_rangelist, 3851 consider_inheritance, result_pool)); 3852 } 3853 else 3854 { 3855 *out_rangelist = apr_array_make(result_pool, 0, 3856 sizeof(svn_merge_range_t *)); 3857 } 3858 return SVN_NO_ERROR; 3859} 3860 3861/* Helper for fix_deleted_subtree_ranges(). Like fix_deleted_subtree_ranges() 3862 this function should only be called when honoring mergeinfo. 3863 3864 CHILD, PARENT, REVISION1, REVISION2, and RA_SESSION are all cascaded from 3865 fix_deleted_subtree_ranges() -- see that function for more information on 3866 each. 3867 3868 If PARENT is not the merge target then PARENT must have already have been 3869 processed by this function as a child. Specifically, this means that 3870 PARENT->REMAINING_RANGES must already be populated -- it can be an empty 3871 rangelist but cannot be NULL. 3872 3873 PRIMARY_URL is the merge source url of CHILD at the younger of REVISION1 3874 and REVISION2. 3875 3876 Since this function is only invoked for subtrees of the merge target, the 3877 guarantees afforded by normalize_merge_sources() don't apply - see the 3878 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file. 3879 Therefore it is possible that PRIMARY_URL@REVISION1 and 3880 PRIMARY_URL@REVISION2 don't describe the endpoints of an unbroken line of 3881 history. The purpose of this helper is to identify these cases of broken 3882 history and adjust CHILD->REMAINING_RANGES in such a way we don't later try 3883 to describe nonexistent path/revisions to the merge report editor -- see 3884 drive_merge_report_editor(). 3885 3886 If PRIMARY_URL@REVISION1 and PRIMARY_URL@REVISION2 describe an unbroken 3887 line of history then do nothing and leave CHILD->REMAINING_RANGES as-is. 3888 3889 If neither PRIMARY_URL@REVISION1 nor PRIMARY_URL@REVISION2 exist then 3890 there is nothing to merge to CHILD->ABSPATH so set CHILD->REMAINING_RANGES 3891 equal to PARENT->REMAINING_RANGES. This will cause the subtree to 3892 effectively ignore CHILD -- see 'Note: If the first svn_merge_range_t...' 3893 in drive_merge_report_editor()'s doc string. 3894 3895 If PRIMARY_URL@REVISION1 *xor* PRIMARY_URL@REVISION2 exist then we take the 3896 subset of REVISION1:REVISION2 in CHILD->REMAINING_RANGES at which 3897 PRIMARY_URL doesn't exist and set that subset equal to 3898 PARENT->REMAINING_RANGES' intersection with that non-existent range. Why? 3899 Because this causes CHILD->REMAINING_RANGES to be identical to 3900 PARENT->REMAINING_RANGES for revisions between REVISION1 and REVISION2 at 3901 which PRIMARY_URL doesn't exist. As mentioned above this means that 3902 drive_merge_report_editor() won't attempt to describe these non-existent 3903 subtree path/ranges to the reporter (which would break the merge). 3904 3905 If the preceding paragraph wasn't terribly clear then what follows spells 3906 out this function's behavior a bit more explicitly: 3907 3908 For forward merges (REVISION1 < REVISION2) 3909 3910 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then 3911 find the revision 'N' in which PRIMARY_URL@REVISION1 was deleted. Leave 3912 the subset of CHILD->REMAINING_RANGES that intersects with 3913 REVISION1:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3914 that intersects with (N - 1):REVISION2 equal to PARENT->REMAINING_RANGES' 3915 intersection with (N - 1):REVISION2. 3916 3917 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does, 3918 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into 3919 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with 3920 (M - 1):REVISION2 as-is and set the subset of CHILD->REMAINING_RANGES 3921 that intersects with REVISION1:(M - 1) equal to PARENT->REMAINING_RANGES' 3922 intersection with REVISION1:(M - 1). 3923 3924 For reverse merges (REVISION1 > REVISION2) 3925 3926 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then 3927 find the revision 'N' in which PRIMARY_URL@REVISION1 came into existence. 3928 Leave the subset of CHILD->REMAINING_RANGES that intersects with 3929 REVISION2:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3930 that intersects with (N - 1):REVISION1 equal to PARENT->REMAINING_RANGES' 3931 intersection with (N - 1):REVISION1. 3932 3933 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does, 3934 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into 3935 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with 3936 REVISION2:(M - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3937 that intersects with (M - 1):REVISION1 equal to PARENT->REMAINING_RANGES' 3938 intersection with REVISION1:(M - 1). 3939 3940 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD are 3941 allocated in RESULT_POOL. */ 3942static svn_error_t * 3943adjust_deleted_subtree_ranges(svn_client__merge_path_t *child, 3944 svn_client__merge_path_t *parent, 3945 svn_revnum_t revision1, 3946 svn_revnum_t revision2, 3947 const char *primary_url, 3948 svn_ra_session_t *ra_session, 3949 svn_client_ctx_t *ctx, 3950 apr_pool_t *result_pool, 3951 apr_pool_t *scratch_pool) 3952{ 3953 svn_boolean_t is_rollback = revision2 < revision1; 3954 svn_revnum_t younger_rev = is_rollback ? revision1 : revision2; 3955 svn_revnum_t peg_rev = younger_rev; 3956 svn_revnum_t older_rev = is_rollback ? revision2 : revision1; 3957 apr_array_header_t *segments; 3958 svn_error_t *err; 3959 3960 SVN_ERR_ASSERT(parent->remaining_ranges); 3961 3962 err = svn_client__repos_location_segments(&segments, ra_session, 3963 primary_url, peg_rev, 3964 younger_rev, older_rev, ctx, 3965 scratch_pool); 3966 3967 if (err) 3968 { 3969 const char *rel_source_path; /* PRIMARY_URL relative to RA_SESSION */ 3970 svn_node_kind_t kind; 3971 3972 if (err->apr_err != SVN_ERR_FS_NOT_FOUND) 3973 return svn_error_trace(err); 3974 3975 svn_error_clear(err); 3976 3977 /* PRIMARY_URL@peg_rev doesn't exist. Check if PRIMARY_URL@older_rev 3978 exists, if neither exist then the editor can simply ignore this 3979 subtree. */ 3980 3981 SVN_ERR(svn_ra_get_path_relative_to_session( 3982 ra_session, &rel_source_path, primary_url, scratch_pool)); 3983 3984 SVN_ERR(svn_ra_check_path(ra_session, rel_source_path, 3985 older_rev, &kind, scratch_pool)); 3986 if (kind == svn_node_none) 3987 { 3988 /* Neither PRIMARY_URL@peg_rev nor PRIMARY_URL@older_rev exist, 3989 so there is nothing to merge. Set CHILD->REMAINING_RANGES 3990 identical to PARENT's. */ 3991 child->remaining_ranges = 3992 svn_rangelist_dup(parent->remaining_ranges, scratch_pool); 3993 } 3994 else 3995 { 3996 svn_rangelist_t *deleted_rangelist; 3997 svn_revnum_t rev_primary_url_deleted; 3998 3999 /* PRIMARY_URL@older_rev exists, so it was deleted at some 4000 revision prior to peg_rev, find that revision. */ 4001 SVN_ERR(svn_ra_get_deleted_rev(ra_session, rel_source_path, 4002 older_rev, younger_rev, 4003 &rev_primary_url_deleted, 4004 scratch_pool)); 4005 4006 /* PRIMARY_URL@older_rev exists and PRIMARY_URL@peg_rev doesn't, 4007 so svn_ra_get_deleted_rev() should always find the revision 4008 PRIMARY_URL@older_rev was deleted. */ 4009 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev_primary_url_deleted)); 4010 4011 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and 4012 PARENT->REMAINING_RANGES so both will work with the 4013 svn_rangelist_* APIs below. */ 4014 if (is_rollback) 4015 { 4016 /* svn_rangelist_reverse operates in place so it's safe 4017 to use our scratch_pool. */ 4018 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 4019 scratch_pool)); 4020 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 4021 scratch_pool)); 4022 } 4023 4024 /* Find the intersection of CHILD->REMAINING_RANGES with the 4025 range over which PRIMARY_URL@older_rev exists (ending at 4026 the youngest revision at which it still exists). */ 4027 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges, 4028 child->remaining_ranges, 4029 older_rev, 4030 rev_primary_url_deleted - 1, 4031 FALSE, 4032 scratch_pool, scratch_pool)); 4033 4034 /* Merge into CHILD->REMAINING_RANGES the intersection of 4035 PARENT->REMAINING_RANGES with the range beginning when 4036 PRIMARY_URL@older_rev was deleted until younger_rev. */ 4037 SVN_ERR(rangelist_intersect_range(&deleted_rangelist, 4038 parent->remaining_ranges, 4039 rev_primary_url_deleted - 1, 4040 peg_rev, 4041 FALSE, 4042 scratch_pool, scratch_pool)); 4043 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 4044 deleted_rangelist, scratch_pool, 4045 scratch_pool)); 4046 4047 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES 4048 to reverse order if necessary. */ 4049 if (is_rollback) 4050 { 4051 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 4052 scratch_pool)); 4053 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 4054 scratch_pool)); 4055 } 4056 } 4057 } 4058 else /* PRIMARY_URL@peg_rev exists. */ 4059 { 4060 svn_rangelist_t *non_existent_rangelist; 4061 svn_location_segment_t *segment = 4062 APR_ARRAY_IDX(segments, (segments->nelts - 1), 4063 svn_location_segment_t *); 4064 4065 /* We know PRIMARY_URL@peg_rev exists as the call to 4066 svn_client__repos_location_segments() succeeded. If there is only 4067 one segment that starts at oldest_rev then we know that 4068 PRIMARY_URL@oldest_rev:PRIMARY_URL@peg_rev describes an unbroken 4069 line of history, so there is nothing more to adjust in 4070 CHILD->REMAINING_RANGES. */ 4071 if (segment->range_start == older_rev) 4072 { 4073 return SVN_NO_ERROR; 4074 } 4075 4076 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and 4077 PARENT->REMAINING_RANGES so both will work with the 4078 svn_rangelist_* APIs below. */ 4079 if (is_rollback) 4080 { 4081 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 4082 scratch_pool)); 4083 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 4084 scratch_pool)); 4085 } 4086 4087 /* Intersect CHILD->REMAINING_RANGES with the range where PRIMARY_URL 4088 exists. Since segment doesn't span older_rev:peg_rev we know 4089 PRIMARY_URL@peg_rev didn't come into existence until 4090 segment->range_start + 1. */ 4091 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges, 4092 child->remaining_ranges, 4093 segment->range_start, peg_rev, 4094 FALSE, scratch_pool, scratch_pool)); 4095 4096 /* Merge into CHILD->REMAINING_RANGES the intersection of 4097 PARENT->REMAINING_RANGES with the range before PRIMARY_URL@peg_rev 4098 came into existence. */ 4099 SVN_ERR(rangelist_intersect_range(&non_existent_rangelist, 4100 parent->remaining_ranges, 4101 older_rev, segment->range_start, 4102 FALSE, scratch_pool, scratch_pool)); 4103 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 4104 non_existent_rangelist, scratch_pool, 4105 scratch_pool)); 4106 4107 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES 4108 to reverse order if necessary. */ 4109 if (is_rollback) 4110 { 4111 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 4112 scratch_pool)); 4113 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 4114 scratch_pool)); 4115 } 4116 } 4117 4118 /* Make a lasting copy of CHILD->REMAINING_RANGES using POOL. */ 4119 child->remaining_ranges = svn_rangelist_dup(child->remaining_ranges, 4120 result_pool); 4121 return SVN_NO_ERROR; 4122} 4123 4124/* Helper for do_directory_merge(). 4125 4126 SOURCE is cascaded from the argument of the same name in 4127 do_directory_merge(). TARGET is the merge target. RA_SESSION is the 4128 session for the younger of SOURCE->loc1 and SOURCE->loc2. 4129 4130 Adjust the subtrees in CHILDREN_WITH_MERGEINFO so that we don't 4131 later try to describe invalid paths in drive_merge_report_editor(). 4132 This function is just a thin wrapper around 4133 adjust_deleted_subtree_ranges(), which see for further details. 4134 4135 SCRATCH_POOL is used for all temporary allocations. Changes to 4136 CHILDREN_WITH_MERGEINFO are allocated in RESULT_POOL. 4137*/ 4138static svn_error_t * 4139fix_deleted_subtree_ranges(const merge_source_t *source, 4140 const merge_target_t *target, 4141 svn_ra_session_t *ra_session, 4142 apr_array_header_t *children_with_mergeinfo, 4143 svn_client_ctx_t *ctx, 4144 apr_pool_t *result_pool, 4145 apr_pool_t *scratch_pool) 4146{ 4147 int i; 4148 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 4149 svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev; 4150 4151 assert(session_url_is(ra_session, 4152 (is_rollback ? source->loc1 : source->loc2)->url, 4153 scratch_pool)); 4154 4155 /* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so 4156 start at index 1 to examine only subtrees. */ 4157 for (i = 1; i < children_with_mergeinfo->nelts; i++) 4158 { 4159 svn_client__merge_path_t *child = 4160 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 4161 svn_client__merge_path_t *parent; 4162 svn_rangelist_t *deleted_rangelist, *added_rangelist; 4163 4164 SVN_ERR_ASSERT(child); 4165 if (child->absent) 4166 continue; 4167 4168 svn_pool_clear(iterpool); 4169 4170 /* Find CHILD's parent. */ 4171 parent = find_nearest_ancestor(children_with_mergeinfo, 4172 FALSE, child->abspath); 4173 4174 /* Since CHILD is a subtree then its parent must be in 4175 CHILDREN_WITH_MERGEINFO, see the global comment 4176 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 4177 SVN_ERR_ASSERT(parent); 4178 4179 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 4180 so it will work with the svn_rangelist_diff API. */ 4181 if (is_rollback) 4182 { 4183 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 4184 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool)); 4185 } 4186 4187 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist, 4188 child->remaining_ranges, 4189 parent->remaining_ranges, 4190 TRUE, iterpool)); 4191 4192 if (is_rollback) 4193 { 4194 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 4195 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool)); 4196 } 4197 4198 /* If CHILD is the merge target we then know that SOURCE is provided 4199 by normalize_merge_sources() -- see 'MERGEINFO MERGE SOURCE 4200 NORMALIZATION'. Due to this normalization we know that SOURCE 4201 describes an unbroken line of history such that the entire range 4202 described by SOURCE can potentially be merged to CHILD. 4203 4204 But if CHILD is a subtree we don't have the same guarantees about 4205 SOURCE as we do for the merge target. SOURCE->loc1 and/or 4206 SOURCE->loc2 might not exist. 4207 4208 If one or both doesn't exist, then adjust CHILD->REMAINING_RANGES 4209 such that we don't later try to describe invalid subtrees in 4210 drive_merge_report_editor(), as that will break the merge. 4211 If CHILD has the same remaining ranges as PARENT however, then 4212 there is no need to make these adjustments, since 4213 drive_merge_report_editor() won't attempt to describe CHILD in this 4214 case, see the 'Note' in drive_merge_report_editor's docstring. */ 4215 if (deleted_rangelist->nelts || added_rangelist->nelts) 4216 { 4217 const char *child_primary_source_url; 4218 const char *child_repos_src_path = 4219 svn_dirent_is_child(target->abspath, child->abspath, iterpool); 4220 4221 /* This loop is only processing subtrees, so CHILD->ABSPATH 4222 better be a proper child of the merge target. */ 4223 SVN_ERR_ASSERT(child_repos_src_path); 4224 4225 child_primary_source_url = 4226 svn_path_url_add_component2((source->loc1->rev < source->loc2->rev) 4227 ? source->loc2->url : source->loc1->url, 4228 child_repos_src_path, iterpool); 4229 4230 SVN_ERR(adjust_deleted_subtree_ranges(child, parent, 4231 source->loc1->rev, 4232 source->loc2->rev, 4233 child_primary_source_url, 4234 ra_session, 4235 ctx, result_pool, iterpool)); 4236 } 4237 } 4238 4239 svn_pool_destroy(iterpool); 4240 return SVN_NO_ERROR; 4241} 4242 4243/*-----------------------------------------------------------------------*/ 4244 4245/*** Determining What Remains To Be Merged ***/ 4246 4247/* Get explicit and/or implicit mergeinfo for the working copy path 4248 TARGET_ABSPATH. 4249 4250 If RECORDED_MERGEINFO is not NULL then set *RECORDED_MERGEINFO 4251 to TARGET_ABSPATH's explicit or inherited mergeinfo as dictated by 4252 INHERIT. 4253 4254 If IMPLICIT_MERGEINFO is not NULL then set *IMPLICIT_MERGEINFO 4255 to TARGET_ABSPATH's implicit mergeinfo (a.k.a. natural history). 4256 4257 If both RECORDED_MERGEINFO and IMPLICIT_MERGEINFO are not NULL and 4258 *RECORDED_MERGEINFO is inherited, then *IMPLICIT_MERGEINFO will be 4259 removed from *RECORDED_MERGEINFO. 4260 4261 If INHERITED is not NULL set *INHERITED to TRUE if *RECORDED_MERGEINFO 4262 is inherited rather than explicit. If RECORDED_MERGEINFO is NULL then 4263 INHERITED is ignored. 4264 4265 4266 If IMPLICIT_MERGEINFO is not NULL then START and END are limits on 4267 the natural history sought, must both be valid revision numbers, and 4268 START must be greater than END. If TARGET_ABSPATH's base revision 4269 is older than START, then the base revision is used as the younger 4270 bound in place of START. 4271 4272 RA_SESSION is an RA session open to the repository in which TARGET_ABSPATH 4273 lives. It may be temporarily reparented as needed by this function. 4274 4275 Allocate *RECORDED_MERGEINFO and *IMPLICIT_MERGEINFO in RESULT_POOL. 4276 Use SCRATCH_POOL for any temporary allocations. */ 4277static svn_error_t * 4278get_full_mergeinfo(svn_mergeinfo_t *recorded_mergeinfo, 4279 svn_mergeinfo_t *implicit_mergeinfo, 4280 svn_boolean_t *inherited, 4281 svn_mergeinfo_inheritance_t inherit, 4282 svn_ra_session_t *ra_session, 4283 const char *target_abspath, 4284 svn_revnum_t start, 4285 svn_revnum_t end, 4286 svn_client_ctx_t *ctx, 4287 apr_pool_t *result_pool, 4288 apr_pool_t *scratch_pool) 4289{ 4290 /* First, we get the real mergeinfo. */ 4291 if (recorded_mergeinfo) 4292 { 4293 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(recorded_mergeinfo, 4294 inherited, 4295 NULL /* from_repos */, 4296 FALSE, 4297 inherit, ra_session, 4298 target_abspath, 4299 ctx, result_pool)); 4300 } 4301 4302 if (implicit_mergeinfo) 4303 { 4304 svn_client__pathrev_t *target; 4305 4306 /* Assert that we have sane input. */ 4307 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start) && SVN_IS_VALID_REVNUM(end) 4308 && (start > end)); 4309 4310 /* Retrieve the origin (original_*) of the node, or just the 4311 url if the node was not copied. */ 4312 SVN_ERR(svn_client__wc_node_get_origin(&target, target_abspath, ctx, 4313 scratch_pool, scratch_pool)); 4314 4315 if (! target) 4316 { 4317 /* We've been asked to operate on a locally added target, so its 4318 * implicit mergeinfo is empty. */ 4319 *implicit_mergeinfo = apr_hash_make(result_pool); 4320 } 4321 else if (target->rev <= end) 4322 { 4323 /* We're asking about a range outside our natural history 4324 altogether. That means our implicit mergeinfo is empty. */ 4325 *implicit_mergeinfo = apr_hash_make(result_pool); 4326 } 4327 else 4328 { 4329 /* Fetch so-called "implicit mergeinfo" (that is, natural 4330 history). */ 4331 4332 /* Do not ask for implicit mergeinfo from TARGET_ABSPATH's future. 4333 TARGET_ABSPATH might not even exist, and even if it does the 4334 working copy is *at* TARGET_REV so its implicit history ends 4335 at TARGET_REV! */ 4336 if (target->rev < start) 4337 start = target->rev; 4338 4339 /* Fetch the implicit mergeinfo. */ 4340 SVN_ERR(svn_client__get_history_as_mergeinfo(implicit_mergeinfo, 4341 NULL, 4342 target, start, end, 4343 ra_session, ctx, 4344 result_pool)); 4345 } 4346 } /*if (implicit_mergeinfo) */ 4347 4348 return SVN_NO_ERROR; 4349} 4350 4351/* Helper for ensure_implicit_mergeinfo(). 4352 4353 PARENT, CHILD, REVISION1, REVISION2 and CTX 4354 are all cascaded from the arguments of the same names in 4355 ensure_implicit_mergeinfo(). PARENT and CHILD must both exist, i.e. 4356 this function should never be called where CHILD is the merge target. 4357 4358 If PARENT->IMPLICIT_MERGEINFO is NULL, obtain it from the server. 4359 4360 Set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from 4361 PARENT->IMPLICIT_MERGEINFO. CHILD->IMPLICIT_MERGEINFO is allocated 4362 in RESULT_POOL. 4363 4364 RA_SESSION is an RA session open to the repository that contains CHILD. 4365 It may be temporarily reparented by this function. 4366 */ 4367static svn_error_t * 4368inherit_implicit_mergeinfo_from_parent(svn_client__merge_path_t *parent, 4369 svn_client__merge_path_t *child, 4370 svn_revnum_t revision1, 4371 svn_revnum_t revision2, 4372 svn_ra_session_t *ra_session, 4373 svn_client_ctx_t *ctx, 4374 apr_pool_t *result_pool, 4375 apr_pool_t *scratch_pool) 4376{ 4377 const char *path_diff; 4378 4379 /* This only works on subtrees! */ 4380 SVN_ERR_ASSERT(parent); 4381 SVN_ERR_ASSERT(child); 4382 4383 /* While PARENT must exist, it is possible we've deferred 4384 getting its implicit mergeinfo. If so get it now. */ 4385 if (!parent->implicit_mergeinfo) 4386 SVN_ERR(get_full_mergeinfo(NULL, &(parent->implicit_mergeinfo), 4387 NULL, svn_mergeinfo_inherited, 4388 ra_session, child->abspath, 4389 MAX(revision1, revision2), 4390 MIN(revision1, revision2), 4391 ctx, result_pool, scratch_pool)); 4392 4393 /* Let CHILD inherit PARENT's implicit mergeinfo. */ 4394 4395 path_diff = svn_dirent_is_child(parent->abspath, child->abspath, 4396 scratch_pool); 4397 /* PARENT->PATH better be an ancestor of CHILD->ABSPATH! */ 4398 SVN_ERR_ASSERT(path_diff); 4399 4400 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo( 4401 &child->implicit_mergeinfo, parent->implicit_mergeinfo, 4402 path_diff, result_pool, scratch_pool)); 4403 child->implicit_mergeinfo = svn_mergeinfo_dup(child->implicit_mergeinfo, 4404 result_pool); 4405 return SVN_NO_ERROR; 4406} 4407 4408/* Helper of filter_merged_revisions(). 4409 4410 If we have deferred obtaining CHILD->IMPLICIT_MERGEINFO, then get 4411 it now, allocating it in RESULT_POOL. If CHILD_INHERITS_PARENT is true 4412 then set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from 4413 PARENT->IMPLICIT_MERGEINFO, otherwise contact the repository. Use 4414 SCRATCH_POOL for all temporary allocations. 4415 4416 RA_SESSION is an RA session open to the repository that contains CHILD. 4417 It may be temporarily reparented by this function. 4418 4419 PARENT, CHILD, REVISION1, REVISION2 and 4420 CTX are all cascaded from the arguments of the same name in 4421 filter_merged_revisions() and the same conditions for that function 4422 hold here. */ 4423static svn_error_t * 4424ensure_implicit_mergeinfo(svn_client__merge_path_t *parent, 4425 svn_client__merge_path_t *child, 4426 svn_boolean_t child_inherits_parent, 4427 svn_revnum_t revision1, 4428 svn_revnum_t revision2, 4429 svn_ra_session_t *ra_session, 4430 svn_client_ctx_t *ctx, 4431 apr_pool_t *result_pool, 4432 apr_pool_t *scratch_pool) 4433{ 4434 /* If we haven't already found CHILD->IMPLICIT_MERGEINFO then 4435 contact the server to get it. */ 4436 4437 if (child->implicit_mergeinfo) 4438 return SVN_NO_ERROR; 4439 4440 if (child_inherits_parent) 4441 SVN_ERR(inherit_implicit_mergeinfo_from_parent(parent, 4442 child, 4443 revision1, 4444 revision2, 4445 ra_session, 4446 ctx, 4447 result_pool, 4448 scratch_pool)); 4449 else 4450 SVN_ERR(get_full_mergeinfo(NULL, 4451 &(child->implicit_mergeinfo), 4452 NULL, svn_mergeinfo_inherited, 4453 ra_session, child->abspath, 4454 MAX(revision1, revision2), 4455 MIN(revision1, revision2), 4456 ctx, result_pool, scratch_pool)); 4457 4458 return SVN_NO_ERROR; 4459} 4460 4461/* Helper for calculate_remaining_ranges(). 4462 4463 Initialize CHILD->REMAINING_RANGES to a rangelist representing the 4464 requested merge of REVISION1:REVISION2 from MERGEINFO_PATH to 4465 CHILD->ABSPATH. 4466 4467 For forward merges remove any ranges from CHILD->REMAINING_RANGES that 4468 have already been merged to CHILD->ABSPATH per TARGET_MERGEINFO or 4469 CHILD->IMPLICIT_MERGEINFO. For reverse merges remove any ranges from 4470 CHILD->REMAINING_RANGES that have not already been merged to CHILD->ABSPATH 4471 per TARGET_MERGEINFO or CHILD->IMPLICIT_MERGEINFO. If we have deferred 4472 obtaining CHILD->IMPLICIT_MERGEINFO and it is necessary to use it for 4473 these calculations, then get it from the server, allocating it in 4474 RESULT_POOL. 4475 4476 CHILD represents a working copy path which is the merge target or one of 4477 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise 4478 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. 4479 4480 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and 4481 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the 4482 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact 4483 the repository for CHILD->IMPLICIT_MERGEINFO. 4484 4485 NOTE: If PARENT is present then this function must have previously been 4486 called for PARENT, i.e. if populate_remaining_ranges() is calling this 4487 function for a set of svn_client__merge_path_t* the calls must be made 4488 in depth-first order. 4489 4490 MERGEINFO_PATH is the merge source relative to the repository root. 4491 4492 REVISION1 and REVISION2 describe the merge range requested from 4493 MERGEINFO_PATH. 4494 4495 TARGET_RANGELIST is the portion of CHILD->ABSPATH's explicit or inherited 4496 mergeinfo that intersects with the merge history described by 4497 MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2. TARGET_RANGELIST 4498 should be NULL if there is no explicit or inherited mergeinfo on 4499 CHILD->ABSPATH or an empty list if CHILD->ABSPATH has empty mergeinfo or 4500 explicit mergeinfo that exclusively describes non-intersecting history 4501 with MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2. 4502 4503 SCRATCH_POOL is used for all temporary allocations. 4504 4505 NOTE: This should only be called when honoring mergeinfo. 4506 4507 NOTE: Like calculate_remaining_ranges() if PARENT is present then this 4508 function must have previously been called for PARENT. 4509*/ 4510static svn_error_t * 4511filter_merged_revisions(svn_client__merge_path_t *parent, 4512 svn_client__merge_path_t *child, 4513 const char *mergeinfo_path, 4514 svn_rangelist_t *target_rangelist, 4515 svn_revnum_t revision1, 4516 svn_revnum_t revision2, 4517 svn_boolean_t child_inherits_implicit, 4518 svn_ra_session_t *ra_session, 4519 svn_client_ctx_t *ctx, 4520 apr_pool_t *result_pool, 4521 apr_pool_t *scratch_pool) 4522{ 4523 svn_rangelist_t *requested_rangelist, 4524 *target_implicit_rangelist, *explicit_rangelist; 4525 4526 /* Convert REVISION1 and REVISION2 to a rangelist. 4527 4528 Note: Talking about a requested merge range's inheritability 4529 doesn't make much sense, but as we are using svn_merge_range_t 4530 to describe it we need to pick *something*. Since all the 4531 rangelist manipulations in this function either don't consider 4532 inheritance by default or we are requesting that they don't (i.e. 4533 svn_rangelist_remove and svn_rangelist_intersect) then we could 4534 set the inheritability as FALSE, it won't matter either way. */ 4535 requested_rangelist = svn_rangelist__initialize(revision1, revision2, 4536 TRUE, scratch_pool); 4537 4538 /* Now filter out revisions that have already been merged to CHILD. */ 4539 4540 if (revision1 > revision2) /* This is a reverse merge. */ 4541 { 4542 svn_rangelist_t *added_rangelist, *deleted_rangelist; 4543 4544 /* The revert range and will need to be reversed for 4545 our svn_rangelist_* APIs to work properly. */ 4546 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool)); 4547 4548 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are 4549 already recorded as merged to target. */ 4550 if (target_rangelist) 4551 { 4552 /* Return the intersection of the revs which are both already 4553 represented by CHILD's explicit or inherited mergeinfo. 4554 4555 We don't consider inheritance when determining intersecting 4556 ranges. If we *did* consider inheritance, then our calculation 4557 would be wrong. For example, if the CHILD->REMAINING_RANGES is 4558 5:3 and TARGET_RANGELIST is r5* (non-inheritable) then the 4559 intersection would be r4. And that would be wrong as we clearly 4560 want to reverse merge both r4 and r5 in this case. Ignoring the 4561 ranges' inheritance results in an intersection of r4-5. 4562 4563 You might be wondering about CHILD's children, doesn't the above 4564 imply that we will reverse merge r4-5 from them? Nope, this is 4565 safe to do because any path whose parent has non-inheritable 4566 ranges is always considered a subtree with differing mergeinfo 4567 even if that path has no explicit mergeinfo prior to the 4568 merge -- See condition 3 in the doc string for 4569 merge.c:get_mergeinfo_paths(). */ 4570 SVN_ERR(svn_rangelist_intersect(&explicit_rangelist, 4571 target_rangelist, 4572 requested_rangelist, 4573 FALSE, scratch_pool)); 4574 } 4575 else 4576 { 4577 explicit_rangelist = 4578 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *)); 4579 } 4580 4581 /* Was any part of the requested reverse merge not accounted for in 4582 CHILD's explicit or inherited mergeinfo? */ 4583 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist, 4584 requested_rangelist, explicit_rangelist, 4585 FALSE, scratch_pool)); 4586 4587 if (deleted_rangelist->nelts == 0) 4588 { 4589 /* The whole of REVISION1:REVISION2 was represented in CHILD's 4590 explicit/inherited mergeinfo, allocate CHILD's remaining 4591 ranges in POOL and then we are done. */ 4592 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool)); 4593 child->remaining_ranges = svn_rangelist_dup(requested_rangelist, 4594 result_pool); 4595 } 4596 else /* We need to check CHILD's implicit mergeinfo. */ 4597 { 4598 svn_rangelist_t *implicit_rangelist; 4599 4600 SVN_ERR(ensure_implicit_mergeinfo(parent, 4601 child, 4602 child_inherits_implicit, 4603 revision1, 4604 revision2, 4605 ra_session, 4606 ctx, 4607 result_pool, 4608 scratch_pool)); 4609 4610 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo, 4611 mergeinfo_path); 4612 4613 if (target_implicit_rangelist) 4614 SVN_ERR(svn_rangelist_intersect(&implicit_rangelist, 4615 target_implicit_rangelist, 4616 requested_rangelist, 4617 FALSE, scratch_pool)); 4618 else 4619 implicit_rangelist = apr_array_make(scratch_pool, 0, 4620 sizeof(svn_merge_range_t *)); 4621 4622 SVN_ERR(svn_rangelist_merge2(implicit_rangelist, 4623 explicit_rangelist, scratch_pool, 4624 scratch_pool)); 4625 SVN_ERR(svn_rangelist_reverse(implicit_rangelist, scratch_pool)); 4626 child->remaining_ranges = svn_rangelist_dup(implicit_rangelist, 4627 result_pool); 4628 } 4629 } 4630 else /* This is a forward merge */ 4631 { 4632 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are 4633 NOT already recorded as merged to target. */ 4634 if (target_rangelist) 4635 { 4636 /* See earlier comment preceding svn_rangelist_intersect() for 4637 why we don't consider inheritance here. */ 4638 SVN_ERR(svn_rangelist_remove(&explicit_rangelist, 4639 target_rangelist, 4640 requested_rangelist, FALSE, 4641 scratch_pool)); 4642 } 4643 else 4644 { 4645 explicit_rangelist = svn_rangelist_dup(requested_rangelist, 4646 scratch_pool); 4647 } 4648 4649 if (explicit_rangelist->nelts == 0) 4650 { 4651 child->remaining_ranges = 4652 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *)); 4653 } 4654 else 4655/* ### TODO: Which evil shall we choose? 4656 ### 4657 ### If we allow all forward-merges not already found in recorded 4658 ### mergeinfo, we destroy the ability to, say, merge the whole of a 4659 ### branch to the trunk while automatically ignoring the revisions 4660 ### common to both. That's bad. 4661 ### 4662 ### If we allow only forward-merges not found in either recorded 4663 ### mergeinfo or implicit mergeinfo (natural history), then the 4664 ### previous scenario works great, but we can't reverse-merge a 4665 ### previous change made to our line of history and then remake it 4666 ### (because the reverse-merge will leave no mergeinfo trace, and 4667 ### the remake-it attempt will still find the original change in 4668 ### natural mergeinfo. But you know, that we happen to use 'merge' 4669 ### for revision undoing is somewhat unnatural anyway, so I'm 4670 ### finding myself having little interest in caring too much about 4671 ### this. That said, if we had a way of storing reverse merge 4672 ### ranges, we'd be in good shape either way. 4673*/ 4674#ifdef SVN_MERGE__ALLOW_ALL_FORWARD_MERGES_FROM_SELF 4675 { 4676 /* ### Don't consider implicit mergeinfo. */ 4677 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist, 4678 pool); 4679 } 4680#else 4681 { 4682 /* Based on CHILD's TARGET_MERGEINFO there are ranges to merge. 4683 Check CHILD's implicit mergeinfo to see if these remaining 4684 ranges are represented there. */ 4685 SVN_ERR(ensure_implicit_mergeinfo(parent, 4686 child, 4687 child_inherits_implicit, 4688 revision1, 4689 revision2, 4690 ra_session, 4691 ctx, 4692 result_pool, 4693 scratch_pool)); 4694 4695 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo, 4696 mergeinfo_path); 4697 if (target_implicit_rangelist) 4698 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 4699 target_implicit_rangelist, 4700 explicit_rangelist, 4701 FALSE, result_pool)); 4702 else 4703 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist, 4704 result_pool); 4705 } 4706#endif 4707 } 4708 4709 return SVN_NO_ERROR; 4710} 4711 4712/* Helper for do_file_merge and do_directory_merge (by way of 4713 populate_remaining_ranges() for the latter). 4714 4715 Determine what portions of SOURCE have already 4716 been merged to CHILD->ABSPATH and populate CHILD->REMAINING_RANGES with 4717 the ranges that still need merging. 4718 4719 SOURCE and CTX are all cascaded from the caller's arguments of the same 4720 names. Note that this means SOURCE adheres to the requirements noted in 4721 `MERGEINFO MERGE SOURCE NORMALIZATION'. 4722 4723 CHILD represents a working copy path which is the merge target or one of 4724 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise 4725 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. TARGET_MERGEINFO is 4726 the working mergeinfo on CHILD. 4727 4728 RA_SESSION is the session for the younger of SOURCE->loc1 and 4729 SOURCE->loc2. 4730 4731 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and 4732 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the 4733 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact 4734 the repository for CHILD->IMPLICIT_MERGEINFO. 4735 4736 If not null, IMPLICIT_SRC_GAP is the gap, if any, in the natural history 4737 of SOURCE, see merge_cmd_baton_t.implicit_src_gap. 4738 4739 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD and 4740 PARENT are made in RESULT_POOL. 4741 4742 NOTE: This should only be called when honoring mergeinfo. 4743 4744 NOTE: If PARENT is present then this function must have previously been 4745 called for PARENT, i.e. if populate_remaining_ranges() is calling this 4746 function for a set of svn_client__merge_path_t* the calls must be made 4747 in depth-first order. 4748 4749 NOTE: When performing reverse merges, return 4750 SVN_ERR_CLIENT_NOT_READY_TO_MERGE if both locations in SOURCE and 4751 CHILD->ABSPATH are all on the same line of history but CHILD->ABSPATH's 4752 base revision is older than the SOURCE->rev1:rev2 range, see comment re 4753 issue #2973 below. 4754*/ 4755static svn_error_t * 4756calculate_remaining_ranges(svn_client__merge_path_t *parent, 4757 svn_client__merge_path_t *child, 4758 const merge_source_t *source, 4759 svn_mergeinfo_t target_mergeinfo, 4760 const apr_array_header_t *implicit_src_gap, 4761 svn_boolean_t child_inherits_implicit, 4762 svn_ra_session_t *ra_session, 4763 svn_client_ctx_t *ctx, 4764 apr_pool_t *result_pool, 4765 apr_pool_t *scratch_pool) 4766{ 4767 const svn_client__pathrev_t *primary_src 4768 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1; 4769 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src, 4770 scratch_pool); 4771 /* Intersection of TARGET_MERGEINFO and the merge history 4772 described by SOURCE. */ 4773 svn_rangelist_t *target_rangelist; 4774 svn_revnum_t child_base_revision; 4775 4776 /* Since this function should only be called when honoring mergeinfo and 4777 * SOURCE adheres to the requirements noted in 'MERGEINFO MERGE SOURCE 4778 * NORMALIZATION', SOURCE must be 'ancestral'. */ 4779 SVN_ERR_ASSERT(source->ancestral); 4780 4781 /* Determine which of the requested ranges to consider merging... */ 4782 4783 /* Set TARGET_RANGELIST to the portion of TARGET_MERGEINFO that refers 4784 to SOURCE (excluding any gap in SOURCE): first get all ranges from 4785 TARGET_MERGEINFO that refer to the path of SOURCE, and then prune 4786 any ranges that lie in the gap in SOURCE. 4787 4788 ### [JAF] In fact, that may still leave some ranges that lie entirely 4789 outside the range of SOURCE; it seems we don't care about that. */ 4790 if (target_mergeinfo) 4791 target_rangelist = svn_hash_gets(target_mergeinfo, mergeinfo_path); 4792 else 4793 target_rangelist = NULL; 4794 if (implicit_src_gap && target_rangelist) 4795 { 4796 /* Remove any mergeinfo referring to the 'gap' in SOURCE, as that 4797 mergeinfo doesn't really refer to SOURCE at all but instead 4798 refers to locations that are non-existent or on a different 4799 line of history. (Issue #3242.) */ 4800 SVN_ERR(svn_rangelist_remove(&target_rangelist, 4801 implicit_src_gap, target_rangelist, 4802 FALSE, result_pool)); 4803 } 4804 4805 /* Initialize CHILD->REMAINING_RANGES and filter out revisions already 4806 merged (or, in the case of reverse merges, ranges not yet merged). */ 4807 SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path, 4808 target_rangelist, 4809 source->loc1->rev, source->loc2->rev, 4810 child_inherits_implicit, 4811 ra_session, ctx, result_pool, 4812 scratch_pool)); 4813 4814 /* Issue #2973 -- from the continuing series of "Why, since the advent of 4815 merge tracking, allowing merges into mixed rev and locally modified 4816 working copies isn't simple and could be considered downright evil". 4817 4818 If reverse merging a range to the WC path represented by CHILD, from 4819 that path's own history, where the path inherits no locally modified 4820 mergeinfo from its WC parents (i.e. there is no uncommitted merge to 4821 the WC), and the path's base revision is older than the range, then 4822 the merge will always be a no-op. This is because we only allow reverse 4823 merges of ranges in the path's explicit or natural mergeinfo and a 4824 reverse merge from the path's future history obviously isn't going to be 4825 in either, hence the no-op. 4826 4827 The problem is two-fold. First, in a mixed rev WC, the change we 4828 want to revert might actually be to some child of the target path 4829 which is at a younger base revision. Sure, we can merge directly 4830 to that child or update the WC or even use --ignore-ancestry and then 4831 successfully run the reverse merge, but that gets to the second 4832 problem: Those courses of action are not very obvious. Before 1.5 if 4833 a user committed a change that didn't touch the commit target, then 4834 immediately decided to revert that change via a reverse merge it would 4835 just DTRT. But with the advent of merge tracking the user gets a no-op. 4836 4837 So in the name of user friendliness, return an error suggesting a helpful 4838 course of action. 4839 */ 4840 SVN_ERR(svn_wc__node_get_base(NULL, &child_base_revision, 4841 NULL, NULL, NULL, NULL, 4842 ctx->wc_ctx, child->abspath, 4843 TRUE /* ignore_enoent */, 4844 scratch_pool, scratch_pool)); 4845 /* If CHILD has no base revision then it hasn't been committed yet, so it 4846 can't have any "future" history. */ 4847 if (SVN_IS_VALID_REVNUM(child_base_revision) 4848 && ((child->remaining_ranges)->nelts == 0) /* Inoperative merge */ 4849 && (source->loc2->rev < source->loc1->rev) /* Reverse merge */ 4850 && (child_base_revision <= source->loc2->rev)) /* From CHILD's future */ 4851 { 4852 /* Hmmm, an inoperative reverse merge from the "future". If it is 4853 from our own future return a helpful error. */ 4854 svn_error_t *err; 4855 svn_client__pathrev_t *start_loc; 4856 4857 err = svn_client__repos_location(&start_loc, 4858 ra_session, 4859 source->loc1, 4860 child_base_revision, 4861 ctx, scratch_pool, scratch_pool); 4862 if (err) 4863 { 4864 if (err->apr_err == SVN_ERR_FS_NOT_FOUND 4865 || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) 4866 svn_error_clear(err); 4867 else 4868 return svn_error_trace(err); 4869 } 4870 else 4871 { 4872 const char *url; 4873 4874 SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath, 4875 scratch_pool, scratch_pool)); 4876 if (strcmp(start_loc->url, url) == 0) 4877 return svn_error_create(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL, 4878 _("Cannot reverse-merge a range from a " 4879 "path's own future history; try " 4880 "updating first")); 4881 } 4882 } 4883 4884 return SVN_NO_ERROR; 4885} 4886 4887/* Helper for populate_remaining_ranges(). 4888 4889 SOURCE is cascaded from the arguments of the same name in 4890 populate_remaining_ranges(). 4891 4892 Note: The following comments assume a forward merge, i.e. 4893 SOURCE->loc1->rev < SOURCE->loc2->rev. If this is a reverse merge then 4894 all the following comments still apply, but with SOURCE->loc1 switched 4895 with SOURCE->loc2. 4896 4897 Like populate_remaining_ranges(), SOURCE must adhere to the restrictions 4898 documented in 'MERGEINFO MERGE SOURCE NORMALIZATION'. These restrictions 4899 allow for a *single* gap in SOURCE, GAP_REV1:GAP_REV2 exclusive:inclusive 4900 (where SOURCE->loc1->rev == GAP_REV1 <= GAP_REV2 < SOURCE->loc2->rev), 4901 if SOURCE->loc2->url@(GAP_REV2+1) was copied from SOURCE->loc1. If such 4902 a gap exists, set *GAP_START and *GAP_END to the starting and ending 4903 revisions of the gap. Otherwise set both to SVN_INVALID_REVNUM. 4904 4905 For example, if the natural history of URL@2:URL@9 is 'trunk/:2,7-9' this 4906 would indicate that trunk@7 was copied from trunk@2. This function would 4907 return GAP_START:GAP_END of 2:6 in this case. Note that a path 'trunk' 4908 might exist at r3-6, but it would not be on the same line of history as 4909 trunk@9. 4910 4911 ### GAP_START is basically redundant, as (if there is a gap at all) it is 4912 necessarily the older revision of SOURCE. 4913 4914 RA_SESSION is an open RA session to the repository in which SOURCE lives. 4915*/ 4916static svn_error_t * 4917find_gaps_in_merge_source_history(svn_revnum_t *gap_start, 4918 svn_revnum_t *gap_end, 4919 const merge_source_t *source, 4920 svn_ra_session_t *ra_session, 4921 svn_client_ctx_t *ctx, 4922 apr_pool_t *scratch_pool) 4923{ 4924 svn_mergeinfo_t implicit_src_mergeinfo; 4925 svn_revnum_t old_rev = MIN(source->loc1->rev, source->loc2->rev); 4926 const svn_client__pathrev_t *primary_src 4927 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1; 4928 const char *merge_src_fspath = svn_client__pathrev_fspath(primary_src, 4929 scratch_pool); 4930 svn_rangelist_t *rangelist; 4931 4932 SVN_ERR_ASSERT(source->ancestral); 4933 4934 /* Start by assuming there is no gap. */ 4935 *gap_start = *gap_end = SVN_INVALID_REVNUM; 4936 4937 /* Easy out: There can't be a gap between adjacent revisions. */ 4938 if (labs(source->loc1->rev - source->loc2->rev) == 1) 4939 return SVN_NO_ERROR; 4940 4941 /* Get SOURCE as mergeinfo. */ 4942 SVN_ERR(svn_client__get_history_as_mergeinfo(&implicit_src_mergeinfo, NULL, 4943 primary_src, 4944 primary_src->rev, old_rev, 4945 ra_session, 4946 ctx, scratch_pool)); 4947 4948 rangelist = svn_hash_gets(implicit_src_mergeinfo, merge_src_fspath); 4949 4950 if (!rangelist) /* ### Can we ever not find a rangelist? */ 4951 return SVN_NO_ERROR; 4952 4953 /* A gap in natural history can result from either a copy or 4954 a rename. If from a copy then history as mergeinfo will look 4955 something like this: 4956 4957 '/trunk:X,Y-Z' 4958 4959 If from a rename it will look like this: 4960 4961 '/trunk_old_name:X' 4962 '/trunk_new_name:Y-Z' 4963 4964 In both cases the gap, if it exists, is M-N, where M = X + 1 and 4965 N = Y - 1. 4966 4967 Note that per the rules of 'MERGEINFO MERGE SOURCE NORMALIZATION' we 4968 should never have multiple gaps, e.g. if we see anything like the 4969 following then something is quite wrong: 4970 4971 '/trunk_old_name:A,B-C' 4972 '/trunk_new_name:D-E' 4973 */ 4974 4975 if (rangelist->nelts > 1) /* Copy */ 4976 { 4977 const svn_merge_range_t *gap; 4978 /* As mentioned above, multiple gaps *shouldn't* be possible. */ 4979 SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1); 4980 4981 gap = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1, 4982 const svn_merge_range_t *); 4983 4984 *gap_start = MIN(source->loc1->rev, source->loc2->rev); 4985 *gap_end = gap->start; 4986 4987 /* ### Issue #4132: 4988 ### This assertion triggers in merge_tests.py svnmucc_abuse_1() 4989 ### when a node is replaced by an older copy of itself. 4990 4991 BH: I think we should review this and the 'rename' case to find 4992 out which behavior we really want, and if we can really 4993 determine what happened this way. */ 4994 SVN_ERR_ASSERT(*gap_start < *gap_end); 4995 } 4996 else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */ 4997 { 4998 svn_rangelist_t *requested_rangelist = 4999 svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev), 5000 MAX(source->loc1->rev, source->loc2->rev), 5001 TRUE, scratch_pool); 5002 svn_rangelist_t *implicit_rangelist = 5003 apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *)); 5004 svn_rangelist_t *gap_rangelist; 5005 5006 SVN_ERR(svn_rangelist__merge_many(implicit_rangelist, 5007 implicit_src_mergeinfo, 5008 scratch_pool, scratch_pool)); 5009 SVN_ERR(svn_rangelist_remove(&gap_rangelist, implicit_rangelist, 5010 requested_rangelist, FALSE, 5011 scratch_pool)); 5012 5013 /* If there is anything left it is the gap. */ 5014 if (gap_rangelist->nelts) 5015 { 5016 svn_merge_range_t *gap_range = 5017 APR_ARRAY_IDX(gap_rangelist, 0, svn_merge_range_t *); 5018 5019 *gap_start = gap_range->start; 5020 *gap_end = gap_range->end; 5021 } 5022 } 5023 5024 SVN_ERR_ASSERT(*gap_start == MIN(source->loc1->rev, source->loc2->rev) 5025 || (*gap_start == SVN_INVALID_REVNUM 5026 && *gap_end == SVN_INVALID_REVNUM)); 5027 return SVN_NO_ERROR; 5028} 5029 5030/* Helper for do_directory_merge(). 5031 5032 For each (svn_client__merge_path_t *) child in CHILDREN_WITH_MERGEINFO, 5033 populate that child's 'remaining_ranges' list with (### ... what?), 5034 and populate that child's 'implicit_mergeinfo' with its implicit 5035 mergeinfo (natural history). CHILDREN_WITH_MERGEINFO is expected 5036 to be sorted in depth first order and each child must be processed in 5037 that order. The inheritability of all calculated ranges is TRUE. 5038 5039 If mergeinfo is being honored (based on MERGE_B -- see HONOR_MERGEINFO() 5040 for how this is determined), this function will actually try to be 5041 intelligent about populating remaining_ranges list. Otherwise, it 5042 will claim that each child has a single remaining range, from 5043 SOURCE->rev1, to SOURCE->rev2. 5044 ### We also take the short-cut if doing record-only. Why? 5045 5046 SCRATCH_POOL is used for all temporary allocations. Changes to 5047 CHILDREN_WITH_MERGEINFO are made in RESULT_POOL. 5048 5049 Note that if SOURCE->rev1 > SOURCE->rev2, then each child's remaining_ranges 5050 member does not adhere to the API rules for rangelists described in 5051 svn_mergeinfo.h -- See svn_client__merge_path_t. 5052 5053 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements 5054 around SOURCE. 5055*/ 5056static svn_error_t * 5057populate_remaining_ranges(apr_array_header_t *children_with_mergeinfo, 5058 const merge_source_t *source, 5059 svn_ra_session_t *ra_session, 5060 merge_cmd_baton_t *merge_b, 5061 apr_pool_t *result_pool, 5062 apr_pool_t *scratch_pool) 5063{ 5064 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5065 int i; 5066 svn_revnum_t gap_start, gap_end; 5067 5068 /* If we aren't honoring mergeinfo or this is a --record-only merge, 5069 we'll make quick work of this by simply adding dummy SOURCE->rev1:rev2 5070 ranges for all children. */ 5071 if (! HONOR_MERGEINFO(merge_b) || merge_b->record_only) 5072 { 5073 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5074 { 5075 svn_client__merge_path_t *child = 5076 APR_ARRAY_IDX(children_with_mergeinfo, i, 5077 svn_client__merge_path_t *); 5078 5079 svn_pool_clear(iterpool); 5080 5081 /* Issue #3646 'record-only merges create self-referential 5082 mergeinfo'. Get the merge target's implicit mergeinfo (natural 5083 history). We'll use it later to avoid setting self-referential 5084 mergeinfo -- see filter_natural_history_from_mergeinfo(). */ 5085 if (i == 0) /* First item is always the merge target. */ 5086 { 5087 SVN_ERR(get_full_mergeinfo(NULL, /* child->pre_merge_mergeinfo */ 5088 &(child->implicit_mergeinfo), 5089 NULL, /* child->inherited_mergeinfo */ 5090 svn_mergeinfo_inherited, ra_session, 5091 child->abspath, 5092 MAX(source->loc1->rev, 5093 source->loc2->rev), 5094 MIN(source->loc1->rev, 5095 source->loc2->rev), 5096 merge_b->ctx, result_pool, 5097 iterpool)); 5098 } 5099 else 5100 { 5101 /* Issue #3443 - Subtrees of the merge target can inherit 5102 their parent's implicit mergeinfo in most cases. */ 5103 svn_client__merge_path_t *parent 5104 = find_nearest_ancestor(children_with_mergeinfo, 5105 FALSE, child->abspath); 5106 svn_boolean_t child_inherits_implicit; 5107 5108 /* If CHILD is a subtree then its parent must be in 5109 CHILDREN_WITH_MERGEINFO, see the global comment 5110 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 5111 SVN_ERR_ASSERT(parent); 5112 5113 child_inherits_implicit = (parent && !child->switched); 5114 SVN_ERR(ensure_implicit_mergeinfo(parent, child, 5115 child_inherits_implicit, 5116 source->loc1->rev, 5117 source->loc2->rev, 5118 ra_session, merge_b->ctx, 5119 result_pool, iterpool)); 5120 } 5121 5122 child->remaining_ranges = svn_rangelist__initialize(source->loc1->rev, 5123 source->loc2->rev, 5124 TRUE, 5125 result_pool); 5126 } 5127 svn_pool_destroy(iterpool); 5128 return SVN_NO_ERROR; 5129 } 5130 5131 /* If, in the merge source's history, there was a copy from an older 5132 revision, then SOURCE->loc2->url won't exist at some range M:N, where 5133 SOURCE->loc1->rev < M < N < SOURCE->loc2->rev. The rules of 'MERGEINFO 5134 MERGE SOURCE NORMALIZATION' allow this, but we must ignore these gaps 5135 when calculating what ranges remain to be merged from SOURCE. If we 5136 don't and try to merge any part of SOURCE->loc2->url@M:N we would 5137 break the editor since no part of that actually exists. See 5138 http://svn.haxx.se/dev/archive-2008-11/0618.shtml. 5139 5140 Find the gaps in the merge target's history, if any. Eventually 5141 we will adjust CHILD->REMAINING_RANGES such that we don't describe 5142 non-existent paths to the editor. */ 5143 SVN_ERR(find_gaps_in_merge_source_history(&gap_start, &gap_end, 5144 source, 5145 ra_session, merge_b->ctx, 5146 iterpool)); 5147 5148 /* Stash any gap in the merge command baton, we'll need it later when 5149 recording mergeinfo describing this merge. */ 5150 if (SVN_IS_VALID_REVNUM(gap_start) && SVN_IS_VALID_REVNUM(gap_end)) 5151 merge_b->implicit_src_gap = svn_rangelist__initialize(gap_start, gap_end, 5152 TRUE, result_pool); 5153 5154 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5155 { 5156 svn_client__merge_path_t *child = 5157 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5158 const char *child_repos_path 5159 = svn_dirent_skip_ancestor(merge_b->target->abspath, child->abspath); 5160 merge_source_t child_source; 5161 svn_client__merge_path_t *parent = NULL; 5162 svn_boolean_t child_inherits_implicit; 5163 5164 svn_pool_clear(iterpool); 5165 5166 /* If the path is absent don't do subtree merge either. */ 5167 SVN_ERR_ASSERT(child); 5168 if (child->absent) 5169 continue; 5170 5171 SVN_ERR_ASSERT(child_repos_path != NULL); 5172 child_source.loc1 = svn_client__pathrev_join_relpath( 5173 source->loc1, child_repos_path, iterpool); 5174 child_source.loc2 = svn_client__pathrev_join_relpath( 5175 source->loc2, child_repos_path, iterpool); 5176 /* ### Is the child 'ancestral' over the same revision range? It's 5177 * not necessarily true that a child is 'ancestral' if the parent is, 5178 * nor that it's not if the parent is not. However, here we claim 5179 * that it is. Before we had this 'ancestral' field that we need to 5180 * set explicitly, the claim was implicit. Either way, the impact is 5181 * that we might pass calculate_remaining_ranges() a source that is 5182 * not in fact 'ancestral' (despite its 'ancestral' field being true), 5183 * contrary to its doc-string. */ 5184 child_source.ancestral = source->ancestral; 5185 5186 /* Get the explicit/inherited mergeinfo for CHILD. If CHILD is the 5187 merge target then also get its implicit mergeinfo. Otherwise defer 5188 this until we know it is absolutely necessary, since it requires an 5189 expensive round trip communication with the server. */ 5190 SVN_ERR(get_full_mergeinfo( 5191 child->pre_merge_mergeinfo ? NULL : &(child->pre_merge_mergeinfo), 5192 /* Get implicit only for merge target. */ 5193 (i == 0) ? &(child->implicit_mergeinfo) : NULL, 5194 &(child->inherited_mergeinfo), 5195 svn_mergeinfo_inherited, ra_session, 5196 child->abspath, 5197 MAX(source->loc1->rev, source->loc2->rev), 5198 MIN(source->loc1->rev, source->loc2->rev), 5199 merge_b->ctx, result_pool, iterpool)); 5200 5201 /* If CHILD isn't the merge target find its parent. */ 5202 if (i > 0) 5203 { 5204 parent = find_nearest_ancestor(children_with_mergeinfo, 5205 FALSE, child->abspath); 5206 /* If CHILD is a subtree then its parent must be in 5207 CHILDREN_WITH_MERGEINFO, see the global comment 5208 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 5209 SVN_ERR_ASSERT(parent); 5210 } 5211 5212 /* Issue #3443 - Can CHILD inherit PARENT's implicit mergeinfo, saving 5213 us from having to ask the repos? The only time we can't do this is if 5214 CHILD is the merge target and so there is no PARENT to inherit from 5215 or if CHILD is the root of a switched subtree, in which case PARENT 5216 exists but is not CHILD's repository parent. */ 5217 child_inherits_implicit = (parent && !child->switched); 5218 5219 SVN_ERR(calculate_remaining_ranges(parent, child, 5220 &child_source, 5221 child->pre_merge_mergeinfo, 5222 merge_b->implicit_src_gap, 5223 child_inherits_implicit, 5224 ra_session, 5225 merge_b->ctx, result_pool, 5226 iterpool)); 5227 5228 /* Deal with any gap in SOURCE's natural history. 5229 5230 If the gap is a proper subset of CHILD->REMAINING_RANGES then we can 5231 safely ignore it since we won't describe this path/rev pair. 5232 5233 If the gap exactly matches or is a superset of a range in 5234 CHILD->REMAINING_RANGES then we must remove that range so we don't 5235 attempt to describe non-existent paths via the reporter, this will 5236 break the editor and our merge. 5237 5238 If the gap adjoins or overlaps a range in CHILD->REMAINING_RANGES 5239 then we must *add* the gap so we span the missing revisions. */ 5240 if (child->remaining_ranges->nelts 5241 && merge_b->implicit_src_gap) 5242 { 5243 int j; 5244 svn_boolean_t proper_subset = FALSE; 5245 svn_boolean_t overlaps_or_adjoins = FALSE; 5246 5247 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 5248 so it will work with the svn_rangelist_* APIs below. */ 5249 if (source->loc1->rev > source->loc2->rev) 5250 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 5251 5252 for (j = 0; j < child->remaining_ranges->nelts; j++) 5253 { 5254 svn_merge_range_t *range 5255 = APR_ARRAY_IDX(child->remaining_ranges, j, svn_merge_range_t *); 5256 5257 if ((range->start <= gap_start && gap_end < range->end) 5258 || (range->start < gap_start && gap_end <= range->end)) 5259 { 5260 proper_subset = TRUE; 5261 break; 5262 } 5263 else if ((gap_start == range->start) && (range->end == gap_end)) 5264 { 5265 break; 5266 } 5267 else if (gap_start <= range->end && range->start <= gap_end) 5268 /* intersect */ 5269 { 5270 overlaps_or_adjoins = TRUE; 5271 break; 5272 } 5273 } 5274 5275 if (!proper_subset) 5276 { 5277 /* We need to make adjustments. Remove from, or add the gap 5278 to, CHILD->REMAINING_RANGES as appropriate. */ 5279 5280 if (overlaps_or_adjoins) 5281 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 5282 merge_b->implicit_src_gap, 5283 result_pool, iterpool)); 5284 else /* equals == TRUE */ 5285 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 5286 merge_b->implicit_src_gap, 5287 child->remaining_ranges, FALSE, 5288 result_pool)); 5289 } 5290 5291 if (source->loc1->rev > source->loc2->rev) /* Reverse merge */ 5292 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 5293 } 5294 } 5295 5296 svn_pool_destroy(iterpool); 5297 return SVN_NO_ERROR; 5298} 5299 5300 5301/*-----------------------------------------------------------------------*/ 5302 5303/*** Other Helper Functions ***/ 5304 5305/* Calculate the new mergeinfo for the target tree rooted at TARGET_ABSPATH 5306 based on MERGES (a mapping of absolute WC paths to rangelists representing 5307 a merge from the source SOURCE_FSPATH). 5308 5309 If RESULT_CATALOG is NULL, then record the new mergeinfo in the WC (at, 5310 and possibly below, TARGET_ABSPATH). 5311 5312 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the 5313 WC, but instead record it in RESULT_CATALOG, where the keys are absolute 5314 working copy paths and the values are the new mergeinfos for each. 5315 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was 5316 created in. */ 5317static svn_error_t * 5318update_wc_mergeinfo(svn_mergeinfo_catalog_t result_catalog, 5319 const char *target_abspath, 5320 const char *source_fspath, 5321 apr_hash_t *merges, 5322 svn_boolean_t is_rollback, 5323 svn_client_ctx_t *ctx, 5324 apr_pool_t *scratch_pool) 5325{ 5326 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5327 apr_hash_index_t *hi; 5328 5329 /* Combine the mergeinfo for the revision range just merged into 5330 the WC with its on-disk mergeinfo. */ 5331 for (hi = apr_hash_first(scratch_pool, merges); hi; hi = apr_hash_next(hi)) 5332 { 5333 const char *local_abspath = apr_hash_this_key(hi); 5334 svn_rangelist_t *ranges = apr_hash_this_val(hi); 5335 svn_rangelist_t *rangelist; 5336 svn_error_t *err; 5337 const char *local_abspath_rel_to_target; 5338 const char *fspath; 5339 svn_mergeinfo_t mergeinfo; 5340 5341 svn_pool_clear(iterpool); 5342 5343 /* As some of the merges may've changed the WC's mergeinfo, get 5344 a fresh copy before using it to update the WC's mergeinfo. */ 5345 err = svn_client__parse_mergeinfo(&mergeinfo, ctx->wc_ctx, 5346 local_abspath, iterpool, iterpool); 5347 5348 /* If a directory PATH was skipped because it is missing or was 5349 obstructed by an unversioned item then there's nothing we can 5350 do with that, so skip it. */ 5351 if (err) 5352 { 5353 if (err->apr_err == SVN_ERR_WC_NOT_LOCKED 5354 || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 5355 { 5356 svn_error_clear(err); 5357 continue; 5358 } 5359 else 5360 { 5361 return svn_error_trace(err); 5362 } 5363 } 5364 5365 /* If we are attempting to set empty revision range override mergeinfo 5366 on a path with no explicit mergeinfo, we first need the 5367 mergeinfo that path inherits. */ 5368 if (mergeinfo == NULL && ranges->nelts == 0) 5369 { 5370 SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, NULL, 5371 svn_mergeinfo_nearest_ancestor, 5372 local_abspath, NULL, NULL, 5373 FALSE, ctx, iterpool, iterpool)); 5374 } 5375 5376 if (mergeinfo == NULL) 5377 mergeinfo = apr_hash_make(iterpool); 5378 5379 local_abspath_rel_to_target = svn_dirent_skip_ancestor(target_abspath, 5380 local_abspath); 5381 SVN_ERR_ASSERT(local_abspath_rel_to_target != NULL); 5382 fspath = svn_fspath__join(source_fspath, 5383 local_abspath_rel_to_target, 5384 iterpool); 5385 rangelist = svn_hash_gets(mergeinfo, fspath); 5386 if (rangelist == NULL) 5387 rangelist = apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *)); 5388 5389 if (is_rollback) 5390 { 5391 ranges = svn_rangelist_dup(ranges, iterpool); 5392 SVN_ERR(svn_rangelist_reverse(ranges, iterpool)); 5393 SVN_ERR(svn_rangelist_remove(&rangelist, ranges, rangelist, 5394 FALSE, 5395 iterpool)); 5396 } 5397 else 5398 { 5399 SVN_ERR(svn_rangelist_merge2(rangelist, ranges, iterpool, iterpool)); 5400 } 5401 /* Update the mergeinfo by adjusting the path's rangelist. */ 5402 svn_hash_sets(mergeinfo, fspath, rangelist); 5403 5404 if (is_rollback && apr_hash_count(mergeinfo) == 0) 5405 mergeinfo = NULL; 5406 5407 svn_mergeinfo__remove_empty_rangelists(mergeinfo, scratch_pool); 5408 5409 if (result_catalog) 5410 { 5411 svn_mergeinfo_t existing_mergeinfo = 5412 svn_hash_gets(result_catalog, local_abspath); 5413 apr_pool_t *result_catalog_pool = apr_hash_pool_get(result_catalog); 5414 5415 if (existing_mergeinfo) 5416 SVN_ERR(svn_mergeinfo_merge2(mergeinfo, existing_mergeinfo, 5417 result_catalog_pool, scratch_pool)); 5418 svn_hash_sets(result_catalog, 5419 apr_pstrdup(result_catalog_pool, local_abspath), 5420 svn_mergeinfo_dup(mergeinfo, result_catalog_pool)); 5421 } 5422 else 5423 { 5424 err = svn_client__record_wc_mergeinfo(local_abspath, mergeinfo, 5425 TRUE, ctx, iterpool); 5426 5427 if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) 5428 { 5429 /* PATH isn't just missing, it's not even versioned as far 5430 as this working copy knows. But it was included in 5431 MERGES, which means that the server knows about it. 5432 Likely we don't have access to the source due to authz 5433 restrictions. For now just clear the error and 5434 continue... 5435 5436 ### TODO: Set non-inheritable mergeinfo on PATH's immediate 5437 ### parent and normal mergeinfo on PATH's siblings which we 5438 ### do have access to. */ 5439 svn_error_clear(err); 5440 } 5441 else 5442 SVN_ERR(err); 5443 } 5444 } 5445 5446 svn_pool_destroy(iterpool); 5447 return SVN_NO_ERROR; 5448} 5449 5450/* Helper for record_mergeinfo_for_dir_merge(). 5451 5452 Record override mergeinfo on any paths skipped during a merge. 5453 5454 Set empty mergeinfo on each path in MERGE_B->SKIPPED_ABSPATHS so the path 5455 does not incorrectly inherit mergeinfo that will later be describing 5456 the merge. 5457 5458 MERGEINFO_PATH and MERGE_B are cascaded from 5459 arguments of the same name in the caller. 5460 5461 IS_ROLLBACK is true if the caller is recording a reverse merge and false 5462 otherwise. RANGELIST is the set of revisions being merged from 5463 MERGEINFO_PATH to MERGE_B->target. */ 5464static svn_error_t * 5465record_skips_in_mergeinfo(const char *mergeinfo_path, 5466 const svn_rangelist_t *rangelist, 5467 svn_boolean_t is_rollback, 5468 merge_cmd_baton_t *merge_b, 5469 apr_pool_t *scratch_pool) 5470{ 5471 apr_hash_index_t *hi; 5472 apr_hash_t *merges; 5473 apr_size_t nbr_skips = apr_hash_count(merge_b->skipped_abspaths); 5474 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5475 5476 if (nbr_skips == 0) 5477 return SVN_NO_ERROR; 5478 5479 merges = apr_hash_make(scratch_pool); 5480 5481 /* Override the mergeinfo for child paths which weren't actually merged. */ 5482 for (hi = apr_hash_first(scratch_pool, merge_b->skipped_abspaths); hi; 5483 hi = apr_hash_next(hi)) 5484 { 5485 const char *skipped_abspath = apr_hash_this_key(hi); 5486 svn_wc_notify_state_t obstruction_state; 5487 5488 svn_pool_clear(iterpool); 5489 5490 /* Before we override, make sure this is a versioned path, it might 5491 be an external or missing from disk due to authz restrictions. */ 5492 SVN_ERR(perform_obstruction_check(&obstruction_state, NULL, NULL, 5493 NULL, NULL, 5494 merge_b, skipped_abspath, 5495 iterpool)); 5496 if (obstruction_state == svn_wc_notify_state_obstructed 5497 || obstruction_state == svn_wc_notify_state_missing) 5498 continue; 5499 5500 /* Add an empty range list for this path. 5501 5502 ### TODO: This works fine for a file path skipped because it is 5503 ### missing as long as the file's parent directory is present. 5504 ### But missing directory paths skipped are not handled yet, 5505 ### see issue #2915. 5506 5507 ### TODO: An empty range is fine if the skipped path doesn't 5508 ### inherit any mergeinfo from a parent, but if it does 5509 ### we need to account for that. See issue #3440 5510 ### https://issues.apache.org/jira/browse/SVN-3440. */ 5511 svn_hash_sets(merges, skipped_abspath, 5512 apr_array_make(scratch_pool, 0, 5513 sizeof(svn_merge_range_t *))); 5514 5515 /* if (nbr_skips < notify_b->nbr_notifications) 5516 ### Use RANGELIST as the mergeinfo for all children of 5517 ### this path which were not also explicitly 5518 ### skipped? */ 5519 } 5520 SVN_ERR(update_wc_mergeinfo(NULL, merge_b->target->abspath, 5521 mergeinfo_path, merges, 5522 is_rollback, merge_b->ctx, iterpool)); 5523 svn_pool_destroy(iterpool); 5524 return SVN_NO_ERROR; 5525} 5526 5527/* Data for reporting when a merge aborted because of raising conflicts. 5528 */ 5529typedef struct single_range_conflict_report_t 5530{ 5531 /* What sub-range of the requested source raised conflicts? 5532 * The 'inheritable' flag is ignored. */ 5533 merge_source_t *conflicted_range; 5534 /* What sub-range of the requested source remains to be merged? 5535 * NULL if no more. The 'inheritable' flag is ignored. */ 5536 merge_source_t *remaining_source; 5537 5538} single_range_conflict_report_t; 5539 5540/* Create a single_range_conflict_report_t, containing deep copies of 5541 * CONFLICTED_RANGE and REMAINING_SOURCE, allocated in RESULT_POOL. */ 5542static single_range_conflict_report_t * 5543single_range_conflict_report_create(const merge_source_t *conflicted_range, 5544 const merge_source_t *remaining_source, 5545 apr_pool_t *result_pool) 5546{ 5547 single_range_conflict_report_t *report 5548 = apr_palloc(result_pool, sizeof(*report)); 5549 5550 assert(conflicted_range != NULL); 5551 5552 report->conflicted_range = merge_source_dup(conflicted_range, result_pool); 5553 report->remaining_source 5554 = remaining_source ? merge_source_dup(remaining_source, result_pool) 5555 : NULL; 5556 return report; 5557} 5558 5559/* Return a new svn_client__conflict_report_t containing deep copies of the 5560 * parameters, allocated in RESULT_POOL. */ 5561static svn_client__conflict_report_t * 5562conflict_report_create(const char *target_abspath, 5563 const merge_source_t *conflicted_range, 5564 svn_boolean_t was_last_range, 5565 apr_pool_t *result_pool) 5566{ 5567 svn_client__conflict_report_t *report = apr_palloc(result_pool, 5568 sizeof(*report)); 5569 5570 report->target_abspath = apr_pstrdup(result_pool, target_abspath); 5571 report->conflicted_range = merge_source_dup(conflicted_range, result_pool); 5572 report->was_last_range = was_last_range; 5573 return report; 5574} 5575 5576/* Return a deep copy of REPORT, allocated in RESULT_POOL. */ 5577static svn_client__conflict_report_t * 5578conflict_report_dup(const svn_client__conflict_report_t *report, 5579 apr_pool_t *result_pool) 5580{ 5581 svn_client__conflict_report_t *new = apr_pmemdup(result_pool, report, 5582 sizeof(*new)); 5583 5584 new->target_abspath = apr_pstrdup(result_pool, report->target_abspath); 5585 new->conflicted_range = merge_source_dup(report->conflicted_range, 5586 result_pool); 5587 return new; 5588} 5589 5590svn_error_t * 5591svn_client__make_merge_conflict_error(svn_client__conflict_report_t *report, 5592 apr_pool_t *scratch_pool) 5593{ 5594 assert(!report || svn_dirent_is_absolute(report->target_abspath)); 5595 5596 if (report && ! report->was_last_range) 5597 { 5598 svn_error_t *err = svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, 5599 _("One or more conflicts were produced while merging r%ld:%ld into\n" 5600 "'%s' --\n" 5601 "resolve all conflicts and rerun the merge to apply the remaining\n" 5602 "unmerged revisions"), 5603 report->conflicted_range->loc1->rev, report->conflicted_range->loc2->rev, 5604 svn_dirent_local_style(report->target_abspath, scratch_pool)); 5605 assert(report->conflicted_range->loc1->rev != report->conflicted_range->loc2->rev); /* ### is a valid case in a 2-URL merge */ 5606 return err; 5607 } 5608 return SVN_NO_ERROR; 5609} 5610 5611/* Helper for do_directory_merge(). 5612 5613 TARGET_WCPATH is a directory and CHILDREN_WITH_MERGEINFO is filled 5614 with paths (svn_client__merge_path_t *) arranged in depth first order, 5615 which have mergeinfo set on them or meet one of the other criteria 5616 defined in get_mergeinfo_paths(). Remove any paths absent from disk 5617 from CHILDREN_WITH_MERGEINFO which are equal to 5618 or are descendants of TARGET_WCPATH by setting those children to NULL. */ 5619static svn_error_t * 5620remove_absent_children(const char *target_wcpath, 5621 apr_array_header_t *children_with_mergeinfo) 5622{ 5623 /* Before we try to override mergeinfo for skipped paths, make sure 5624 the path isn't absent due to authz restrictions, because there's 5625 nothing we can do about those. */ 5626 int i; 5627 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5628 { 5629 svn_client__merge_path_t *child = 5630 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5631 if (child->absent 5632 && svn_dirent_is_ancestor(target_wcpath, child->abspath)) 5633 { 5634 SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1)); 5635 } 5636 } 5637 return SVN_NO_ERROR; 5638} 5639 5640/* Helper for do_directory_merge() to handle the case where a merge editor 5641 drive removes explicit mergeinfo from a subtree of the merge target. 5642 5643 MERGE_B is cascaded from the argument of the same name in 5644 do_directory_merge(). For each path (if any) in 5645 MERGE_B->PATHS_WITH_DELETED_MERGEINFO remove that path from 5646 CHILDREN_WITH_MERGEINFO. 5647 5648 The one exception is for the merge target itself, 5649 MERGE_B->target->abspath, this must always be present in 5650 CHILDREN_WITH_MERGEINFO so this is never removed by this 5651 function. */ 5652static svn_error_t * 5653remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b, 5654 apr_array_header_t *children_with_mergeinfo) 5655{ 5656 int i; 5657 5658 if (!merge_b->paths_with_deleted_mergeinfo) 5659 return SVN_NO_ERROR; 5660 5661 /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target 5662 so start at the first child. */ 5663 for (i = 1; i < children_with_mergeinfo->nelts; i++) 5664 { 5665 svn_client__merge_path_t *child = 5666 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5667 5668 if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath)) 5669 { 5670 SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1)); 5671 } 5672 } 5673 return SVN_NO_ERROR; 5674} 5675 5676/* Helper for do_directory_merge(). 5677 5678 Set up the diff editor report to merge the SOURCE diff 5679 into TARGET_ABSPATH and drive it. 5680 5681 If mergeinfo is not being honored (based on MERGE_B -- see the doc 5682 string for HONOR_MERGEINFO() for how this is determined), then ignore 5683 CHILDREN_WITH_MERGEINFO and merge the SOURCE diff to TARGET_ABSPATH. 5684 5685 If mergeinfo is being honored then perform a history-aware merge, 5686 describing TARGET_ABSPATH and its subtrees to the reporter in such as way 5687 as to avoid repeating merges already performed per the mergeinfo and 5688 natural history of TARGET_ABSPATH and its subtrees. 5689 5690 The ranges that still need to be merged to the TARGET_ABSPATH and its 5691 subtrees are described in CHILDREN_WITH_MERGEINFO, an array of 5692 svn_client__merge_path_t * -- see 'THE CHILDREN_WITH_MERGEINFO ARRAY' 5693 comment at the top of this file for more info. Note that it is possible 5694 TARGET_ABSPATH and/or some of its subtrees need only a subset, or no part, 5695 of SOURCE to be merged. Though there is little point to 5696 calling this function if TARGET_ABSPATH and all its subtrees have already 5697 had SOURCE merged, this will work but is a no-op. 5698 5699 SOURCE->rev1 and SOURCE->rev2 must be bound by the set of remaining_ranges 5700 fields in CHILDREN_WITH_MERGEINFO's elements, specifically: 5701 5702 For forward merges (SOURCE->rev1 < SOURCE->rev2): 5703 5704 1) The first svn_merge_range_t * element of each child's remaining_ranges 5705 array must meet one of the following conditions: 5706 5707 a) The range's start field is greater than or equal to SOURCE->rev2. 5708 5709 b) The range's end field is SOURCE->rev2. 5710 5711 2) Among all the ranges that meet condition 'b' the oldest start 5712 revision must equal SOURCE->rev1. 5713 5714 For reverse merges (SOURCE->rev1 > SOURCE->rev2): 5715 5716 1) The first svn_merge_range_t * element of each child's remaining_ranges 5717 array must meet one of the following conditions: 5718 5719 a) The range's start field is less than or equal to SOURCE->rev2. 5720 5721 b) The range's end field is SOURCE->rev2. 5722 5723 2) Among all the ranges that meet condition 'b' the youngest start 5724 revision must equal SOURCE->rev1. 5725 5726 Note: If the first svn_merge_range_t * element of some subtree child's 5727 remaining_ranges array is the same as the first range of that child's 5728 nearest path-wise ancestor, then the subtree child *will not* be described 5729 to the reporter. 5730 5731 DEPTH, NOTIFY_B, and MERGE_B are cascaded from do_directory_merge(), see 5732 that function for more info. 5733 5734 MERGE_B->ra_session1 and MERGE_B->ra_session2 are RA sessions open to any 5735 URL in the repository of SOURCE; they may be temporarily reparented within 5736 this function. 5737 5738 If SOURCE->ancestral is set, then SOURCE->loc1 must be a 5739 historical ancestor of SOURCE->loc2, or vice-versa (see 5740 `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around 5741 SOURCE in this case). 5742*/ 5743static svn_error_t * 5744drive_merge_report_editor(const char *target_abspath, 5745 const merge_source_t *source, 5746 const apr_array_header_t *children_with_mergeinfo, 5747 const svn_diff_tree_processor_t *processor, 5748 svn_depth_t depth, 5749 merge_cmd_baton_t *merge_b, 5750 apr_pool_t *scratch_pool) 5751{ 5752 const svn_ra_reporter3_t *reporter; 5753 const svn_delta_editor_t *diff_editor; 5754 void *diff_edit_baton; 5755 void *report_baton; 5756 svn_revnum_t target_start; 5757 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b); 5758 const char *old_sess1_url, *old_sess2_url; 5759 svn_boolean_t is_rollback = source->loc1->rev > source->loc2->rev; 5760 5761 /* Start with a safe default starting revision for the editor and the 5762 merge target. */ 5763 target_start = source->loc1->rev; 5764 5765 /* If we are honoring mergeinfo the starting revision for the merge target 5766 might not be SOURCE->rev1, in fact the merge target might not need *any* 5767 part of SOURCE merged -- Instead some subtree of the target 5768 needs SOURCE -- So get the right starting revision for the 5769 target. */ 5770 if (honor_mergeinfo) 5771 { 5772 svn_client__merge_path_t *child; 5773 5774 /* CHILDREN_WITH_MERGEINFO must always exist if we are honoring 5775 mergeinfo and must have at least one element (describing the 5776 merge target). */ 5777 SVN_ERR_ASSERT(children_with_mergeinfo); 5778 SVN_ERR_ASSERT(children_with_mergeinfo->nelts); 5779 5780 /* Get the merge target's svn_client__merge_path_t, which is always 5781 the first in the array due to depth first sorting requirement, 5782 see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 5783 child = APR_ARRAY_IDX(children_with_mergeinfo, 0, 5784 svn_client__merge_path_t *); 5785 SVN_ERR_ASSERT(child); 5786 if (child->remaining_ranges->nelts == 0) 5787 { 5788 /* The merge target doesn't need anything merged. */ 5789 target_start = source->loc2->rev; 5790 } 5791 else 5792 { 5793 /* The merge target has remaining revisions to merge. These 5794 ranges may fully or partially overlap the range described 5795 by SOURCE->rev1:rev2 or may not intersect that range at 5796 all. */ 5797 svn_merge_range_t *range = 5798 APR_ARRAY_IDX(child->remaining_ranges, 0, 5799 svn_merge_range_t *); 5800 if ((!is_rollback && range->start > source->loc2->rev) 5801 || (is_rollback && range->start < source->loc2->rev)) 5802 { 5803 /* Merge target's first remaining range doesn't intersect. */ 5804 target_start = source->loc2->rev; 5805 } 5806 else 5807 { 5808 /* Merge target's first remaining range partially or 5809 fully overlaps. */ 5810 target_start = range->start; 5811 } 5812 } 5813 } 5814 5815 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url, 5816 merge_b->ra_session1, 5817 source->loc1->url, scratch_pool)); 5818 /* Temporarily point our second RA session to SOURCE->loc1->url, too. We use 5819 this to request individual file contents. */ 5820 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url, 5821 merge_b->ra_session2, 5822 source->loc1->url, scratch_pool)); 5823 5824 /* Get the diff editor and a reporter with which to, ultimately, 5825 drive it. */ 5826 SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton, 5827 merge_b->ra_session2, 5828 depth, 5829 source->loc1->rev, 5830 TRUE /* text_deltas */, 5831 processor, 5832 merge_b->ctx->cancel_func, 5833 merge_b->ctx->cancel_baton, 5834 scratch_pool)); 5835 SVN_ERR(svn_ra_do_diff3(merge_b->ra_session1, 5836 &reporter, &report_baton, source->loc2->rev, 5837 "", depth, merge_b->diff_ignore_ancestry, 5838 TRUE, /* text_deltas */ 5839 source->loc2->url, diff_editor, diff_edit_baton, 5840 scratch_pool)); 5841 5842 /* Drive the reporter. */ 5843 SVN_ERR(reporter->set_path(report_baton, "", target_start, depth, 5844 FALSE, NULL, scratch_pool)); 5845 if (honor_mergeinfo && children_with_mergeinfo) 5846 { 5847 /* Describe children with mergeinfo overlapping this merge 5848 operation such that no repeated diff is retrieved for them from 5849 the repository. */ 5850 int i; 5851 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5852 5853 /* Start with CHILDREN_WITH_MERGEINFO[1], CHILDREN_WITH_MERGEINFO[0] 5854 is always the merge target (TARGET_ABSPATH). */ 5855 for (i = 1; i < children_with_mergeinfo->nelts; i++) 5856 { 5857 svn_merge_range_t *range; 5858 const char *child_repos_path; 5859 const svn_client__merge_path_t *parent; 5860 const svn_client__merge_path_t *child = 5861 APR_ARRAY_IDX(children_with_mergeinfo, i, 5862 svn_client__merge_path_t *); 5863 5864 SVN_ERR_ASSERT(child); 5865 if (child->absent) 5866 continue; 5867 5868 svn_pool_clear(iterpool); 5869 5870 /* Find this child's nearest wc ancestor with mergeinfo. */ 5871 parent = find_nearest_ancestor(children_with_mergeinfo, 5872 FALSE, child->abspath); 5873 5874 /* If a subtree needs the same range applied as its nearest parent 5875 with mergeinfo or neither the subtree nor this parent need 5876 SOURCE->rev1:rev2 merged, then we don't need to describe the 5877 subtree separately. In the latter case this could break the 5878 editor if child->abspath didn't exist at SOURCE->rev2 and we 5879 attempt to describe it via a reporter set_path call. */ 5880 if (child->remaining_ranges->nelts) 5881 { 5882 range = APR_ARRAY_IDX(child->remaining_ranges, 0, 5883 svn_merge_range_t *); 5884 if ((!is_rollback && range->start > source->loc2->rev) 5885 || (is_rollback && range->start < source->loc2->rev)) 5886 { 5887 /* This child's first remaining range comes after the range 5888 we are currently merging, so skip it. We expect to get 5889 to it in a subsequent call to this function. */ 5890 continue; 5891 } 5892 else if (parent->remaining_ranges->nelts) 5893 { 5894 svn_merge_range_t *parent_range = 5895 APR_ARRAY_IDX(parent->remaining_ranges, 0, 5896 svn_merge_range_t *); 5897 svn_merge_range_t *child_range = 5898 APR_ARRAY_IDX(child->remaining_ranges, 0, 5899 svn_merge_range_t *); 5900 if (parent_range->start == child_range->start) 5901 continue; /* Subtree needs same range as parent. */ 5902 } 5903 } 5904 else /* child->remaining_ranges->nelts == 0*/ 5905 { 5906 /* If both the subtree and its parent need no ranges applied 5907 consider that as the "same ranges" and don't describe 5908 the subtree. */ 5909 if (parent->remaining_ranges->nelts == 0) 5910 continue; 5911 } 5912 5913 /* Ok, we really need to describe this subtree as it needs different 5914 ranges applied than its nearest working copy parent. */ 5915 child_repos_path = svn_dirent_is_child(target_abspath, 5916 child->abspath, 5917 iterpool); 5918 /* This loop is only processing subtrees, so CHILD->ABSPATH 5919 better be a proper child of the merge target. */ 5920 SVN_ERR_ASSERT(child_repos_path); 5921 5922 if ((child->remaining_ranges->nelts == 0) 5923 || (is_rollback && (range->start < source->loc2->rev)) 5924 || (!is_rollback && (range->start > source->loc2->rev))) 5925 { 5926 /* Nothing to merge to this child. We'll claim we have 5927 it up to date so the server doesn't send us 5928 anything. */ 5929 SVN_ERR(reporter->set_path(report_baton, child_repos_path, 5930 source->loc2->rev, depth, FALSE, 5931 NULL, iterpool)); 5932 } 5933 else 5934 { 5935 SVN_ERR(reporter->set_path(report_baton, child_repos_path, 5936 range->start, depth, FALSE, 5937 NULL, iterpool)); 5938 } 5939 } 5940 svn_pool_destroy(iterpool); 5941 } 5942 SVN_ERR(reporter->finish_report(report_baton, scratch_pool)); 5943 5944 /* Point the merge baton's RA sessions back where they were. */ 5945 SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess1_url, scratch_pool)); 5946 SVN_ERR(svn_ra_reparent(merge_b->ra_session2, old_sess2_url, scratch_pool)); 5947 5948 return SVN_NO_ERROR; 5949} 5950 5951/* Iterate over each svn_client__merge_path_t * element in 5952 CHILDREN_WITH_MERGEINFO and, if START_REV is true, find the most inclusive 5953 start revision among those element's first remaining_ranges element. If 5954 START_REV is false, then look for the most inclusive end revision. 5955 5956 If IS_ROLLBACK is true the youngest start or end (as per START_REV) 5957 revision is considered the "most inclusive" otherwise the oldest revision 5958 is. 5959 5960 If none of CHILDREN_WITH_MERGEINFO's elements have any remaining ranges 5961 return SVN_INVALID_REVNUM. */ 5962static svn_revnum_t 5963get_most_inclusive_rev(const apr_array_header_t *children_with_mergeinfo, 5964 svn_boolean_t is_rollback, 5965 svn_boolean_t start_rev) 5966{ 5967 int i; 5968 svn_revnum_t most_inclusive_rev = SVN_INVALID_REVNUM; 5969 5970 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5971 { 5972 svn_client__merge_path_t *child = 5973 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5974 5975 if ((! child) || child->absent) 5976 continue; 5977 if (child->remaining_ranges->nelts > 0) 5978 { 5979 svn_merge_range_t *range = 5980 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); 5981 5982 /* Are we looking for the most inclusive start or end rev? */ 5983 svn_revnum_t rev = start_rev ? range->start : range->end; 5984 5985 if ((most_inclusive_rev == SVN_INVALID_REVNUM) 5986 || (is_rollback && (rev > most_inclusive_rev)) 5987 || ((! is_rollback) && (rev < most_inclusive_rev))) 5988 most_inclusive_rev = rev; 5989 } 5990 } 5991 return most_inclusive_rev; 5992} 5993 5994 5995/* If first item in each child of CHILDREN_WITH_MERGEINFO's 5996 remaining_ranges is inclusive of END_REV, Slice the first range in 5997 to two at END_REV. All the allocations are persistent and allocated 5998 from POOL. */ 5999static svn_error_t * 6000slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo, 6001 svn_boolean_t is_rollback, svn_revnum_t end_rev, 6002 apr_pool_t *pool) 6003{ 6004 int i; 6005 for (i = 0; i < children_with_mergeinfo->nelts; i++) 6006 { 6007 svn_client__merge_path_t *child = 6008 APR_ARRAY_IDX(children_with_mergeinfo, i, 6009 svn_client__merge_path_t *); 6010 if (!child || child->absent) 6011 continue; 6012 if (child->remaining_ranges->nelts > 0) 6013 { 6014 svn_merge_range_t *range = APR_ARRAY_IDX(child->remaining_ranges, 0, 6015 svn_merge_range_t *); 6016 if ((is_rollback && (range->start > end_rev) 6017 && (range->end < end_rev)) 6018 || (!is_rollback && (range->start < end_rev) 6019 && (range->end > end_rev))) 6020 { 6021 svn_merge_range_t *split_range1, *split_range2; 6022 6023 split_range1 = svn_merge_range_dup(range, pool); 6024 split_range2 = svn_merge_range_dup(range, pool); 6025 split_range1->end = end_rev; 6026 split_range2->start = end_rev; 6027 APR_ARRAY_IDX(child->remaining_ranges, 0, 6028 svn_merge_range_t *) = split_range1; 6029 SVN_ERR(svn_sort__array_insert2(child->remaining_ranges, 6030 &split_range2, 1)); 6031 } 6032 } 6033 } 6034 return SVN_NO_ERROR; 6035} 6036 6037/* Helper for do_directory_merge(). 6038 6039 For each child in CHILDREN_WITH_MERGEINFO remove the first remaining_ranges 6040 svn_merge_range_t *element of the child if that range has an end revision 6041 equal to REVISION. 6042 6043 If a range is removed from a child's remaining_ranges array, allocate the 6044 new remaining_ranges array in POOL. 6045 */ 6046static svn_error_t * 6047remove_first_range_from_remaining_ranges(svn_revnum_t revision, 6048 apr_array_header_t 6049 *children_with_mergeinfo, 6050 apr_pool_t *pool) 6051{ 6052 int i; 6053 6054 for (i = 0; i < children_with_mergeinfo->nelts; i++) 6055 { 6056 svn_client__merge_path_t *child = 6057 APR_ARRAY_IDX(children_with_mergeinfo, i, 6058 svn_client__merge_path_t *); 6059 if (!child || child->absent) 6060 continue; 6061 if (child->remaining_ranges->nelts > 0) 6062 { 6063 svn_merge_range_t *first_range = 6064 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); 6065 if (first_range->end == revision) 6066 { 6067 SVN_ERR(svn_sort__array_delete2(child->remaining_ranges, 0, 1)); 6068 } 6069 } 6070 } 6071 return SVN_NO_ERROR; 6072} 6073 6074/* Get a file's content and properties from the repository. 6075 Set *FILENAME to the local path to a new temporary file holding its text, 6076 and set *PROPS to a new hash of its properties. 6077 6078 RA_SESSION is a session open to the correct repository, which will be 6079 temporarily reparented to the URL of the file itself. LOCATION is the 6080 repository location of the file. 6081 6082 The resulting file and the return values live as long as RESULT_POOL, all 6083 other allocations occur in SCRATCH_POOL. 6084*/ 6085static svn_error_t * 6086single_file_merge_get_file(const char **filename, 6087 apr_hash_t **props, 6088 svn_ra_session_t *ra_session, 6089 const svn_client__pathrev_t *location, 6090 const char *wc_target, 6091 apr_pool_t *result_pool, 6092 apr_pool_t *scratch_pool) 6093{ 6094 svn_stream_t *stream; 6095 const char *old_sess_url; 6096 svn_error_t *err; 6097 6098 SVN_ERR(svn_stream_open_unique(&stream, filename, NULL, 6099 svn_io_file_del_on_pool_cleanup, 6100 result_pool, scratch_pool)); 6101 6102 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, ra_session, location->url, 6103 scratch_pool)); 6104 err = svn_ra_get_file(ra_session, "", location->rev, 6105 stream, NULL, props, scratch_pool); 6106 SVN_ERR(svn_error_compose_create( 6107 err, svn_ra_reparent(ra_session, old_sess_url, scratch_pool))); 6108 6109 return svn_error_trace(svn_stream_close(stream)); 6110} 6111 6112/* Compare two svn_client__merge_path_t elements **A and **B, given the 6113 addresses of pointers to them. Return an integer less than, equal to, or 6114 greater than zero if A sorts before, the same as, or after B, respectively. 6115 This is a helper for qsort() and bsearch() on an array of such elements. */ 6116static int 6117compare_merge_path_t_as_paths(const void *a, 6118 const void *b) 6119{ 6120 const svn_client__merge_path_t *child1 6121 = *((const svn_client__merge_path_t * const *) a); 6122 const svn_client__merge_path_t *child2 6123 = *((const svn_client__merge_path_t * const *) b); 6124 6125 return svn_path_compare_paths(child1->abspath, child2->abspath); 6126} 6127 6128/* Return a pointer to the element of CHILDREN_WITH_MERGEINFO whose path 6129 * is PATH, or return NULL if there is no such element. */ 6130static svn_client__merge_path_t * 6131get_child_with_mergeinfo(const apr_array_header_t *children_with_mergeinfo, 6132 const char *abspath) 6133{ 6134 svn_client__merge_path_t merge_path; 6135 svn_client__merge_path_t *key; 6136 svn_client__merge_path_t **pchild; 6137 6138 merge_path.abspath = abspath; 6139 key = &merge_path; 6140 pchild = bsearch(&key, children_with_mergeinfo->elts, 6141 children_with_mergeinfo->nelts, 6142 children_with_mergeinfo->elt_size, 6143 compare_merge_path_t_as_paths); 6144 return pchild ? *pchild : NULL; 6145} 6146 6147/* Insert a deep copy of INSERT_ELEMENT into the CHILDREN_WITH_MERGEINFO 6148 array at its correct position. Allocate the new storage in POOL. 6149 CHILDREN_WITH_MERGEINFO is a depth first sorted array of 6150 (svn_client__merge_path_t *). 6151 6152 ### Most callers don't need this to deep-copy the new element. 6153 ### It may be more efficient for some callers to insert a bunch of items 6154 out of order and then sort afterwards. (One caller is doing a qsort 6155 after calling this anyway.) 6156 */ 6157static svn_error_t * 6158insert_child_to_merge(apr_array_header_t *children_with_mergeinfo, 6159 const svn_client__merge_path_t *insert_element, 6160 apr_pool_t *pool) 6161{ 6162 int insert_index; 6163 const svn_client__merge_path_t *new_element; 6164 6165 /* Find where to insert the new element */ 6166 insert_index = 6167 svn_sort__bsearch_lower_bound(children_with_mergeinfo, &insert_element, 6168 compare_merge_path_t_as_paths); 6169 6170 new_element = svn_client__merge_path_dup(insert_element, pool); 6171 SVN_ERR(svn_sort__array_insert2(children_with_mergeinfo, 6172 &new_element, insert_index)); 6173 return SVN_NO_ERROR; 6174} 6175 6176/* Helper for get_mergeinfo_paths(). 6177 6178 CHILDREN_WITH_MERGEINFO, DEPTH, and POOL are 6179 all cascaded from the arguments of the same name to get_mergeinfo_paths(). 6180 6181 TARGET is the merge target. 6182 6183 *CHILD is the element in in CHILDREN_WITH_MERGEINFO that 6184 get_mergeinfo_paths() is iterating over and *CURR_INDEX is index for 6185 *CHILD. 6186 6187 If CHILD->ABSPATH is equal to MERGE_CMD_BATON->target->abspath do nothing. 6188 Else if CHILD->ABSPATH is switched or absent then make sure its immediate 6189 (as opposed to nearest) parent in CHILDREN_WITH_MERGEINFO is marked as 6190 missing a child. If the immediate parent does not exist in 6191 CHILDREN_WITH_MERGEINFO then create it (and increment *CURR_INDEX so that 6192 caller doesn't process the inserted element). Also ensure that 6193 CHILD->ABSPATH's siblings which are not already present in 6194 CHILDREN_WITH_MERGEINFO are also added to the array, limited by DEPTH 6195 (e.g. don't add directory siblings of a switched file). 6196 Use POOL for temporary allocations only, any new CHILDREN_WITH_MERGEINFO 6197 elements are allocated in POOL. */ 6198static svn_error_t * 6199insert_parent_and_sibs_of_sw_absent_del_subtree( 6200 apr_array_header_t *children_with_mergeinfo, 6201 const merge_target_t *target, 6202 int *curr_index, 6203 svn_client__merge_path_t *child, 6204 svn_depth_t depth, 6205 svn_client_ctx_t *ctx, 6206 apr_pool_t *pool) 6207{ 6208 svn_client__merge_path_t *parent; 6209 const char *parent_abspath; 6210 apr_pool_t *iterpool; 6211 const apr_array_header_t *children; 6212 int i; 6213 6214 if (!(child->absent 6215 || (child->switched 6216 && strcmp(target->abspath, 6217 child->abspath) != 0))) 6218 return SVN_NO_ERROR; 6219 6220 parent_abspath = svn_dirent_dirname(child->abspath, pool); 6221 parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath); 6222 if (parent) 6223 { 6224 parent->missing_child = child->absent; 6225 parent->switched_child = child->switched; 6226 } 6227 else 6228 { 6229 /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */ 6230 parent = svn_client__merge_path_create(parent_abspath, pool); 6231 parent->missing_child = child->absent; 6232 parent->switched_child = child->switched; 6233 /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */ 6234 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, parent, pool)); 6235 /* Increment for loop index so we don't process the inserted element. */ 6236 (*curr_index)++; 6237 } /*(parent == NULL) */ 6238 6239 /* Add all of PARENT's non-missing children that are not already present.*/ 6240 SVN_ERR(svn_wc__node_get_children_of_working_node(&children, ctx->wc_ctx, 6241 parent_abspath, 6242 pool, pool)); 6243 iterpool = svn_pool_create(pool); 6244 for (i = 0; i < children->nelts; i++) 6245 { 6246 const char *child_abspath = APR_ARRAY_IDX(children, i, const char *); 6247 svn_client__merge_path_t *sibling_of_missing; 6248 6249 svn_pool_clear(iterpool); 6250 6251 /* Does this child already exist in CHILDREN_WITH_MERGEINFO? */ 6252 sibling_of_missing = get_child_with_mergeinfo(children_with_mergeinfo, 6253 child_abspath); 6254 /* Create the missing child and insert it into CHILDREN_WITH_MERGEINFO.*/ 6255 if (!sibling_of_missing) 6256 { 6257 /* Don't add directory children if DEPTH is svn_depth_files. */ 6258 if (depth == svn_depth_files) 6259 { 6260 svn_node_kind_t child_kind; 6261 6262 SVN_ERR(svn_wc_read_kind2(&child_kind, 6263 ctx->wc_ctx, child_abspath, 6264 FALSE, FALSE, iterpool)); 6265 if (child_kind != svn_node_file) 6266 continue; 6267 } 6268 6269 sibling_of_missing = svn_client__merge_path_create(child_abspath, 6270 pool); 6271 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6272 sibling_of_missing, pool)); 6273 } 6274 } 6275 6276 svn_pool_destroy(iterpool); 6277 6278 return SVN_NO_ERROR; 6279} 6280 6281/* pre_merge_status_cb's baton */ 6282struct pre_merge_status_baton_t 6283{ 6284 svn_wc_context_t *wc_ctx; 6285 6286 /* const char *absolute_wc_path to svn_depth_t * mapping for depths 6287 of empty, immediates, and files. */ 6288 apr_hash_t *shallow_subtrees; 6289 6290 /* const char *absolute_wc_path to the same, for all paths missing 6291 from the working copy. */ 6292 apr_hash_t *missing_subtrees; 6293 6294 /* const char *absolute_wc_path const char * repos relative path, describing 6295 the root of each switched subtree in the working copy and the repository 6296 relative path it is switched to. */ 6297 apr_hash_t *switched_subtrees; 6298 6299 /* A pool to allocate additions to the above hashes in. */ 6300 apr_pool_t *pool; 6301}; 6302 6303/* A svn_wc_status_func4_t callback used by get_mergeinfo_paths to gather 6304 all switched, depth filtered and missing subtrees under a merge target. 6305 6306 Note that this doesn't see server and user excluded trees. */ 6307static svn_error_t * 6308pre_merge_status_cb(void *baton, 6309 const char *local_abspath, 6310 const svn_wc_status3_t *status, 6311 apr_pool_t *scratch_pool) 6312{ 6313 struct pre_merge_status_baton_t *pmsb = baton; 6314 6315 if (status->switched && !status->file_external) 6316 { 6317 store_path(pmsb->switched_subtrees, local_abspath); 6318 } 6319 6320 if (status->depth == svn_depth_empty 6321 || status->depth == svn_depth_files) 6322 { 6323 const char *dup_abspath; 6324 svn_depth_t *depth = apr_pmemdup(pmsb->pool, &status->depth, 6325 sizeof *depth); 6326 6327 dup_abspath = apr_pstrdup(pmsb->pool, local_abspath); 6328 6329 svn_hash_sets(pmsb->shallow_subtrees, dup_abspath, depth); 6330 } 6331 6332 if (status->node_status == svn_wc_status_missing) 6333 { 6334 svn_boolean_t new_missing_root = TRUE; 6335 apr_hash_index_t *hi; 6336 6337 for (hi = apr_hash_first(scratch_pool, pmsb->missing_subtrees); 6338 hi; 6339 hi = apr_hash_next(hi)) 6340 { 6341 const char *missing_root_path = apr_hash_this_key(hi); 6342 6343 if (svn_dirent_is_ancestor(missing_root_path, 6344 local_abspath)) 6345 { 6346 new_missing_root = FALSE; 6347 break; 6348 } 6349 } 6350 6351 if (new_missing_root) 6352 store_path(pmsb->missing_subtrees, local_abspath); 6353 } 6354 6355 return SVN_NO_ERROR; 6356} 6357 6358/* Find all the subtrees in the working copy tree rooted at TARGET_ABSPATH 6359 * that have explicit mergeinfo. 6360 * Set *SUBTREES_WITH_MERGEINFO to a hash mapping (const char *) absolute 6361 * WC path to (svn_mergeinfo_t *) mergeinfo. 6362 * 6363 * ### Is this function equivalent to: 6364 * 6365 * svn_client__get_wc_mergeinfo_catalog( 6366 * subtrees_with_mergeinfo, inherited=NULL, include_descendants=TRUE, 6367 * svn_mergeinfo_explicit, target_abspath, limit_path=NULL, 6368 * walked_path=NULL, ignore_invalid_mergeinfo=FALSE, ...) 6369 * 6370 * except for the catalog keys being abspaths instead of repo-relpaths? 6371 */ 6372static svn_error_t * 6373get_wc_explicit_mergeinfo_catalog(apr_hash_t **subtrees_with_mergeinfo, 6374 const char *target_abspath, 6375 svn_depth_t depth, 6376 svn_client_ctx_t *ctx, 6377 apr_pool_t *result_pool, 6378 apr_pool_t *scratch_pool) 6379{ 6380 svn_opt_revision_t working_revision = { svn_opt_revision_working, { 0 } }; 6381 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 6382 apr_hash_index_t *hi; 6383 apr_hash_t *externals; 6384 6385 SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL, 6386 SVN_PROP_MERGEINFO, target_abspath, 6387 &working_revision, &working_revision, NULL, 6388 depth, NULL, ctx, result_pool, scratch_pool)); 6389 6390 SVN_ERR(svn_wc__externals_defined_below(&externals, ctx->wc_ctx, 6391 target_abspath, scratch_pool, 6392 scratch_pool)); 6393 6394 /* Convert property values to svn_mergeinfo_t. */ 6395 for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo); 6396 hi; 6397 hi = apr_hash_next(hi)) 6398 { 6399 const char *wc_path = apr_hash_this_key(hi); 6400 svn_string_t *mergeinfo_string = apr_hash_this_val(hi); 6401 svn_mergeinfo_t mergeinfo; 6402 svn_error_t *err; 6403 6404 /* svn_client_propget5 picks up file externals with 6405 mergeinfo, but we don't want those. */ 6406 if (svn_hash_gets(externals, wc_path)) 6407 { 6408 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, NULL); 6409 continue; 6410 } 6411 6412 svn_pool_clear(iterpool); 6413 6414 err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_string->data, 6415 result_pool); 6416 if (err) 6417 { 6418 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 6419 { 6420 err = svn_error_createf( 6421 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err, 6422 _("Invalid mergeinfo detected on '%s', " 6423 "merge tracking not possible"), 6424 svn_dirent_local_style(wc_path, scratch_pool)); 6425 } 6426 return svn_error_trace(err); 6427 } 6428 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, mergeinfo); 6429 } 6430 svn_pool_destroy(iterpool); 6431 6432 return SVN_NO_ERROR; 6433} 6434 6435/* Helper for do_directory_merge() when performing merge-tracking aware 6436 merges. 6437 6438 Walk of the working copy tree rooted at TARGET->abspath to 6439 depth DEPTH. Create an svn_client__merge_path_t * for any path which meets 6440 one or more of the following criteria: 6441 6442 1) Path has working svn:mergeinfo. 6443 2) Path is switched. 6444 3) Path is a subtree of the merge target (i.e. is not equal to 6445 TARGET->abspath) and has no mergeinfo of its own but 6446 its immediate parent has mergeinfo with non-inheritable ranges. If 6447 this isn't a dry-run and the merge is between differences in the same 6448 repository, then this function will set working mergeinfo on the path 6449 equal to the mergeinfo inheritable from its parent. 6450 4) Path has an immediate child (or children) missing from the WC because 6451 the child is switched or absent from the WC, or due to a sparse 6452 checkout. 6453 5) Path has a sibling (or siblings) missing from the WC because the 6454 sibling is switched, absent, scheduled for deletion, or missing due to 6455 a sparse checkout. 6456 6) Path is absent from disk due to an authz restriction. 6457 7) Path is equal to TARGET->abspath. 6458 8) Path is an immediate *directory* child of 6459 TARGET->abspath and DEPTH is svn_depth_immediates. 6460 9) Path is an immediate *file* child of TARGET->abspath 6461 and DEPTH is svn_depth_files. 6462 10) Path is at a depth of 'empty' or 'files'. 6463 11) Path is missing from disk (e.g. due to an OS-level deletion). 6464 6465 If subtrees within the requested DEPTH are unexpectedly missing disk, 6466 then raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE. 6467 6468 Store the svn_client__merge_path_t *'s in *CHILDREN_WITH_MERGEINFO in 6469 depth-first order based on the svn_client__merge_path_t *s path member as 6470 sorted by svn_path_compare_paths(). Set the remaining_ranges field of each 6471 element to NULL. 6472 6473 Note: Since the walk is rooted at TARGET->abspath, the 6474 latter is guaranteed to be in *CHILDREN_WITH_MERGEINFO and due to the 6475 depth-first ordering it is guaranteed to be the first element in 6476 *CHILDREN_WITH_MERGEINFO. 6477 6478 MERGE_CMD_BATON is cascaded from the argument of the same name in 6479 do_directory_merge(). 6480*/ 6481static svn_error_t * 6482get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo, 6483 const merge_target_t *target, 6484 svn_depth_t depth, 6485 svn_boolean_t dry_run, 6486 svn_boolean_t same_repos, 6487 svn_client_ctx_t *ctx, 6488 apr_pool_t *result_pool, 6489 apr_pool_t *scratch_pool) 6490{ 6491 int i; 6492 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 6493 apr_pool_t *swmi_pool; 6494 apr_hash_t *subtrees_with_mergeinfo; 6495 apr_hash_t *excluded_subtrees; 6496 apr_hash_t *switched_subtrees; 6497 apr_hash_t *shallow_subtrees; 6498 apr_hash_t *missing_subtrees; 6499 struct pre_merge_status_baton_t pre_merge_status_baton; 6500 6501 /* Case 1: Subtrees with explicit mergeinfo. */ 6502 /* Use a subpool for subtrees_with_mergeinfo, as it can be very large 6503 and is temporary. */ 6504 swmi_pool = svn_pool_create(scratch_pool); 6505 SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo, 6506 target->abspath, 6507 depth, ctx, 6508 swmi_pool, swmi_pool)); 6509 if (subtrees_with_mergeinfo) 6510 { 6511 apr_hash_index_t *hi; 6512 6513 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo); 6514 hi; 6515 hi = apr_hash_next(hi)) 6516 { 6517 const char *wc_path = apr_hash_this_key(hi); 6518 svn_mergeinfo_t mergeinfo = apr_hash_this_val(hi); 6519 svn_client__merge_path_t *mergeinfo_child = 6520 svn_client__merge_path_create(wc_path, result_pool); 6521 6522 svn_pool_clear(iterpool); 6523 6524 /* Stash this child's pre-existing mergeinfo. */ 6525 mergeinfo_child->pre_merge_mergeinfo = mergeinfo; 6526 6527 /* Note if this child has non-inheritable mergeinfo */ 6528 mergeinfo_child->has_noninheritable 6529 = svn_mergeinfo__is_noninheritable( 6530 mergeinfo_child->pre_merge_mergeinfo, iterpool); 6531 6532 /* Append it. We'll sort below. */ 6533 APR_ARRAY_PUSH(children_with_mergeinfo, svn_client__merge_path_t *) 6534 = svn_client__merge_path_dup(mergeinfo_child, result_pool); 6535 } 6536 6537 /* Sort CHILDREN_WITH_MERGEINFO by each child's path (i.e. as per 6538 compare_merge_path_t_as_paths). Any subsequent insertions of new 6539 children with insert_child_to_merge() require this ordering. */ 6540 svn_sort__array(children_with_mergeinfo, compare_merge_path_t_as_paths); 6541 } 6542 svn_pool_destroy(swmi_pool); 6543 6544 /* Case 2: Switched subtrees 6545 Case 10: Paths at depths of 'empty' or 'files' 6546 Case 11: Paths missing from disk */ 6547 pre_merge_status_baton.wc_ctx = ctx->wc_ctx; 6548 switched_subtrees = apr_hash_make(scratch_pool); 6549 pre_merge_status_baton.switched_subtrees = switched_subtrees; 6550 shallow_subtrees = apr_hash_make(scratch_pool); 6551 pre_merge_status_baton.shallow_subtrees = shallow_subtrees; 6552 missing_subtrees = apr_hash_make(scratch_pool); 6553 pre_merge_status_baton.missing_subtrees = missing_subtrees; 6554 pre_merge_status_baton.pool = scratch_pool; 6555 SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, 6556 target->abspath, 6557 depth, 6558 TRUE /* get_all */, 6559 FALSE /* no_ignore */, 6560 TRUE /* ignore_text_mods */, 6561 NULL /* ingore_patterns */, 6562 pre_merge_status_cb, &pre_merge_status_baton, 6563 ctx->cancel_func, ctx->cancel_baton, 6564 scratch_pool)); 6565 6566 /* Issue #2915: Raise an error describing the roots of any missing 6567 subtrees, i.e. those that the WC thinks are on disk but have been 6568 removed outside of Subversion. */ 6569 if (apr_hash_count(missing_subtrees)) 6570 { 6571 apr_hash_index_t *hi; 6572 svn_stringbuf_t *missing_subtree_err_buf = 6573 svn_stringbuf_create(_("Merge tracking not allowed with missing " 6574 "subtrees; try restoring these items " 6575 "first:\n"), scratch_pool); 6576 6577 for (hi = apr_hash_first(scratch_pool, missing_subtrees); 6578 hi; 6579 hi = apr_hash_next(hi)) 6580 { 6581 svn_pool_clear(iterpool); 6582 svn_stringbuf_appendcstr(missing_subtree_err_buf, 6583 svn_dirent_local_style( 6584 apr_hash_this_key(hi), iterpool)); 6585 svn_stringbuf_appendcstr(missing_subtree_err_buf, "\n"); 6586 } 6587 6588 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, 6589 NULL, missing_subtree_err_buf->data); 6590 } 6591 6592 if (apr_hash_count(switched_subtrees)) 6593 { 6594 apr_hash_index_t *hi; 6595 6596 for (hi = apr_hash_first(scratch_pool, switched_subtrees); 6597 hi; 6598 hi = apr_hash_next(hi)) 6599 { 6600 const char *wc_path = apr_hash_this_key(hi); 6601 svn_client__merge_path_t *child = get_child_with_mergeinfo( 6602 children_with_mergeinfo, wc_path); 6603 6604 if (child) 6605 { 6606 child->switched = TRUE; 6607 } 6608 else 6609 { 6610 svn_client__merge_path_t *switched_child = 6611 svn_client__merge_path_create(wc_path, result_pool); 6612 switched_child->switched = TRUE; 6613 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6614 switched_child, result_pool)); 6615 } 6616 } 6617 } 6618 6619 if (apr_hash_count(shallow_subtrees)) 6620 { 6621 apr_hash_index_t *hi; 6622 6623 for (hi = apr_hash_first(scratch_pool, shallow_subtrees); 6624 hi; 6625 hi = apr_hash_next(hi)) 6626 { 6627 svn_boolean_t new_shallow_child = FALSE; 6628 const char *wc_path = apr_hash_this_key(hi); 6629 svn_depth_t *child_depth = apr_hash_this_val(hi); 6630 svn_client__merge_path_t *shallow_child = get_child_with_mergeinfo( 6631 children_with_mergeinfo, wc_path); 6632 6633 if (shallow_child) 6634 { 6635 if (*child_depth == svn_depth_empty 6636 || *child_depth == svn_depth_files) 6637 shallow_child->missing_child = TRUE; 6638 } 6639 else 6640 { 6641 shallow_child = svn_client__merge_path_create(wc_path, 6642 result_pool); 6643 new_shallow_child = TRUE; 6644 6645 if (*child_depth == svn_depth_empty 6646 || *child_depth == svn_depth_files) 6647 shallow_child->missing_child = TRUE; 6648 } 6649 6650 /* A little trickery: If PATH doesn't have any mergeinfo or has 6651 only inheritable mergeinfo, we still describe it as having 6652 non-inheritable mergeinfo if it is missing a child due to 6653 a shallow depth. Why? Because the mergeinfo we'll add to PATH 6654 to describe the merge must be non-inheritable, so PATH's missing 6655 children don't inherit it. Marking these PATHs as non- 6656 inheritable allows the logic for case 3 to properly account 6657 for PATH's children. */ 6658 if (!shallow_child->has_noninheritable 6659 && (*child_depth == svn_depth_empty 6660 || *child_depth == svn_depth_files)) 6661 { 6662 shallow_child->has_noninheritable = TRUE; 6663 } 6664 6665 if (new_shallow_child) 6666 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6667 shallow_child, result_pool)); 6668 } 6669 } 6670 6671 /* Case 6: Paths absent from disk due to server or user exclusion. */ 6672 SVN_ERR(svn_wc__get_excluded_subtrees(&excluded_subtrees, 6673 ctx->wc_ctx, target->abspath, 6674 result_pool, scratch_pool)); 6675 if (excluded_subtrees) 6676 { 6677 apr_hash_index_t *hi; 6678 6679 for (hi = apr_hash_first(scratch_pool, excluded_subtrees); 6680 hi; 6681 hi = apr_hash_next(hi)) 6682 { 6683 const char *wc_path = apr_hash_this_key(hi); 6684 svn_client__merge_path_t *child = get_child_with_mergeinfo( 6685 children_with_mergeinfo, wc_path); 6686 6687 if (child) 6688 { 6689 child->absent = TRUE; 6690 } 6691 else 6692 { 6693 svn_client__merge_path_t *absent_child = 6694 svn_client__merge_path_create(wc_path, result_pool); 6695 absent_child->absent = TRUE; 6696 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6697 absent_child, result_pool)); 6698 } 6699 } 6700 } 6701 6702 /* Case 7: The merge target MERGE_CMD_BATON->target->abspath is always 6703 present. */ 6704 if (!get_child_with_mergeinfo(children_with_mergeinfo, 6705 target->abspath)) 6706 { 6707 svn_client__merge_path_t *target_child = 6708 svn_client__merge_path_create(target->abspath, 6709 result_pool); 6710 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, target_child, 6711 result_pool)); 6712 } 6713 6714 /* Case 8: Path is an immediate *directory* child of 6715 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates. 6716 6717 Case 9: Path is an immediate *file* child of 6718 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_files. */ 6719 if (depth == svn_depth_immediates || depth == svn_depth_files) 6720 { 6721 int j; 6722 const apr_array_header_t *immediate_children; 6723 6724 SVN_ERR(svn_wc__node_get_children_of_working_node( 6725 &immediate_children, ctx->wc_ctx, 6726 target->abspath, scratch_pool, scratch_pool)); 6727 6728 for (j = 0; j < immediate_children->nelts; j++) 6729 { 6730 const char *immediate_child_abspath = 6731 APR_ARRAY_IDX(immediate_children, j, const char *); 6732 svn_node_kind_t immediate_child_kind; 6733 6734 svn_pool_clear(iterpool); 6735 SVN_ERR(svn_wc_read_kind2(&immediate_child_kind, 6736 ctx->wc_ctx, immediate_child_abspath, 6737 FALSE, FALSE, iterpool)); 6738 if ((immediate_child_kind == svn_node_dir 6739 && depth == svn_depth_immediates) 6740 || (immediate_child_kind == svn_node_file 6741 && depth == svn_depth_files)) 6742 { 6743 if (!get_child_with_mergeinfo(children_with_mergeinfo, 6744 immediate_child_abspath)) 6745 { 6746 svn_client__merge_path_t *immediate_child = 6747 svn_client__merge_path_create(immediate_child_abspath, 6748 result_pool); 6749 6750 if (immediate_child_kind == svn_node_dir 6751 && depth == svn_depth_immediates) 6752 immediate_child->immediate_child_dir = TRUE; 6753 6754 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6755 immediate_child, result_pool)); 6756 } 6757 } 6758 } 6759 } 6760 6761 /* If DEPTH isn't empty then cover cases 3), 4), and 5), possibly adding 6762 elements to CHILDREN_WITH_MERGEINFO. */ 6763 if (depth <= svn_depth_empty) 6764 return SVN_NO_ERROR; 6765 6766 for (i = 0; i < children_with_mergeinfo->nelts; i++) 6767 { 6768 svn_client__merge_path_t *child = 6769 APR_ARRAY_IDX(children_with_mergeinfo, i, 6770 svn_client__merge_path_t *); 6771 svn_pool_clear(iterpool); 6772 6773 /* Case 3) Where merging to a path with a switched child the path 6774 gets non-inheritable mergeinfo for the merge range performed and 6775 the child gets its own set of mergeinfo. If the switched child 6776 later "returns", e.g. a switched path is unswitched, the child 6777 may not have any explicit mergeinfo. If the initial merge is 6778 repeated we don't want to repeat the merge for the path, but we 6779 do want to repeat it for the previously switched child. To 6780 ensure this we check if all of CHILD's non-missing children have 6781 explicit mergeinfo (they should already be present in 6782 CHILDREN_WITH_MERGEINFO if they do). If not, 6783 add the children without mergeinfo to CHILDREN_WITH_MERGEINFO so 6784 do_directory_merge() will merge them independently. 6785 6786 But that's not enough! Since do_directory_merge() performs 6787 the merges on the paths in CHILDREN_WITH_MERGEINFO in a depth 6788 first manner it will merge the previously switched path's parent 6789 first. As part of this merge it will update the parent's 6790 previously non-inheritable mergeinfo and make it inheritable 6791 (since it notices the path has no missing children), then when 6792 do_directory_merge() finally merges the previously missing 6793 child it needs to get mergeinfo from the child's nearest 6794 ancestor, but since do_directory_merge() already tweaked that 6795 mergeinfo, removing the non-inheritable flag, it appears that the 6796 child already has been merged to. To prevent this we set 6797 override mergeinfo on the child now, before any merging is done, 6798 so it has explicit mergeinfo that reflects only CHILD's 6799 inheritable mergeinfo. */ 6800 6801 /* If depth is immediates or files then don't add new children if 6802 CHILD is a subtree of the merge target; those children are below 6803 the operational depth of the merge. */ 6804 if (child->has_noninheritable 6805 && (i == 0 || depth == svn_depth_infinity)) 6806 { 6807 const apr_array_header_t *children; 6808 int j; 6809 6810 SVN_ERR(svn_wc__node_get_children_of_working_node( 6811 &children, 6812 ctx->wc_ctx, 6813 child->abspath, 6814 iterpool, iterpool)); 6815 for (j = 0; j < children->nelts; j++) 6816 { 6817 svn_client__merge_path_t *child_of_noninheritable; 6818 const char *child_abspath = APR_ARRAY_IDX(children, j, 6819 const char*); 6820 6821 /* Does this child already exist in CHILDREN_WITH_MERGEINFO? 6822 If not, create it and insert it into 6823 CHILDREN_WITH_MERGEINFO and set override mergeinfo on 6824 it. */ 6825 child_of_noninheritable = 6826 get_child_with_mergeinfo(children_with_mergeinfo, 6827 child_abspath); 6828 if (!child_of_noninheritable) 6829 { 6830 /* Don't add directory children if DEPTH 6831 is svn_depth_files. */ 6832 if (depth == svn_depth_files) 6833 { 6834 svn_node_kind_t child_kind; 6835 SVN_ERR(svn_wc_read_kind2(&child_kind, 6836 ctx->wc_ctx, child_abspath, 6837 FALSE, FALSE, iterpool)); 6838 if (child_kind != svn_node_file) 6839 continue; 6840 } 6841 /* else DEPTH is infinity or immediates so we want both 6842 directory and file children. */ 6843 6844 child_of_noninheritable = 6845 svn_client__merge_path_create(child_abspath, result_pool); 6846 child_of_noninheritable->child_of_noninheritable = TRUE; 6847 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 6848 child_of_noninheritable, 6849 result_pool)); 6850 if (!dry_run && same_repos) 6851 { 6852 svn_mergeinfo_t mergeinfo; 6853 6854 SVN_ERR(svn_client__get_wc_mergeinfo( 6855 &mergeinfo, NULL, 6856 svn_mergeinfo_nearest_ancestor, 6857 child_of_noninheritable->abspath, 6858 target->abspath, NULL, FALSE, 6859 ctx, iterpool, iterpool)); 6860 6861 SVN_ERR(svn_client__record_wc_mergeinfo( 6862 child_of_noninheritable->abspath, mergeinfo, 6863 FALSE, ctx, iterpool)); 6864 } 6865 } 6866 } 6867 } 6868 /* Case 4 and 5 are handled by the following function. */ 6869 SVN_ERR(insert_parent_and_sibs_of_sw_absent_del_subtree( 6870 children_with_mergeinfo, target, &i, child, 6871 depth, ctx, result_pool)); 6872 } /* i < children_with_mergeinfo->nelts */ 6873 svn_pool_destroy(iterpool); 6874 6875 return SVN_NO_ERROR; 6876} 6877 6878 6879/* Implements the svn_log_entry_receiver_t interface. 6880 * 6881 * BATON is an 'apr_array_header_t *' array of 'svn_revnum_t'. 6882 * Push a copy of LOG_ENTRY->revision onto BATON. Thus, a 6883 * series of invocations of this callback accumulates the 6884 * corresponding set of revisions into BATON. 6885 */ 6886static svn_error_t * 6887log_changed_revs(void *baton, 6888 svn_log_entry_t *log_entry, 6889 apr_pool_t *pool) 6890{ 6891 apr_array_header_t *revs = baton; 6892 6893 APR_ARRAY_PUSH(revs, svn_revnum_t) = log_entry->revision; 6894 return SVN_NO_ERROR; 6895} 6896 6897 6898/* Set *MIN_REV_P to the oldest and *MAX_REV_P to the youngest start or end 6899 * revision occurring in RANGELIST, or to SVN_INVALID_REVNUM if RANGELIST 6900 * is empty. */ 6901static void 6902merge_range_find_extremes(svn_revnum_t *min_rev_p, 6903 svn_revnum_t *max_rev_p, 6904 const svn_rangelist_t *rangelist) 6905{ 6906 int i; 6907 6908 *min_rev_p = SVN_INVALID_REVNUM; 6909 *max_rev_p = SVN_INVALID_REVNUM; 6910 for (i = 0; i < rangelist->nelts; i++) 6911 { 6912 svn_merge_range_t *range 6913 = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 6914 svn_revnum_t range_min = MIN(range->start, range->end); 6915 svn_revnum_t range_max = MAX(range->start, range->end); 6916 6917 if ((! SVN_IS_VALID_REVNUM(*min_rev_p)) || (range_min < *min_rev_p)) 6918 *min_rev_p = range_min; 6919 if ((! SVN_IS_VALID_REVNUM(*max_rev_p)) || (range_max > *max_rev_p)) 6920 *max_rev_p = range_max; 6921 } 6922} 6923 6924/* Wrapper around svn_ra_get_log2(). Invoke RECEIVER with RECEIVER_BATON 6925 * on each commit from YOUNGEST_REV to OLDEST_REV in which TARGET_RELPATH 6926 * changed. TARGET_RELPATH is relative to RA_SESSION's URL. 6927 * Important: Revision properties are not retrieved by this function for 6928 * performance reasons. 6929 */ 6930static svn_error_t * 6931get_log(svn_ra_session_t *ra_session, 6932 const char *target_relpath, 6933 svn_revnum_t youngest_rev, 6934 svn_revnum_t oldest_rev, 6935 svn_boolean_t discover_changed_paths, 6936 svn_log_entry_receiver_t receiver, 6937 void *receiver_baton, 6938 apr_pool_t *pool) 6939{ 6940 apr_array_header_t *log_targets; 6941 apr_array_header_t *revprops; 6942 6943 log_targets = apr_array_make(pool, 1, sizeof(const char *)); 6944 APR_ARRAY_PUSH(log_targets, const char *) = target_relpath; 6945 6946 revprops = apr_array_make(pool, 0, sizeof(const char *)); 6947 6948 SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev, 6949 oldest_rev, 0 /* limit */, discover_changed_paths, 6950 FALSE /* strict_node_history */, 6951 FALSE /* include_merged_revisions */, 6952 revprops, receiver, receiver_baton, pool)); 6953 6954 return SVN_NO_ERROR; 6955} 6956 6957/* Set *OPERATIVE_RANGES_P to an array of svn_merge_range_t * merge 6958 range objects copied wholesale from RANGES which have the property 6959 that in some revision within that range the object identified by 6960 RA_SESSION was modified (if by "modified" we mean "'svn log' would 6961 return that revision). *OPERATIVE_RANGES_P is allocated from the 6962 same pool as RANGES, and the ranges within it are shared with 6963 RANGES, too. 6964 6965 *OPERATIVE_RANGES_P may be the same as RANGES (that is, the output 6966 parameter is set only after the input is no longer used). 6967 6968 Use POOL for temporary allocations. */ 6969static svn_error_t * 6970remove_noop_merge_ranges(svn_rangelist_t **operative_ranges_p, 6971 svn_ra_session_t *ra_session, 6972 const svn_rangelist_t *ranges, 6973 apr_pool_t *pool) 6974{ 6975 int i; 6976 svn_revnum_t oldest_rev, youngest_rev; 6977 apr_array_header_t *changed_revs = 6978 apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t)); 6979 svn_rangelist_t *operative_ranges = 6980 apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size); 6981 6982 /* Find the revision extremes of the RANGES we have. */ 6983 merge_range_find_extremes(&oldest_rev, &youngest_rev, ranges); 6984 if (SVN_IS_VALID_REVNUM(oldest_rev)) 6985 oldest_rev++; /* make it inclusive */ 6986 6987 /* Get logs across those ranges, recording which revisions hold 6988 changes to our object's history. */ 6989 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, FALSE, 6990 log_changed_revs, changed_revs, pool)); 6991 6992 /* Are there *any* changes? */ 6993 if (changed_revs->nelts) 6994 { 6995 /* Our list of changed revisions should be in youngest-to-oldest 6996 order. */ 6997 svn_revnum_t youngest_changed_rev 6998 = APR_ARRAY_IDX(changed_revs, 0, svn_revnum_t); 6999 svn_revnum_t oldest_changed_rev 7000 = APR_ARRAY_IDX(changed_revs, changed_revs->nelts - 1, svn_revnum_t); 7001 7002 /* Now, copy from RANGES to *OPERATIVE_RANGES, filtering out ranges 7003 that aren't operative (by virtue of not having any revisions 7004 represented in the CHANGED_REVS array). */ 7005 for (i = 0; i < ranges->nelts; i++) 7006 { 7007 svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i, 7008 svn_merge_range_t *); 7009 svn_revnum_t range_min = MIN(range->start, range->end) + 1; 7010 svn_revnum_t range_max = MAX(range->start, range->end); 7011 int j; 7012 7013 /* If the merge range is entirely outside the range of changed 7014 revisions, we've no use for it. */ 7015 if ((range_min > youngest_changed_rev) 7016 || (range_max < oldest_changed_rev)) 7017 continue; 7018 7019 /* Walk through the changed_revs to see if any of them fall 7020 inside our current range. */ 7021 for (j = 0; j < changed_revs->nelts; j++) 7022 { 7023 svn_revnum_t changed_rev 7024 = APR_ARRAY_IDX(changed_revs, j, svn_revnum_t); 7025 if ((changed_rev >= range_min) && (changed_rev <= range_max)) 7026 { 7027 APR_ARRAY_PUSH(operative_ranges, svn_merge_range_t *) = 7028 range; 7029 break; 7030 } 7031 } 7032 } 7033 } 7034 7035 *operative_ranges_p = operative_ranges; 7036 return SVN_NO_ERROR; 7037} 7038 7039 7040/*-----------------------------------------------------------------------*/ 7041 7042/*** Merge Source Normalization ***/ 7043 7044/* qsort-compatible sort routine, rating merge_source_t * objects to 7045 be in descending (youngest-to-oldest) order based on their ->loc1->rev 7046 component. */ 7047static int 7048compare_merge_source_ts(const void *a, 7049 const void *b) 7050{ 7051 svn_revnum_t a_rev = (*(const merge_source_t *const *)a)->loc1->rev; 7052 svn_revnum_t b_rev = (*(const merge_source_t *const *)b)->loc1->rev; 7053 if (a_rev == b_rev) 7054 return 0; 7055 return a_rev < b_rev ? 1 : -1; 7056} 7057 7058/* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by 7059 slicing history location SEGMENTS with a given requested merge 7060 RANGE. Use SOURCE_LOC for full source URL calculation. 7061 7062 Order the merge sources in *MERGE_SOURCE_TS_P from oldest to 7063 youngest. */ 7064static svn_error_t * 7065combine_range_with_segments(apr_array_header_t **merge_source_ts_p, 7066 const svn_merge_range_t *range, 7067 const apr_array_header_t *segments, 7068 const svn_client__pathrev_t *source_loc, 7069 apr_pool_t *pool) 7070{ 7071 apr_array_header_t *merge_source_ts = 7072 apr_array_make(pool, 1, sizeof(merge_source_t *)); 7073 svn_revnum_t minrev = MIN(range->start, range->end) + 1; 7074 svn_revnum_t maxrev = MAX(range->start, range->end); 7075 svn_boolean_t subtractive = (range->start > range->end); 7076 int i; 7077 7078 for (i = 0; i < segments->nelts; i++) 7079 { 7080 svn_location_segment_t *segment = 7081 APR_ARRAY_IDX(segments, i, svn_location_segment_t *); 7082 svn_client__pathrev_t *loc1, *loc2; 7083 merge_source_t *merge_source; 7084 const char *path1 = NULL; 7085 svn_revnum_t rev1; 7086 7087 /* If this segment doesn't overlap our range at all, or 7088 represents a gap, ignore it. */ 7089 if ((segment->range_end < minrev) 7090 || (segment->range_start > maxrev) 7091 || (! segment->path)) 7092 continue; 7093 7094 /* If our range spans a segment boundary, we have to point our 7095 merge_source_t's path1 to the path of the immediately older 7096 segment, else it points to the same location as its path2. */ 7097 rev1 = MAX(segment->range_start, minrev) - 1; 7098 if (minrev <= segment->range_start) 7099 { 7100 if (i > 0) 7101 { 7102 path1 = (APR_ARRAY_IDX(segments, i - 1, 7103 svn_location_segment_t *))->path; 7104 } 7105 /* If we've backed PATH1 up into a segment gap, let's back 7106 it up further still to the segment before the gap. We'll 7107 have to adjust rev1, too. */ 7108 if ((! path1) && (i > 1)) 7109 { 7110 path1 = (APR_ARRAY_IDX(segments, i - 2, 7111 svn_location_segment_t *))->path; 7112 rev1 = (APR_ARRAY_IDX(segments, i - 2, 7113 svn_location_segment_t *))->range_end; 7114 } 7115 } 7116 else 7117 { 7118 path1 = apr_pstrdup(pool, segment->path); 7119 } 7120 7121 /* If we don't have two valid paths, we won't know what to do 7122 when merging. This could happen if someone requested a merge 7123 where the source didn't exist in a particular revision or 7124 something. The merge code would probably bomb out anyway, so 7125 we'll just *not* create a merge source in this case. */ 7126 if (! (path1 && segment->path)) 7127 continue; 7128 7129 /* Build our merge source structure. */ 7130 loc1 = svn_client__pathrev_create_with_relpath( 7131 source_loc->repos_root_url, source_loc->repos_uuid, 7132 rev1, path1, pool); 7133 loc2 = svn_client__pathrev_create_with_relpath( 7134 source_loc->repos_root_url, source_loc->repos_uuid, 7135 MIN(segment->range_end, maxrev), segment->path, pool); 7136 /* If this is subtractive, reverse the whole calculation. */ 7137 if (subtractive) 7138 merge_source = merge_source_create(loc2, loc1, TRUE /* ancestral */, 7139 pool); 7140 else 7141 merge_source = merge_source_create(loc1, loc2, TRUE /* ancestral */, 7142 pool); 7143 7144 APR_ARRAY_PUSH(merge_source_ts, merge_source_t *) = merge_source; 7145 } 7146 7147 /* If this was a subtractive merge, and we created more than one 7148 merge source, we need to reverse the sort ordering of our sources. */ 7149 if (subtractive && (merge_source_ts->nelts > 1)) 7150 svn_sort__array(merge_source_ts, compare_merge_source_ts); 7151 7152 *merge_source_ts_p = merge_source_ts; 7153 return SVN_NO_ERROR; 7154} 7155 7156/* Similar to normalize_merge_sources() except the input MERGE_RANGE_TS is a 7157 * rangelist. 7158 */ 7159static svn_error_t * 7160normalize_merge_sources_internal(apr_array_header_t **merge_sources_p, 7161 const svn_client__pathrev_t *source_loc, 7162 const svn_rangelist_t *merge_range_ts, 7163 svn_ra_session_t *ra_session, 7164 svn_client_ctx_t *ctx, 7165 apr_pool_t *result_pool, 7166 apr_pool_t *scratch_pool) 7167{ 7168 svn_revnum_t source_peg_revnum = source_loc->rev; 7169 svn_revnum_t oldest_requested, youngest_requested; 7170 svn_revnum_t trim_revision = SVN_INVALID_REVNUM; 7171 apr_array_header_t *segments; 7172 int i; 7173 7174 /* Initialize our return variable. */ 7175 *merge_sources_p = apr_array_make(result_pool, 1, sizeof(merge_source_t *)); 7176 7177 /* No ranges to merge? No problem. */ 7178 if (merge_range_ts->nelts == 0) 7179 return SVN_NO_ERROR; 7180 7181 /* Find the extremes of the revisions across our set of ranges. */ 7182 merge_range_find_extremes(&oldest_requested, &youngest_requested, 7183 merge_range_ts); 7184 7185 /* ### FIXME: Our underlying APIs can't yet handle the case where 7186 the peg revision isn't the youngest of the three revisions. So 7187 we'll just verify that the source in the peg revision is related 7188 to the source in the youngest requested revision (which is 7189 all the underlying APIs would do in this case right now anyway). */ 7190 if (source_peg_revnum < youngest_requested) 7191 { 7192 svn_client__pathrev_t *start_loc; 7193 7194 SVN_ERR(svn_client__repos_location(&start_loc, 7195 ra_session, source_loc, 7196 youngest_requested, 7197 ctx, scratch_pool, scratch_pool)); 7198 source_peg_revnum = youngest_requested; 7199 } 7200 7201 /* Fetch the locations for our merge range span. */ 7202 SVN_ERR(svn_client__repos_location_segments(&segments, 7203 ra_session, source_loc->url, 7204 source_peg_revnum, 7205 youngest_requested, 7206 oldest_requested, 7207 ctx, result_pool)); 7208 7209 /* See if we fetched enough history to do the job. "Surely we did," 7210 you say. "After all, we covered the entire requested merge 7211 range." Yes, that's true, but if our first segment doesn't 7212 extend back to the oldest request revision, we've got a special 7213 case to deal with. Or if the first segment represents a gap, 7214 that's another special case. */ 7215 trim_revision = SVN_INVALID_REVNUM; 7216 if (segments->nelts) 7217 { 7218 svn_location_segment_t *first_segment = 7219 APR_ARRAY_IDX(segments, 0, svn_location_segment_t *); 7220 7221 /* If the first segment doesn't start with the OLDEST_REQUESTED 7222 revision, we'll need to pass a trim revision to our range 7223 cruncher. */ 7224 if (first_segment->range_start != oldest_requested) 7225 { 7226 trim_revision = first_segment->range_start; 7227 } 7228 7229 /* Else, if the first segment has no path (and therefore is a 7230 gap), then we'll fetch the copy source revision from the 7231 second segment (provided there is one, of course) and use it 7232 to prepend an extra pathful segment to our list. 7233 7234 ### We could avoid this bit entirely if we'd passed 7235 ### SVN_INVALID_REVNUM instead of OLDEST_REQUESTED to 7236 ### svn_client__repos_location_segments(), but that would 7237 ### really penalize clients hitting pre-1.5 repositories with 7238 ### the typical small merge range request (because of the 7239 ### lack of a node-origins cache in the repository). */ 7240 else if (! first_segment->path) 7241 { 7242 if (segments->nelts > 1) 7243 { 7244 svn_location_segment_t *second_segment = 7245 APR_ARRAY_IDX(segments, 1, svn_location_segment_t *); 7246 const char *segment_url; 7247 const char *original_repos_relpath; 7248 svn_revnum_t original_revision; 7249 svn_opt_revision_t range_start_rev; 7250 range_start_rev.kind = svn_opt_revision_number; 7251 range_start_rev.value.number = second_segment->range_start; 7252 7253 segment_url = svn_path_url_add_component2( 7254 source_loc->repos_root_url, second_segment->path, 7255 scratch_pool); 7256 SVN_ERR(svn_client__get_copy_source(&original_repos_relpath, 7257 &original_revision, 7258 segment_url, 7259 &range_start_rev, 7260 ra_session, ctx, 7261 result_pool, scratch_pool)); 7262 /* Got copyfrom data? Fix up the first segment to cover 7263 back to COPYFROM_REV + 1, and then prepend a new 7264 segment covering just COPYFROM_REV. */ 7265 if (original_repos_relpath) 7266 { 7267 svn_location_segment_t *new_segment = 7268 apr_pcalloc(result_pool, sizeof(*new_segment)); 7269 7270 new_segment->path = original_repos_relpath; 7271 new_segment->range_start = original_revision; 7272 new_segment->range_end = original_revision; 7273 SVN_ERR(svn_sort__array_insert2(segments, &new_segment, 0)); 7274 } 7275 } 7276 } 7277 } 7278 7279 /* For each range in our requested range set, try to determine the 7280 path(s) associated with that range. */ 7281 for (i = 0; i < merge_range_ts->nelts; i++) 7282 { 7283 svn_merge_range_t *range = 7284 APR_ARRAY_IDX(merge_range_ts, i, svn_merge_range_t *); 7285 apr_array_header_t *merge_sources; 7286 7287 if (SVN_IS_VALID_REVNUM(trim_revision)) 7288 { 7289 /* If the range predates the trim revision, discard it. */ 7290 if (MAX(range->start, range->end) < trim_revision) 7291 continue; 7292 7293 /* If the range overlaps the trim revision, trim it. */ 7294 if (range->start < trim_revision) 7295 range->start = trim_revision; 7296 if (range->end < trim_revision) 7297 range->end = trim_revision; 7298 } 7299 7300 /* Copy the resulting merge sources into master list thereof. */ 7301 SVN_ERR(combine_range_with_segments(&merge_sources, range, 7302 segments, source_loc, 7303 result_pool)); 7304 apr_array_cat(*merge_sources_p, merge_sources); 7305 } 7306 7307 return SVN_NO_ERROR; 7308} 7309 7310/* Determine the normalized ranges to merge from a given line of history. 7311 7312 Calculate the result by intersecting the list of location segments at 7313 which SOURCE_LOC existed along its line of history with the requested 7314 revision ranges in RANGES_TO_MERGE. RANGES_TO_MERGE is an array of 7315 (svn_opt_revision_range_t *) revision ranges. Use SOURCE_PATH_OR_URL to 7316 resolve any WC-relative revision specifiers (such as 'base') in 7317 RANGES_TO_MERGE. 7318 7319 Set *MERGE_SOURCES_P to an array of merge_source_t * objects, each 7320 describing a normalized range of revisions to be merged from the line 7321 history of SOURCE_LOC. Order the objects from oldest to youngest. 7322 7323 RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may 7324 be temporarily reparented within this function. Use RA_SESSION to find 7325 the location segments along the line of history of SOURCE_LOC. 7326 7327 Allocate MERGE_SOURCES_P and its contents in RESULT_POOL. 7328 7329 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more on the 7330 background of this function. 7331*/ 7332static svn_error_t * 7333normalize_merge_sources(apr_array_header_t **merge_sources_p, 7334 const char *source_path_or_url, 7335 const svn_client__pathrev_t *source_loc, 7336 const apr_array_header_t *ranges_to_merge, 7337 svn_ra_session_t *ra_session, 7338 svn_client_ctx_t *ctx, 7339 apr_pool_t *result_pool, 7340 apr_pool_t *scratch_pool) 7341{ 7342 const char *source_abspath_or_url; 7343 svn_revnum_t youngest_rev = SVN_INVALID_REVNUM; 7344 svn_rangelist_t *merge_range_ts; 7345 int i; 7346 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 7347 7348 if(!svn_path_is_url(source_path_or_url)) 7349 SVN_ERR(svn_dirent_get_absolute(&source_abspath_or_url, source_path_or_url, 7350 scratch_pool)); 7351 else 7352 source_abspath_or_url = source_path_or_url; 7353 7354 /* Create a list to hold svn_merge_range_t's. */ 7355 merge_range_ts = apr_array_make(scratch_pool, ranges_to_merge->nelts, 7356 sizeof(svn_merge_range_t *)); 7357 7358 for (i = 0; i < ranges_to_merge->nelts; i++) 7359 { 7360 svn_opt_revision_range_t *range 7361 = APR_ARRAY_IDX(ranges_to_merge, i, svn_opt_revision_range_t *); 7362 svn_merge_range_t mrange; 7363 7364 svn_pool_clear(iterpool); 7365 7366 /* Resolve revisions to real numbers, validating as we go. */ 7367 if ((range->start.kind == svn_opt_revision_unspecified) 7368 || (range->end.kind == svn_opt_revision_unspecified)) 7369 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, 7370 _("Not all required revisions are specified")); 7371 7372 SVN_ERR(svn_client__get_revision_number(&mrange.start, &youngest_rev, 7373 ctx->wc_ctx, 7374 source_abspath_or_url, 7375 ra_session, &range->start, 7376 iterpool)); 7377 SVN_ERR(svn_client__get_revision_number(&mrange.end, &youngest_rev, 7378 ctx->wc_ctx, 7379 source_abspath_or_url, 7380 ra_session, &range->end, 7381 iterpool)); 7382 7383 /* If this isn't a no-op range... */ 7384 if (mrange.start != mrange.end) 7385 { 7386 /* ...then add it to the list. */ 7387 mrange.inheritable = TRUE; 7388 APR_ARRAY_PUSH(merge_range_ts, svn_merge_range_t *) 7389 = svn_merge_range_dup(&mrange, scratch_pool); 7390 } 7391 } 7392 7393 SVN_ERR(normalize_merge_sources_internal( 7394 merge_sources_p, source_loc, 7395 merge_range_ts, ra_session, ctx, result_pool, scratch_pool)); 7396 7397 svn_pool_destroy(iterpool); 7398 return SVN_NO_ERROR; 7399} 7400 7401 7402/*-----------------------------------------------------------------------*/ 7403 7404/*** Merge Workhorse Functions ***/ 7405 7406/* Helper for do_directory_merge() and do_file_merge() which filters out a 7407 path's own natural history from the mergeinfo describing a merge. 7408 7409 Given the natural history IMPLICIT_MERGEINFO of some wc merge target path, 7410 the repository-relative merge source path SOURCE_REL_PATH, and the 7411 requested merge range REQUESTED_RANGE from SOURCE_REL_PATH, remove any 7412 portion of REQUESTED_RANGE which is already described in 7413 IMPLICIT_MERGEINFO. Store the result in *FILTERED_RANGELIST. 7414 7415 This function only filters natural history for mergeinfo that will be 7416 *added* during a forward merge. Removing natural history from explicit 7417 mergeinfo is harmless. If REQUESTED_RANGE describes a reverse merge, 7418 then *FILTERED_RANGELIST is simply populated with one range described 7419 by REQUESTED_RANGE. *FILTERED_RANGELIST is never NULL. 7420 7421 Allocate *FILTERED_RANGELIST in POOL. */ 7422static svn_error_t * 7423filter_natural_history_from_mergeinfo(svn_rangelist_t **filtered_rangelist, 7424 const char *source_rel_path, 7425 svn_mergeinfo_t implicit_mergeinfo, 7426 svn_merge_range_t *requested_range, 7427 apr_pool_t *pool) 7428{ 7429 /* Make the REQUESTED_RANGE into a rangelist. */ 7430 svn_rangelist_t *requested_rangelist = 7431 svn_rangelist__initialize(requested_range->start, requested_range->end, 7432 requested_range->inheritable, pool); 7433 7434 *filtered_rangelist = NULL; 7435 7436 /* For forward merges: If the IMPLICIT_MERGEINFO already describes ranges 7437 associated with SOURCE_REL_PATH then filter those ranges out. */ 7438 if (implicit_mergeinfo 7439 && (requested_range->start < requested_range->end)) 7440 { 7441 svn_rangelist_t *implied_rangelist = 7442 svn_hash_gets(implicit_mergeinfo, source_rel_path); 7443 7444 if (implied_rangelist) 7445 SVN_ERR(svn_rangelist_remove(filtered_rangelist, 7446 implied_rangelist, 7447 requested_rangelist, 7448 FALSE, pool)); 7449 } 7450 7451 /* If no filtering was performed the filtered rangelist is 7452 simply the requested rangelist.*/ 7453 if (! (*filtered_rangelist)) 7454 *filtered_rangelist = requested_rangelist; 7455 7456 return SVN_NO_ERROR; 7457} 7458 7459/* Return a merge source representing the sub-range from START_REV to 7460 END_REV of SOURCE. SOURCE obeys the rules described in the 7461 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file. 7462 The younger of START_REV and END_REV is inclusive while the older is 7463 exclusive. 7464 7465 Allocate the result structure in POOL but leave the URLs in it as shallow 7466 copies of the URLs in SOURCE. 7467*/ 7468static merge_source_t * 7469subrange_source(const merge_source_t *source, 7470 svn_revnum_t start_rev, 7471 svn_revnum_t end_rev, 7472 apr_pool_t *pool) 7473{ 7474 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 7475 svn_boolean_t same_urls = (strcmp(source->loc1->url, source->loc2->url) == 0); 7476 svn_client__pathrev_t loc1 = *source->loc1; 7477 svn_client__pathrev_t loc2 = *source->loc2; 7478 7479 /* For this function we require that the input source is 'ancestral'. */ 7480 SVN_ERR_ASSERT_NO_RETURN(source->ancestral); 7481 SVN_ERR_ASSERT_NO_RETURN(start_rev != end_rev); 7482 7483 loc1.rev = start_rev; 7484 loc2.rev = end_rev; 7485 if (! same_urls) 7486 { 7487 if (is_rollback && (end_rev != source->loc2->rev)) 7488 { 7489 loc2.url = source->loc1->url; 7490 } 7491 if ((! is_rollback) && (start_rev != source->loc1->rev)) 7492 { 7493 loc1.url = source->loc2->url; 7494 } 7495 } 7496 return merge_source_create(&loc1, &loc2, source->ancestral, pool); 7497} 7498 7499/* The single-file, simplified version of do_directory_merge(), which see for 7500 parameter descriptions. 7501 7502 Additional parameters: 7503 7504 If SOURCES_RELATED is set, the "left" and "right" sides of SOURCE are 7505 historically related (ancestors, uncles, second 7506 cousins thrice removed, etc...). (This is used to simulate the 7507 history checks that the repository logic does in the directory case.) 7508 7509 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 7510 is not NULL, then don't record the new mergeinfo on the TARGET_ABSPATH, 7511 but instead record it in RESULT_CATALOG, where the key is TARGET_ABSPATH 7512 and the value is the new mergeinfo for that path. Allocate additions 7513 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 7514 7515 CONFLICTED_RANGE is as documented for do_directory_merge(). 7516 7517 Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->loc1->url and 7518 MERGE_B->RA_SESSION2 with SOURCE->loc2->url. 7519*/ 7520static svn_error_t * 7521do_file_merge(svn_mergeinfo_catalog_t result_catalog, 7522 single_range_conflict_report_t **conflict_report, 7523 const merge_source_t *source, 7524 const char *target_abspath, 7525 const svn_diff_tree_processor_t *processor, 7526 svn_boolean_t sources_related, 7527 svn_boolean_t squelch_mergeinfo_notifications, 7528 merge_cmd_baton_t *merge_b, 7529 apr_pool_t *result_pool, 7530 apr_pool_t *scratch_pool) 7531{ 7532 svn_rangelist_t *remaining_ranges; 7533 svn_client_ctx_t *ctx = merge_b->ctx; 7534 svn_merge_range_t range; 7535 svn_mergeinfo_t target_mergeinfo; 7536 svn_boolean_t inherited = FALSE; 7537 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 7538 const svn_client__pathrev_t *primary_src 7539 = is_rollback ? source->loc1 : source->loc2; 7540 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b); 7541 svn_client__merge_path_t *merge_target = NULL; 7542 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 7543 7544 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath)); 7545 7546 *conflict_report = NULL; 7547 7548 /* Note that this is a single-file merge. */ 7549 range.start = source->loc1->rev; 7550 range.end = source->loc2->rev; 7551 range.inheritable = TRUE; 7552 7553 merge_target = svn_client__merge_path_create(target_abspath, scratch_pool); 7554 7555 if (honor_mergeinfo) 7556 { 7557 svn_error_t *err; 7558 7559 /* Fetch mergeinfo. */ 7560 err = get_full_mergeinfo(&target_mergeinfo, 7561 &(merge_target->implicit_mergeinfo), 7562 &inherited, svn_mergeinfo_inherited, 7563 merge_b->ra_session1, target_abspath, 7564 MAX(source->loc1->rev, source->loc2->rev), 7565 MIN(source->loc1->rev, source->loc2->rev), 7566 ctx, scratch_pool, iterpool); 7567 7568 if (err) 7569 { 7570 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 7571 { 7572 err = svn_error_createf( 7573 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err, 7574 _("Invalid mergeinfo detected on merge target '%s', " 7575 "merge tracking not possible"), 7576 svn_dirent_local_style(target_abspath, scratch_pool)); 7577 } 7578 return svn_error_trace(err); 7579 } 7580 7581 /* Calculate remaining merges unless this is a record only merge. 7582 In that case the remaining range is the whole range described 7583 by SOURCE->rev1:rev2. */ 7584 if (!merge_b->record_only) 7585 { 7586 /* ### Bug? calculate_remaining_ranges() needs 'source' to adhere 7587 * to the requirements of 'MERGEINFO MERGE SOURCE NORMALIZATION' 7588 * here, but it doesn't appear to be guaranteed so. */ 7589 SVN_ERR(calculate_remaining_ranges(NULL, merge_target, 7590 source, 7591 target_mergeinfo, 7592 merge_b->implicit_src_gap, FALSE, 7593 merge_b->ra_session1, 7594 ctx, scratch_pool, 7595 iterpool)); 7596 remaining_ranges = merge_target->remaining_ranges; 7597 7598 /* We are honoring mergeinfo and this is not a simple record only 7599 merge which blindly records mergeinfo describing the merge of 7600 SOURCE->LOC1->URL@SOURCE->LOC1->REV through 7601 SOURCE->LOC2->URL@SOURCE->LOC2->REV. This means that the oldest 7602 and youngest revisions merged (as determined above by 7603 calculate_remaining_ranges) might differ from those described 7604 in SOURCE. To keep the '--- Merging *' notifications consistent 7605 with the '--- Recording mergeinfo *' notifications, we adjust 7606 RANGE to account for such changes. */ 7607 if (remaining_ranges->nelts) 7608 { 7609 svn_merge_range_t *adj_start_range = 7610 APR_ARRAY_IDX(remaining_ranges, 0, svn_merge_range_t *); 7611 svn_merge_range_t *adj_end_range = 7612 APR_ARRAY_IDX(remaining_ranges, remaining_ranges->nelts - 1, 7613 svn_merge_range_t *); 7614 range.start = adj_start_range->start; 7615 range.end = adj_end_range->end; 7616 } 7617 } 7618 } 7619 7620 /* The simple cases where our remaining range is SOURCE->rev1:rev2. */ 7621 if (!honor_mergeinfo || merge_b->record_only) 7622 { 7623 remaining_ranges = apr_array_make(scratch_pool, 1, sizeof(&range)); 7624 APR_ARRAY_PUSH(remaining_ranges, svn_merge_range_t *) = ⦥ 7625 } 7626 7627 if (!merge_b->record_only) 7628 { 7629 svn_rangelist_t *ranges_to_merge = apr_array_copy(scratch_pool, 7630 remaining_ranges); 7631 const char *target_relpath = ""; /* relative to root of merge */ 7632 7633 if (source->ancestral) 7634 { 7635 apr_array_header_t *child_with_mergeinfo; 7636 svn_client__merge_path_t *target_info; 7637 7638 /* If we have ancestrally related sources and more than one 7639 range to merge, eliminate no-op ranges before going through 7640 the effort of downloading the many copies of the file 7641 required to do these merges (two copies per range). */ 7642 if (remaining_ranges->nelts > 1) 7643 { 7644 const char *old_sess_url; 7645 svn_error_t *err; 7646 7647 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, 7648 merge_b->ra_session1, 7649 primary_src->url, 7650 iterpool)); 7651 err = remove_noop_merge_ranges(&ranges_to_merge, 7652 merge_b->ra_session1, 7653 remaining_ranges, scratch_pool); 7654 SVN_ERR(svn_error_compose_create( 7655 err, svn_ra_reparent(merge_b->ra_session1, 7656 old_sess_url, iterpool))); 7657 } 7658 7659 /* To support notify_merge_begin() initialize our 7660 CHILD_WITH_MERGEINFO. See the comment 7661 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */ 7662 7663 child_with_mergeinfo = apr_array_make(scratch_pool, 1, 7664 sizeof(svn_client__merge_path_t *)); 7665 7666 /* ### Create a fake copy of merge_target as we don't keep 7667 remaining_ranges in sync (yet). */ 7668 target_info = svn_client__merge_path_create(merge_target->abspath, 7669 scratch_pool); 7670 target_info->remaining_ranges = ranges_to_merge; 7671 7672 APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *) 7673 = target_info; 7674 7675 /* And store in baton to allow using it from notify_merge_begin() */ 7676 merge_b->children_with_mergeinfo = child_with_mergeinfo; 7677 } 7678 7679 while (ranges_to_merge->nelts > 0) 7680 { 7681 svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, 0, 7682 svn_merge_range_t *); 7683 const merge_source_t *real_source; 7684 const char *left_file, *right_file; 7685 apr_hash_t *left_props, *right_props; 7686 const svn_diff_source_t *left_source; 7687 const svn_diff_source_t *right_source; 7688 7689 svn_pool_clear(iterpool); 7690 7691 /* Ensure any subsequent drives gets their own notification. */ 7692 merge_b->notify_begin.last_abspath = NULL; 7693 7694 /* While we currently don't allow it, in theory we could be 7695 fetching two fulltexts from two different repositories here. */ 7696 if (source->ancestral) 7697 real_source = subrange_source(source, r->start, r->end, iterpool); 7698 else 7699 real_source = source; 7700 SVN_ERR(single_file_merge_get_file(&left_file, &left_props, 7701 merge_b->ra_session1, 7702 real_source->loc1, 7703 target_abspath, 7704 iterpool, iterpool)); 7705 SVN_ERR(single_file_merge_get_file(&right_file, &right_props, 7706 merge_b->ra_session2, 7707 real_source->loc2, 7708 target_abspath, 7709 iterpool, iterpool)); 7710 /* Calculate sources for the diff processor */ 7711 left_source = svn_diff__source_create(r->start, iterpool); 7712 right_source = svn_diff__source_create(r->end, iterpool); 7713 7714 7715 /* If the sources are related or we're ignoring ancestry in diffs, 7716 do a text-n-props merge; otherwise, do a delete-n-add merge. */ 7717 if (! (merge_b->diff_ignore_ancestry || sources_related)) 7718 { 7719 void *dir_baton = open_dir_for_replace_single_file(iterpool); 7720 void *file_baton; 7721 svn_boolean_t skip; 7722 7723 /* Delete... */ 7724 file_baton = NULL; 7725 skip = FALSE; 7726 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7727 left_source, 7728 NULL /* right_source */, 7729 NULL /* copyfrom_source */, 7730 dir_baton, 7731 processor, 7732 iterpool, iterpool)); 7733 if (! skip) 7734 SVN_ERR(processor->file_deleted(target_relpath, 7735 left_source, 7736 left_file, 7737 left_props, 7738 file_baton, 7739 processor, 7740 iterpool)); 7741 7742 /* ...plus add... */ 7743 file_baton = NULL; 7744 skip = FALSE; 7745 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7746 NULL /* left_source */, 7747 right_source, 7748 NULL /* copyfrom_source */, 7749 dir_baton, 7750 processor, 7751 iterpool, iterpool)); 7752 if (! skip) 7753 SVN_ERR(processor->file_added(target_relpath, 7754 NULL /* copyfrom_source */, 7755 right_source, 7756 NULL /* copyfrom_file */, 7757 right_file, 7758 NULL /* copyfrom_props */, 7759 right_props, 7760 file_baton, 7761 processor, 7762 iterpool)); 7763 /* ... equals replace. */ 7764 } 7765 else 7766 { 7767 void *file_baton = NULL; 7768 svn_boolean_t skip = FALSE; 7769 apr_array_header_t *propchanges; 7770 7771 7772 /* Deduce property diffs. */ 7773 SVN_ERR(svn_prop_diffs(&propchanges, right_props, left_props, 7774 iterpool)); 7775 7776 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7777 left_source, 7778 right_source, 7779 NULL /* copyfrom_source */, 7780 NULL /* dir_baton */, 7781 processor, 7782 iterpool, iterpool)); 7783 if (! skip) 7784 SVN_ERR(processor->file_changed(target_relpath, 7785 left_source, 7786 right_source, 7787 left_file, 7788 right_file, 7789 left_props, 7790 right_props, 7791 TRUE /* file changed */, 7792 propchanges, 7793 file_baton, 7794 processor, 7795 iterpool)); 7796 } 7797 7798 if (is_path_conflicted_by_merge(merge_b)) 7799 { 7800 merge_source_t *remaining_range = NULL; 7801 7802 if (real_source->loc2->rev != source->loc2->rev) 7803 remaining_range = subrange_source(source, 7804 real_source->loc2->rev, 7805 source->loc2->rev, 7806 scratch_pool); 7807 *conflict_report = single_range_conflict_report_create( 7808 real_source, remaining_range, result_pool); 7809 7810 /* Only record partial mergeinfo if only a partial merge was 7811 performed before a conflict was encountered. */ 7812 range.end = r->end; 7813 break; 7814 } 7815 7816 /* Now delete the just merged range from the hash 7817 (This list is used from notify_merge_begin) 7818 7819 Directory merges use remove_first_range_from_remaining_ranges() */ 7820 SVN_ERR(svn_sort__array_delete2(ranges_to_merge, 0, 1)); 7821 } 7822 merge_b->notify_begin.last_abspath = NULL; 7823 } /* !merge_b->record_only */ 7824 7825 /* Record updated WC mergeinfo to account for our new merges, minus 7826 any unresolved conflicts and skips. We use the original 7827 REMAINING_RANGES here because we want to record all the requested 7828 merge ranges, include the noop ones. */ 7829 if (RECORD_MERGEINFO(merge_b) && remaining_ranges->nelts) 7830 { 7831 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src, 7832 scratch_pool); 7833 svn_rangelist_t *filtered_rangelist; 7834 7835 /* Filter any ranges from TARGET_WCPATH's own history, there is no 7836 need to record this explicitly in mergeinfo, it is already part 7837 of TARGET_WCPATH's natural history (implicit mergeinfo). */ 7838 SVN_ERR(filter_natural_history_from_mergeinfo( 7839 &filtered_rangelist, 7840 mergeinfo_path, 7841 merge_target->implicit_mergeinfo, 7842 &range, 7843 iterpool)); 7844 7845 /* Only record mergeinfo if there is something other than 7846 self-referential mergeinfo, but don't record mergeinfo if 7847 TARGET_WCPATH was skipped. */ 7848 if (filtered_rangelist->nelts 7849 && (apr_hash_count(merge_b->skipped_abspaths) == 0)) 7850 { 7851 apr_hash_t *merges = apr_hash_make(iterpool); 7852 7853 /* If merge target has inherited mergeinfo set it before 7854 recording the first merge range. */ 7855 if (inherited) 7856 SVN_ERR(svn_client__record_wc_mergeinfo(target_abspath, 7857 target_mergeinfo, 7858 FALSE, ctx, 7859 iterpool)); 7860 7861 svn_hash_sets(merges, target_abspath, filtered_rangelist); 7862 7863 if (!squelch_mergeinfo_notifications) 7864 { 7865 /* Notify that we are recording mergeinfo describing a merge. */ 7866 svn_merge_range_t n_range; 7867 7868 SVN_ERR(svn_mergeinfo__get_range_endpoints( 7869 &n_range.end, &n_range.start, merges, iterpool)); 7870 n_range.inheritable = TRUE; 7871 notify_mergeinfo_recording(target_abspath, &n_range, 7872 merge_b->ctx, iterpool); 7873 } 7874 7875 SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath, 7876 mergeinfo_path, merges, is_rollback, 7877 ctx, iterpool)); 7878 } 7879 } 7880 7881 merge_b->children_with_mergeinfo = NULL; 7882 7883 svn_pool_destroy(iterpool); 7884 7885 return SVN_NO_ERROR; 7886} 7887 7888/* Helper for do_directory_merge() to handle the case where a merge editor 7889 drive adds explicit mergeinfo to a path which didn't have any explicit 7890 mergeinfo previously. 7891 7892 MERGE_B is cascaded from the argument of the same 7893 name in do_directory_merge(). Should be called only after 7894 do_directory_merge() has called populate_remaining_ranges() and populated 7895 the remaining_ranges field of each child in 7896 CHILDREN_WITH_MERGEINFO (i.e. the remaining_ranges fields can be 7897 empty but never NULL). 7898 7899 If MERGE_B->DRY_RUN is true do nothing, if it is false then 7900 for each path (if any) in MERGE_B->PATHS_WITH_NEW_MERGEINFO merge that 7901 path's inherited mergeinfo (if any) with its working explicit mergeinfo 7902 and set that as the path's new explicit mergeinfo. Then add an 7903 svn_client__merge_path_t * element representing the path to 7904 CHILDREN_WITH_MERGEINFO if it isn't already present. All fields 7905 in any elements added to CHILDREN_WITH_MERGEINFO are initialized 7906 to FALSE/NULL with the exception of 'path' and 'remaining_ranges'. The 7907 latter is set to a rangelist equal to the remaining_ranges of the path's 7908 nearest path-wise ancestor in CHILDREN_WITH_MERGEINFO. 7909 7910 Any elements added to CHILDREN_WITH_MERGEINFO are allocated 7911 in POOL. */ 7912static svn_error_t * 7913process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b, 7914 apr_array_header_t *children_with_mergeinfo, 7915 apr_pool_t *pool) 7916{ 7917 apr_pool_t *iterpool; 7918 apr_array_header_t *a; 7919 int i; 7920 7921 if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run) 7922 return SVN_NO_ERROR; 7923 7924 /* Iterate over each path with explicit mergeinfo added by the merge. */ 7925 /* Iterate over the paths in a parent-to-child order so that inherited 7926 * mergeinfo is propagated consistently from each parent path to its 7927 * children. (Issue #4862) */ 7928 a = svn_sort__hash(merge_b->paths_with_new_mergeinfo, 7929 svn_sort_compare_items_as_paths, pool); 7930 iterpool = svn_pool_create(pool); 7931 for (i = 0; i < a->nelts; i++) 7932 { 7933 svn_sort__item_t *item = &APR_ARRAY_IDX(a, i, svn_sort__item_t); 7934 const char *abspath_with_new_mergeinfo = item->key; 7935 svn_mergeinfo_t path_inherited_mergeinfo; 7936 svn_mergeinfo_t path_explicit_mergeinfo; 7937 svn_client__merge_path_t *new_child; 7938 7939 svn_pool_clear(iterpool); 7940 7941 /* Note: We could skip recording inherited mergeinfo here if this path 7942 was added (with preexisting mergeinfo) by the merge. That's actually 7943 more correct, since the inherited mergeinfo likely describes 7944 non-existent or unrelated merge history, but it's not quite so simple 7945 as that, see https://issues.apache.org/jira/browse/SVN-4309 7946 */ 7947 7948 /* Get the path's new explicit mergeinfo... */ 7949 SVN_ERR(svn_client__get_wc_mergeinfo(&path_explicit_mergeinfo, NULL, 7950 svn_mergeinfo_explicit, 7951 abspath_with_new_mergeinfo, 7952 NULL, NULL, FALSE, 7953 merge_b->ctx, 7954 iterpool, iterpool)); 7955 /* ...there *should* always be explicit mergeinfo at this point 7956 but you can't be too careful. */ 7957 if (path_explicit_mergeinfo) 7958 { 7959 /* Get the mergeinfo the path would have inherited before 7960 the merge. */ 7961 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo( 7962 &path_inherited_mergeinfo, 7963 NULL, NULL, 7964 FALSE, 7965 svn_mergeinfo_nearest_ancestor, /* We only want inherited MI */ 7966 merge_b->ra_session2, 7967 abspath_with_new_mergeinfo, 7968 merge_b->ctx, 7969 iterpool)); 7970 7971 /* If the path inherited any mergeinfo then merge that with the 7972 explicit mergeinfo and record the result as the path's new 7973 explicit mergeinfo. */ 7974 if (path_inherited_mergeinfo) 7975 { 7976 SVN_ERR(svn_mergeinfo_merge2(path_explicit_mergeinfo, 7977 path_inherited_mergeinfo, 7978 iterpool, iterpool)); 7979 SVN_ERR(svn_client__record_wc_mergeinfo( 7980 abspath_with_new_mergeinfo, 7981 path_explicit_mergeinfo, 7982 FALSE, merge_b->ctx, iterpool)); 7983 } 7984 7985 /* If the path is not in CHILDREN_WITH_MERGEINFO then add it. */ 7986 new_child = 7987 get_child_with_mergeinfo(children_with_mergeinfo, 7988 abspath_with_new_mergeinfo); 7989 if (!new_child) 7990 { 7991 const svn_client__merge_path_t *parent 7992 = find_nearest_ancestor(children_with_mergeinfo, 7993 FALSE, abspath_with_new_mergeinfo); 7994 new_child 7995 = svn_client__merge_path_create(abspath_with_new_mergeinfo, 7996 pool); 7997 7998 /* If path_with_new_mergeinfo is the merge target itself 7999 then it should already be in 8000 CHILDREN_WITH_MERGEINFO per the criteria of 8001 get_mergeinfo_paths() and we shouldn't be in this block. 8002 If path_with_new_mergeinfo is a subtree then it must have 8003 a parent in CHILDREN_WITH_MERGEINFO if only 8004 the merge target itself...so if we don't find a parent 8005 the caller has done something quite wrong. */ 8006 SVN_ERR_ASSERT(parent); 8007 SVN_ERR_ASSERT(parent->remaining_ranges); 8008 8009 /* Set the path's remaining_ranges equal to its parent's. */ 8010 new_child->remaining_ranges = svn_rangelist_dup( 8011 parent->remaining_ranges, pool); 8012 SVN_ERR(insert_child_to_merge(children_with_mergeinfo, 8013 new_child, pool)); 8014 } 8015 } 8016 } 8017 svn_pool_destroy(iterpool); 8018 8019 return SVN_NO_ERROR; 8020} 8021 8022/* Return true if any path in SUBTREES is equal to, or is a subtree of, 8023 LOCAL_ABSPATH. Return false otherwise. The keys of SUBTREES are 8024 (const char *) absolute paths and its values are irrelevant. 8025 If SUBTREES is NULL return false. */ 8026static svn_boolean_t 8027path_is_subtree(const char *local_abspath, 8028 apr_hash_t *subtrees, 8029 apr_pool_t *pool) 8030{ 8031 if (subtrees) 8032 { 8033 apr_hash_index_t *hi; 8034 8035 for (hi = apr_hash_first(pool, subtrees); 8036 hi; hi = apr_hash_next(hi)) 8037 { 8038 const char *path_touched_by_merge = apr_hash_this_key(hi); 8039 if (svn_dirent_is_ancestor(local_abspath, path_touched_by_merge)) 8040 return TRUE; 8041 } 8042 } 8043 return FALSE; 8044} 8045 8046/* Return true if any merged, skipped, added or tree-conflicted path 8047 recorded in MERGE_B is equal to, or is a subtree of LOCAL_ABSPATH. Return 8048 false otherwise. 8049 8050 ### Why not text- or prop-conflicted paths? Are such paths guaranteed 8051 to be recorded as 'merged' or 'skipped' or 'added', perhaps? 8052*/ 8053static svn_boolean_t 8054subtree_touched_by_merge(const char *local_abspath, 8055 merge_cmd_baton_t *merge_b, 8056 apr_pool_t *pool) 8057{ 8058 return (path_is_subtree(local_abspath, merge_b->merged_abspaths, pool) 8059 || path_is_subtree(local_abspath, merge_b->skipped_abspaths, pool) 8060 || path_is_subtree(local_abspath, merge_b->added_abspaths, pool) 8061 || path_is_subtree(local_abspath, merge_b->tree_conflicted_abspaths, 8062 pool)); 8063} 8064 8065/* Helper for do_directory_merge() when performing mergeinfo unaware merges. 8066 8067 Merge the SOURCE diff into TARGET_DIR_WCPATH. 8068 8069 SOURCE, DEPTH, NOTIFY_B, and MERGE_B 8070 are all cascaded from do_directory_merge's arguments of the same names. 8071 8072 CONFLICT_REPORT is as documented for do_directory_merge(). 8073 8074 NOTE: This is a very thin wrapper around drive_merge_report_editor() and 8075 exists only to populate CHILDREN_WITH_MERGEINFO with the single element 8076 expected during mergeinfo unaware merges. 8077*/ 8078static svn_error_t * 8079do_mergeinfo_unaware_dir_merge(single_range_conflict_report_t **conflict_report, 8080 const merge_source_t *source, 8081 const char *target_dir_wcpath, 8082 apr_array_header_t *children_with_mergeinfo, 8083 const svn_diff_tree_processor_t *processor, 8084 svn_depth_t depth, 8085 merge_cmd_baton_t *merge_b, 8086 apr_pool_t *result_pool, 8087 apr_pool_t *scratch_pool) 8088{ 8089 /* Initialize CHILDREN_WITH_MERGEINFO and populate it with 8090 one element describing the merge of SOURCE->rev1:rev2 to 8091 TARGET_DIR_WCPATH. */ 8092 svn_client__merge_path_t *item 8093 = svn_client__merge_path_create(target_dir_wcpath, scratch_pool); 8094 8095 *conflict_report = NULL; 8096 item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev, 8097 source->loc2->rev, 8098 TRUE, scratch_pool); 8099 APR_ARRAY_PUSH(children_with_mergeinfo, 8100 svn_client__merge_path_t *) = item; 8101 SVN_ERR(drive_merge_report_editor(target_dir_wcpath, 8102 source, 8103 NULL, processor, depth, 8104 merge_b, scratch_pool)); 8105 if (is_path_conflicted_by_merge(merge_b)) 8106 { 8107 *conflict_report = single_range_conflict_report_create( 8108 source, NULL, result_pool); 8109 } 8110 return SVN_NO_ERROR; 8111} 8112 8113/* A svn_log_entry_receiver_t baton for log_find_operative_subtree_revs(). */ 8114typedef struct log_find_operative_subtree_baton_t 8115{ 8116 /* Mapping of const char * absolute working copy paths to those 8117 path's const char * repos absolute paths. */ 8118 apr_hash_t *operative_children; 8119 8120 /* As per the arguments of the same name to 8121 get_operative_immediate_children(). */ 8122 const char *merge_source_fspath; 8123 const char *merge_target_abspath; 8124 svn_depth_t depth; 8125 svn_wc_context_t *wc_ctx; 8126 8127 /* A pool to allocate additions to the hashes in. */ 8128 apr_pool_t *result_pool; 8129} log_find_operative_subtree_baton_t; 8130 8131/* A svn_log_entry_receiver_t callback for 8132 get_inoperative_immediate_children(). */ 8133static svn_error_t * 8134log_find_operative_subtree_revs(void *baton, 8135 svn_log_entry_t *log_entry, 8136 apr_pool_t *pool) 8137{ 8138 log_find_operative_subtree_baton_t *log_baton = baton; 8139 apr_hash_index_t *hi; 8140 apr_pool_t *iterpool; 8141 8142 /* It's possible that authz restrictions on the merge source prevent us 8143 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 8144 if (!log_entry->changed_paths2) 8145 return SVN_NO_ERROR; 8146 8147 iterpool = svn_pool_create(pool); 8148 8149 for (hi = apr_hash_first(pool, log_entry->changed_paths2); 8150 hi; 8151 hi = apr_hash_next(hi)) 8152 { 8153 const char *path = apr_hash_this_key(hi); 8154 svn_log_changed_path2_t *change = apr_hash_this_val(hi); 8155 8156 { 8157 const char *child; 8158 const char *potential_child; 8159 const char *rel_path = 8160 svn_fspath__skip_ancestor(log_baton->merge_source_fspath, path); 8161 8162 /* Some affected paths might be the root of the merge source or 8163 entirely outside our subtree of interest. In either case they 8164 are not operative *immediate* children. */ 8165 if (rel_path == NULL 8166 || rel_path[0] == '\0') 8167 continue; 8168 8169 svn_pool_clear(iterpool); 8170 8171 child = svn_relpath_dirname(rel_path, iterpool); 8172 if (child[0] == '\0') 8173 { 8174 /* The svn_log_changed_path2_t.node_kind members in 8175 LOG_ENTRY->CHANGED_PATHS2 may be set to 8176 svn_node_unknown, see svn_log_changed_path2_t and 8177 svn_fs_paths_changed2. In that case we check the 8178 type of the corresponding subtree in the merge 8179 target. */ 8180 svn_node_kind_t node_kind; 8181 8182 if (change->node_kind == svn_node_unknown) 8183 { 8184 const char *wc_child_abspath = 8185 svn_dirent_join(log_baton->merge_target_abspath, 8186 rel_path, iterpool); 8187 8188 SVN_ERR(svn_wc_read_kind2(&node_kind, log_baton->wc_ctx, 8189 wc_child_abspath, FALSE, FALSE, 8190 iterpool)); 8191 } 8192 else 8193 { 8194 node_kind = change->node_kind; 8195 } 8196 8197 /* We only care about immediate directory children if 8198 DEPTH is svn_depth_files. */ 8199 if (log_baton->depth == svn_depth_files 8200 && node_kind != svn_node_dir) 8201 continue; 8202 8203 /* If depth is svn_depth_immediates, then we only care 8204 about changes to proper subtrees of PATH. If the change 8205 is to PATH itself then PATH is within the operational 8206 depth of the merge. */ 8207 if (log_baton->depth == svn_depth_immediates) 8208 continue; 8209 8210 child = rel_path; 8211 } 8212 8213 potential_child = svn_dirent_join(log_baton->merge_target_abspath, 8214 child, iterpool); 8215 8216 if (change->action == 'A' 8217 || !svn_hash_gets(log_baton->operative_children, 8218 potential_child)) 8219 { 8220 svn_hash_sets(log_baton->operative_children, 8221 apr_pstrdup(log_baton->result_pool, 8222 potential_child), 8223 apr_pstrdup(log_baton->result_pool, path)); 8224 } 8225 } 8226 } 8227 svn_pool_destroy(iterpool); 8228 return SVN_NO_ERROR; 8229} 8230 8231/* Find immediate subtrees of MERGE_TARGET_ABSPATH which would have 8232 additional differences applied if record_mergeinfo_for_dir_merge() were 8233 recording mergeinfo describing a merge at svn_depth_infinity, rather 8234 than at DEPTH (which is assumed to be shallow; if 8235 DEPTH == svn_depth_infinity then this function does nothing beyond 8236 setting *OPERATIVE_CHILDREN to an empty hash). 8237 8238 MERGE_SOURCE_FSPATH is the absolute repository path of the merge 8239 source. OLDEST_REV and YOUNGEST_REV are the revisions merged from 8240 MERGE_SOURCE_FSPATH to MERGE_TARGET_ABSPATH. 8241 8242 RA_SESSION points to MERGE_SOURCE_FSPATH. 8243 8244 Set *OPERATIVE_CHILDREN to a hash (mapping const char * absolute 8245 working copy paths to those path's const char * repos absolute paths) 8246 containing all the immediate subtrees of MERGE_TARGET_ABSPATH which would 8247 have a different diff applied if MERGE_SOURCE_FSPATH 8248 -r(OLDEST_REV - 1):YOUNGEST_REV were merged to MERGE_TARGET_ABSPATH at 8249 svn_depth_infinity rather than DEPTH. 8250 8251 RESULT_POOL is used to allocate the contents of *OPERATIVE_CHILDREN. 8252 SCRATCH_POOL is used for temporary allocations. */ 8253static svn_error_t * 8254get_operative_immediate_children(apr_hash_t **operative_children, 8255 const char *merge_source_fspath, 8256 svn_revnum_t oldest_rev, 8257 svn_revnum_t youngest_rev, 8258 const char *merge_target_abspath, 8259 svn_depth_t depth, 8260 svn_wc_context_t *wc_ctx, 8261 svn_ra_session_t *ra_session, 8262 apr_pool_t *result_pool, 8263 apr_pool_t *scratch_pool) 8264{ 8265 log_find_operative_subtree_baton_t log_baton; 8266 8267 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev)); 8268 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev)); 8269 SVN_ERR_ASSERT(oldest_rev <= youngest_rev); 8270 8271 *operative_children = apr_hash_make(result_pool); 8272 8273 if (depth == svn_depth_infinity) 8274 return SVN_NO_ERROR; 8275 8276 /* Now remove any paths from *OPERATIVE_CHILDREN that are inoperative when 8277 merging MERGE_SOURCE_REPOS_PATH -r(OLDEST_REV - 1):YOUNGEST_REV to 8278 MERGE_TARGET_ABSPATH at --depth infinity. */ 8279 log_baton.operative_children = *operative_children; 8280 log_baton.merge_source_fspath = merge_source_fspath; 8281 log_baton.merge_target_abspath = merge_target_abspath; 8282 log_baton.depth = depth; 8283 log_baton.wc_ctx = wc_ctx; 8284 log_baton.result_pool = result_pool; 8285 8286 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, 8287 TRUE, /* discover_changed_paths */ 8288 log_find_operative_subtree_revs, 8289 &log_baton, scratch_pool)); 8290 8291 return SVN_NO_ERROR; 8292} 8293 8294/* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of 8295 CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately 8296 describe a merge, what inheritance type such new mergeinfo should have, 8297 and what subtrees can be ignored altogether. 8298 8299 For each svn_client__merge_path_t CHILD in CHILDREN_WITH_MERGEINFO, 8300 set CHILD->RECORD_MERGEINFO and CHILD->RECORD_NONINHERITABLE to true 8301 if the subtree needs mergeinfo to describe the merge and if that 8302 mergeinfo should be non-inheritable respectively. 8303 8304 If OPERATIVE_MERGE is true, then the merge being described is operative 8305 as per subtree_touched_by_merge(). OPERATIVE_MERGE is false otherwise. 8306 8307 MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all 8308 cascaded from record_mergeinfo_for_dir_merge's arguments of the same 8309 names. 8310 8311 SCRATCH_POOL is used for temporary allocations. 8312*/ 8313static svn_error_t * 8314flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge, 8315 const svn_merge_range_t *merged_range, 8316 apr_array_header_t *children_with_mergeinfo, 8317 const char *mergeinfo_fspath, 8318 svn_depth_t depth, 8319 merge_cmd_baton_t *merge_b, 8320 apr_pool_t *scratch_pool) 8321{ 8322 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 8323 int i; 8324 apr_hash_t *operative_immediate_children = NULL; 8325 8326 assert(! merge_b->dry_run); 8327 8328 if (!merge_b->record_only 8329 && merged_range->start <= merged_range->end 8330 && (depth < svn_depth_infinity)) 8331 SVN_ERR(get_operative_immediate_children( 8332 &operative_immediate_children, 8333 mergeinfo_fspath, merged_range->start + 1, merged_range->end, 8334 merge_b->target->abspath, depth, merge_b->ctx->wc_ctx, 8335 merge_b->ra_session1, scratch_pool, iterpool)); 8336 8337 /* Issue #4056: Walk CHILDREN_WITH_MERGEINFO reverse depth-first 8338 order. This way each child knows if it has operative missing/switched 8339 children which necessitates non-inheritable mergeinfo. */ 8340 for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--) 8341 { 8342 svn_client__merge_path_t *child = 8343 APR_ARRAY_IDX(children_with_mergeinfo, i, 8344 svn_client__merge_path_t *); 8345 8346 /* Can't record mergeinfo on something that isn't here. */ 8347 if (child->absent) 8348 continue; 8349 8350 /* Verify that remove_children_with_deleted_mergeinfo() did its job */ 8351 assert((i == 0) 8352 ||! merge_b->paths_with_deleted_mergeinfo 8353 || !svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, 8354 child->abspath)); 8355 8356 /* Don't record mergeinfo on skipped paths. */ 8357 if (svn_hash_gets(merge_b->skipped_abspaths, child->abspath)) 8358 continue; 8359 8360 /* ### ptb: Yes, we could combine the following into a single 8361 ### conditional, but clarity would suffer (even more than 8362 ### it does now). */ 8363 if (i == 0) 8364 { 8365 /* Always record mergeinfo on the merge target. */ 8366 child->record_mergeinfo = TRUE; 8367 } 8368 else if (merge_b->record_only && !merge_b->reintegrate_merge) 8369 { 8370 /* Always record mergeinfo for --record-only merges. */ 8371 child->record_mergeinfo = TRUE; 8372 } 8373 else if (child->immediate_child_dir 8374 && !child->pre_merge_mergeinfo 8375 && operative_immediate_children 8376 && svn_hash_gets(operative_immediate_children, child->abspath)) 8377 { 8378 /* We must record mergeinfo on those issue #3642 children 8379 that are operative at a greater depth. */ 8380 child->record_mergeinfo = TRUE; 8381 } 8382 8383 if (operative_merge 8384 && subtree_touched_by_merge(child->abspath, merge_b, iterpool)) 8385 { 8386 svn_pool_clear(iterpool); 8387 8388 /* This subtree was affected by the merge. */ 8389 child->record_mergeinfo = TRUE; 8390 8391 /* Were any CHILD's missing children skipped by the merge? 8392 If not, then CHILD's missing children don't need to be 8393 considered when recording mergeinfo describing the merge. */ 8394 if (! merge_b->reintegrate_merge 8395 && child->missing_child 8396 && !path_is_subtree(child->abspath, 8397 merge_b->skipped_abspaths, 8398 iterpool)) 8399 { 8400 child->missing_child = FALSE; 8401 } 8402 8403 /* If CHILD has an immediate switched child or children and 8404 none of these were touched by the merge, then we don't need 8405 need to do any special handling of those switched subtrees 8406 (e.g. record non-inheritable mergeinfo) when recording 8407 mergeinfo describing the merge. */ 8408 if (child->switched_child) 8409 { 8410 int j; 8411 svn_boolean_t operative_switched_child = FALSE; 8412 8413 for (j = i + 1; 8414 j < children_with_mergeinfo->nelts; 8415 j++) 8416 { 8417 svn_client__merge_path_t *potential_child = 8418 APR_ARRAY_IDX(children_with_mergeinfo, j, 8419 svn_client__merge_path_t *); 8420 if (!svn_dirent_is_ancestor(child->abspath, 8421 potential_child->abspath)) 8422 break; 8423 8424 /* POTENTIAL_CHILD is a subtree of CHILD, but is it 8425 an immediate child? */ 8426 if (strcmp(child->abspath, 8427 svn_dirent_dirname(potential_child->abspath, 8428 iterpool))) 8429 continue; 8430 8431 if (potential_child->switched 8432 && potential_child->record_mergeinfo) 8433 { 8434 operative_switched_child = TRUE; 8435 break; 8436 } 8437 } 8438 8439 /* Can we treat CHILD as if it has no switched children? */ 8440 if (! operative_switched_child) 8441 child->switched_child = FALSE; 8442 } 8443 } 8444 8445 if (child->record_mergeinfo) 8446 { 8447 /* We need to record mergeinfo, but should that mergeinfo be 8448 non-inheritable? */ 8449 svn_node_kind_t path_kind; 8450 SVN_ERR(svn_wc_read_kind2(&path_kind, merge_b->ctx->wc_ctx, 8451 child->abspath, FALSE, FALSE, iterpool)); 8452 8453 /* Only directories can have non-inheritable mergeinfo. */ 8454 if (path_kind == svn_node_dir) 8455 { 8456 /* There are two general cases where non-inheritable mergeinfo 8457 is required: 8458 8459 1) There merge target has missing subtrees (due to authz 8460 restrictions, switched subtrees, or a shallow working 8461 copy). 8462 8463 2) The operational depth of the merge itself is shallow. */ 8464 8465 /* We've already determined the first case. */ 8466 child->record_noninheritable = 8467 child->missing_child || child->switched_child; 8468 8469 /* The second case requires a bit more work. */ 8470 if (i == 0) 8471 { 8472 /* If CHILD is the root of the merge target and the 8473 operational depth is empty or files, then the mere 8474 existence of operative immediate children means we 8475 must record non-inheritable mergeinfo. 8476 8477 ### What about svn_depth_immediates? In that case 8478 ### the merge target needs only normal inheritable 8479 ### mergeinfo and the target's immediate children will 8480 ### get non-inheritable mergeinfo, assuming they 8481 ### need even that. */ 8482 if (depth < svn_depth_immediates 8483 && operative_immediate_children 8484 && apr_hash_count(operative_immediate_children)) 8485 child->record_noninheritable = TRUE; 8486 } 8487 else if (depth == svn_depth_immediates) 8488 { 8489 /* An immediate directory child of the merge target, which 8490 was affected by a --depth=immediates merge, needs 8491 non-inheritable mergeinfo. */ 8492 if (svn_hash_gets(operative_immediate_children, 8493 child->abspath)) 8494 child->record_noninheritable = TRUE; 8495 } 8496 } 8497 } 8498 else /* child->record_mergeinfo */ 8499 { 8500 /* If CHILD is in CHILDREN_WITH_MERGEINFO simply 8501 because it had no explicit mergeinfo of its own at the 8502 start of the merge but is the child of of some path with 8503 non-inheritable mergeinfo, then the explicit mergeinfo it 8504 has *now* was set by get_mergeinfo_paths() -- see criteria 8505 3 in that function's doc string. So since CHILD->ABSPATH 8506 was not touched by the merge we can remove the 8507 mergeinfo. */ 8508 if (child->child_of_noninheritable) 8509 SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath, 8510 NULL, FALSE, 8511 merge_b->ctx, 8512 iterpool)); 8513 } 8514 } 8515 8516 svn_pool_destroy(iterpool); 8517 return SVN_NO_ERROR; 8518} 8519 8520/* Helper for do_directory_merge(). 8521 8522 If RESULT_CATALOG is NULL then record mergeinfo describing a merge of 8523 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path 8524 MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described 8525 by CHILDREN_WITH_MERGEINFO -- see the global comment 8526 'THE CHILDREN_WITH_MERGEINFO ARRAY'. Obviously this should only 8527 be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO(). 8528 8529 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the 8530 WC, but instead record it in RESULT_CATALOG, where the keys are absolute 8531 working copy paths and the values are the new mergeinfos for each. 8532 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was 8533 created in. 8534 8535 DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS are all 8536 cascaded from do_directory_merge's arguments of the same names. 8537 8538 SCRATCH_POOL is used for temporary allocations. 8539*/ 8540static svn_error_t * 8541record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog, 8542 const svn_merge_range_t *merged_range, 8543 const char *mergeinfo_fspath, 8544 apr_array_header_t *children_with_mergeinfo, 8545 svn_depth_t depth, 8546 svn_boolean_t squelch_mergeinfo_notifications, 8547 merge_cmd_baton_t *merge_b, 8548 apr_pool_t *scratch_pool) 8549{ 8550 int i; 8551 svn_boolean_t is_rollback = (merged_range->start > merged_range->end); 8552 svn_boolean_t operative_merge; 8553 8554 /* Update the WC mergeinfo here to account for our new 8555 merges, minus any unresolved conflicts and skips. */ 8556 8557 /* We need a scratch pool for iterations below. */ 8558 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 8559 8560 svn_merge_range_t range = *merged_range; 8561 8562 assert(! merge_b->dry_run); 8563 8564 /* Regardless of what subtrees in MERGE_B->target->abspath might be missing 8565 could this merge have been operative? */ 8566 operative_merge = subtree_touched_by_merge(merge_b->target->abspath, 8567 merge_b, iterpool); 8568 8569 /* If this couldn't be an operative merge then don't bother with 8570 the added complexity (and user confusion) of non-inheritable ranges. 8571 There is no harm in subtrees inheriting inoperative mergeinfo. */ 8572 if (!operative_merge) 8573 range.inheritable = TRUE; 8574 8575 /* Remove absent children at or under MERGE_B->target->abspath from 8576 CHILDREN_WITH_MERGEINFO 8577 before we calculate the merges performed. */ 8578 SVN_ERR(remove_absent_children(merge_b->target->abspath, 8579 children_with_mergeinfo)); 8580 8581 /* Determine which subtrees of interest need mergeinfo recorded... */ 8582 SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range, 8583 children_with_mergeinfo, 8584 mergeinfo_fspath, depth, 8585 merge_b, iterpool)); 8586 8587 /* ...and then record it. */ 8588 for (i = 0; i < children_with_mergeinfo->nelts; i++) 8589 { 8590 const char *child_repos_path; 8591 const char *child_merge_src_fspath; 8592 svn_rangelist_t *child_merge_rangelist; 8593 apr_hash_t *child_merges; 8594 svn_client__merge_path_t *child = 8595 APR_ARRAY_IDX(children_with_mergeinfo, i, 8596 svn_client__merge_path_t *); 8597 SVN_ERR_ASSERT(child); 8598 8599 svn_pool_clear(iterpool); 8600 8601 if (child->record_mergeinfo) 8602 { 8603 child_repos_path = svn_dirent_skip_ancestor(merge_b->target->abspath, 8604 child->abspath); 8605 SVN_ERR_ASSERT(child_repos_path != NULL); 8606 child_merge_src_fspath = svn_fspath__join(mergeinfo_fspath, 8607 child_repos_path, 8608 iterpool); 8609 /* Filter any ranges from each child's natural history before 8610 setting mergeinfo describing the merge. */ 8611 SVN_ERR(filter_natural_history_from_mergeinfo( 8612 &child_merge_rangelist, child_merge_src_fspath, 8613 child->implicit_mergeinfo, &range, iterpool)); 8614 8615 if (child_merge_rangelist->nelts == 0) 8616 continue; 8617 8618 if (!squelch_mergeinfo_notifications) 8619 { 8620 /* If the merge source has a gap, then don't mention 8621 those gap revisions in the notification. */ 8622 remove_source_gap(&range, merge_b->implicit_src_gap); 8623 notify_mergeinfo_recording(child->abspath, &range, 8624 merge_b->ctx, iterpool); 8625 } 8626 8627 /* If we are here we know we will be recording some mergeinfo, but 8628 before we do, set override mergeinfo on skipped paths so they 8629 don't incorrectly inherit the mergeinfo we are about to set. */ 8630 if (i == 0) 8631 SVN_ERR(record_skips_in_mergeinfo(mergeinfo_fspath, 8632 child_merge_rangelist, 8633 is_rollback, merge_b, iterpool)); 8634 8635 /* We may need to record non-inheritable mergeinfo that applies 8636 only to CHILD->ABSPATH. */ 8637 if (child->record_noninheritable) 8638 svn_rangelist__set_inheritance(child_merge_rangelist, FALSE); 8639 8640 /* If CHILD has inherited mergeinfo set it before 8641 recording the first merge range. */ 8642 if (child->inherited_mergeinfo) 8643 SVN_ERR(svn_client__record_wc_mergeinfo( 8644 child->abspath, 8645 child->pre_merge_mergeinfo, 8646 FALSE, merge_b->ctx, 8647 iterpool)); 8648 if (merge_b->implicit_src_gap) 8649 { 8650 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 8651 so it will work with the svn_rangelist_remove API. */ 8652 if (is_rollback) 8653 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist, 8654 iterpool)); 8655 8656 SVN_ERR(svn_rangelist_remove(&child_merge_rangelist, 8657 merge_b->implicit_src_gap, 8658 child_merge_rangelist, FALSE, 8659 iterpool)); 8660 if (is_rollback) 8661 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist, 8662 iterpool)); 8663 } 8664 8665 child_merges = apr_hash_make(iterpool); 8666 8667 /* The short story: 8668 8669 If we are describing a forward merge, then the naive mergeinfo 8670 defined by MERGE_SOURCE_PATH:MERGED_RANGE->START: 8671 MERGE_SOURCE_PATH:MERGED_RANGE->END may contain non-existent 8672 path-revs or may describe other lines of history. We must 8673 remove these invalid portion(s) before recording mergeinfo 8674 describing the merge. 8675 8676 The long story: 8677 8678 If CHILD is the merge target we know that 8679 MERGE_SOURCE_PATH:MERGED_RANGE->END exists. Further, if there 8680 were no copies in MERGE_SOURCE_PATH's history going back to 8681 RANGE->START then we know that 8682 MERGE_SOURCE_PATH:MERGED_RANGE->START exists too and the two 8683 describe an unbroken line of history, and thus 8684 MERGE_SOURCE_PATH:MERGED_RANGE->START: 8685 MERGE_SOURCE_PATH:MERGED_RANGE->END is a valid description of 8686 the merge -- see normalize_merge_sources() and the global comment 8687 'MERGEINFO MERGE SOURCE NORMALIZATION'. 8688 8689 However, if there *was* a copy, then 8690 MERGE_SOURCE_PATH:MERGED_RANGE->START doesn't exist or is 8691 unrelated to MERGE_SOURCE_PATH:MERGED_RANGE->END. Also, we 8692 don't know if (MERGE_SOURCE_PATH:MERGED_RANGE->START)+1 through 8693 (MERGE_SOURCE_PATH:MERGED_RANGE->END)-1 actually exist. 8694 8695 If CHILD is a subtree of the merge target, then nothing is 8696 guaranteed beyond the fact that MERGE_SOURCE_PATH exists at 8697 MERGED_RANGE->END. */ 8698 if ((!merge_b->record_only || merge_b->reintegrate_merge) 8699 && (!is_rollback)) 8700 { 8701 svn_error_t *err; 8702 svn_mergeinfo_t subtree_history_as_mergeinfo; 8703 svn_rangelist_t *child_merge_src_rangelist; 8704 svn_client__pathrev_t *subtree_mergeinfo_pathrev 8705 = svn_client__pathrev_create_with_relpath( 8706 merge_b->target->loc.repos_root_url, 8707 merge_b->target->loc.repos_uuid, 8708 merged_range->end, child_merge_src_fspath + 1, 8709 iterpool); 8710 8711 /* Confirm that the naive mergeinfo we want to set on 8712 CHILD->ABSPATH both exists and is part of 8713 (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's 8714 history. */ 8715 /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START 8716 because we only do this for forward merges. */ 8717 err = svn_client__get_history_as_mergeinfo( 8718 &subtree_history_as_mergeinfo, NULL, 8719 subtree_mergeinfo_pathrev, 8720 merged_range->end, merged_range->start, 8721 merge_b->ra_session2, merge_b->ctx, iterpool); 8722 8723 /* If CHILD is a subtree it may have been deleted prior to 8724 MERGED_RANGE->END so the above call to get its history 8725 will fail. */ 8726 if (err) 8727 { 8728 if (err->apr_err != SVN_ERR_FS_NOT_FOUND) 8729 return svn_error_trace(err); 8730 svn_error_clear(err); 8731 } 8732 else 8733 { 8734 child_merge_src_rangelist = svn_hash_gets( 8735 subtree_history_as_mergeinfo, 8736 child_merge_src_fspath); 8737 SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist, 8738 child_merge_rangelist, 8739 child_merge_src_rangelist, 8740 FALSE, iterpool)); 8741 if (child->record_noninheritable) 8742 svn_rangelist__set_inheritance(child_merge_rangelist, 8743 FALSE); 8744 } 8745 } 8746 8747 svn_hash_sets(child_merges, child->abspath, child_merge_rangelist); 8748 SVN_ERR(update_wc_mergeinfo(result_catalog, 8749 child->abspath, 8750 child_merge_src_fspath, 8751 child_merges, is_rollback, 8752 merge_b->ctx, iterpool)); 8753 8754 /* Once is enough: We don't need to record mergeinfo describing 8755 the merge a second. If CHILD->ABSPATH is in 8756 MERGE_B->ADDED_ABSPATHS, we'll do just that, so remove the 8757 former from the latter. */ 8758 svn_hash_sets(merge_b->added_abspaths, child->abspath, NULL); 8759 } 8760 8761 /* Elide explicit subtree mergeinfo whether or not we updated it. */ 8762 if (i > 0) 8763 { 8764 svn_boolean_t in_switched_subtree = FALSE; 8765 8766 if (child->switched) 8767 in_switched_subtree = TRUE; 8768 else if (i > 1) 8769 { 8770 /* Check if CHILD is part of a switched subtree */ 8771 svn_client__merge_path_t *parent; 8772 int j = i - 1; 8773 for (; j > 0; j--) 8774 { 8775 parent = APR_ARRAY_IDX(children_with_mergeinfo, 8776 j, svn_client__merge_path_t *); 8777 if (parent 8778 && parent->switched 8779 && svn_dirent_is_ancestor(parent->abspath, 8780 child->abspath)) 8781 { 8782 in_switched_subtree = TRUE; 8783 break; 8784 } 8785 } 8786 } 8787 8788 /* Allow mergeinfo on switched subtrees to elide to the 8789 repository. Otherwise limit elision to the merge target 8790 for now. do_merge() will eventually try to 8791 elide that when the merge is complete. */ 8792 SVN_ERR(svn_client__elide_mergeinfo( 8793 child->abspath, 8794 in_switched_subtree ? NULL : merge_b->target->abspath, 8795 merge_b->ctx, iterpool)); 8796 } 8797 } /* (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++) */ 8798 8799 svn_pool_destroy(iterpool); 8800 return SVN_NO_ERROR; 8801} 8802 8803/* Helper for do_directory_merge(). 8804 8805 Record mergeinfo describing a merge of 8806 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path 8807 MERGEINFO_FSPATH to each path in ADDED_ABSPATHS which has explicit 8808 mergeinfo or is the immediate child of a parent with explicit 8809 non-inheritable mergeinfo. 8810 8811 DEPTH, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS, are 8812 cascaded from do_directory_merge's arguments of the same names. 8813 8814 Note: This is intended to support forward merges only, i.e. 8815 MERGED_RANGE->START must be older than MERGED_RANGE->END. 8816*/ 8817static svn_error_t * 8818record_mergeinfo_for_added_subtrees( 8819 svn_merge_range_t *merged_range, 8820 const char *mergeinfo_fspath, 8821 svn_depth_t depth, 8822 svn_boolean_t squelch_mergeinfo_notifications, 8823 apr_hash_t *added_abspaths, 8824 merge_cmd_baton_t *merge_b, 8825 apr_pool_t *pool) 8826{ 8827 apr_pool_t *iterpool; 8828 apr_hash_index_t *hi; 8829 8830 /* If no paths were added by the merge then we have nothing to do. */ 8831 if (!added_abspaths) 8832 return SVN_NO_ERROR; 8833 8834 SVN_ERR_ASSERT(merged_range->start < merged_range->end); 8835 8836 iterpool = svn_pool_create(pool); 8837 for (hi = apr_hash_first(pool, added_abspaths); hi; hi = apr_hash_next(hi)) 8838 { 8839 const char *added_abspath = apr_hash_this_key(hi); 8840 const char *dir_abspath; 8841 svn_mergeinfo_t parent_mergeinfo; 8842 svn_mergeinfo_t added_path_mergeinfo; 8843 8844 svn_pool_clear(iterpool); 8845 dir_abspath = svn_dirent_dirname(added_abspath, iterpool); 8846 8847 /* Grab the added path's explicit mergeinfo. */ 8848 SVN_ERR(svn_client__get_wc_mergeinfo(&added_path_mergeinfo, NULL, 8849 svn_mergeinfo_explicit, 8850 added_abspath, NULL, NULL, FALSE, 8851 merge_b->ctx, iterpool, iterpool)); 8852 8853 /* If the added path doesn't have explicit mergeinfo, does its immediate 8854 parent have non-inheritable mergeinfo? */ 8855 if (!added_path_mergeinfo) 8856 SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, NULL, 8857 svn_mergeinfo_explicit, 8858 dir_abspath, NULL, NULL, FALSE, 8859 merge_b->ctx, 8860 iterpool, iterpool)); 8861 8862 if (added_path_mergeinfo 8863 || svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool)) 8864 { 8865 svn_node_kind_t added_path_kind; 8866 svn_mergeinfo_t merge_mergeinfo; 8867 svn_mergeinfo_t adds_history_as_mergeinfo; 8868 svn_rangelist_t *rangelist; 8869 const char *rel_added_path; 8870 const char *added_path_mergeinfo_fspath; 8871 svn_client__pathrev_t *added_path_pathrev; 8872 8873 SVN_ERR(svn_wc_read_kind2(&added_path_kind, merge_b->ctx->wc_ctx, 8874 added_abspath, FALSE, FALSE, iterpool)); 8875 8876 /* Calculate the naive mergeinfo describing the merge. */ 8877 merge_mergeinfo = apr_hash_make(iterpool); 8878 rangelist = svn_rangelist__initialize( 8879 merged_range->start, merged_range->end, 8880 ((added_path_kind == svn_node_file) 8881 || (!(depth == svn_depth_infinity 8882 || depth == svn_depth_immediates))), 8883 iterpool); 8884 8885 /* Create the new mergeinfo path for added_path's mergeinfo. 8886 (added_abspath had better be a child of MERGE_B->target->abspath 8887 or something is *really* wrong.) */ 8888 rel_added_path = svn_dirent_is_child(merge_b->target->abspath, 8889 added_abspath, iterpool); 8890 SVN_ERR_ASSERT(rel_added_path); 8891 added_path_mergeinfo_fspath = svn_fspath__join(mergeinfo_fspath, 8892 rel_added_path, 8893 iterpool); 8894 svn_hash_sets(merge_mergeinfo, added_path_mergeinfo_fspath, 8895 rangelist); 8896 8897 /* Don't add new mergeinfo to describe the merge if that mergeinfo 8898 contains non-existent merge sources. 8899 8900 We know that MERGEINFO_PATH/rel_added_path's history does not 8901 span MERGED_RANGE->START:MERGED_RANGE->END but rather that it 8902 was added at some revions greater than MERGED_RANGE->START 8903 (assuming this is a forward merge). It may have been added, 8904 deleted, and re-added many times. The point is that we cannot 8905 blindly apply the naive mergeinfo calculated above because it 8906 will describe non-existent merge sources. To avoid this we get 8907 take the intersection of the naive mergeinfo with 8908 MERGEINFO_PATH/rel_added_path's history. */ 8909 added_path_pathrev = svn_client__pathrev_create_with_relpath( 8910 merge_b->target->loc.repos_root_url, 8911 merge_b->target->loc.repos_uuid, 8912 MAX(merged_range->start, merged_range->end), 8913 added_path_mergeinfo_fspath + 1, iterpool); 8914 SVN_ERR(svn_client__get_history_as_mergeinfo( 8915 &adds_history_as_mergeinfo, NULL, 8916 added_path_pathrev, 8917 MAX(merged_range->start, merged_range->end), 8918 MIN(merged_range->start, merged_range->end), 8919 merge_b->ra_session2, merge_b->ctx, iterpool)); 8920 8921 SVN_ERR(svn_mergeinfo_intersect2(&merge_mergeinfo, 8922 merge_mergeinfo, 8923 adds_history_as_mergeinfo, 8924 FALSE, iterpool, iterpool)); 8925 8926 /* Combine the explicit mergeinfo on the added path (if any) 8927 with the mergeinfo describing this merge. */ 8928 if (added_path_mergeinfo) 8929 SVN_ERR(svn_mergeinfo_merge2(merge_mergeinfo, 8930 added_path_mergeinfo, 8931 iterpool, iterpool)); 8932 SVN_ERR(svn_client__record_wc_mergeinfo( 8933 added_abspath, merge_mergeinfo, 8934 !squelch_mergeinfo_notifications, merge_b->ctx, iterpool)); 8935 } 8936 } 8937 svn_pool_destroy(iterpool); 8938 8939 return SVN_NO_ERROR; 8940} 8941/* Baton structure for log_noop_revs. */ 8942typedef struct log_noop_baton_t 8943{ 8944 /* See the comment 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start 8945 of this file.*/ 8946 apr_array_header_t *children_with_mergeinfo; 8947 8948 /* Absolute repository path of younger of the two merge sources 8949 being diffed. */ 8950 const char *source_fspath; 8951 8952 /* The merge target. */ 8953 const merge_target_t *target; 8954 8955 /* Initially empty rangelists allocated in POOL. The rangelists are 8956 * populated across multiple invocations of log_noop_revs(). */ 8957 svn_rangelist_t *operative_ranges; 8958 svn_rangelist_t *merged_ranges; 8959 8960 /* Pool to store the rangelists. */ 8961 apr_pool_t *pool; 8962} log_noop_baton_t; 8963 8964/* Helper for log_noop_revs: Merge a svn_merge_range_t representation of 8965 REVISION into RANGELIST. New elements added to rangelist are allocated 8966 in RESULT_POOL. 8967 8968 This is *not* a general purpose rangelist merge but a special replacement 8969 for svn_rangelist_merge when REVISION is guaranteed to be younger than any 8970 element in RANGELIST. svn_rangelist_merge is O(n) worst-case (i.e. when 8971 all the ranges in output rangelist are older than the incoming changes). 8972 This turns the special case of a single incoming younger range into O(1). 8973 */ 8974static svn_error_t * 8975rangelist_merge_revision(svn_rangelist_t *rangelist, 8976 svn_revnum_t revision, 8977 apr_pool_t *result_pool) 8978{ 8979 svn_merge_range_t *new_range; 8980 if (rangelist->nelts) 8981 { 8982 svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1, 8983 svn_merge_range_t *); 8984 if (range->end == revision - 1) 8985 { 8986 /* REVISION is adjacent to the youngest range in RANGELIST 8987 so we can simply expand that range to encompass REVISION. */ 8988 range->end = revision; 8989 return SVN_NO_ERROR; 8990 } 8991 } 8992 new_range = apr_palloc(result_pool, sizeof(*new_range)); 8993 new_range->start = revision - 1; 8994 new_range->end = revision; 8995 new_range->inheritable = TRUE; 8996 8997 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = new_range; 8998 8999 return SVN_NO_ERROR; 9000} 9001 9002/* Implements the svn_log_entry_receiver_t interface. 9003 9004 BATON is an log_noop_baton_t *. 9005 9006 Add LOG_ENTRY->REVISION to BATON->OPERATIVE_RANGES. 9007 9008 If LOG_ENTRY->REVISION has already been fully merged to 9009 BATON->target->abspath per the mergeinfo in BATON->CHILDREN_WITH_MERGEINFO, 9010 then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. 9011 9012 Use SCRATCH_POOL for temporary allocations. Allocate additions to 9013 BATON->MERGED_RANGES and BATON->OPERATIVE_RANGES in BATON->POOL. 9014 9015 Note: This callback must be invoked from oldest LOG_ENTRY->REVISION 9016 to youngest LOG_ENTRY->REVISION -- see rangelist_merge_revision(). 9017*/ 9018static svn_error_t * 9019log_noop_revs(void *baton, 9020 svn_log_entry_t *log_entry, 9021 apr_pool_t *scratch_pool) 9022{ 9023 log_noop_baton_t *log_gap_baton = baton; 9024 apr_hash_index_t *hi; 9025 svn_revnum_t revision; 9026 svn_boolean_t log_entry_rev_required = FALSE; 9027 9028 revision = log_entry->revision; 9029 9030 /* It's possible that authz restrictions on the merge source prevent us 9031 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 9032 if (!log_entry->changed_paths2) 9033 return SVN_NO_ERROR; 9034 9035 /* Unconditionally add LOG_ENTRY->REVISION to BATON->OPERATIVE_MERGES. */ 9036 SVN_ERR(rangelist_merge_revision(log_gap_baton->operative_ranges, 9037 revision, 9038 log_gap_baton->pool)); 9039 9040 /* Examine each path affected by LOG_ENTRY->REVISION. If the explicit or 9041 inherited mergeinfo for *all* of the corresponding paths under 9042 BATON->target->abspath reflects that LOG_ENTRY->REVISION has been 9043 merged, then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. */ 9044 for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2); 9045 hi; 9046 hi = apr_hash_next(hi)) 9047 { 9048 const char *fspath = apr_hash_this_key(hi); 9049 const char *rel_path; 9050 const char *cwmi_abspath; 9051 svn_rangelist_t *paths_explicit_rangelist = NULL; 9052 svn_boolean_t mergeinfo_inherited = FALSE; 9053 9054 /* Adjust REL_PATH so it is relative to the merge source then use it to 9055 calculate what path in the merge target would be affected by this 9056 revision. */ 9057 rel_path = svn_fspath__skip_ancestor(log_gap_baton->source_fspath, 9058 fspath); 9059 /* Is PATH even within the merge target? If it isn't we 9060 can disregard it altogether. */ 9061 if (rel_path == NULL) 9062 continue; 9063 cwmi_abspath = svn_dirent_join(log_gap_baton->target->abspath, 9064 rel_path, scratch_pool); 9065 9066 /* Find any explicit or inherited mergeinfo for PATH. */ 9067 while (!log_entry_rev_required) 9068 { 9069 svn_client__merge_path_t *child = get_child_with_mergeinfo( 9070 log_gap_baton->children_with_mergeinfo, cwmi_abspath); 9071 9072 if (child && child->pre_merge_mergeinfo) 9073 { 9074 /* Found some explicit mergeinfo, grab any ranges 9075 for PATH. */ 9076 paths_explicit_rangelist = 9077 svn_hash_gets(child->pre_merge_mergeinfo, fspath); 9078 break; 9079 } 9080 9081 if (cwmi_abspath[0] == '\0' 9082 || svn_dirent_is_root(cwmi_abspath, strlen(cwmi_abspath)) 9083 || strcmp(log_gap_baton->target->abspath, cwmi_abspath) == 0) 9084 { 9085 /* Can't crawl any higher. */ 9086 break; 9087 } 9088 9089 /* Didn't find anything so crawl up to the parent. */ 9090 cwmi_abspath = svn_dirent_dirname(cwmi_abspath, scratch_pool); 9091 fspath = svn_fspath__dirname(fspath, scratch_pool); 9092 9093 /* At this point *if* we find mergeinfo it will be inherited. */ 9094 mergeinfo_inherited = TRUE; 9095 } 9096 9097 if (paths_explicit_rangelist) 9098 { 9099 svn_rangelist_t *intersecting_range; 9100 svn_rangelist_t *rangelist; 9101 9102 rangelist = svn_rangelist__initialize(revision - 1, revision, TRUE, 9103 scratch_pool); 9104 9105 /* If PATH inherited mergeinfo we must consider inheritance in the 9106 event the inherited mergeinfo is actually non-inheritable. */ 9107 SVN_ERR(svn_rangelist_intersect(&intersecting_range, 9108 paths_explicit_rangelist, 9109 rangelist, 9110 mergeinfo_inherited, scratch_pool)); 9111 9112 if (intersecting_range->nelts == 0) 9113 log_entry_rev_required = TRUE; 9114 } 9115 else 9116 { 9117 log_entry_rev_required = TRUE; 9118 } 9119 } 9120 9121 if (!log_entry_rev_required) 9122 SVN_ERR(rangelist_merge_revision(log_gap_baton->merged_ranges, 9123 revision, 9124 log_gap_baton->pool)); 9125 9126 return SVN_NO_ERROR; 9127} 9128 9129/* Helper for do_directory_merge(). 9130 9131 SOURCE is cascaded from the argument of the same name in 9132 do_directory_merge(). TARGET is the merge target. RA_SESSION is the 9133 session for SOURCE->loc2. 9134 9135 Find all the ranges required by subtrees in 9136 CHILDREN_WITH_MERGEINFO that are *not* required by 9137 TARGET->abspath (i.e. CHILDREN_WITH_MERGEINFO[0]). If such 9138 ranges exist, then find any subset of ranges which, if merged, would be 9139 inoperative. Finally, if any inoperative ranges are found then remove 9140 these ranges from all of the subtree's REMAINING_RANGES. 9141 9142 This function should only be called when honoring mergeinfo during 9143 forward merges (i.e. SOURCE->rev1 < SOURCE->rev2). 9144*/ 9145static svn_error_t * 9146remove_noop_subtree_ranges(const merge_source_t *source, 9147 const merge_target_t *target, 9148 svn_ra_session_t *ra_session, 9149 apr_array_header_t *children_with_mergeinfo, 9150 apr_pool_t *result_pool, 9151 apr_pool_t *scratch_pool) 9152{ 9153 /* ### Do we need to check that we are at a uniform working revision? */ 9154 int i; 9155 svn_client__merge_path_t *root_child = 9156 APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *); 9157 svn_rangelist_t *requested_ranges; 9158 svn_rangelist_t *subtree_gap_ranges; 9159 svn_rangelist_t *subtree_remaining_ranges; 9160 log_noop_baton_t log_gap_baton; 9161 svn_merge_range_t *oldest_gap_rev; 9162 svn_merge_range_t *youngest_gap_rev; 9163 svn_rangelist_t *inoperative_ranges; 9164 apr_pool_t *iterpool; 9165 const char *longest_common_subtree_ancestor = NULL; 9166 svn_error_t *err; 9167 9168 assert(session_url_is(ra_session, source->loc2->url, scratch_pool)); 9169 9170 /* This function is only intended to work with forward merges. */ 9171 if (source->loc1->rev > source->loc2->rev) 9172 return SVN_NO_ERROR; 9173 9174 /* Another easy out: There are no subtrees. */ 9175 if (children_with_mergeinfo->nelts < 2) 9176 return SVN_NO_ERROR; 9177 9178 subtree_remaining_ranges = apr_array_make(scratch_pool, 1, 9179 sizeof(svn_merge_range_t *)); 9180 9181 /* Given the requested merge of SOURCE->rev1:rev2 might there be any 9182 part of this range required for subtrees but not for the target? */ 9183 requested_ranges = svn_rangelist__initialize(MIN(source->loc1->rev, 9184 source->loc2->rev), 9185 MAX(source->loc1->rev, 9186 source->loc2->rev), 9187 TRUE, scratch_pool); 9188 SVN_ERR(svn_rangelist_remove(&subtree_gap_ranges, 9189 root_child->remaining_ranges, 9190 requested_ranges, FALSE, scratch_pool)); 9191 9192 /* Early out, nothing to operate on */ 9193 if (!subtree_gap_ranges->nelts) 9194 return SVN_NO_ERROR; 9195 9196 /* Create a rangelist describing every range required across all subtrees. */ 9197 iterpool = svn_pool_create(scratch_pool); 9198 for (i = 1; i < children_with_mergeinfo->nelts; i++) 9199 { 9200 svn_client__merge_path_t *child = 9201 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 9202 9203 svn_pool_clear(iterpool); 9204 9205 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */ 9206 if (child->remaining_ranges && child->remaining_ranges->nelts) 9207 { 9208 /* Issue #4269: Keep track of the longest common ancestor of all the 9209 subtrees which require merges. This may be a child of 9210 TARGET->ABSPATH, which will allow us to narrow the log request 9211 below. */ 9212 if (longest_common_subtree_ancestor) 9213 longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor( 9214 longest_common_subtree_ancestor, child->abspath, scratch_pool); 9215 else 9216 longest_common_subtree_ancestor = child->abspath; 9217 9218 SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges, 9219 child->remaining_ranges, 9220 scratch_pool, iterpool)); 9221 } 9222 } 9223 svn_pool_destroy(iterpool); 9224 9225 /* It's possible that none of the subtrees had any remaining ranges. */ 9226 if (!subtree_remaining_ranges->nelts) 9227 return SVN_NO_ERROR; 9228 9229 /* Ok, *finally* we can answer what part(s) of SOURCE->rev1:rev2 are 9230 required for the subtrees but not the target. */ 9231 SVN_ERR(svn_rangelist_intersect(&subtree_gap_ranges, 9232 subtree_gap_ranges, 9233 subtree_remaining_ranges, FALSE, 9234 scratch_pool)); 9235 9236 /* Another early out */ 9237 if (!subtree_gap_ranges->nelts) 9238 return SVN_NO_ERROR; 9239 9240 /* One or more subtrees need some revisions that the target doesn't need. 9241 Use log to determine if any of these revisions are inoperative. */ 9242 oldest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 0, svn_merge_range_t *); 9243 youngest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 9244 subtree_gap_ranges->nelts - 1, svn_merge_range_t *); 9245 9246 /* Set up the log baton. */ 9247 log_gap_baton.children_with_mergeinfo = children_with_mergeinfo; 9248 log_gap_baton.source_fspath 9249 = svn_client__pathrev_fspath(source->loc2, result_pool); 9250 log_gap_baton.target = target; 9251 log_gap_baton.merged_ranges = apr_array_make(scratch_pool, 0, 9252 sizeof(svn_revnum_t *)); 9253 log_gap_baton.operative_ranges = apr_array_make(scratch_pool, 0, 9254 sizeof(svn_revnum_t *)); 9255 log_gap_baton.pool = svn_pool_create(scratch_pool); 9256 9257 /* Find the longest common ancestor of all subtrees relative to 9258 RA_SESSION's URL. */ 9259 if (longest_common_subtree_ancestor) 9260 longest_common_subtree_ancestor = 9261 svn_dirent_skip_ancestor(target->abspath, 9262 longest_common_subtree_ancestor); 9263 else 9264 longest_common_subtree_ancestor = ""; 9265 9266 /* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from 9267 oldest to youngest. The receiver is optimized to add ranges to 9268 log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but 9269 requires that the revs arrive oldest to youngest -- see log_noop_revs() 9270 and rangelist_merge_revision(). */ 9271 err = get_log(ra_session, longest_common_subtree_ancestor, 9272 oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE, 9273 log_noop_revs, &log_gap_baton, scratch_pool); 9274 9275 /* It's possible that the only subtrees with mergeinfo in TARGET don't have 9276 any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2. 9277 So it's also possible that we may ask for the logs of non-existent paths. 9278 If we do, then assume that no subtree requires any ranges that are not 9279 already required by the TARGET. */ 9280 if (err) 9281 { 9282 if (err->apr_err != SVN_ERR_FS_NOT_FOUND 9283 && longest_common_subtree_ancestor[0] != '\0') 9284 return svn_error_trace(err); 9285 9286 /* Asked about a non-existent subtree in SOURCE. */ 9287 svn_error_clear(err); 9288 log_gap_baton.merged_ranges = 9289 svn_rangelist__initialize(oldest_gap_rev->start, 9290 youngest_gap_rev->end, 9291 TRUE, scratch_pool); 9292 } 9293 else 9294 { 9295 inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start, 9296 youngest_gap_rev->end, 9297 TRUE, scratch_pool); 9298 SVN_ERR(svn_rangelist_remove(&(inoperative_ranges), 9299 log_gap_baton.operative_ranges, 9300 inoperative_ranges, FALSE, scratch_pool)); 9301 SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges, 9302 scratch_pool, scratch_pool)); 9303 } 9304 9305 for (i = 1; i < children_with_mergeinfo->nelts; i++) 9306 { 9307 svn_client__merge_path_t *child = 9308 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 9309 9310 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */ 9311 if (child->remaining_ranges && child->remaining_ranges->nelts) 9312 { 9313 /* Remove inoperative ranges from all children so we don't perform 9314 inoperative editor drives. */ 9315 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 9316 log_gap_baton.merged_ranges, 9317 child->remaining_ranges, 9318 FALSE, result_pool)); 9319 } 9320 } 9321 9322 svn_pool_destroy(log_gap_baton.pool); 9323 9324 return SVN_NO_ERROR; 9325} 9326 9327/* Perform a merge of changes in SOURCE to the working copy path 9328 TARGET_ABSPATH. Both URLs in SOURCE, and TARGET_ABSPATH all represent 9329 directories -- for the single file case, the caller should use 9330 do_file_merge(). 9331 9332 CHILDREN_WITH_MERGEINFO and MERGE_B describe the merge being performed 9333 As this function is for a mergeinfo-aware merge, SOURCE->ancestral 9334 should be TRUE, and SOURCE->loc1 must be a historical ancestor of 9335 SOURCE->loc2, or vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION' 9336 for more requirements around SOURCE). 9337 9338 Mergeinfo changes will be recorded unless MERGE_B->dry_run is true. 9339 9340 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE, 9341 and MERGE_B->CTX->NOTIFY_FUNC2 is not NULL, then call 9342 MERGE_B->CTX->NOTIFY_FUNC2 with MERGE_B->CTX->NOTIFY_BATON2 and a 9343 svn_wc_notify_merge_record_info_begin notification before any mergeinfo 9344 changes are made to describe the merge performed. 9345 9346 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 9347 is not NULL, then don't record the new mergeinfo on the WC, but instead 9348 record it in RESULT_CATALOG, where the keys are absolute working copy 9349 paths and the values are the new mergeinfos for each. Allocate additions 9350 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 9351 9352 Handle DEPTH as documented for svn_client_merge5(). 9353 9354 CONFLICT_REPORT is as documented for do_directory_merge(). 9355 9356 Perform any temporary allocations in SCRATCH_POOL. 9357 9358 NOTE: This is a wrapper around drive_merge_report_editor() which 9359 handles the complexities inherent to situations where a given 9360 directory's children may have intersecting merges (because they 9361 meet one or more of the criteria described in get_mergeinfo_paths()). 9362*/ 9363static svn_error_t * 9364do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog, 9365 single_range_conflict_report_t **conflict_report, 9366 const merge_source_t *source, 9367 const char *target_abspath, 9368 apr_array_header_t *children_with_mergeinfo, 9369 const svn_diff_tree_processor_t *processor, 9370 svn_depth_t depth, 9371 svn_boolean_t squelch_mergeinfo_notifications, 9372 merge_cmd_baton_t *merge_b, 9373 apr_pool_t *result_pool, 9374 apr_pool_t *scratch_pool) 9375{ 9376 /* The range defining the mergeinfo we will record to describe the merge 9377 (assuming we are recording mergeinfo 9378 9379 Note: This may be a subset of SOURCE->rev1:rev2 if 9380 populate_remaining_ranges() determines that some part of 9381 SOURCE->rev1:rev2 has already been wholly merged to TARGET_ABSPATH. 9382 Also, the actual editor drive(s) may be a subset of RANGE, if 9383 remove_noop_subtree_ranges() and/or fix_deleted_subtree_ranges() 9384 further tweak things. */ 9385 svn_merge_range_t range; 9386 9387 svn_ra_session_t *ra_session; 9388 svn_client__merge_path_t *target_merge_path; 9389 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 9390 9391 SVN_ERR_ASSERT(source->ancestral); 9392 9393 /*** If we get here, we're dealing with related sources from the 9394 same repository as the target -- merge tracking might be 9395 happenin'! ***/ 9396 9397 *conflict_report = NULL; 9398 9399 /* Point our RA_SESSION to the URL of our youngest merge source side. */ 9400 ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2; 9401 9402 /* Fill CHILDREN_WITH_MERGEINFO with child paths (const 9403 svn_client__merge_path_t *) which might have intersecting merges 9404 because they meet one or more of the criteria described in 9405 get_mergeinfo_paths(). Here the paths are arranged in a depth 9406 first order. */ 9407 SVN_ERR(get_mergeinfo_paths(children_with_mergeinfo, 9408 merge_b->target, depth, 9409 merge_b->dry_run, merge_b->same_repos, 9410 merge_b->ctx, scratch_pool, scratch_pool)); 9411 9412 /* The first item from the CHILDREN_WITH_MERGEINFO is always 9413 the target thanks to depth-first ordering. */ 9414 target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0, 9415 svn_client__merge_path_t *); 9416 9417 /* If we are honoring mergeinfo, then for each item in 9418 CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be 9419 merged, and then merge it. Otherwise, we just merge what we were asked 9420 to merge across the whole tree. */ 9421 SVN_ERR(populate_remaining_ranges(children_with_mergeinfo, 9422 source, ra_session, 9423 merge_b, scratch_pool, scratch_pool)); 9424 9425 /* Always start with a range which describes the most inclusive merge 9426 possible, i.e. SOURCE->rev1:rev2. */ 9427 range.start = source->loc1->rev; 9428 range.end = source->loc2->rev; 9429 range.inheritable = TRUE; 9430 9431 if (!merge_b->reintegrate_merge) 9432 { 9433 svn_revnum_t new_range_start, start_rev; 9434 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 9435 9436 /* The merge target TARGET_ABSPATH and/or its subtrees may not need all 9437 of SOURCE->rev1:rev2 applied. So examine 9438 CHILDREN_WITH_MERGEINFO to find the oldest starting 9439 revision that actually needs to be merged (for reverse merges this is 9440 the youngest starting revision). 9441 9442 We'll do this twice, right now for the start of the mergeinfo we will 9443 ultimately record to describe this merge and then later for the 9444 start of the actual editor drive. */ 9445 new_range_start = get_most_inclusive_rev( 9446 children_with_mergeinfo, is_rollback, TRUE); 9447 if (SVN_IS_VALID_REVNUM(new_range_start)) 9448 range.start = new_range_start; 9449 9450 /* Remove inoperative ranges from any subtrees' remaining_ranges 9451 to spare the expense of noop editor drives. */ 9452 if (!is_rollback) 9453 SVN_ERR(remove_noop_subtree_ranges(source, merge_b->target, 9454 ra_session, 9455 children_with_mergeinfo, 9456 scratch_pool, iterpool)); 9457 9458 /* Adjust subtrees' remaining_ranges to deal with issue #3067: 9459 * "subtrees that don't exist at the start or end of a merge range 9460 * shouldn't break the merge". */ 9461 SVN_ERR(fix_deleted_subtree_ranges(source, merge_b->target, 9462 ra_session, 9463 children_with_mergeinfo, 9464 merge_b->ctx, scratch_pool, iterpool)); 9465 9466 /* remove_noop_subtree_ranges() and/or fix_deleted_subtree_range() 9467 may have further refined the starting revision for our editor 9468 drive. */ 9469 start_rev = 9470 get_most_inclusive_rev(children_with_mergeinfo, 9471 is_rollback, TRUE); 9472 9473 /* Is there anything to merge? */ 9474 if (SVN_IS_VALID_REVNUM(start_rev)) 9475 { 9476 /* Now examine CHILDREN_WITH_MERGEINFO to find the oldest 9477 ending revision that actually needs to be merged (for reverse 9478 merges this is the youngest ending revision). */ 9479 svn_revnum_t end_rev = 9480 get_most_inclusive_rev(children_with_mergeinfo, 9481 is_rollback, FALSE); 9482 9483 /* While END_REV is valid, do the following: 9484 9485 1. Tweak each CHILDREN_WITH_MERGEINFO element so that 9486 the element's remaining_ranges member has as its first element 9487 a range that ends with end_rev. 9488 9489 2. Starting with start_rev, call drive_merge_report_editor() 9490 on MERGE_B->target->abspath for start_rev:end_rev. 9491 9492 3. Remove the first element from each 9493 CHILDREN_WITH_MERGEINFO element's remaining_ranges 9494 member. 9495 9496 4. Again examine CHILDREN_WITH_MERGEINFO to find the most 9497 inclusive starting revision that actually needs to be merged and 9498 update start_rev. This prevents us from needlessly contacting the 9499 repository and doing a diff where we describe the entire target 9500 tree as *not* needing any of the requested range. This can happen 9501 whenever we have mergeinfo with gaps in it for the merge source. 9502 9503 5. Again examine CHILDREN_WITH_MERGEINFO to find the most 9504 inclusive ending revision that actually needs to be merged and 9505 update end_rev. 9506 9507 6. Lather, rinse, repeat. 9508 */ 9509 9510 while (end_rev != SVN_INVALID_REVNUM) 9511 { 9512 merge_source_t *real_source; 9513 svn_merge_range_t *first_target_range 9514 = (target_merge_path->remaining_ranges->nelts == 0 ? NULL 9515 : APR_ARRAY_IDX(target_merge_path->remaining_ranges, 0, 9516 svn_merge_range_t *)); 9517 9518 /* Issue #3324: Stop editor abuse! Don't call 9519 drive_merge_report_editor() in such a way that we request an 9520 editor with svn_client__get_diff_editor() for some rev X, 9521 then call svn_ra_do_diff3() for some revision Y, and then 9522 call reporter->set_path(PATH=="") to set the root revision 9523 for the editor drive to revision Z where 9524 (X != Z && X < Z < Y). This is bogus because the server will 9525 send us the diff between X:Y but the client is expecting the 9526 diff between Y:Z. See issue #3324 for full details on the 9527 problems this can cause. */ 9528 if (first_target_range 9529 && start_rev != first_target_range->start) 9530 { 9531 if (is_rollback) 9532 { 9533 if (end_rev < first_target_range->start) 9534 end_rev = first_target_range->start; 9535 } 9536 else 9537 { 9538 if (end_rev > first_target_range->start) 9539 end_rev = first_target_range->start; 9540 } 9541 } 9542 9543 svn_pool_clear(iterpool); 9544 9545 SVN_ERR(slice_remaining_ranges(children_with_mergeinfo, 9546 is_rollback, end_rev, 9547 scratch_pool)); 9548 9549 /* Reset variables that must be reset for every drive */ 9550 merge_b->notify_begin.last_abspath = NULL; 9551 9552 real_source = subrange_source(source, start_rev, end_rev, iterpool); 9553 SVN_ERR(drive_merge_report_editor( 9554 merge_b->target->abspath, 9555 real_source, 9556 children_with_mergeinfo, 9557 processor, 9558 depth, 9559 merge_b, 9560 iterpool)); 9561 9562 /* If any paths picked up explicit mergeinfo as a result of 9563 the merge we need to make sure any mergeinfo those paths 9564 inherited is recorded and then add these paths to 9565 CHILDREN_WITH_MERGEINFO.*/ 9566 SVN_ERR(process_children_with_new_mergeinfo( 9567 merge_b, children_with_mergeinfo, 9568 scratch_pool)); 9569 9570 /* If any subtrees had their explicit mergeinfo deleted as a 9571 result of the merge then remove these paths from 9572 CHILDREN_WITH_MERGEINFO since there is no need 9573 to consider these subtrees for subsequent editor drives 9574 nor do we want to record mergeinfo on them describing 9575 the merge itself. */ 9576 SVN_ERR(remove_children_with_deleted_mergeinfo( 9577 merge_b, children_with_mergeinfo)); 9578 9579 /* Prepare for the next iteration (if any). */ 9580 SVN_ERR(remove_first_range_from_remaining_ranges( 9581 end_rev, children_with_mergeinfo, scratch_pool)); 9582 9583 /* If we raised any conflicts, break out and report how much 9584 we have merged. */ 9585 if (is_path_conflicted_by_merge(merge_b)) 9586 { 9587 merge_source_t *remaining_range = NULL; 9588 9589 if (real_source->loc2->rev != source->loc2->rev) 9590 remaining_range = subrange_source(source, 9591 real_source->loc2->rev, 9592 source->loc2->rev, 9593 scratch_pool); 9594 *conflict_report = single_range_conflict_report_create( 9595 real_source, remaining_range, 9596 result_pool); 9597 9598 range.end = end_rev; 9599 break; 9600 } 9601 9602 start_rev = 9603 get_most_inclusive_rev(children_with_mergeinfo, 9604 is_rollback, TRUE); 9605 end_rev = 9606 get_most_inclusive_rev(children_with_mergeinfo, 9607 is_rollback, FALSE); 9608 } 9609 } 9610 svn_pool_destroy(iterpool); 9611 } 9612 else 9613 { 9614 if (!merge_b->record_only) 9615 { 9616 /* Reset the last notification path so that subsequent cherry 9617 picked revision ranges will be notified upon subsequent 9618 operative merge. */ 9619 merge_b->notify_begin.last_abspath = NULL; 9620 9621 SVN_ERR(drive_merge_report_editor(merge_b->target->abspath, 9622 source, 9623 NULL, 9624 processor, 9625 depth, 9626 merge_b, 9627 scratch_pool)); 9628 } 9629 } 9630 9631 /* Record mergeinfo where appropriate.*/ 9632 if (RECORD_MERGEINFO(merge_b)) 9633 { 9634 const svn_client__pathrev_t *primary_src 9635 = is_rollback ? source->loc1 : source->loc2; 9636 const char *mergeinfo_path 9637 = svn_client__pathrev_fspath(primary_src, scratch_pool); 9638 9639 SVN_ERR(record_mergeinfo_for_dir_merge(result_catalog, 9640 &range, 9641 mergeinfo_path, 9642 children_with_mergeinfo, 9643 depth, 9644 squelch_mergeinfo_notifications, 9645 merge_b, 9646 scratch_pool)); 9647 9648 /* If a path has an immediate parent with non-inheritable mergeinfo at 9649 this point, then it meets criteria 3 or 5 described in 9650 get_mergeinfo_paths' doc string. For paths which exist prior to a 9651 merge explicit mergeinfo has already been set. But for paths added 9652 during the merge this is not the case. The path might have explicit 9653 mergeinfo from the merge source, but no mergeinfo yet exists 9654 describing *this* merge. So the added path has either incomplete 9655 explicit mergeinfo or inherits incomplete mergeinfo from its 9656 immediate parent (if any, the parent might have only non-inheritable 9657 ranges in which case the path simply inherits empty mergeinfo). 9658 9659 So here we look at the root path of each subtree added during the 9660 merge and set explicit mergeinfo on it if it meets the aforementioned 9661 conditions. */ 9662 if (range.start < range.end) /* Nothing to record on added subtrees 9663 resulting from reverse merges. */ 9664 { 9665 SVN_ERR(record_mergeinfo_for_added_subtrees( 9666 &range, mergeinfo_path, depth, 9667 squelch_mergeinfo_notifications, 9668 merge_b->added_abspaths, merge_b, scratch_pool)); 9669 } 9670 } 9671 9672 return SVN_NO_ERROR; 9673} 9674 9675/* Helper for do_merge() when the merge target is a directory. 9676 * 9677 * If any conflict is raised during the merge, set *CONFLICTED_RANGE to 9678 * the revision sub-range that raised the conflict. In this case, the 9679 * merge will have ended at revision CONFLICTED_RANGE and mergeinfo will 9680 * have been recorded for all revision sub-ranges up to and including 9681 * CONFLICTED_RANGE. Otherwise, set *CONFLICTED_RANGE to NULL. 9682 */ 9683static svn_error_t * 9684do_directory_merge(svn_mergeinfo_catalog_t result_catalog, 9685 single_range_conflict_report_t **conflict_report, 9686 const merge_source_t *source, 9687 const char *target_abspath, 9688 const svn_diff_tree_processor_t *processor, 9689 svn_depth_t depth, 9690 svn_boolean_t squelch_mergeinfo_notifications, 9691 merge_cmd_baton_t *merge_b, 9692 apr_pool_t *result_pool, 9693 apr_pool_t *scratch_pool) 9694{ 9695 apr_array_header_t *children_with_mergeinfo; 9696 9697 /* Initialize CHILDREN_WITH_MERGEINFO. See the comment 9698 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */ 9699 children_with_mergeinfo = 9700 apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *)); 9701 9702 /* And make it read-only accessible from the baton */ 9703 merge_b->children_with_mergeinfo = children_with_mergeinfo; 9704 9705 /* If we are not honoring mergeinfo we can skip right to the 9706 business of merging changes! */ 9707 if (HONOR_MERGEINFO(merge_b)) 9708 SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflict_report, 9709 source, target_abspath, 9710 children_with_mergeinfo, 9711 processor, depth, 9712 squelch_mergeinfo_notifications, 9713 merge_b, result_pool, scratch_pool)); 9714 else 9715 SVN_ERR(do_mergeinfo_unaware_dir_merge(conflict_report, 9716 source, target_abspath, 9717 children_with_mergeinfo, 9718 processor, depth, 9719 merge_b, result_pool, scratch_pool)); 9720 9721 merge_b->children_with_mergeinfo = NULL; 9722 9723 return SVN_NO_ERROR; 9724} 9725 9726/** Ensure that *RA_SESSION is opened to URL, either by reusing 9727 * *RA_SESSION if it is non-null and already opened to URL's 9728 * repository, or by allocating a new *RA_SESSION in POOL. 9729 * (RA_SESSION itself cannot be null, of course.) 9730 * 9731 * CTX is used as for svn_client_open_ra_session(). 9732 */ 9733static svn_error_t * 9734ensure_ra_session_url(svn_ra_session_t **ra_session, 9735 const char *url, 9736 const char *wri_abspath, 9737 svn_client_ctx_t *ctx, 9738 apr_pool_t *pool) 9739{ 9740 svn_error_t *err = SVN_NO_ERROR; 9741 9742 if (*ra_session) 9743 { 9744 err = svn_ra_reparent(*ra_session, url, pool); 9745 } 9746 9747 /* SVN_ERR_RA_ILLEGAL_URL is raised when url doesn't point to the same 9748 repository as ra_session. */ 9749 if (! *ra_session || (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL)) 9750 { 9751 svn_error_clear(err); 9752 err = svn_client_open_ra_session2(ra_session, url, wri_abspath, 9753 ctx, pool, pool); 9754 } 9755 SVN_ERR(err); 9756 9757 return SVN_NO_ERROR; 9758} 9759 9760/* Drive a merge of MERGE_SOURCES into working copy node TARGET 9761 and possibly record mergeinfo describing the merge -- see 9762 RECORD_MERGEINFO(). 9763 9764 If MODIFIED_SUBTREES is not NULL and all the MERGE_SOURCES are 'ancestral' 9765 or REINTEGRATE_MERGE is true, then replace *MODIFIED_SUBTREES with a new 9766 hash containing all the paths that *MODIFIED_SUBTREES contained before, 9767 and also every path modified, skipped, added, or tree-conflicted 9768 by the merge. Keys and values of the hash are both (const char *) 9769 absolute paths. The contents of the hash are allocated in RESULT_POOL. 9770 9771 If the merge raises any conflicts while merging a revision range, return 9772 early and set *CONFLICT_REPORT to describe the details. (In this case, 9773 notify that the merge is complete if and only if this was the last 9774 revision range of the merge.) If there are no conflicts, set 9775 *CONFLICT_REPORT to NULL. A revision range here can be one specified 9776 in MERGE_SOURCES or an internally generated sub-range of one of those 9777 when merge tracking is in use. 9778 9779 For every (const merge_source_t *) merge source in MERGE_SOURCES, if 9780 SOURCE->ANCESTRAL is set, then the "left" and "right" side are 9781 ancestrally related. (See 'MERGEINFO MERGE SOURCE NORMALIZATION' 9782 for more on what that means and how it matters.) 9783 9784 If SOURCES_RELATED is set, the "left" and "right" sides of the 9785 merge source are historically related (ancestors, uncles, second 9786 cousins thrice removed, etc...). (This is passed through to 9787 do_file_merge() to simulate the history checks that the repository 9788 logic does in the directory case.) 9789 9790 SAME_REPOS is TRUE iff the merge sources live in the same 9791 repository as the one from which the target working copy has been 9792 checked out. 9793 9794 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE, 9795 and CTX->NOTIFY_FUNC2 is not NULL, then call CTX->NOTIFY_FUNC2 with 9796 CTX->NOTIFY_BATON2 and a svn_wc_notify_merge_record_info_begin 9797 notification before any mergeinfo changes are made to describe the merge 9798 performed. 9799 9800 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 9801 is not NULL, then don't record the new mergeinfo on the WC, but instead 9802 record it in RESULT_CATALOG, where the keys are absolute working copy 9803 paths and the values are the new mergeinfos for each. Allocate additions 9804 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 9805 9806 FORCE_DELETE, DRY_RUN, RECORD_ONLY, DEPTH, MERGE_OPTIONS, 9807 and CTX are as described in the docstring for svn_client_merge_peg3(). 9808 9809 If IGNORE_MERGEINFO is true, disable merge tracking, by treating the two 9810 sources as unrelated even if they actually have a common ancestor. See 9811 the macro HONOR_MERGEINFO(). 9812 9813 If DIFF_IGNORE_ANCESTRY is true, diff the 'left' and 'right' versions 9814 of a node (if they are the same kind) as if they were related, even if 9815 they are not related. Otherwise, diff unrelated items as a deletion 9816 of one thing and the addition of another. 9817 9818 If not NULL, RECORD_ONLY_PATHS is a hash of (const char *) paths mapped 9819 to the same. If RECORD_ONLY is true and RECORD_ONLY_PATHS is not NULL, 9820 then record mergeinfo describing the merge only on subtrees which contain 9821 items from RECORD_ONLY_PATHS. If RECORD_ONLY is true and RECORD_ONLY_PATHS 9822 is NULL, then record mergeinfo on every subtree with mergeinfo in 9823 TARGET. 9824 9825 REINTEGRATE_MERGE is TRUE if this is a reintegrate merge. 9826 9827 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp 9828 integrity, *USE_SLEEP will be unchanged if no sleep is required. 9829 9830 SCRATCH_POOL is used for all temporary allocations. 9831*/ 9832static svn_error_t * 9833do_merge(apr_hash_t **modified_subtrees, 9834 svn_mergeinfo_catalog_t result_catalog, 9835 svn_client__conflict_report_t **conflict_report, 9836 svn_boolean_t *use_sleep, 9837 const apr_array_header_t *merge_sources, 9838 const merge_target_t *target, 9839 svn_ra_session_t *src_session, 9840 svn_boolean_t sources_related, 9841 svn_boolean_t same_repos, 9842 svn_boolean_t ignore_mergeinfo, 9843 svn_boolean_t diff_ignore_ancestry, 9844 svn_boolean_t force_delete, 9845 svn_boolean_t dry_run, 9846 svn_boolean_t record_only, 9847 apr_hash_t *record_only_paths, 9848 svn_boolean_t reintegrate_merge, 9849 svn_boolean_t squelch_mergeinfo_notifications, 9850 svn_depth_t depth, 9851 const apr_array_header_t *merge_options, 9852 svn_client_ctx_t *ctx, 9853 apr_pool_t *result_pool, 9854 apr_pool_t *scratch_pool) 9855{ 9856 merge_cmd_baton_t merge_cmd_baton = { 0 }; 9857 svn_config_t *cfg; 9858 const char *diff3_cmd; 9859 const char *preserved_exts_str; 9860 int i; 9861 svn_boolean_t checked_mergeinfo_capability = FALSE; 9862 svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL; 9863 const char *old_src_session_url = NULL; 9864 apr_pool_t *iterpool; 9865 const svn_diff_tree_processor_t *processor; 9866 9867 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath)); 9868 9869 *conflict_report = NULL; 9870 9871 /* Check from some special conditions when in record-only mode 9872 (which is a merge-tracking thing). */ 9873 if (record_only) 9874 { 9875 svn_boolean_t sources_ancestral = TRUE; 9876 int j; 9877 9878 /* Find out whether all of the sources are 'ancestral'. */ 9879 for (j = 0; j < merge_sources->nelts; j++) 9880 if (! APR_ARRAY_IDX(merge_sources, j, merge_source_t *)->ancestral) 9881 { 9882 sources_ancestral = FALSE; 9883 break; 9884 } 9885 9886 /* We can't do a record-only merge if the sources aren't related. */ 9887 if (! sources_ancestral) 9888 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 9889 _("Use of two URLs is not compatible with " 9890 "mergeinfo modification")); 9891 9892 /* We can't do a record-only merge if the sources aren't from 9893 the same repository as the target. */ 9894 if (! same_repos) 9895 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 9896 _("Merge from foreign repository is not " 9897 "compatible with mergeinfo modification")); 9898 9899 /* If this is a dry-run record-only merge, there's nothing to do. */ 9900 if (dry_run) 9901 return SVN_NO_ERROR; 9902 } 9903 9904 iterpool = svn_pool_create(scratch_pool); 9905 9906 /* Ensure a known depth. */ 9907 if (depth == svn_depth_unknown) 9908 depth = svn_depth_infinity; 9909 9910 /* Set up the diff3 command, so various callers don't have to. */ 9911 cfg = ctx->config 9912 ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG) 9913 : NULL; 9914 svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS, 9915 SVN_CONFIG_OPTION_DIFF3_CMD, NULL); 9916 9917 if (diff3_cmd != NULL) 9918 SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool)); 9919 9920 /* See which files the user wants to preserve the extension of when 9921 conflict files are made. */ 9922 svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY, 9923 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, ""); 9924 9925 /* Build the merge context baton (or at least the parts of it that 9926 don't need to be reset for each merge source). */ 9927 merge_cmd_baton.force_delete = force_delete; 9928 merge_cmd_baton.dry_run = dry_run; 9929 merge_cmd_baton.record_only = record_only; 9930 merge_cmd_baton.ignore_mergeinfo = ignore_mergeinfo; 9931 merge_cmd_baton.diff_ignore_ancestry = diff_ignore_ancestry; 9932 merge_cmd_baton.same_repos = same_repos; 9933 merge_cmd_baton.mergeinfo_capable = FALSE; 9934 merge_cmd_baton.ctx = ctx; 9935 merge_cmd_baton.reintegrate_merge = reintegrate_merge; 9936 merge_cmd_baton.target = target; 9937 merge_cmd_baton.pool = iterpool; 9938 merge_cmd_baton.merge_options = merge_options; 9939 merge_cmd_baton.diff3_cmd = diff3_cmd; 9940 merge_cmd_baton.ext_patterns = *preserved_exts_str 9941 ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", 9942 FALSE, scratch_pool) 9943 : NULL; 9944 9945 merge_cmd_baton.use_sleep = use_sleep; 9946 9947 /* Do we already know the specific subtrees with mergeinfo we want 9948 to record-only mergeinfo on? */ 9949 if (record_only && record_only_paths) 9950 merge_cmd_baton.merged_abspaths = record_only_paths; 9951 else 9952 merge_cmd_baton.merged_abspaths = apr_hash_make(result_pool); 9953 9954 merge_cmd_baton.skipped_abspaths = apr_hash_make(result_pool); 9955 merge_cmd_baton.added_abspaths = apr_hash_make(result_pool); 9956 merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool); 9957 9958 merge_cmd_baton.notify_func = notify_merging; 9959 merge_cmd_baton.notify_baton = &merge_cmd_baton.notify_begin; 9960 merge_cmd_baton.notify_begin.merge_b = &merge_cmd_baton; 9961 merge_cmd_baton.notify_begin.notify_func2 = ctx->notify_func2; 9962 merge_cmd_baton.notify_begin.notify_baton2 = ctx->notify_baton2; 9963 9964 processor = merge_apply_processor(&merge_cmd_baton, scratch_pool); 9965 9966 if (src_session) 9967 { 9968 SVN_ERR(svn_ra_get_session_url(src_session, &old_src_session_url, 9969 scratch_pool)); 9970 ra_session1 = src_session; 9971 } 9972 9973 for (i = 0; i < merge_sources->nelts; i++) 9974 { 9975 svn_node_kind_t src1_kind; 9976 merge_source_t *source = 9977 APR_ARRAY_IDX(merge_sources, i, merge_source_t *); 9978 single_range_conflict_report_t *conflicted_range_report; 9979 9980 svn_pool_clear(iterpool); 9981 9982 /* Sanity check: if our left- and right-side merge sources are 9983 the same, there's nothing to here. */ 9984 if ((strcmp(source->loc1->url, source->loc2->url) == 0) 9985 && (source->loc1->rev == source->loc2->rev)) 9986 continue; 9987 9988 /* Establish RA sessions to our URLs, reuse where possible. */ 9989 SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url, 9990 target->abspath, ctx, scratch_pool)); 9991 SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2->url, 9992 target->abspath, ctx, scratch_pool)); 9993 9994 /* Populate the portions of the merge context baton that need to 9995 be reset for each merge source iteration. */ 9996 merge_cmd_baton.merge_source = *source; 9997 merge_cmd_baton.implicit_src_gap = NULL; 9998 merge_cmd_baton.conflicted_paths = NULL; 9999 merge_cmd_baton.paths_with_new_mergeinfo = NULL; 10000 merge_cmd_baton.paths_with_deleted_mergeinfo = NULL; 10001 merge_cmd_baton.ra_session1 = ra_session1; 10002 merge_cmd_baton.ra_session2 = ra_session2; 10003 10004 merge_cmd_baton.notify_begin.last_abspath = NULL; 10005 10006 /* Populate the portions of the merge context baton that require 10007 an RA session to set, but shouldn't be reset for each iteration. */ 10008 if (! checked_mergeinfo_capability) 10009 { 10010 SVN_ERR(svn_ra_has_capability(ra_session1, 10011 &merge_cmd_baton.mergeinfo_capable, 10012 SVN_RA_CAPABILITY_MERGEINFO, 10013 iterpool)); 10014 checked_mergeinfo_capability = TRUE; 10015 } 10016 10017 SVN_ERR(svn_ra_check_path(ra_session1, "", source->loc1->rev, 10018 &src1_kind, iterpool)); 10019 10020 /* Run the merge; if there are conflicts, allow the callback to 10021 * resolve them, and if it resolves all of them, then run the 10022 * merge again with the remaining revision range, until it is all 10023 * done. */ 10024 do 10025 { 10026 /* Merge as far as possible without resolving any conflicts */ 10027 if (src1_kind != svn_node_dir) 10028 { 10029 SVN_ERR(do_file_merge(result_catalog, &conflicted_range_report, 10030 source, target->abspath, 10031 processor, 10032 sources_related, 10033 squelch_mergeinfo_notifications, 10034 &merge_cmd_baton, iterpool, iterpool)); 10035 } 10036 else /* Directory */ 10037 { 10038 SVN_ERR(do_directory_merge(result_catalog, &conflicted_range_report, 10039 source, target->abspath, 10040 processor, 10041 depth, squelch_mergeinfo_notifications, 10042 &merge_cmd_baton, iterpool, iterpool)); 10043 } 10044 10045 /* Give the conflict resolver callback the opportunity to 10046 * resolve any conflicts that were raised. If it resolves all 10047 * of them, go around again to merge the next sub-range (if any). */ 10048 if (conflicted_range_report && ctx->conflict_func2 && ! dry_run) 10049 { 10050 svn_boolean_t conflicts_remain; 10051 10052 SVN_ERR(svn_client__resolve_conflicts( 10053 &conflicts_remain, merge_cmd_baton.conflicted_paths, 10054 ctx, iterpool)); 10055 if (conflicts_remain) 10056 break; 10057 10058 merge_cmd_baton.conflicted_paths = NULL; 10059 /* Caution: this source is in iterpool */ 10060 source = conflicted_range_report->remaining_source; 10061 conflicted_range_report = NULL; 10062 } 10063 else 10064 break; 10065 } 10066 while (source); 10067 10068 /* The final mergeinfo on TARGET_WCPATH may itself elide. */ 10069 if (! dry_run) 10070 SVN_ERR(svn_client__elide_mergeinfo(target->abspath, NULL, 10071 ctx, iterpool)); 10072 10073 /* If conflicts occurred while merging any but the very last 10074 * range of a multi-pass merge, we raise an error that aborts 10075 * the merge. The user will be asked to resolve conflicts 10076 * before merging subsequent revision ranges. */ 10077 if (conflicted_range_report) 10078 { 10079 *conflict_report = conflict_report_create( 10080 target->abspath, conflicted_range_report->conflicted_range, 10081 (i == merge_sources->nelts - 1 10082 && ! conflicted_range_report->remaining_source), 10083 result_pool); 10084 break; 10085 } 10086 } 10087 10088 if (! *conflict_report || (*conflict_report)->was_last_range) 10089 { 10090 /* Let everyone know we're finished here. */ 10091 notify_merge_completed(target->abspath, ctx, iterpool); 10092 } 10093 10094 /* Does the caller want to know what the merge has done? */ 10095 if (modified_subtrees) 10096 { 10097 *modified_subtrees = 10098 apr_hash_overlay(result_pool, *modified_subtrees, 10099 merge_cmd_baton.merged_abspaths); 10100 *modified_subtrees = 10101 apr_hash_overlay(result_pool, *modified_subtrees, 10102 merge_cmd_baton.added_abspaths); 10103 *modified_subtrees = 10104 apr_hash_overlay(result_pool, *modified_subtrees, 10105 merge_cmd_baton.skipped_abspaths); 10106 *modified_subtrees = 10107 apr_hash_overlay(result_pool, *modified_subtrees, 10108 merge_cmd_baton.tree_conflicted_abspaths); 10109 } 10110 10111 if (src_session) 10112 SVN_ERR(svn_ra_reparent(src_session, old_src_session_url, iterpool)); 10113 10114 svn_pool_destroy(iterpool); 10115 return SVN_NO_ERROR; 10116} 10117 10118/* Perform a two-URL merge between URLs which are related, but neither 10119 is a direct ancestor of the other. This first does a real two-URL 10120 merge (unless this is record-only), followed by record-only merges 10121 to represent the changed mergeinfo. 10122 10123 Set *CONFLICT_REPORT to indicate if there were any conflicts, as in 10124 do_merge(). 10125 10126 The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1) 10127 and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest 10128 common ancestor. 10129 10130 SAME_REPOS must be true if and only if the source URLs are in the same 10131 repository as the target working copy. 10132 10133 DIFF_IGNORE_ANCESTRY is as in do_merge(). 10134 10135 Other arguments are as in all of the public merge APIs. 10136 10137 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp 10138 integrity, *USE_SLEEP will be unchanged if no sleep is required. 10139 10140 SCRATCH_POOL is used for all temporary allocations. 10141 */ 10142static svn_error_t * 10143merge_cousins_and_supplement_mergeinfo( 10144 svn_client__conflict_report_t **conflict_report, 10145 svn_boolean_t *use_sleep, 10146 const merge_target_t *target, 10147 svn_ra_session_t *URL1_ra_session, 10148 svn_ra_session_t *URL2_ra_session, 10149 const merge_source_t *source, 10150 const svn_client__pathrev_t *yca, 10151 svn_boolean_t same_repos, 10152 svn_depth_t depth, 10153 svn_boolean_t diff_ignore_ancestry, 10154 svn_boolean_t force_delete, 10155 svn_boolean_t record_only, 10156 svn_boolean_t dry_run, 10157 const apr_array_header_t *merge_options, 10158 svn_client_ctx_t *ctx, 10159 apr_pool_t *result_pool, 10160 apr_pool_t *scratch_pool) 10161{ 10162 apr_array_header_t *remove_sources, *add_sources; 10163 apr_hash_t *modified_subtrees = NULL; 10164 10165 /* Sure we could use SCRATCH_POOL throughout this function, but since this 10166 is a wrapper around three separate merges we'll create a subpool we can 10167 clear between each of the three. If the merge target has a lot of 10168 subtree mergeinfo, then this will help keep memory use in check. */ 10169 apr_pool_t *subpool = svn_pool_create(scratch_pool); 10170 10171 assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool)); 10172 assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool)); 10173 10174 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath)); 10175 SVN_ERR_ASSERT(! source->ancestral); 10176 10177 SVN_ERR(normalize_merge_sources_internal( 10178 &remove_sources, source->loc1, 10179 svn_rangelist__initialize(source->loc1->rev, yca->rev, TRUE, 10180 scratch_pool), 10181 URL1_ra_session, ctx, scratch_pool, subpool)); 10182 10183 SVN_ERR(normalize_merge_sources_internal( 10184 &add_sources, source->loc2, 10185 svn_rangelist__initialize(yca->rev, source->loc2->rev, TRUE, 10186 scratch_pool), 10187 URL2_ra_session, ctx, scratch_pool, subpool)); 10188 10189 *conflict_report = NULL; 10190 10191 /* If this isn't a record-only merge, we'll first do a stupid 10192 point-to-point merge... */ 10193 if (! record_only) 10194 { 10195 apr_array_header_t *faux_sources = 10196 apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); 10197 10198 modified_subtrees = apr_hash_make(scratch_pool); 10199 APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source; 10200 SVN_ERR(do_merge(&modified_subtrees, NULL, conflict_report, use_sleep, 10201 faux_sources, target, 10202 URL1_ra_session, TRUE, same_repos, 10203 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10204 force_delete, dry_run, FALSE, NULL, TRUE, 10205 FALSE, depth, merge_options, ctx, 10206 scratch_pool, subpool)); 10207 if (*conflict_report) 10208 { 10209 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10210 if (! (*conflict_report)->was_last_range) 10211 return SVN_NO_ERROR; 10212 } 10213 } 10214 else if (! same_repos) 10215 { 10216 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 10217 _("Merge from foreign repository is not " 10218 "compatible with mergeinfo modification")); 10219 } 10220 10221 /* ... and now, if we're doing the mergeinfo thang, we execute a 10222 pair of record-only merges using the real sources we've 10223 calculated. 10224 10225 Issue #3648: We don't actually perform these two record-only merges 10226 on the WC at first, but rather see what each would do and store that 10227 in two mergeinfo catalogs. We then merge the catalogs together and 10228 then record the result in the WC. This prevents the second record 10229 only merge from removing legitimate mergeinfo history, from the same 10230 source, that was made in prior merges. */ 10231 if (same_repos && !dry_run) 10232 { 10233 svn_mergeinfo_catalog_t add_result_catalog = 10234 apr_hash_make(scratch_pool); 10235 svn_mergeinfo_catalog_t remove_result_catalog = 10236 apr_hash_make(scratch_pool); 10237 10238 notify_mergeinfo_recording(target->abspath, NULL, ctx, scratch_pool); 10239 svn_pool_clear(subpool); 10240 SVN_ERR(do_merge(NULL, add_result_catalog, conflict_report, use_sleep, 10241 add_sources, target, 10242 URL1_ra_session, TRUE, same_repos, 10243 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10244 force_delete, dry_run, TRUE, 10245 modified_subtrees, TRUE, 10246 TRUE, depth, merge_options, ctx, 10247 scratch_pool, subpool)); 10248 if (*conflict_report) 10249 { 10250 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10251 if (! (*conflict_report)->was_last_range) 10252 return SVN_NO_ERROR; 10253 } 10254 svn_pool_clear(subpool); 10255 SVN_ERR(do_merge(NULL, remove_result_catalog, conflict_report, use_sleep, 10256 remove_sources, target, 10257 URL1_ra_session, TRUE, same_repos, 10258 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10259 force_delete, dry_run, TRUE, 10260 modified_subtrees, TRUE, 10261 TRUE, depth, merge_options, ctx, 10262 scratch_pool, subpool)); 10263 if (*conflict_report) 10264 { 10265 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10266 if (! (*conflict_report)->was_last_range) 10267 return SVN_NO_ERROR; 10268 } 10269 SVN_ERR(svn_mergeinfo_catalog_merge(add_result_catalog, 10270 remove_result_catalog, 10271 scratch_pool, scratch_pool)); 10272 SVN_ERR(svn_client__record_wc_mergeinfo_catalog(add_result_catalog, 10273 ctx, scratch_pool)); 10274 } 10275 10276 svn_pool_destroy(subpool); 10277 return SVN_NO_ERROR; 10278} 10279 10280/* Perform checks to determine whether the working copy at TARGET_ABSPATH 10281 * can safely be used as a merge target. Checks are performed according to 10282 * the ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, and ALLOW_SWITCHED_SUBTREES 10283 * parameters. If any checks fail, raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE. 10284 * 10285 * E.g. if all the ALLOW_* parameters are FALSE, TARGET_ABSPATH must 10286 * be a single-revision, pristine, unswitched working copy. 10287 * In other words, it must reflect a subtree of the repository as found 10288 * at single revision -- although sparse checkouts are permitted. */ 10289static svn_error_t * 10290ensure_wc_is_suitable_merge_target(const char *target_abspath, 10291 svn_client_ctx_t *ctx, 10292 svn_boolean_t allow_mixed_rev, 10293 svn_boolean_t allow_local_mods, 10294 svn_boolean_t allow_switched_subtrees, 10295 apr_pool_t *scratch_pool) 10296{ 10297 svn_node_kind_t target_kind; 10298 10299 /* Check the target exists. */ 10300 SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool)); 10301 if (target_kind == svn_node_none) 10302 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 10303 _("Path '%s' does not exist"), 10304 svn_dirent_local_style(target_abspath, 10305 scratch_pool)); 10306 SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, target_abspath, 10307 FALSE, FALSE, scratch_pool)); 10308 if (target_kind != svn_node_dir && target_kind != svn_node_file) 10309 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, 10310 _("Merge target '%s' does not exist in the " 10311 "working copy"), target_abspath); 10312 10313 /* Perform the mixed-revision check first because it's the cheapest one. */ 10314 if (! allow_mixed_rev) 10315 { 10316 svn_revnum_t min_rev; 10317 svn_revnum_t max_rev; 10318 10319 SVN_ERR(svn_client_min_max_revisions(&min_rev, &max_rev, target_abspath, 10320 FALSE, ctx, scratch_pool)); 10321 10322 if (!(SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev))) 10323 { 10324 svn_boolean_t is_added; 10325 10326 /* Allow merge into added nodes. */ 10327 SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath, 10328 scratch_pool)); 10329 if (is_added) 10330 return SVN_NO_ERROR; 10331 else 10332 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10333 _("Cannot determine revision of working " 10334 "copy")); 10335 } 10336 10337 if (min_rev != max_rev) 10338 return svn_error_createf(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL, 10339 _("Cannot merge into mixed-revision working " 10340 "copy [%ld:%ld]; try updating first"), 10341 min_rev, max_rev); 10342 } 10343 10344 /* Next, check for switched subtrees. */ 10345 if (! allow_switched_subtrees) 10346 { 10347 svn_boolean_t is_switched; 10348 10349 SVN_ERR(svn_wc__has_switched_subtrees(&is_switched, ctx->wc_ctx, 10350 target_abspath, NULL, 10351 scratch_pool)); 10352 if (is_switched) 10353 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10354 _("Cannot merge into a working copy " 10355 "with a switched subtree")); 10356 } 10357 10358 /* This is the most expensive check, so it is performed last.*/ 10359 if (! allow_local_mods) 10360 { 10361 svn_boolean_t is_modified; 10362 10363 SVN_ERR(svn_wc__has_local_mods(&is_modified, ctx->wc_ctx, 10364 target_abspath, TRUE, 10365 ctx->cancel_func, 10366 ctx->cancel_baton, 10367 scratch_pool)); 10368 if (is_modified) 10369 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10370 _("Cannot merge into a working copy " 10371 "that has local modifications")); 10372 } 10373 10374 return SVN_NO_ERROR; 10375} 10376 10377/* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository 10378 * revision. */ 10379static svn_error_t * 10380ensure_wc_path_has_repo_revision(const char *path_or_url, 10381 const svn_opt_revision_t *revision, 10382 apr_pool_t *scratch_pool) 10383{ 10384 if (revision->kind != svn_opt_revision_number 10385 && revision->kind != svn_opt_revision_date 10386 && revision->kind != svn_opt_revision_head 10387 && ! svn_path_is_url(path_or_url)) 10388 return svn_error_createf( 10389 SVN_ERR_CLIENT_BAD_REVISION, NULL, 10390 _("Invalid merge source '%s'; a working copy path can only be " 10391 "used with a repository revision (a number, a date, or head)"), 10392 svn_dirent_local_style(path_or_url, scratch_pool)); 10393 return SVN_NO_ERROR; 10394} 10395 10396/* "Open" the target WC for a merge. That means: 10397 * - find out its exact repository location 10398 * - check the WC for suitability (throw an error if unsuitable) 10399 * 10400 * Set *TARGET_P to a new, fully initialized, target description structure. 10401 * 10402 * ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, ALLOW_SWITCHED_SUBTREES determine 10403 * whether the WC is deemed suitable; see ensure_wc_is_suitable_merge_target() 10404 * for details. 10405 * 10406 * If the node is locally added, the rev and URL will be null/invalid. Some 10407 * kinds of merge can use such a target; others can't. 10408 */ 10409static svn_error_t * 10410open_target_wc(merge_target_t **target_p, 10411 const char *wc_abspath, 10412 svn_boolean_t allow_mixed_rev, 10413 svn_boolean_t allow_local_mods, 10414 svn_boolean_t allow_switched_subtrees, 10415 svn_client_ctx_t *ctx, 10416 apr_pool_t *result_pool, 10417 apr_pool_t *scratch_pool) 10418{ 10419 merge_target_t *target = apr_palloc(result_pool, sizeof(*target)); 10420 svn_client__pathrev_t *origin; 10421 10422 target->abspath = apr_pstrdup(result_pool, wc_abspath); 10423 10424 SVN_ERR(svn_client__wc_node_get_origin(&origin, wc_abspath, ctx, 10425 result_pool, scratch_pool)); 10426 if (origin) 10427 { 10428 target->loc = *origin; 10429 } 10430 else 10431 { 10432 svn_error_t *err; 10433 /* The node has no location in the repository. It's unversioned or 10434 * locally added or locally deleted. 10435 * 10436 * If it's locally added or deleted, find the repository root 10437 * URL and UUID anyway, and leave the node URL and revision as NULL 10438 * and INVALID. If it's unversioned, this will throw an error. */ 10439 err = svn_wc__node_get_repos_info(NULL, NULL, 10440 &target->loc.repos_root_url, 10441 &target->loc.repos_uuid, 10442 ctx->wc_ctx, wc_abspath, 10443 result_pool, scratch_pool); 10444 10445 if (err) 10446 { 10447 if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND 10448 && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY 10449 && err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED) 10450 return svn_error_trace(err); 10451 10452 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, err, 10453 _("Merge target '%s' does not exist in the " 10454 "working copy"), 10455 svn_dirent_local_style(wc_abspath, 10456 scratch_pool)); 10457 } 10458 10459 target->loc.rev = SVN_INVALID_REVNUM; 10460 target->loc.url = NULL; 10461 } 10462 10463 SVN_ERR(ensure_wc_is_suitable_merge_target( 10464 wc_abspath, ctx, 10465 allow_mixed_rev, allow_local_mods, allow_switched_subtrees, 10466 scratch_pool)); 10467 10468 *target_p = target; 10469 return SVN_NO_ERROR; 10470} 10471 10472/*-----------------------------------------------------------------------*/ 10473 10474/*** Public APIs ***/ 10475 10476/* The body of svn_client_merge5(), which see for details. 10477 * 10478 * If SOURCE1 @ REVISION1 is related to SOURCE2 @ REVISION2 then use merge 10479 * tracking (subject to other constraints -- see HONOR_MERGEINFO()); 10480 * otherwise disable merge tracking. 10481 * 10482 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge(). 10483 */ 10484svn_error_t * 10485svn_client__merge_locked(svn_client__conflict_report_t **conflict_report, 10486 const char *source1, 10487 const svn_opt_revision_t *revision1, 10488 const char *source2, 10489 const svn_opt_revision_t *revision2, 10490 const char *target_abspath, 10491 svn_depth_t depth, 10492 svn_boolean_t ignore_mergeinfo, 10493 svn_boolean_t diff_ignore_ancestry, 10494 svn_boolean_t force_delete, 10495 svn_boolean_t record_only, 10496 svn_boolean_t dry_run, 10497 svn_boolean_t allow_mixed_rev, 10498 const apr_array_header_t *merge_options, 10499 svn_client_ctx_t *ctx, 10500 apr_pool_t *result_pool, 10501 apr_pool_t *scratch_pool) 10502{ 10503 merge_target_t *target; 10504 svn_client__pathrev_t *source1_loc, *source2_loc; 10505 svn_boolean_t sources_related = FALSE; 10506 svn_ra_session_t *ra_session1, *ra_session2; 10507 apr_array_header_t *merge_sources; 10508 svn_error_t *err; 10509 svn_boolean_t use_sleep = FALSE; 10510 svn_client__pathrev_t *yca = NULL; 10511 apr_pool_t *sesspool; 10512 svn_boolean_t same_repos; 10513 10514 /* ### FIXME: This function really ought to do a history check on 10515 the left and right sides of the merge source, and -- if one is an 10516 ancestor of the other -- just call svn_client_merge_peg3() with 10517 the appropriate args. */ 10518 10519 SVN_ERR(open_target_wc(&target, target_abspath, 10520 allow_mixed_rev, TRUE, TRUE, 10521 ctx, scratch_pool, scratch_pool)); 10522 10523 /* Open RA sessions to both sides of our merge source, and resolve URLs 10524 * and revisions. */ 10525 sesspool = svn_pool_create(scratch_pool); 10526 SVN_ERR(svn_client__ra_session_from_path2( 10527 &ra_session1, &source1_loc, 10528 source1, NULL, revision1, revision1, ctx, sesspool)); 10529 SVN_ERR(svn_client__ra_session_from_path2( 10530 &ra_session2, &source2_loc, 10531 source2, NULL, revision2, revision2, ctx, sesspool)); 10532 10533 /* We can't do a diff between different repositories. */ 10534 /* ### We should also insist that the root URLs of the two sources match, 10535 * as we are only carrying around a single source-repos-root from now 10536 * on, and URL calculations will go wrong if they differ. 10537 * Alternatively, teach the code to cope with differing root URLs. */ 10538 SVN_ERR(check_same_repos(source1_loc, source1_loc->url, 10539 source2_loc, source2_loc->url, 10540 FALSE /* strict_urls */, scratch_pool)); 10541 10542 /* Do our working copy and sources come from the same repository? */ 10543 same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */); 10544 10545 /* Unless we're ignoring ancestry, see if the two sources are related. */ 10546 if (! ignore_mergeinfo) 10547 SVN_ERR(svn_client__get_youngest_common_ancestor( 10548 &yca, source1_loc, source2_loc, ra_session1, ctx, 10549 scratch_pool, scratch_pool)); 10550 10551 /* Check for a youngest common ancestor. If we have one, we'll be 10552 doing merge tracking. 10553 10554 So, given a requested merge of the differences between A and 10555 B, and a common ancestor of C, we will find ourselves in one of 10556 four positions, and four different approaches: 10557 10558 A == B == C there's nothing to merge 10559 10560 A == C != B we merge the changes between A (or C) and B 10561 10562 B == C != A we merge the changes between B (or C) and A 10563 10564 A != B != C we merge the changes between A and B without 10565 merge recording, then record-only two merges: 10566 from A to C, and from C to B 10567 */ 10568 if (yca) 10569 { 10570 /* Note that our merge sources are related. */ 10571 sources_related = TRUE; 10572 10573 /* If the common ancestor matches the right side of our merge, 10574 then we only need to reverse-merge the left side. */ 10575 if ((strcmp(yca->url, source2_loc->url) == 0) 10576 && (yca->rev == source2_loc->rev)) 10577 { 10578 SVN_ERR(normalize_merge_sources_internal( 10579 &merge_sources, source1_loc, 10580 svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE, 10581 scratch_pool), 10582 ra_session1, ctx, scratch_pool, scratch_pool)); 10583 } 10584 /* If the common ancestor matches the left side of our merge, 10585 then we only need to merge the right side. */ 10586 else if ((strcmp(yca->url, source1_loc->url) == 0) 10587 && (yca->rev == source1_loc->rev)) 10588 { 10589 SVN_ERR(normalize_merge_sources_internal( 10590 &merge_sources, source2_loc, 10591 svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE, 10592 scratch_pool), 10593 ra_session2, ctx, scratch_pool, scratch_pool)); 10594 } 10595 /* And otherwise, we need to do both: reverse merge the left 10596 side, and merge the right. */ 10597 else 10598 { 10599 merge_source_t source; 10600 10601 source.loc1 = source1_loc; 10602 source.loc2 = source2_loc; 10603 source.ancestral = FALSE; 10604 10605 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 10606 &use_sleep, 10607 target, 10608 ra_session1, 10609 ra_session2, 10610 &source, 10611 yca, 10612 same_repos, 10613 depth, 10614 diff_ignore_ancestry, 10615 force_delete, 10616 record_only, dry_run, 10617 merge_options, 10618 ctx, 10619 result_pool, 10620 scratch_pool); 10621 /* Close our temporary RA sessions (this could've happened 10622 after the second call to normalize_merge_sources() inside 10623 the merge_cousins_and_supplement_mergeinfo() routine). */ 10624 svn_pool_destroy(sesspool); 10625 10626 if (use_sleep) 10627 svn_io_sleep_for_timestamps(target->abspath, scratch_pool); 10628 10629 SVN_ERR(err); 10630 return SVN_NO_ERROR; 10631 } 10632 } 10633 else 10634 { 10635 /* Build a single-item merge_source_t array. */ 10636 merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); 10637 APR_ARRAY_PUSH(merge_sources, merge_source_t *) 10638 = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool); 10639 } 10640 10641 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 10642 merge_sources, target, 10643 ra_session1, sources_related, same_repos, 10644 ignore_mergeinfo, diff_ignore_ancestry, force_delete, dry_run, 10645 record_only, NULL, FALSE, FALSE, depth, merge_options, 10646 ctx, result_pool, scratch_pool); 10647 10648 /* Close our temporary RA sessions. */ 10649 svn_pool_destroy(sesspool); 10650 10651 if (use_sleep) 10652 svn_io_sleep_for_timestamps(target->abspath, scratch_pool); 10653 10654 SVN_ERR(err); 10655 return SVN_NO_ERROR; 10656} 10657 10658/* Set *TARGET_ABSPATH to the absolute path of, and *LOCK_ABSPATH to 10659 the absolute path to lock for, TARGET_WCPATH. */ 10660static svn_error_t * 10661get_target_and_lock_abspath(const char **target_abspath, 10662 const char **lock_abspath, 10663 const char *target_wcpath, 10664 svn_client_ctx_t *ctx, 10665 apr_pool_t *result_pool) 10666{ 10667 svn_node_kind_t kind; 10668 SVN_ERR(svn_dirent_get_absolute(target_abspath, target_wcpath, 10669 result_pool)); 10670 SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, *target_abspath, 10671 FALSE, FALSE, result_pool)); 10672 if (kind == svn_node_dir) 10673 *lock_abspath = *target_abspath; 10674 else 10675 *lock_abspath = svn_dirent_dirname(*target_abspath, result_pool); 10676 10677 return SVN_NO_ERROR; 10678} 10679 10680svn_error_t * 10681svn_client_merge5(const char *source1, 10682 const svn_opt_revision_t *revision1, 10683 const char *source2, 10684 const svn_opt_revision_t *revision2, 10685 const char *target_wcpath, 10686 svn_depth_t depth, 10687 svn_boolean_t ignore_mergeinfo, 10688 svn_boolean_t diff_ignore_ancestry, 10689 svn_boolean_t force_delete, 10690 svn_boolean_t record_only, 10691 svn_boolean_t dry_run, 10692 svn_boolean_t allow_mixed_rev, 10693 const apr_array_header_t *merge_options, 10694 svn_client_ctx_t *ctx, 10695 apr_pool_t *pool) 10696{ 10697 const char *target_abspath, *lock_abspath; 10698 svn_client__conflict_report_t *conflict_report; 10699 10700 /* Sanity check our input -- we require specified revisions, 10701 * and either 2 paths or 2 URLs. */ 10702 if ((revision1->kind == svn_opt_revision_unspecified) 10703 || (revision2->kind == svn_opt_revision_unspecified)) 10704 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, 10705 _("Not all required revisions are specified")); 10706 if (svn_path_is_url(source1) != svn_path_is_url(source2)) 10707 return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, 10708 _("Merge sources must both be " 10709 "either paths or URLs")); 10710 /* A WC path must be used with a repository revision, as we can't 10711 * (currently) use the WC itself as a source, we can only read the URL 10712 * from it and use that. */ 10713 SVN_ERR(ensure_wc_path_has_repo_revision(source1, revision1, pool)); 10714 SVN_ERR(ensure_wc_path_has_repo_revision(source2, revision2, pool)); 10715 10716 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 10717 target_wcpath, ctx, pool)); 10718 10719 if (!dry_run) 10720 SVN_WC__CALL_WITH_WRITE_LOCK( 10721 svn_client__merge_locked(&conflict_report, 10722 source1, revision1, source2, revision2, 10723 target_abspath, depth, ignore_mergeinfo, 10724 diff_ignore_ancestry, 10725 force_delete, record_only, dry_run, 10726 allow_mixed_rev, merge_options, ctx, pool, pool), 10727 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 10728 else 10729 SVN_ERR(svn_client__merge_locked(&conflict_report, 10730 source1, revision1, source2, revision2, 10731 target_abspath, depth, ignore_mergeinfo, 10732 diff_ignore_ancestry, 10733 force_delete, record_only, dry_run, 10734 allow_mixed_rev, merge_options, ctx, pool, 10735 pool)); 10736 10737 SVN_ERR(svn_client__make_merge_conflict_error(conflict_report, pool)); 10738 return SVN_NO_ERROR; 10739} 10740 10741 10742/* Check if mergeinfo for a given path is described explicitly or via 10743 inheritance in a mergeinfo catalog. 10744 10745 If REPOS_REL_PATH exists in CATALOG and has mergeinfo containing 10746 MERGEINFO, then set *IN_CATALOG to TRUE. If REPOS_REL_PATH does 10747 not exist in CATALOG, then find its nearest parent which does exist. 10748 If the mergeinfo REPOS_REL_PATH would inherit from that parent 10749 contains MERGEINFO then set *IN_CATALOG to TRUE. Set *IN_CATALOG 10750 to FALSE in all other cases. 10751 10752 Set *CAT_KEY_PATH to the key path in CATALOG for REPOS_REL_PATH's 10753 explicit or inherited mergeinfo. If no explicit or inherited mergeinfo 10754 is found for REPOS_REL_PATH then set *CAT_KEY_PATH to NULL. 10755 10756 User RESULT_POOL to allocate *CAT_KEY_PATH. Use SCRATCH_POOL for 10757 temporary allocations. */ 10758static svn_error_t * 10759mergeinfo_in_catalog(svn_boolean_t *in_catalog, 10760 const char **cat_key_path, 10761 const char *repos_rel_path, 10762 svn_mergeinfo_t mergeinfo, 10763 svn_mergeinfo_catalog_t catalog, 10764 apr_pool_t *result_pool, 10765 apr_pool_t *scratch_pool) 10766{ 10767 const char *walk_path = NULL; 10768 10769 *in_catalog = FALSE; 10770 *cat_key_path = NULL; 10771 10772 if (mergeinfo && catalog && apr_hash_count(catalog)) 10773 { 10774 const char *path = repos_rel_path; 10775 10776 /* Start with the assumption there is no explicit or inherited 10777 mergeinfo for REPOS_REL_PATH in CATALOG. */ 10778 svn_mergeinfo_t mergeinfo_in_cat = NULL; 10779 10780 while (1) 10781 { 10782 mergeinfo_in_cat = svn_hash_gets(catalog, path); 10783 10784 if (mergeinfo_in_cat) /* Found it! */ 10785 { 10786 *cat_key_path = apr_pstrdup(result_pool, path); 10787 break; 10788 } 10789 else /* Look for inherited mergeinfo. */ 10790 { 10791 walk_path = svn_relpath_join(svn_relpath_basename(path, 10792 scratch_pool), 10793 walk_path ? walk_path : "", 10794 scratch_pool); 10795 path = svn_relpath_dirname(path, scratch_pool); 10796 10797 if (path[0] == '\0') /* No mergeinfo to inherit. */ 10798 break; 10799 } 10800 } 10801 10802 if (mergeinfo_in_cat) 10803 { 10804 if (walk_path) 10805 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(&mergeinfo_in_cat, 10806 mergeinfo_in_cat, 10807 walk_path, 10808 scratch_pool, 10809 scratch_pool)); 10810 SVN_ERR(svn_mergeinfo_intersect2(&mergeinfo_in_cat, 10811 mergeinfo_in_cat, mergeinfo, 10812 TRUE, 10813 scratch_pool, scratch_pool)); 10814 SVN_ERR(svn_mergeinfo__equals(in_catalog, mergeinfo_in_cat, 10815 mergeinfo, TRUE, scratch_pool)); 10816 } 10817 } 10818 10819 return SVN_NO_ERROR; 10820} 10821 10822/* A svn_log_entry_receiver_t baton for log_find_operative_revs(). */ 10823typedef struct log_find_operative_baton_t 10824{ 10825 /* The catalog of explicit mergeinfo on a reintegrate source. */ 10826 svn_mergeinfo_catalog_t merged_catalog; 10827 10828 /* The catalog of unmerged history from the reintegrate target to 10829 the source which we will create. Allocated in RESULT_POOL. */ 10830 svn_mergeinfo_catalog_t unmerged_catalog; 10831 10832 /* The repository absolute path of the reintegrate target. */ 10833 const char *target_fspath; 10834 10835 /* The path of the reintegrate source relative to the repository root. */ 10836 const char *source_repos_rel_path; 10837 10838 apr_pool_t *result_pool; 10839} log_find_operative_baton_t; 10840 10841/* A svn_log_entry_receiver_t callback for find_unsynced_ranges(). */ 10842static svn_error_t * 10843log_find_operative_revs(void *baton, 10844 svn_log_entry_t *log_entry, 10845 apr_pool_t *pool) 10846{ 10847 log_find_operative_baton_t *log_baton = baton; 10848 apr_hash_index_t *hi; 10849 svn_revnum_t revision; 10850 10851 /* It's possible that authz restrictions on the merge source prevent us 10852 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 10853 if (!log_entry->changed_paths2) 10854 return SVN_NO_ERROR; 10855 10856 revision = log_entry->revision; 10857 10858 for (hi = apr_hash_first(pool, log_entry->changed_paths2); 10859 hi; 10860 hi = apr_hash_next(hi)) 10861 { 10862 const char *subtree_missing_this_rev; 10863 const char *path = apr_hash_this_key(hi); 10864 const char *rel_path; 10865 const char *source_rel_path; 10866 svn_boolean_t in_catalog; 10867 svn_mergeinfo_t log_entry_as_mergeinfo; 10868 10869 rel_path = svn_fspath__skip_ancestor(log_baton->target_fspath, path); 10870 /* Easy out: The path is not within the tree of interest. */ 10871 if (rel_path == NULL) 10872 continue; 10873 10874 source_rel_path = svn_relpath_join(log_baton->source_repos_rel_path, 10875 rel_path, pool); 10876 10877 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo, 10878 apr_psprintf(pool, "%s:%ld", 10879 path, revision), 10880 pool)); 10881 10882 SVN_ERR(mergeinfo_in_catalog(&in_catalog, &subtree_missing_this_rev, 10883 source_rel_path, log_entry_as_mergeinfo, 10884 log_baton->merged_catalog, 10885 pool, pool)); 10886 10887 if (!in_catalog) 10888 { 10889 svn_mergeinfo_t unmerged_for_key; 10890 const char *suffix, *missing_path; 10891 10892 /* If there is no mergeinfo on the source tree we'll say 10893 the "subtree" missing this revision is the root of the 10894 source. */ 10895 if (!subtree_missing_this_rev) 10896 subtree_missing_this_rev = log_baton->source_repos_rel_path; 10897 10898 suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev, 10899 source_rel_path); 10900 if (suffix && suffix[0] != '\0') 10901 { 10902 missing_path = apr_pstrmemdup(pool, path, 10903 strlen(path) - strlen(suffix) - 1); 10904 } 10905 else 10906 { 10907 missing_path = path; 10908 } 10909 10910 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo, 10911 apr_psprintf(pool, "%s:%ld", 10912 missing_path, revision), 10913 log_baton->result_pool)); 10914 unmerged_for_key = svn_hash_gets(log_baton->unmerged_catalog, 10915 subtree_missing_this_rev); 10916 10917 if (unmerged_for_key) 10918 { 10919 SVN_ERR(svn_mergeinfo_merge2(unmerged_for_key, 10920 log_entry_as_mergeinfo, 10921 log_baton->result_pool, 10922 pool)); 10923 } 10924 else 10925 { 10926 svn_hash_sets(log_baton->unmerged_catalog, 10927 apr_pstrdup(log_baton->result_pool, 10928 subtree_missing_this_rev), 10929 log_entry_as_mergeinfo); 10930 } 10931 10932 } 10933 } 10934 return SVN_NO_ERROR; 10935} 10936 10937/* Determine if the mergeinfo on a reintegrate source SOURCE_LOC, 10938 reflects that the source is fully synced with the reintegrate target 10939 TARGET_LOC, even if a naive interpretation of the source's 10940 mergeinfo says otherwise -- See issue #3577. 10941 10942 UNMERGED_CATALOG represents the history (as mergeinfo) from 10943 TARGET_LOC that is not represented in SOURCE_LOC's 10944 explicit/inherited mergeinfo as represented by MERGED_CATALOG. 10945 MERGED_CATALOG may be empty if the source has no explicit or inherited 10946 mergeinfo. 10947 10948 Check that all of the unmerged revisions in UNMERGED_CATALOG's 10949 mergeinfos are "phantoms", that is, one of the following conditions holds: 10950 10951 1) The revision affects no corresponding paths in SOURCE_LOC. 10952 10953 2) The revision affects corresponding paths in SOURCE_LOC, 10954 but based on the mergeinfo in MERGED_CATALOG, the change was 10955 previously merged. 10956 10957 Make a deep copy, allocated in RESULT_POOL, of any portions of 10958 UNMERGED_CATALOG that are not phantoms, to TRUE_UNMERGED_CATALOG. 10959 10960 Note: The keys in all mergeinfo catalogs used here are relative to the 10961 root of the repository. 10962 10963 RA_SESSION is an RA session open to the repository of TARGET_LOC; it may 10964 be temporarily reparented within this function. 10965 10966 Use SCRATCH_POOL for all temporary allocations. */ 10967static svn_error_t * 10968find_unsynced_ranges(const svn_client__pathrev_t *source_loc, 10969 const svn_client__pathrev_t *target_loc, 10970 svn_mergeinfo_catalog_t unmerged_catalog, 10971 svn_mergeinfo_catalog_t merged_catalog, 10972 svn_mergeinfo_catalog_t true_unmerged_catalog, 10973 svn_ra_session_t *ra_session, 10974 apr_pool_t *result_pool, 10975 apr_pool_t *scratch_pool) 10976{ 10977 svn_rangelist_t *potentially_unmerged_ranges = NULL; 10978 10979 /* Convert all the unmerged history to a rangelist. */ 10980 if (apr_hash_count(unmerged_catalog)) 10981 { 10982 apr_hash_index_t *hi_catalog; 10983 10984 potentially_unmerged_ranges = 10985 apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *)); 10986 10987 for (hi_catalog = apr_hash_first(scratch_pool, unmerged_catalog); 10988 hi_catalog; 10989 hi_catalog = apr_hash_next(hi_catalog)) 10990 { 10991 svn_mergeinfo_t mergeinfo = apr_hash_this_val(hi_catalog); 10992 10993 SVN_ERR(svn_rangelist__merge_many(potentially_unmerged_ranges, 10994 mergeinfo, 10995 scratch_pool, scratch_pool)); 10996 } 10997 } 10998 10999 /* Find any unmerged revisions which both affect the source and 11000 are not yet merged to it. */ 11001 if (potentially_unmerged_ranges) 11002 { 11003 svn_revnum_t oldest_rev = 11004 (APR_ARRAY_IDX(potentially_unmerged_ranges, 11005 0, 11006 svn_merge_range_t *))->start + 1; 11007 svn_revnum_t youngest_rev = 11008 (APR_ARRAY_IDX(potentially_unmerged_ranges, 11009 potentially_unmerged_ranges->nelts - 1, 11010 svn_merge_range_t *))->end; 11011 log_find_operative_baton_t log_baton; 11012 const char *old_session_url = NULL; 11013 svn_error_t *err; 11014 11015 log_baton.merged_catalog = merged_catalog; 11016 log_baton.unmerged_catalog = true_unmerged_catalog; 11017 log_baton.source_repos_rel_path 11018 = svn_client__pathrev_relpath(source_loc, scratch_pool); 11019 log_baton.target_fspath 11020 = svn_client__pathrev_fspath(target_loc, scratch_pool); 11021 log_baton.result_pool = result_pool; 11022 11023 /* Reparent the session to TARGET_LOC if this target location 11024 * exists within the unmerged revision range. */ 11025 if (target_loc->rev <= youngest_rev && target_loc->rev >= oldest_rev) 11026 SVN_ERR(svn_client__ensure_ra_session_url( 11027 &old_session_url, ra_session, target_loc->url, scratch_pool)); 11028 11029 err = get_log(ra_session, "", youngest_rev, oldest_rev, 11030 TRUE, /* discover_changed_paths */ 11031 log_find_operative_revs, &log_baton, 11032 scratch_pool); 11033 if (old_session_url) 11034 err = svn_error_compose_create(err, 11035 svn_ra_reparent(ra_session, 11036 old_session_url, 11037 scratch_pool)); 11038 SVN_ERR(err); 11039 } 11040 11041 return SVN_NO_ERROR; 11042} 11043 11044 11045/* Find the youngest revision that has been merged from target to source. 11046 * 11047 * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in 11048 * SOURCE_MERGEINFO, then we know that at least one merge was done from the 11049 * target to the source. In that case, set *YOUNGEST_MERGED_REV to the 11050 * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is 11051 * already younger than that). Otherwise, leave *YOUNGEST_MERGED_REV alone. 11052 */ 11053static svn_error_t * 11054find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev, 11055 svn_mergeinfo_t target_history_as_mergeinfo, 11056 svn_mergeinfo_t source_mergeinfo, 11057 apr_pool_t *scratch_pool) 11058{ 11059 svn_mergeinfo_t explicit_source_target_history_intersection; 11060 11061 SVN_ERR(svn_mergeinfo_intersect2( 11062 &explicit_source_target_history_intersection, 11063 source_mergeinfo, target_history_as_mergeinfo, TRUE, 11064 scratch_pool, scratch_pool)); 11065 if (apr_hash_count(explicit_source_target_history_intersection)) 11066 { 11067 svn_revnum_t old_rev, young_rev; 11068 11069 /* Keep track of the youngest revision merged from target to source. */ 11070 SVN_ERR(svn_mergeinfo__get_range_endpoints( 11071 &young_rev, &old_rev, 11072 explicit_source_target_history_intersection, scratch_pool)); 11073 if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev) 11074 || (young_rev > *youngest_merged_rev)) 11075 *youngest_merged_rev = young_rev; 11076 } 11077 11078 return SVN_NO_ERROR; 11079} 11080 11081/* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO 11082 * that are not present in the source branch. 11083 * 11084 * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source 11085 * branch SOURCE_PATHREV. Extend SOURCE_MERGEINFO, modifying it in 11086 * place, to include the natural history (implicit mergeinfo) of 11087 * SOURCE_PATHREV. ### But make these additions in SCRATCH_POOL. 11088 * 11089 * SOURCE_RA_SESSION is an RA session open to the repository containing 11090 * SOURCE_PATHREV; it may be temporarily reparented within this function. 11091 * 11092 * ### [JAF] This function is named '..._subroutine' simply because I 11093 * factored it out based on code similarity, without knowing what it's 11094 * purpose is. We should clarify its purpose and choose a better name. 11095 */ 11096static svn_error_t * 11097find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p, 11098 svn_mergeinfo_t target_history_as_mergeinfo, 11099 svn_mergeinfo_t source_mergeinfo, 11100 const svn_client__pathrev_t *source_pathrev, 11101 svn_ra_session_t *source_ra_session, 11102 svn_client_ctx_t *ctx, 11103 apr_pool_t *result_pool, 11104 apr_pool_t *scratch_pool) 11105{ 11106 svn_mergeinfo_t source_history_as_mergeinfo; 11107 11108 /* Get the source path's natural history and merge it into source 11109 path's explicit or inherited mergeinfo. */ 11110 SVN_ERR(svn_client__get_history_as_mergeinfo( 11111 &source_history_as_mergeinfo, NULL /* has_rev_zero_history */, 11112 source_pathrev, source_pathrev->rev, SVN_INVALID_REVNUM, 11113 source_ra_session, ctx, scratch_pool)); 11114 SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo, 11115 source_history_as_mergeinfo, 11116 scratch_pool, scratch_pool)); 11117 11118 /* Now source_mergeinfo represents everything we know about 11119 source_path's history. Now we need to know what part, if any, of the 11120 corresponding target's history is *not* part of source_path's total 11121 history; because it is neither shared history nor was it ever merged 11122 from the target to the source. */ 11123 SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p, 11124 source_mergeinfo, 11125 target_history_as_mergeinfo, TRUE, 11126 result_pool, scratch_pool)); 11127 return SVN_NO_ERROR; 11128} 11129 11130/* Helper for calculate_left_hand_side() which produces a mergeinfo catalog 11131 describing what parts of of the reintegrate target have not previously been 11132 merged to the reintegrate source. 11133 11134 SOURCE_CATALOG is the collection of explicit mergeinfo on SOURCE_LOC and 11135 all its children, i.e. the mergeinfo catalog for the reintegrate source. 11136 11137 TARGET_HISTORY_HASH is a hash of (const char *) paths mapped to 11138 svn_mergeinfo_t representing the location history. Each of these 11139 path keys represent a path in the reintegrate target, relative to the 11140 repository root, which has explicit mergeinfo and/or is the reintegrate 11141 target itself. The svn_mergeinfo_t's contain the natural history of each 11142 path@TARGET_REV. Effectively this is the mergeinfo catalog on the 11143 reintegrate target. 11144 11145 YC_ANCESTOR_REV is the revision of the youngest common ancestor of the 11146 reintegrate source and the reintegrate target. 11147 11148 SOURCE_LOC is the reintegrate source. 11149 11150 SOURCE_RA_SESSION is a session opened to the URL of SOURCE_LOC 11151 and TARGET_RA_SESSION is open to TARGET->loc.url. 11152 11153 For each entry in TARGET_HISTORY_HASH check that the history it 11154 represents is contained in either the explicit mergeinfo for the 11155 corresponding path in SOURCE_CATALOG, the corresponding path's inherited 11156 mergeinfo (if no explicit mergeinfo for the path is found in 11157 SOURCE_CATALOG), or the corresponding path's natural history. Populate 11158 *UNMERGED_TO_SOURCE_CATALOG with the corresponding source paths mapped to 11159 the mergeinfo from the target's natural history which is *not* found. Also 11160 include any mergeinfo from SOURCE_CATALOG which explicitly describes the 11161 target's history but for which *no* entry was found in 11162 TARGET_HISTORY_HASH. 11163 11164 If no part of TARGET_HISTORY_HASH is found in SOURCE_CATALOG set 11165 *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM; otherwise set it to the youngest 11166 revision previously merged from the target to the source, and filter 11167 *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than 11168 *YOUNGEST_MERGED_REV. 11169 11170 *UNMERGED_TO_SOURCE_CATALOG is (deeply) allocated in RESULT_POOL. 11171 SCRATCH_POOL is used for all temporary allocations. */ 11172static svn_error_t * 11173find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog, 11174 svn_revnum_t *youngest_merged_rev, 11175 svn_revnum_t yc_ancestor_rev, 11176 svn_mergeinfo_catalog_t source_catalog, 11177 apr_hash_t *target_history_hash, 11178 const svn_client__pathrev_t *source_loc, 11179 const merge_target_t *target, 11180 svn_ra_session_t *source_ra_session, 11181 svn_ra_session_t *target_ra_session, 11182 svn_client_ctx_t *ctx, 11183 apr_pool_t *result_pool, 11184 apr_pool_t *scratch_pool) 11185{ 11186 const char *source_repos_rel_path 11187 = svn_client__pathrev_relpath(source_loc, scratch_pool); 11188 const char *target_repos_rel_path 11189 = svn_client__pathrev_relpath(&target->loc, scratch_pool); 11190 apr_hash_index_t *hi; 11191 svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool); 11192 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 11193 11194 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11195 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11196 11197 *youngest_merged_rev = SVN_INVALID_REVNUM; 11198 11199 /* Examine the natural history of each path in the reintegrate target 11200 with explicit mergeinfo. */ 11201 for (hi = apr_hash_first(scratch_pool, target_history_hash); 11202 hi; 11203 hi = apr_hash_next(hi)) 11204 { 11205 const char *target_path = apr_hash_this_key(hi); 11206 svn_mergeinfo_t target_history_as_mergeinfo = apr_hash_this_val(hi); 11207 const char *path_rel_to_session 11208 = svn_relpath_skip_ancestor(target_repos_rel_path, target_path); 11209 const char *source_path; 11210 svn_client__pathrev_t *source_pathrev; 11211 svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo; 11212 11213 svn_pool_clear(iterpool); 11214 11215 source_path = svn_relpath_join(source_repos_rel_path, 11216 path_rel_to_session, iterpool); 11217 source_pathrev = svn_client__pathrev_join_relpath( 11218 source_loc, path_rel_to_session, iterpool); 11219 11220 /* Remove any target history that is also part of the source's history, 11221 i.e. their common ancestry. By definition this has already been 11222 "merged" from the target to the source. If the source has explicit 11223 self referential mergeinfo it would intersect with the target's 11224 history below, making it appear that some merges had been done from 11225 the target to the source, when this might not actually be the case. */ 11226 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( 11227 &target_history_as_mergeinfo, target_history_as_mergeinfo, 11228 source_loc->rev, yc_ancestor_rev, TRUE, iterpool, iterpool)); 11229 11230 /* Look for any explicit mergeinfo on the source path corresponding to 11231 the target path. If we find any remove that from SOURCE_CATALOG. 11232 When this iteration over TARGET_HISTORY_HASH is complete all that 11233 should be left in SOURCE_CATALOG are subtrees that have explicit 11234 mergeinfo on the reintegrate source where there is no corresponding 11235 explicit mergeinfo on the reintegrate target. */ 11236 source_mergeinfo = svn_hash_gets(source_catalog, source_path); 11237 if (source_mergeinfo) 11238 { 11239 svn_hash_sets(source_catalog, source_path, NULL); 11240 11241 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev, 11242 target_history_as_mergeinfo, 11243 source_mergeinfo, 11244 iterpool)); 11245 } 11246 else 11247 { 11248 /* There is no mergeinfo on source_path *or* source_path doesn't 11249 exist at all. If simply doesn't exist we can ignore it 11250 altogether. */ 11251 svn_node_kind_t kind; 11252 11253 SVN_ERR(svn_ra_check_path(source_ra_session, 11254 path_rel_to_session, 11255 source_loc->rev, &kind, iterpool)); 11256 if (kind == svn_node_none) 11257 continue; 11258 /* Else source_path does exist though it has no explicit mergeinfo. 11259 Find its inherited mergeinfo. If it doesn't have any then simply 11260 set source_mergeinfo to an empty hash. */ 11261 SVN_ERR(svn_client__get_repos_mergeinfo( 11262 &source_mergeinfo, source_ra_session, 11263 source_pathrev->url, source_pathrev->rev, 11264 svn_mergeinfo_inherited, FALSE /*squelch_incapable*/, 11265 iterpool)); 11266 if (!source_mergeinfo) 11267 source_mergeinfo = apr_hash_make(iterpool); 11268 } 11269 11270 /* Use scratch_pool rather than iterpool because filtered_mergeinfo 11271 is going into new_catalog below and needs to last to the end of 11272 this function. */ 11273 SVN_ERR(find_unmerged_mergeinfo_subroutine( 11274 &filtered_mergeinfo, target_history_as_mergeinfo, 11275 source_mergeinfo, source_pathrev, 11276 source_ra_session, ctx, scratch_pool, iterpool)); 11277 svn_hash_sets(new_catalog, apr_pstrdup(scratch_pool, source_path), 11278 filtered_mergeinfo); 11279 } 11280 11281 /* Are there any subtrees with explicit mergeinfo still left in the merge 11282 source where there was no explicit mergeinfo for the corresponding path 11283 in the merge target? If so, add the intersection of those path's 11284 mergeinfo and the corresponding target path's mergeinfo to 11285 new_catalog. */ 11286 for (hi = apr_hash_first(scratch_pool, source_catalog); 11287 hi; 11288 hi = apr_hash_next(hi)) 11289 { 11290 const char *source_path = apr_hash_this_key(hi); 11291 const char *path_rel_to_session = 11292 svn_relpath_skip_ancestor(source_repos_rel_path, source_path); 11293 const char *source_url; 11294 svn_mergeinfo_t source_mergeinfo = apr_hash_this_val(hi); 11295 svn_mergeinfo_t filtered_mergeinfo; 11296 svn_client__pathrev_t *target_pathrev; 11297 svn_mergeinfo_t target_history_as_mergeinfo; 11298 svn_error_t *err; 11299 11300 svn_pool_clear(iterpool); 11301 11302 source_url = svn_path_url_add_component2(source_loc->url, 11303 path_rel_to_session, iterpool); 11304 target_pathrev = svn_client__pathrev_join_relpath( 11305 &target->loc, path_rel_to_session, iterpool); 11306 err = svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo, 11307 NULL /* has_rev_zero_history */, 11308 target_pathrev, 11309 target->loc.rev, 11310 SVN_INVALID_REVNUM, 11311 target_ra_session, 11312 ctx, iterpool); 11313 if (err) 11314 { 11315 if (err->apr_err == SVN_ERR_FS_NOT_FOUND 11316 || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED) 11317 { 11318 /* This path with explicit mergeinfo in the source doesn't 11319 exist on the target. */ 11320 svn_error_clear(err); 11321 err = NULL; 11322 } 11323 else 11324 { 11325 return svn_error_trace(err); 11326 } 11327 } 11328 else 11329 { 11330 svn_client__pathrev_t *pathrev; 11331 11332 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev, 11333 target_history_as_mergeinfo, 11334 source_mergeinfo, 11335 iterpool)); 11336 11337 /* Use scratch_pool rather than iterpool because filtered_mergeinfo 11338 is going into new_catalog below and needs to last to the end of 11339 this function. */ 11340 /* ### Why looking at SOURCE_url at TARGET_rev? */ 11341 SVN_ERR(svn_client__pathrev_create_with_session( 11342 &pathrev, source_ra_session, target->loc.rev, source_url, 11343 iterpool)); 11344 SVN_ERR(find_unmerged_mergeinfo_subroutine( 11345 &filtered_mergeinfo, target_history_as_mergeinfo, 11346 source_mergeinfo, pathrev, 11347 source_ra_session, ctx, scratch_pool, iterpool)); 11348 if (apr_hash_count(filtered_mergeinfo)) 11349 svn_hash_sets(new_catalog, 11350 apr_pstrdup(scratch_pool, source_path), 11351 filtered_mergeinfo); 11352 } 11353 } 11354 11355 /* Limit new_catalog to the youngest revisions previously merged from 11356 the target to the source. */ 11357 if (SVN_IS_VALID_REVNUM(*youngest_merged_rev)) 11358 SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog, 11359 new_catalog, 11360 *youngest_merged_rev, 11361 0, /* No oldest bound. */ 11362 TRUE, 11363 scratch_pool, 11364 scratch_pool)); 11365 11366 /* Make a shiny new copy before blowing away all the temporary pools. */ 11367 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(new_catalog, 11368 result_pool); 11369 svn_pool_destroy(iterpool); 11370 return SVN_NO_ERROR; 11371} 11372 11373/* Helper for svn_client_merge_reintegrate() which calculates the 11374 'left hand side' of the underlying two-URL merge that a --reintegrate 11375 merge actually performs. If no merge should be performed, set 11376 *LEFT_P to NULL. 11377 11378 TARGET->abspath is the absolute working copy path of the reintegrate 11379 merge. 11380 11381 SOURCE_LOC is the reintegrate source. 11382 11383 SUBTREES_WITH_MERGEINFO is a hash of (const char *) absolute paths mapped 11384 to (svn_mergeinfo_t *) mergeinfo values for each working copy path with 11385 explicit mergeinfo in TARGET->abspath. Actually we only need to know the 11386 paths, not the mergeinfo. 11387 11388 TARGET->loc.rev is the working revision the entire WC tree rooted at 11389 TARGET is at. 11390 11391 Populate *UNMERGED_TO_SOURCE_CATALOG with the mergeinfo describing what 11392 parts of TARGET->loc have not been merged to SOURCE_LOC, up to the 11393 youngest revision ever merged from the TARGET->abspath to the source if 11394 such exists, see doc string for find_unmerged_mergeinfo(). 11395 11396 SOURCE_RA_SESSION is a session opened to the SOURCE_LOC 11397 and TARGET_RA_SESSION is open to TARGET->loc.url. 11398 11399 *LEFT_P, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are 11400 allocated in RESULT_POOL. SCRATCH_POOL is used for all temporary 11401 allocations. */ 11402static svn_error_t * 11403calculate_left_hand_side(svn_client__pathrev_t **left_p, 11404 svn_mergeinfo_catalog_t *merged_to_source_catalog, 11405 svn_mergeinfo_catalog_t *unmerged_to_source_catalog, 11406 const merge_target_t *target, 11407 apr_hash_t *subtrees_with_mergeinfo, 11408 const svn_client__pathrev_t *source_loc, 11409 svn_ra_session_t *source_ra_session, 11410 svn_ra_session_t *target_ra_session, 11411 svn_client_ctx_t *ctx, 11412 apr_pool_t *result_pool, 11413 apr_pool_t *scratch_pool) 11414{ 11415 svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog; 11416 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 11417 apr_hash_index_t *hi; 11418 /* hash of paths mapped to arrays of svn_mergeinfo_t. */ 11419 apr_hash_t *target_history_hash = apr_hash_make(scratch_pool); 11420 svn_revnum_t youngest_merged_rev; 11421 svn_client__pathrev_t *yc_ancestor; 11422 11423 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11424 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11425 11426 /* Initialize our return variables. */ 11427 *left_p = NULL; 11428 11429 /* TARGET->abspath may not have explicit mergeinfo and thus may not be 11430 contained within SUBTREES_WITH_MERGEINFO. If this is the case then 11431 add a dummy item for TARGET->abspath so we get its history (i.e. implicit 11432 mergeinfo) below. */ 11433 if (!svn_hash_gets(subtrees_with_mergeinfo, target->abspath)) 11434 svn_hash_sets(subtrees_with_mergeinfo, target->abspath, 11435 apr_hash_make(result_pool)); 11436 11437 /* Get the history segments (as mergeinfo) for TARGET->abspath and any of 11438 its subtrees with explicit mergeinfo. */ 11439 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo); 11440 hi; 11441 hi = apr_hash_next(hi)) 11442 { 11443 const char *local_abspath = apr_hash_this_key(hi); 11444 svn_client__pathrev_t *target_child; 11445 const char *repos_relpath; 11446 svn_mergeinfo_t target_history_as_mergeinfo; 11447 11448 svn_pool_clear(iterpool); 11449 11450 /* Convert the absolute path with mergeinfo on it to a path relative 11451 to the session root. */ 11452 SVN_ERR(svn_wc__node_get_repos_info(NULL, &repos_relpath, NULL, NULL, 11453 ctx->wc_ctx, local_abspath, 11454 scratch_pool, iterpool)); 11455 target_child = svn_client__pathrev_create_with_relpath( 11456 target->loc.repos_root_url, target->loc.repos_uuid, 11457 target->loc.rev, repos_relpath, iterpool); 11458 SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo, 11459 NULL /* has_rev_zero_hist */, 11460 target_child, 11461 target->loc.rev, 11462 SVN_INVALID_REVNUM, 11463 target_ra_session, 11464 ctx, scratch_pool)); 11465 11466 svn_hash_sets(target_history_hash, repos_relpath, 11467 target_history_as_mergeinfo); 11468 } 11469 11470 /* Check that SOURCE_LOC and TARGET->loc are 11471 actually related, we can't reintegrate if they are not. Also 11472 get an initial value for the YCA revision number. */ 11473 SVN_ERR(svn_client__get_youngest_common_ancestor( 11474 &yc_ancestor, source_loc, &target->loc, target_ra_session, ctx, 11475 iterpool, iterpool)); 11476 if (! yc_ancestor) 11477 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11478 _("'%s@%ld' must be ancestrally related to " 11479 "'%s@%ld'"), source_loc->url, source_loc->rev, 11480 target->loc.url, target->loc.rev); 11481 11482 /* If the source revision is the same as the youngest common 11483 revision, then there can't possibly be any unmerged revisions 11484 that we need to apply to target. */ 11485 if (source_loc->rev == yc_ancestor->rev) 11486 { 11487 svn_pool_destroy(iterpool); 11488 return SVN_NO_ERROR; 11489 } 11490 11491 /* Get the mergeinfo from the source, including its descendants 11492 with differing explicit mergeinfo. */ 11493 SVN_ERR(svn_client__get_repos_mergeinfo_catalog( 11494 &mergeinfo_catalog, source_ra_session, 11495 source_loc->url, source_loc->rev, 11496 svn_mergeinfo_inherited, FALSE /* squelch_incapable */, 11497 TRUE /* include_descendants */, iterpool, iterpool)); 11498 11499 if (!mergeinfo_catalog) 11500 mergeinfo_catalog = apr_hash_make(iterpool); 11501 11502 *merged_to_source_catalog = svn_mergeinfo_catalog_dup(mergeinfo_catalog, 11503 result_pool); 11504 11505 /* Filter the source's mergeinfo catalog so that we are left with 11506 mergeinfo that describes what has *not* previously been merged from 11507 TARGET->loc to SOURCE_LOC. */ 11508 SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog, 11509 &youngest_merged_rev, 11510 yc_ancestor->rev, 11511 mergeinfo_catalog, 11512 target_history_hash, 11513 source_loc, 11514 target, 11515 source_ra_session, 11516 target_ra_session, 11517 ctx, 11518 iterpool, iterpool)); 11519 11520 /* Simplify unmerged_catalog through elision then make a copy in POOL. */ 11521 SVN_ERR(svn_client__elide_mergeinfo_catalog(unmerged_catalog, 11522 iterpool)); 11523 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(unmerged_catalog, 11524 result_pool); 11525 11526 if (youngest_merged_rev == SVN_INVALID_REVNUM) 11527 { 11528 /* We never merged to the source. Just return the branch point. */ 11529 *left_p = svn_client__pathrev_dup(yc_ancestor, result_pool); 11530 } 11531 else 11532 { 11533 /* We've previously merged some or all of the target, up to 11534 youngest_merged_rev, to the source. Set 11535 *LEFT_P to cover the youngest part of this range. */ 11536 SVN_ERR(svn_client__repos_location(left_p, target_ra_session, 11537 &target->loc, youngest_merged_rev, 11538 ctx, result_pool, iterpool)); 11539 } 11540 11541 svn_pool_destroy(iterpool); 11542 return SVN_NO_ERROR; 11543} 11544 11545/* Determine the URLs and revisions needed to perform a reintegrate merge 11546 * from SOURCE_LOC into the working copy at TARGET. 11547 * 11548 * SOURCE_RA_SESSION and TARGET_RA_SESSION are RA sessions opened to the 11549 * URLs of SOURCE_LOC and TARGET->loc respectively. 11550 * 11551 * Set *SOURCE_P to 11552 * the source-left and source-right locations of the required merge. Set 11553 * *YC_ANCESTOR_P to the location of the youngest ancestor. 11554 * Any of these output pointers may be NULL if not wanted. 11555 * 11556 * See svn_client_find_reintegrate_merge() for other details. 11557 */ 11558static svn_error_t * 11559find_reintegrate_merge(merge_source_t **source_p, 11560 svn_client__pathrev_t **yc_ancestor_p, 11561 svn_ra_session_t *source_ra_session, 11562 const svn_client__pathrev_t *source_loc, 11563 svn_ra_session_t *target_ra_session, 11564 const merge_target_t *target, 11565 svn_client_ctx_t *ctx, 11566 apr_pool_t *result_pool, 11567 apr_pool_t *scratch_pool) 11568{ 11569 svn_client__pathrev_t *yc_ancestor; 11570 svn_client__pathrev_t *loc1; 11571 merge_source_t source; 11572 svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog; 11573 svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog; 11574 svn_error_t *err; 11575 apr_hash_t *subtrees_with_mergeinfo; 11576 11577 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11578 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11579 11580 /* As the WC tree is "pure", use its last-updated-to revision as 11581 the default revision for the left side of our merge, since that's 11582 what the repository sub-tree is required to be up to date with 11583 (with regard to the WC). */ 11584 /* ### Bogus/obsolete comment? */ 11585 11586 /* Can't reintegrate to or from the root of the repository. */ 11587 if (strcmp(source_loc->url, source_loc->repos_root_url) == 0 11588 || strcmp(target->loc.url, target->loc.repos_root_url) == 0) 11589 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11590 _("Neither the reintegrate source nor target " 11591 "can be the root of the repository")); 11592 11593 /* Find all the subtrees in TARGET_WCPATH that have explicit mergeinfo. */ 11594 err = get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo, 11595 target->abspath, svn_depth_infinity, 11596 ctx, scratch_pool, scratch_pool); 11597 /* Issue #3896: If invalid mergeinfo in the reintegrate target 11598 prevents us from proceeding, then raise the best error possible. */ 11599 if (err && err->apr_err == SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING) 11600 err = svn_error_quick_wrap(err, _("Reintegrate merge not possible")); 11601 SVN_ERR(err); 11602 11603 SVN_ERR(calculate_left_hand_side(&loc1, 11604 &merged_to_source_mergeinfo_catalog, 11605 &unmerged_to_source_mergeinfo_catalog, 11606 target, 11607 subtrees_with_mergeinfo, 11608 source_loc, 11609 source_ra_session, 11610 target_ra_session, 11611 ctx, 11612 scratch_pool, scratch_pool)); 11613 11614 /* Did calculate_left_hand_side() decide that there was no merge to 11615 be performed here? */ 11616 if (! loc1) 11617 { 11618 if (source_p) 11619 *source_p = NULL; 11620 if (yc_ancestor_p) 11621 *yc_ancestor_p = NULL; 11622 return SVN_NO_ERROR; 11623 } 11624 11625 source.loc1 = loc1; 11626 source.loc2 = source_loc; 11627 11628 /* If the target was moved after the source was branched from it, 11629 it is possible that the left URL differs from the target's current 11630 URL. If so, then adjust TARGET_RA_SESSION to point to the old URL. */ 11631 if (strcmp(source.loc1->url, target->loc.url)) 11632 SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1->url, scratch_pool)); 11633 11634 SVN_ERR(svn_client__get_youngest_common_ancestor( 11635 &yc_ancestor, source.loc2, source.loc1, target_ra_session, 11636 ctx, scratch_pool, scratch_pool)); 11637 11638 if (! yc_ancestor) 11639 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11640 _("'%s@%ld' must be ancestrally related to " 11641 "'%s@%ld'"), 11642 source.loc1->url, source.loc1->rev, 11643 source.loc2->url, source.loc2->rev); 11644 11645 /* The source side of a reintegrate merge is not 'ancestral', except in 11646 * the degenerate case where source == YCA. */ 11647 source.ancestral = (loc1->rev == yc_ancestor->rev); 11648 11649 if (source.loc1->rev > yc_ancestor->rev) 11650 { 11651 /* Have we actually merged anything to the source from the 11652 target? If so, make sure we've merged a contiguous 11653 prefix. */ 11654 svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool); 11655 11656 SVN_ERR(find_unsynced_ranges(source_loc, &target->loc, 11657 unmerged_to_source_mergeinfo_catalog, 11658 merged_to_source_mergeinfo_catalog, 11659 final_unmerged_catalog, 11660 target_ra_session, scratch_pool, 11661 scratch_pool)); 11662 11663 if (apr_hash_count(final_unmerged_catalog)) 11664 { 11665 svn_string_t *source_mergeinfo_cat_string; 11666 11667 SVN_ERR(svn_mergeinfo__catalog_to_formatted_string( 11668 &source_mergeinfo_cat_string, 11669 final_unmerged_catalog, 11670 " ", _(" Missing ranges: "), scratch_pool)); 11671 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, 11672 NULL, 11673 _("Reintegrate can only be used if " 11674 "revisions %ld through %ld were " 11675 "previously merged from %s to the " 11676 "reintegrate source, but this is " 11677 "not the case:\n%s"), 11678 yc_ancestor->rev + 1, source.loc2->rev, 11679 target->loc.url, 11680 source_mergeinfo_cat_string->data); 11681 } 11682 } 11683 11684 /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev 11685 * Right side: branch@specified-peg-revision */ 11686 if (source_p) 11687 *source_p = merge_source_dup(&source, result_pool); 11688 11689 if (yc_ancestor_p) 11690 *yc_ancestor_p = svn_client__pathrev_dup(yc_ancestor, result_pool); 11691 return SVN_NO_ERROR; 11692} 11693 11694/* Resolve the source and target locations and open RA sessions to them, and 11695 * perform some checks appropriate for a reintegrate merge. 11696 * 11697 * Set *SOURCE_RA_SESSION_P and *SOURCE_LOC_P to a new session and the 11698 * repository location of SOURCE_PATH_OR_URL at SOURCE_PEG_REVISION. Set 11699 * *TARGET_RA_SESSION_P and *TARGET_P to a new session and the repository 11700 * location of the WC at TARGET_ABSPATH. 11701 * 11702 * Throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES error if the target WC node is 11703 * a locally added node or if the source and target are not in the same 11704 * repository. Throw a SVN_ERR_CLIENT_NOT_READY_TO_MERGE error if the 11705 * target WC is not at a single revision without switched subtrees and 11706 * without local mods. 11707 * 11708 * Allocate all the outputs in RESULT_POOL. 11709 */ 11710static svn_error_t * 11711open_reintegrate_source_and_target(svn_ra_session_t **source_ra_session_p, 11712 svn_client__pathrev_t **source_loc_p, 11713 svn_ra_session_t **target_ra_session_p, 11714 merge_target_t **target_p, 11715 const char *source_path_or_url, 11716 const svn_opt_revision_t *source_peg_revision, 11717 const char *target_abspath, 11718 svn_client_ctx_t *ctx, 11719 apr_pool_t *result_pool, 11720 apr_pool_t *scratch_pool) 11721{ 11722 svn_client__pathrev_t *source_loc; 11723 merge_target_t *target; 11724 11725 /* Open the target WC. A reintegrate merge requires the merge target to 11726 * reflect a subtree of the repository as found at a single revision. */ 11727 SVN_ERR(open_target_wc(&target, target_abspath, 11728 FALSE, FALSE, FALSE, 11729 ctx, scratch_pool, scratch_pool)); 11730 if (! target->loc.url) 11731 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, 11732 _("Can't reintegrate into '%s' because it is " 11733 "locally added and therefore not related to " 11734 "the merge source"), 11735 svn_dirent_local_style(target->abspath, 11736 scratch_pool)); 11737 11738 SVN_ERR(svn_client_open_ra_session2(target_ra_session_p, 11739 target->loc.url, target->abspath, 11740 ctx, result_pool, scratch_pool)); 11741 11742 SVN_ERR(svn_client__ra_session_from_path2( 11743 source_ra_session_p, &source_loc, 11744 source_path_or_url, NULL, source_peg_revision, source_peg_revision, 11745 ctx, result_pool)); 11746 11747 /* source_loc and target->loc are required to be in the same repository, 11748 as mergeinfo doesn't come into play for cross-repository merging. */ 11749 SVN_ERR(check_same_repos(source_loc, 11750 svn_dirent_local_style(source_path_or_url, 11751 scratch_pool), 11752 &target->loc, 11753 svn_dirent_local_style(target->abspath, 11754 scratch_pool), 11755 TRUE /* strict_urls */, scratch_pool)); 11756 11757 *source_loc_p = source_loc; 11758 *target_p = target; 11759 return SVN_NO_ERROR; 11760} 11761 11762/* The body of svn_client_merge_reintegrate(), which see for details. */ 11763static svn_error_t * 11764merge_reintegrate_locked(svn_client__conflict_report_t **conflict_report, 11765 const char *source_path_or_url, 11766 const svn_opt_revision_t *source_peg_revision, 11767 const char *target_abspath, 11768 svn_boolean_t diff_ignore_ancestry, 11769 svn_boolean_t dry_run, 11770 const apr_array_header_t *merge_options, 11771 svn_client_ctx_t *ctx, 11772 apr_pool_t *result_pool, 11773 apr_pool_t *scratch_pool) 11774{ 11775 svn_ra_session_t *target_ra_session, *source_ra_session; 11776 merge_target_t *target; 11777 svn_client__pathrev_t *source_loc; 11778 merge_source_t *source; 11779 svn_client__pathrev_t *yc_ancestor; 11780 svn_boolean_t use_sleep = FALSE; 11781 svn_error_t *err; 11782 11783 SVN_ERR(open_reintegrate_source_and_target( 11784 &source_ra_session, &source_loc, &target_ra_session, &target, 11785 source_path_or_url, source_peg_revision, target_abspath, 11786 ctx, scratch_pool, scratch_pool)); 11787 11788 SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor, 11789 source_ra_session, source_loc, 11790 target_ra_session, target, 11791 ctx, scratch_pool, scratch_pool)); 11792 11793 if (! source) 11794 { 11795 *conflict_report = NULL; 11796 return SVN_NO_ERROR; 11797 } 11798 11799 /* Do the real merge! */ 11800 /* ### TODO(reint): Make sure that one isn't the same line ancestor 11801 ### of the other (what's erroneously referred to as "ancestrally 11802 ### related" in this source file). For now, we just say the source 11803 ### isn't "ancestral" even if it is (in the degenerate case where 11804 ### source-left equals YCA). */ 11805 source->ancestral = FALSE; 11806 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 11807 &use_sleep, 11808 target, 11809 target_ra_session, 11810 source_ra_session, 11811 source, yc_ancestor, 11812 TRUE /* same_repos */, 11813 svn_depth_infinity, 11814 diff_ignore_ancestry, 11815 FALSE /* force_delete */, 11816 FALSE /* record_only */, 11817 dry_run, 11818 merge_options, 11819 ctx, 11820 result_pool, scratch_pool); 11821 11822 if (use_sleep) 11823 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 11824 11825 SVN_ERR(err); 11826 return SVN_NO_ERROR; 11827} 11828 11829svn_error_t * 11830svn_client_merge_reintegrate(const char *source_path_or_url, 11831 const svn_opt_revision_t *source_peg_revision, 11832 const char *target_wcpath, 11833 svn_boolean_t dry_run, 11834 const apr_array_header_t *merge_options, 11835 svn_client_ctx_t *ctx, 11836 apr_pool_t *pool) 11837{ 11838 const char *target_abspath, *lock_abspath; 11839 svn_client__conflict_report_t *conflict_report; 11840 11841 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 11842 target_wcpath, ctx, pool)); 11843 11844 if (!dry_run) 11845 SVN_WC__CALL_WITH_WRITE_LOCK( 11846 merge_reintegrate_locked(&conflict_report, 11847 source_path_or_url, source_peg_revision, 11848 target_abspath, 11849 FALSE /*diff_ignore_ancestry*/, 11850 dry_run, merge_options, ctx, pool, pool), 11851 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 11852 else 11853 SVN_ERR(merge_reintegrate_locked(&conflict_report, 11854 source_path_or_url, source_peg_revision, 11855 target_abspath, 11856 FALSE /*diff_ignore_ancestry*/, 11857 dry_run, merge_options, ctx, pool, pool)); 11858 11859 SVN_ERR(svn_client__make_merge_conflict_error(conflict_report, pool)); 11860 return SVN_NO_ERROR; 11861} 11862 11863 11864/* The body of svn_client_merge_peg5(), which see for details. 11865 * 11866 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge(). 11867 */ 11868static svn_error_t * 11869merge_peg_locked(svn_client__conflict_report_t **conflict_report, 11870 const char *source_path_or_url, 11871 const svn_opt_revision_t *source_peg_revision, 11872 const svn_rangelist_t *ranges_to_merge, 11873 const char *target_abspath, 11874 svn_depth_t depth, 11875 svn_boolean_t ignore_mergeinfo, 11876 svn_boolean_t diff_ignore_ancestry, 11877 svn_boolean_t force_delete, 11878 svn_boolean_t record_only, 11879 svn_boolean_t dry_run, 11880 svn_boolean_t allow_mixed_rev, 11881 const apr_array_header_t *merge_options, 11882 svn_client_ctx_t *ctx, 11883 apr_pool_t *result_pool, 11884 apr_pool_t *scratch_pool) 11885{ 11886 merge_target_t *target; 11887 svn_client__pathrev_t *source_loc; 11888 apr_array_header_t *merge_sources; 11889 svn_ra_session_t *ra_session; 11890 apr_pool_t *sesspool; 11891 svn_boolean_t use_sleep = FALSE; 11892 svn_error_t *err; 11893 svn_boolean_t same_repos; 11894 11895 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath)); 11896 11897 SVN_ERR(open_target_wc(&target, target_abspath, 11898 allow_mixed_rev, TRUE, TRUE, 11899 ctx, scratch_pool, scratch_pool)); 11900 11901 /* Create a short lived session pool */ 11902 sesspool = svn_pool_create(scratch_pool); 11903 11904 /* Open an RA session to our source URL, and determine its root URL. */ 11905 SVN_ERR(svn_client__ra_session_from_path2( 11906 &ra_session, &source_loc, 11907 source_path_or_url, NULL, source_peg_revision, source_peg_revision, 11908 ctx, sesspool)); 11909 11910 /* Normalize our merge sources. */ 11911 SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url, 11912 source_loc, 11913 ranges_to_merge, ra_session, ctx, 11914 scratch_pool, scratch_pool)); 11915 11916 /* Check for same_repos. */ 11917 same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */); 11918 11919 /* Do the real merge! (We say with confidence that our merge 11920 sources are both ancestral and related.) */ 11921 if (getenv("SVN_ELEMENT_MERGE") 11922 && same_repos 11923 && (depth == svn_depth_infinity || depth == svn_depth_unknown) 11924 && ignore_mergeinfo 11925 && !record_only) 11926 { 11927 err = svn_client__merge_elements(&use_sleep, 11928 merge_sources, target, ra_session, 11929 diff_ignore_ancestry, force_delete, 11930 dry_run, merge_options, 11931 ctx, result_pool, scratch_pool); 11932 /* ### Currently this merge just errors out on any conflicts */ 11933 *conflict_report = NULL; 11934 } 11935 else 11936 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 11937 merge_sources, target, ra_session, 11938 TRUE /*sources_related*/, same_repos, ignore_mergeinfo, 11939 diff_ignore_ancestry, force_delete, dry_run, 11940 record_only, NULL, FALSE, FALSE, depth, merge_options, 11941 ctx, result_pool, scratch_pool); 11942 11943 /* We're done with our RA session. */ 11944 svn_pool_destroy(sesspool); 11945 11946 if (use_sleep) 11947 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 11948 11949 SVN_ERR(err); 11950 return SVN_NO_ERROR; 11951} 11952 11953/* Details of an automatic merge. */ 11954typedef struct automatic_merge_t 11955{ 11956 svn_client__pathrev_t *yca, *base, *right, *target; 11957 svn_boolean_t is_reintegrate_like; 11958 svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees; 11959} automatic_merge_t; 11960 11961static svn_error_t * 11962client_find_automatic_merge(automatic_merge_t **merge_p, 11963 const char *source_path_or_url, 11964 const svn_opt_revision_t *source_revision, 11965 const char *target_abspath, 11966 svn_boolean_t allow_mixed_rev, 11967 svn_boolean_t allow_local_mods, 11968 svn_boolean_t allow_switched_subtrees, 11969 svn_client_ctx_t *ctx, 11970 apr_pool_t *result_pool, 11971 apr_pool_t *scratch_pool); 11972 11973static svn_error_t * 11974do_automatic_merge_locked(svn_client__conflict_report_t **conflict_report, 11975 const automatic_merge_t *merge, 11976 const char *target_abspath, 11977 svn_depth_t depth, 11978 svn_boolean_t diff_ignore_ancestry, 11979 svn_boolean_t force_delete, 11980 svn_boolean_t record_only, 11981 svn_boolean_t dry_run, 11982 const apr_array_header_t *merge_options, 11983 svn_client_ctx_t *ctx, 11984 apr_pool_t *result_pool, 11985 apr_pool_t *scratch_pool); 11986 11987svn_error_t * 11988svn_client_merge_peg5(const char *source_path_or_url, 11989 const apr_array_header_t *ranges_to_merge, 11990 const svn_opt_revision_t *source_peg_revision, 11991 const char *target_wcpath, 11992 svn_depth_t depth, 11993 svn_boolean_t ignore_mergeinfo, 11994 svn_boolean_t diff_ignore_ancestry, 11995 svn_boolean_t force_delete, 11996 svn_boolean_t record_only, 11997 svn_boolean_t dry_run, 11998 svn_boolean_t allow_mixed_rev, 11999 const apr_array_header_t *merge_options, 12000 svn_client_ctx_t *ctx, 12001 apr_pool_t *pool) 12002{ 12003 const char *target_abspath, *lock_abspath; 12004 svn_client__conflict_report_t *conflict_report; 12005 12006 /* No ranges to merge? No problem. */ 12007 if (ranges_to_merge != NULL && ranges_to_merge->nelts == 0) 12008 return SVN_NO_ERROR; 12009 12010 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 12011 target_wcpath, ctx, pool)); 12012 12013 /* Do an automatic merge if no revision ranges are specified. */ 12014 if (ranges_to_merge == NULL) 12015 { 12016 automatic_merge_t *merge; 12017 12018 if (ignore_mergeinfo) 12019 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12020 _("Cannot merge automatically while " 12021 "ignoring mergeinfo")); 12022 12023 /* Find the details of the merge needed. */ 12024 SVN_ERR(client_find_automatic_merge( 12025 &merge, 12026 source_path_or_url, source_peg_revision, 12027 target_abspath, 12028 allow_mixed_rev, 12029 TRUE /*allow_local_mods*/, 12030 TRUE /*allow_switched_subtrees*/, 12031 ctx, pool, pool)); 12032 12033 if (!dry_run) 12034 SVN_WC__CALL_WITH_WRITE_LOCK( 12035 do_automatic_merge_locked(&conflict_report, 12036 merge, 12037 target_abspath, depth, 12038 diff_ignore_ancestry, 12039 force_delete, record_only, dry_run, 12040 merge_options, ctx, pool, pool), 12041 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 12042 else 12043 SVN_ERR(do_automatic_merge_locked(&conflict_report, 12044 merge, 12045 target_abspath, depth, 12046 diff_ignore_ancestry, 12047 force_delete, record_only, dry_run, 12048 merge_options, ctx, pool, pool)); 12049 } 12050 else if (!dry_run) 12051 SVN_WC__CALL_WITH_WRITE_LOCK( 12052 merge_peg_locked(&conflict_report, 12053 source_path_or_url, source_peg_revision, 12054 ranges_to_merge, 12055 target_abspath, depth, ignore_mergeinfo, 12056 diff_ignore_ancestry, 12057 force_delete, record_only, dry_run, 12058 allow_mixed_rev, merge_options, ctx, pool, pool), 12059 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 12060 else 12061 SVN_ERR(merge_peg_locked(&conflict_report, 12062 source_path_or_url, source_peg_revision, 12063 ranges_to_merge, 12064 target_abspath, depth, ignore_mergeinfo, 12065 diff_ignore_ancestry, 12066 force_delete, record_only, dry_run, 12067 allow_mixed_rev, merge_options, ctx, pool, pool)); 12068 12069 SVN_ERR(svn_client__make_merge_conflict_error(conflict_report, pool)); 12070 return SVN_NO_ERROR; 12071} 12072 12073 12074/* The location-history of a branch. 12075 * 12076 * This structure holds the set of path-revisions occupied by a branch, 12077 * from an externally chosen 'tip' location back to its origin. The 12078 * 'tip' location is the youngest location that we are considering on 12079 * the branch. */ 12080typedef struct branch_history_t 12081{ 12082 /* The tip location of the branch. That is, the youngest location that's 12083 * in the repository and that we're considering. If we're considering a 12084 * target branch right up to an uncommitted WC, then this is the WC base 12085 * (pristine) location. */ 12086 svn_client__pathrev_t *tip; 12087 /* The location-segment history, as mergeinfo. */ 12088 svn_mergeinfo_t history; 12089 /* Whether the location-segment history reached as far as (necessarily 12090 the root path in) revision 0 -- a fact that can't be represented as 12091 mergeinfo. */ 12092 svn_boolean_t has_r0_history; 12093} branch_history_t; 12094 12095/* Return the location on BRANCH_HISTORY at revision REV, or NULL if none. */ 12096static svn_client__pathrev_t * 12097location_on_branch_at_rev(const branch_history_t *branch_history, 12098 svn_revnum_t rev, 12099 apr_pool_t *result_pool, 12100 apr_pool_t *scratch_pool) 12101{ 12102 apr_hash_index_t *hi; 12103 12104 for (hi = apr_hash_first(scratch_pool, branch_history->history); hi; 12105 hi = apr_hash_next(hi)) 12106 { 12107 const char *fspath = apr_hash_this_key(hi); 12108 svn_rangelist_t *rangelist = apr_hash_this_val(hi); 12109 int i; 12110 12111 for (i = 0; i < rangelist->nelts; i++) 12112 { 12113 svn_merge_range_t *r = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 12114 if (r->start < rev && rev <= r->end) 12115 { 12116 return svn_client__pathrev_create_with_relpath( 12117 branch_history->tip->repos_root_url, 12118 branch_history->tip->repos_uuid, 12119 rev, fspath + 1, result_pool); 12120 } 12121 } 12122 } 12123 return NULL; 12124} 12125 12126/* */ 12127typedef struct source_and_target_t 12128{ 12129 svn_client__pathrev_t *source; 12130 svn_ra_session_t *source_ra_session; 12131 branch_history_t source_branch; 12132 12133 merge_target_t *target; 12134 svn_ra_session_t *target_ra_session; 12135 branch_history_t target_branch; 12136 12137 /* Repos location of the youngest common ancestor of SOURCE and TARGET. */ 12138 svn_client__pathrev_t *yca; 12139} source_and_target_t; 12140 12141/* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the 12142 * revision range OLDEST_REV to YOUNGEST_REV (inclusive). 12143 * 12144 * If the intersection is empty, the result will be a branch history object 12145 * containing an empty (not null) history. 12146 * 12147 * ### The 'tip' of the result is currently unchanged. 12148 */ 12149static svn_error_t * 12150branch_history_intersect_range(branch_history_t **intersection_p, 12151 const branch_history_t *branch_history, 12152 svn_revnum_t oldest_rev, 12153 svn_revnum_t youngest_rev, 12154 apr_pool_t *result_pool, 12155 apr_pool_t *scratch_pool) 12156{ 12157 branch_history_t *result = apr_palloc(result_pool, sizeof(*result)); 12158 12159 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev)); 12160 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev)); 12161 SVN_ERR_ASSERT(oldest_rev >= 1); 12162 /* Allow a just-empty range (oldest = youngest + 1) but not an 12163 * arbitrary reverse range (such as oldest = youngest + 2). */ 12164 SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1); 12165 12166 if (oldest_rev <= youngest_rev) 12167 { 12168 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( 12169 &result->history, branch_history->history, 12170 youngest_rev, oldest_rev - 1, TRUE /* include_range */, 12171 result_pool, scratch_pool)); 12172 result->history = svn_mergeinfo_dup(result->history, result_pool); 12173 } 12174 else 12175 { 12176 result->history = apr_hash_make(result_pool); 12177 } 12178 result->has_r0_history = FALSE; 12179 12180 /* ### TODO: Set RESULT->tip to the tip of the intersection. */ 12181 result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool); 12182 12183 *intersection_p = result; 12184 return SVN_NO_ERROR; 12185} 12186 12187/* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations 12188 * (inclusive) along BRANCH. OLDEST_P and/or YOUNGEST_P may be NULL if not 12189 * wanted. 12190 */ 12191static svn_error_t * 12192branch_history_get_endpoints(svn_client__pathrev_t **oldest_p, 12193 svn_client__pathrev_t **youngest_p, 12194 const branch_history_t *branch, 12195 apr_pool_t *result_pool, 12196 apr_pool_t *scratch_pool) 12197{ 12198 svn_revnum_t youngest_rev, oldest_rev; 12199 12200 SVN_ERR(svn_mergeinfo__get_range_endpoints( 12201 &youngest_rev, &oldest_rev, 12202 branch->history, scratch_pool)); 12203 if (oldest_p) 12204 *oldest_p = location_on_branch_at_rev( 12205 branch, oldest_rev + 1, result_pool, scratch_pool); 12206 if (youngest_p) 12207 *youngest_p = location_on_branch_at_rev( 12208 branch, youngest_rev, result_pool, scratch_pool); 12209 return SVN_NO_ERROR; 12210} 12211 12212/* Implements the svn_log_entry_receiver_t interface. 12213 12214 Set *BATON to LOG_ENTRY->revision and return SVN_ERR_CEASE_INVOCATION. */ 12215static svn_error_t * 12216operative_rev_receiver(void *baton, 12217 svn_log_entry_t *log_entry, 12218 apr_pool_t *pool) 12219{ 12220 svn_revnum_t *operative_rev = baton; 12221 12222 *operative_rev = log_entry->revision; 12223 12224 /* We've found the youngest merged or oldest eligible revision, so 12225 we're done... 12226 12227 ...but wait, shouldn't we care if LOG_ENTRY->NON_INHERITABLE is 12228 true? Because if it is, then LOG_ENTRY->REVISION is only 12229 partially merged/elgibile! And our only caller, 12230 find_last_merged_location (via short_circuit_mergeinfo_log) is 12231 interested in *fully* merged revisions. That's all true, but if 12232 find_last_merged_location() finds the youngest merged revision it 12233 will also check for the oldest eligible revision. So in the case 12234 the youngest merged rev is non-inheritable, the *same* non-inheritable 12235 rev will be found as the oldest eligible rev -- and 12236 find_last_merged_location() handles that situation. */ 12237 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL); 12238} 12239 12240/* Wrapper around svn_client__mergeinfo_log. All arguments are as per 12241 that private API. The discover_changed_paths, depth, and revprops args to 12242 svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t, 12243 and empty array respectively. 12244 12245 If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets 12246 *REVISION to a valid revnum, then clear the error. Otherwise return 12247 any error. */ 12248static svn_error_t* 12249short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat, 12250 svn_boolean_t finding_merged, 12251 const char *target_path_or_url, 12252 const svn_opt_revision_t *target_peg_revision, 12253 const char *source_path_or_url, 12254 const svn_opt_revision_t *source_peg_revision, 12255 const svn_opt_revision_t *source_start_revision, 12256 const svn_opt_revision_t *source_end_revision, 12257 svn_log_entry_receiver_t receiver, 12258 svn_revnum_t *revision, 12259 svn_client_ctx_t *ctx, 12260 svn_ra_session_t *ra_session, 12261 apr_pool_t *result_pool, 12262 apr_pool_t *scratch_pool) 12263{ 12264 apr_array_header_t *revprops; 12265 svn_error_t *err; 12266 const char *session_url; 12267 12268 SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool)); 12269 12270 revprops = apr_array_make(scratch_pool, 0, sizeof(const char *)); 12271 err = svn_client__mergeinfo_log(finding_merged, 12272 target_path_or_url, 12273 target_peg_revision, 12274 target_mergeinfo_cat, 12275 source_path_or_url, 12276 source_peg_revision, 12277 source_start_revision, 12278 source_end_revision, 12279 receiver, revision, 12280 TRUE, svn_depth_infinity, 12281 revprops, ctx, ra_session, 12282 result_pool, scratch_pool); 12283 12284 err = svn_error_compose_create( 12285 err, 12286 svn_ra_reparent(ra_session, session_url, scratch_pool)); 12287 12288 if (err) 12289 { 12290 /* We expect RECEIVER to short-circuit the (potentially expensive) log 12291 by raising an SVN_ERR_CEASE_INVOCATION -- see operative_rev_receiver. 12292 So we can ignore that error, but only as long as we actually found a 12293 valid revision. */ 12294 if (SVN_IS_VALID_REVNUM(*revision) 12295 && err->apr_err == SVN_ERR_CEASE_INVOCATION) 12296 { 12297 svn_error_clear(err); 12298 err = NULL; 12299 } 12300 else 12301 { 12302 return svn_error_trace(err); 12303 } 12304 } 12305 return SVN_NO_ERROR; 12306} 12307 12308/* Set *BASE_P to the last location on SOURCE_BRANCH such that all changes 12309 * on SOURCE_BRANCH after YCA up to and including *BASE_P have already 12310 * been fully merged into TARGET. 12311 * 12312 * *BASE_P TIP 12313 * o-------o-----------o--- SOURCE_BRANCH 12314 * / \ 12315 * -----o prev. \ 12316 * YCA \ merges \ 12317 * o-----------o----------- TARGET branch 12318 * 12319 * In terms of mergeinfo: 12320 * 12321 * Source a--... o=change, -=no-op revision 12322 * branch / \ 12323 * YCA --> o a---o---o---o---o--- d=delete, a=add-as-a-copy 12324 * 12325 * Eligible -.eee.eeeeeeeeeeeeeeeeeeee .=not a source branch location 12326 * 12327 * Tgt-mi -.mmm.mm-mm-------m------- m=merged to root of TARGET or 12328 * subtree of TARGET with no 12329 * operative changes outside of that 12330 * subtree, -=not merged 12331 * 12332 * Eligible -.---.--e--eeeeeee-eeeeeee 12333 * 12334 * Next --------^----------------- BASE is just before here. 12335 * 12336 * / \ 12337 * -----o prev. \ 12338 * YCA \ merges \ 12339 * o-----------o------------- 12340 * 12341 * If no revisions from SOURCE_BRANCH have been completely merged to TARGET, 12342 * then set *BASE_P to the YCA. 12343 */ 12344static svn_error_t * 12345find_last_merged_location(svn_client__pathrev_t **base_p, 12346 svn_client__pathrev_t *yca, 12347 const branch_history_t *source_branch, 12348 svn_client__pathrev_t *target, 12349 svn_client_ctx_t *ctx, 12350 svn_ra_session_t *ra_session, 12351 apr_pool_t *result_pool, 12352 apr_pool_t *scratch_pool) 12353{ 12354 svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev, 12355 target_opt_rev; 12356 svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM; 12357 svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL; 12358 12359 /* Using a local subpool for 'target_mergeinfo_cat' can make a big 12360 reduction in overall memory usage. */ 12361 apr_pool_t *tmic_pool = svn_pool_create(scratch_pool); 12362 12363 source_peg_rev.kind = svn_opt_revision_number; 12364 source_peg_rev.value.number = source_branch->tip->rev; 12365 source_start_rev.kind = svn_opt_revision_number; 12366 source_start_rev.value.number = yca->rev; 12367 source_end_rev.kind = svn_opt_revision_number; 12368 source_end_rev.value.number = source_branch->tip->rev; 12369 target_opt_rev.kind = svn_opt_revision_number; 12370 target_opt_rev.value.number = target->rev; 12371 12372 /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET, 12373 if such a revision exists. */ 12374 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, 12375 TRUE, /* Find merged */ 12376 target->url, &target_opt_rev, 12377 source_branch->tip->url, 12378 &source_peg_rev, 12379 &source_end_rev, &source_start_rev, 12380 operative_rev_receiver, 12381 &youngest_merged_rev, 12382 ctx, ra_session, 12383 tmic_pool, tmic_pool)); 12384 12385 if (!SVN_IS_VALID_REVNUM(youngest_merged_rev)) 12386 { 12387 /* No revisions have been completely merged from SOURCE_BRANCH to 12388 TARGET so the base for the next merge is the YCA. */ 12389 *base_p = yca; 12390 } 12391 else 12392 { 12393 /* One or more revisions have already been completely merged from 12394 SOURCE_BRANCH to TARGET, now find the oldest revision, older 12395 than the youngest merged revision, which is still eligible to 12396 be merged, if such exists. */ 12397 branch_history_t *contiguous_source; 12398 svn_revnum_t base_rev; 12399 svn_revnum_t oldest_eligible_rev = SVN_INVALID_REVNUM; 12400 12401 /* If the only revisions eligible are younger than the youngest merged 12402 revision we can simply assume that the youngest eligible revision 12403 is the youngest merged revision. Obviously this may not be true! 12404 The revisions between the youngest merged revision and the tip of 12405 the branch may have several inoperative revisions -- they may *all* 12406 be inoperative revisions! But for the purpose of this function 12407 (i.e. finding the youngest revision after the YCA where all revs have 12408 been merged) that doesn't matter. */ 12409 source_end_rev.value.number = youngest_merged_rev; 12410 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, 12411 FALSE, /* Find eligible */ 12412 target->url, &target_opt_rev, 12413 source_branch->tip->url, 12414 &source_peg_rev, 12415 &source_start_rev, &source_end_rev, 12416 operative_rev_receiver, 12417 &oldest_eligible_rev, 12418 ctx, ra_session, 12419 tmic_pool, tmic_pool)); 12420 12421 /* If there are revisions eligible for merging, use the oldest one 12422 to calculate the base. Otherwise there are no operative revisions 12423 to merge and we can simple set the base to the youngest revision 12424 already merged. */ 12425 if (SVN_IS_VALID_REVNUM(oldest_eligible_rev)) 12426 base_rev = oldest_eligible_rev - 1; 12427 else 12428 base_rev = youngest_merged_rev; 12429 12430 /* Find the branch location just before the oldest eligible rev. 12431 (We can't just use the base revs calculated above because the branch 12432 might have a gap there.) */ 12433 SVN_ERR(branch_history_intersect_range(&contiguous_source, 12434 source_branch, yca->rev, 12435 base_rev, 12436 scratch_pool, scratch_pool)); 12437 SVN_ERR(branch_history_get_endpoints(NULL, base_p, contiguous_source, 12438 result_pool, scratch_pool)); 12439 } 12440 12441 svn_pool_destroy(tmic_pool); 12442 return SVN_NO_ERROR; 12443} 12444 12445/* Find a merge base location on the target branch, like in a sync 12446 * merge. 12447 * 12448 * BASE S_T->source 12449 * o-------o-----------o--- 12450 * / \ \ 12451 * -----o prev. \ \ this 12452 * YCA \ merge \ \ merge 12453 * o-----------o-----------o 12454 * S_T->target 12455 * 12456 * Set *BASE_P to BASE, the youngest location in the history of S_T->source 12457 * (at or after the YCA) at which all revisions up to BASE are effectively 12458 * merged into S_T->target. 12459 * 12460 * If no locations on the history of S_T->source are effectively merged to 12461 * S_T->target, set *BASE_P to the YCA. 12462 */ 12463static svn_error_t * 12464find_base_on_source(svn_client__pathrev_t **base_p, 12465 source_and_target_t *s_t, 12466 svn_client_ctx_t *ctx, 12467 apr_pool_t *result_pool, 12468 apr_pool_t *scratch_pool) 12469{ 12470 SVN_ERR(find_last_merged_location(base_p, 12471 s_t->yca, 12472 &s_t->source_branch, 12473 s_t->target_branch.tip, 12474 ctx, 12475 s_t->source_ra_session, 12476 result_pool, scratch_pool)); 12477 return SVN_NO_ERROR; 12478} 12479 12480/* Find a merge base location on the target branch, like in a reintegrate 12481 * merge. 12482 * 12483 * S_T->source 12484 * o-----------o-------o--- 12485 * / prev. / \ 12486 * -----o merge / \ this 12487 * YCA \ / \ merge 12488 * o-------o---------------o 12489 * BASE S_T->target 12490 * 12491 * Set *BASE_P to BASE, the youngest location in the history of S_T->target 12492 * (at or after the YCA) at which all revisions up to BASE are effectively 12493 * merged into S_T->source. 12494 * 12495 * If no locations on the history of S_T->target are effectively merged to 12496 * S_T->source, set *BASE_P to the YCA. 12497 */ 12498static svn_error_t * 12499find_base_on_target(svn_client__pathrev_t **base_p, 12500 source_and_target_t *s_t, 12501 svn_client_ctx_t *ctx, 12502 apr_pool_t *result_pool, 12503 apr_pool_t *scratch_pool) 12504{ 12505 SVN_ERR(find_last_merged_location(base_p, 12506 s_t->yca, 12507 &s_t->target_branch, 12508 s_t->source, 12509 ctx, 12510 s_t->target_ra_session, 12511 result_pool, scratch_pool)); 12512 12513 return SVN_NO_ERROR; 12514} 12515 12516/* Find the last point at which the branch at S_T->source was completely 12517 * merged to the branch at S_T->target or vice-versa. 12518 * 12519 * Fill in S_T->source_branch and S_T->target_branch and S_T->yca. 12520 * Set *BASE_P to the merge base. Set *IS_REINTEGRATE_LIKE to true if 12521 * an automatic merge from source to target would be a reintegration 12522 * merge: that is, if the last automatic merge was in the opposite 12523 * direction; or to false otherwise. 12524 * 12525 * If there is no youngest common ancestor, throw an error. 12526 */ 12527static svn_error_t * 12528find_automatic_merge(svn_client__pathrev_t **base_p, 12529 svn_boolean_t *is_reintegrate_like, 12530 source_and_target_t *s_t, 12531 svn_client_ctx_t *ctx, 12532 apr_pool_t *result_pool, 12533 apr_pool_t *scratch_pool) 12534{ 12535 svn_client__pathrev_t *base_on_source, *base_on_target; 12536 12537 /* Get the location-history of each branch. */ 12538 s_t->source_branch.tip = s_t->source; 12539 SVN_ERR(svn_client__get_history_as_mergeinfo( 12540 &s_t->source_branch.history, &s_t->source_branch.has_r0_history, 12541 s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, 12542 s_t->source_ra_session, ctx, scratch_pool)); 12543 s_t->target_branch.tip = &s_t->target->loc; 12544 SVN_ERR(svn_client__get_history_as_mergeinfo( 12545 &s_t->target_branch.history, &s_t->target_branch.has_r0_history, 12546 &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, 12547 s_t->target_ra_session, ctx, scratch_pool)); 12548 12549 SVN_ERR(svn_client__calc_youngest_common_ancestor( 12550 &s_t->yca, s_t->source, s_t->source_branch.history, 12551 s_t->source_branch.has_r0_history, 12552 &s_t->target->loc, s_t->target_branch.history, 12553 s_t->target_branch.has_r0_history, 12554 result_pool, scratch_pool)); 12555 12556 if (! s_t->yca) 12557 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 12558 _("'%s@%ld' must be ancestrally related to " 12559 "'%s@%ld'"), 12560 s_t->source->url, s_t->source->rev, 12561 s_t->target->loc.url, s_t->target->loc.rev); 12562 12563 /* Find the latest revision of A synced to B and the latest 12564 * revision of B synced to A. 12565 * 12566 * base_on_source = youngest_complete_synced_point(source, target) 12567 * base_on_target = youngest_complete_synced_point(target, source) 12568 */ 12569 SVN_ERR(find_base_on_source(&base_on_source, s_t, 12570 ctx, scratch_pool, scratch_pool)); 12571 SVN_ERR(find_base_on_target(&base_on_target, s_t, 12572 ctx, scratch_pool, scratch_pool)); 12573 12574 /* Choose a base. */ 12575 if (base_on_source->rev >= base_on_target->rev) 12576 { 12577 *base_p = base_on_source; 12578 *is_reintegrate_like = FALSE; 12579 } 12580 else 12581 { 12582 *base_p = base_on_target; 12583 *is_reintegrate_like = TRUE; 12584 } 12585 12586 return SVN_NO_ERROR; 12587} 12588 12589/** Find out what kind of automatic merge would be needed, when the target 12590 * is only known as a repository location rather than a WC. 12591 * 12592 * Like find_automatic_merge() except that the target is 12593 * specified by @a target_path_or_url at @a target_revision, which must 12594 * refer to a repository location, instead of by a WC path argument. 12595 * 12596 * Set *MERGE_P to a new structure with all fields filled in except the 12597 * 'allow_*' flags. 12598 */ 12599static svn_error_t * 12600find_automatic_merge_no_wc(automatic_merge_t **merge_p, 12601 const char *source_path_or_url, 12602 const svn_opt_revision_t *source_revision, 12603 const char *target_path_or_url, 12604 const svn_opt_revision_t *target_revision, 12605 svn_client_ctx_t *ctx, 12606 apr_pool_t *result_pool, 12607 apr_pool_t *scratch_pool) 12608{ 12609 source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t)); 12610 svn_client__pathrev_t *target_loc; 12611 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge)); 12612 12613 /* Source */ 12614 SVN_ERR(svn_client__ra_session_from_path2( 12615 &s_t->source_ra_session, &s_t->source, 12616 source_path_or_url, NULL, source_revision, source_revision, 12617 ctx, result_pool)); 12618 12619 /* Target */ 12620 SVN_ERR(svn_client__ra_session_from_path2( 12621 &s_t->target_ra_session, &target_loc, 12622 target_path_or_url, NULL, target_revision, target_revision, 12623 ctx, result_pool)); 12624 s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target)); 12625 s_t->target->abspath = NULL; /* indicate the target is not a WC */ 12626 s_t->target->loc = *target_loc; 12627 12628 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t, 12629 ctx, result_pool, scratch_pool)); 12630 12631 merge->right = s_t->source; 12632 merge->target = &s_t->target->loc; 12633 merge->yca = s_t->yca; 12634 *merge_p = merge; 12635 12636 return SVN_NO_ERROR; 12637} 12638 12639/* Find the information needed to merge all unmerged changes from a source 12640 * branch into a target branch. 12641 * 12642 * Set @a *merge_p to the information needed to merge all unmerged changes 12643 * (up to @a source_revision) from the source branch @a source_path_or_url 12644 * at @a source_revision into the target WC at @a target_abspath. 12645 * 12646 * The flags @a allow_mixed_rev, @a allow_local_mods and 12647 * @a allow_switched_subtrees enable merging into a WC that is in any or all 12648 * of the states described by their names, but only if this function decides 12649 * that the merge will be in the same direction as the last automatic merge. 12650 * If, on the other hand, the last automatic merge was in the opposite 12651 * direction, then such states of the WC are not allowed regardless 12652 * of these flags. This function merely records these flags in the 12653 * @a *merge_p structure; do_automatic_merge_locked() checks the WC 12654 * state for compliance. 12655 * 12656 * Allocate the @a *merge_p structure in @a result_pool. 12657 */ 12658static svn_error_t * 12659client_find_automatic_merge(automatic_merge_t **merge_p, 12660 const char *source_path_or_url, 12661 const svn_opt_revision_t *source_revision, 12662 const char *target_abspath, 12663 svn_boolean_t allow_mixed_rev, 12664 svn_boolean_t allow_local_mods, 12665 svn_boolean_t allow_switched_subtrees, 12666 svn_client_ctx_t *ctx, 12667 apr_pool_t *result_pool, 12668 apr_pool_t *scratch_pool) 12669{ 12670 source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t)); 12671 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge)); 12672 12673 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath)); 12674 12675 /* "Open" the target WC. Check the target WC for mixed-rev, local mods and 12676 * switched subtrees yet to faster exit and notify user before contacting 12677 * with server. After we find out what kind of merge is required, then if a 12678 * reintegrate-like merge is required we'll do the stricter checks, in 12679 * do_automatic_merge_locked(). */ 12680 SVN_ERR(open_target_wc(&s_t->target, target_abspath, 12681 allow_mixed_rev, 12682 allow_local_mods, 12683 allow_switched_subtrees, 12684 ctx, result_pool, scratch_pool)); 12685 12686 if (!s_t->target->loc.url) 12687 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, 12688 _("Can't perform automatic merge into '%s' " 12689 "because it is locally added and therefore " 12690 "not related to the merge source"), 12691 svn_dirent_local_style(target_abspath, 12692 scratch_pool)); 12693 12694 /* Open RA sessions to the source and target trees. */ 12695 SVN_ERR(svn_client_open_ra_session2(&s_t->target_ra_session, 12696 s_t->target->loc.url, 12697 s_t->target->abspath, 12698 ctx, result_pool, scratch_pool)); 12699 SVN_ERR(svn_client__ra_session_from_path2( 12700 &s_t->source_ra_session, &s_t->source, 12701 source_path_or_url, NULL, source_revision, source_revision, 12702 ctx, result_pool)); 12703 12704 /* Check source is in same repos as target. */ 12705 SVN_ERR(check_same_repos(s_t->source, source_path_or_url, 12706 &s_t->target->loc, target_abspath, 12707 TRUE /* strict_urls */, scratch_pool)); 12708 12709 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t, 12710 ctx, result_pool, scratch_pool)); 12711 merge->yca = s_t->yca; 12712 merge->right = s_t->source; 12713 merge->target = &s_t->target->loc; 12714 merge->allow_mixed_rev = allow_mixed_rev; 12715 merge->allow_local_mods = allow_local_mods; 12716 merge->allow_switched_subtrees = allow_switched_subtrees; 12717 12718 *merge_p = merge; 12719 12720 /* TODO: Close the source and target sessions here? */ 12721 12722 return SVN_NO_ERROR; 12723} 12724 12725/* Perform an automatic merge, given the information in MERGE which 12726 * must have come from calling client_find_automatic_merge(). 12727 * 12728 * Four locations are inputs: YCA, BASE, RIGHT, TARGET, as shown 12729 * depending on whether the base is on the source branch or the target 12730 * branch of this merge. 12731 * 12732 * RIGHT (is_reintegrate_like) 12733 * o-----------o-------o--- 12734 * / prev. / \ 12735 * -----o merge / \ this 12736 * YCA \ / \ merge 12737 * o-------o---------------o 12738 * BASE TARGET 12739 * 12740 * or 12741 * 12742 * BASE RIGHT (! is_reintegrate_like) 12743 * o-------o-----------o--- 12744 * / \ \ 12745 * -----o prev. \ \ this 12746 * YCA \ merge \ \ merge 12747 * o-----------o-----------o 12748 * TARGET 12749 * 12750 * ### TODO: The reintegrate-like code path does not yet 12751 * eliminate already-cherry-picked revisions from the source. 12752 */ 12753static svn_error_t * 12754do_automatic_merge_locked(svn_client__conflict_report_t **conflict_report, 12755 const automatic_merge_t *merge, 12756 const char *target_abspath, 12757 svn_depth_t depth, 12758 svn_boolean_t diff_ignore_ancestry, 12759 svn_boolean_t force_delete, 12760 svn_boolean_t record_only, 12761 svn_boolean_t dry_run, 12762 const apr_array_header_t *merge_options, 12763 svn_client_ctx_t *ctx, 12764 apr_pool_t *result_pool, 12765 apr_pool_t *scratch_pool) 12766{ 12767 merge_target_t *target; 12768 svn_boolean_t reintegrate_like = merge->is_reintegrate_like; 12769 svn_boolean_t use_sleep = FALSE; 12770 svn_error_t *err; 12771 12772 SVN_ERR(open_target_wc(&target, target_abspath, 12773 merge->allow_mixed_rev && ! reintegrate_like, 12774 merge->allow_local_mods && ! reintegrate_like, 12775 merge->allow_switched_subtrees && ! reintegrate_like, 12776 ctx, scratch_pool, scratch_pool)); 12777 12778 if (reintegrate_like) 12779 { 12780 merge_source_t source; 12781 svn_ra_session_t *base_ra_session = NULL; 12782 svn_ra_session_t *right_ra_session = NULL; 12783 svn_ra_session_t *target_ra_session = NULL; 12784 12785 if (record_only) 12786 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12787 _("The required merge is reintegrate-like, " 12788 "and the record-only option " 12789 "cannot be used with this kind of merge")); 12790 12791 if (depth != svn_depth_unknown) 12792 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12793 _("The required merge is reintegrate-like, " 12794 "and the depth option " 12795 "cannot be used with this kind of merge")); 12796 12797 if (force_delete) 12798 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12799 _("The required merge is reintegrate-like, " 12800 "and the force_delete option " 12801 "cannot be used with this kind of merge")); 12802 12803 SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url, 12804 target->abspath, ctx, scratch_pool)); 12805 SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url, 12806 target->abspath, ctx, scratch_pool)); 12807 SVN_ERR(ensure_ra_session_url(&target_ra_session, target->loc.url, 12808 target->abspath, ctx, scratch_pool)); 12809 12810 /* Check for and reject any abnormalities -- such as revisions that 12811 * have not yet been merged in the opposite direction -- that a 12812 * 'reintegrate' merge would have rejected. */ 12813 { 12814 merge_source_t *source2; 12815 12816 SVN_ERR(find_reintegrate_merge(&source2, NULL, 12817 right_ra_session, merge->right, 12818 target_ra_session, target, 12819 ctx, scratch_pool, scratch_pool)); 12820 } 12821 12822 source.loc1 = merge->base; 12823 source.loc2 = merge->right; 12824 source.ancestral = ! merge->is_reintegrate_like; 12825 12826 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 12827 &use_sleep, 12828 target, 12829 base_ra_session, 12830 right_ra_session, 12831 &source, merge->yca, 12832 TRUE /* same_repos */, 12833 depth, 12834 FALSE /*diff_ignore_ancestry*/, 12835 force_delete, record_only, 12836 dry_run, 12837 merge_options, 12838 ctx, 12839 result_pool, scratch_pool); 12840 } 12841 else /* ! merge->is_reintegrate_like */ 12842 { 12843 /* Ignoring the base that we found, we pass the YCA instead and let 12844 do_merge() work out which subtrees need which revision ranges to 12845 be merged. This enables do_merge() to fill in revision-range 12846 gaps that are older than the base that we calculated (which is 12847 for the root path of the merge). 12848 12849 An improvement would be to change find_automatic_merge() to 12850 find the base for each sutree, and then here use the oldest base 12851 among all subtrees. */ 12852 apr_array_header_t *merge_sources; 12853 svn_ra_session_t *ra_session = NULL; 12854 12855 /* Normalize our merge sources, do_merge() requires this. See the 12856 'MERGEINFO MERGE SOURCE NORMALIZATION' global comment. */ 12857 SVN_ERR(ensure_ra_session_url(&ra_session, merge->right->url, 12858 target->abspath, ctx, scratch_pool)); 12859 SVN_ERR(normalize_merge_sources_internal( 12860 &merge_sources, merge->right, 12861 svn_rangelist__initialize(merge->yca->rev, merge->right->rev, TRUE, 12862 scratch_pool), 12863 ra_session, ctx, scratch_pool, scratch_pool)); 12864 12865 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 12866 merge_sources, target, ra_session, 12867 TRUE /*related*/, TRUE /*same_repos*/, 12868 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 12869 force_delete, dry_run, 12870 record_only, NULL, FALSE, FALSE, depth, merge_options, 12871 ctx, result_pool, scratch_pool); 12872 } 12873 12874 if (use_sleep) 12875 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 12876 12877 SVN_ERR(err); 12878 12879 return SVN_NO_ERROR; 12880} 12881 12882svn_error_t * 12883svn_client_get_merging_summary(svn_boolean_t *needs_reintegration, 12884 const char **yca_url, svn_revnum_t *yca_rev, 12885 const char **base_url, svn_revnum_t *base_rev, 12886 const char **right_url, svn_revnum_t *right_rev, 12887 const char **target_url, svn_revnum_t *target_rev, 12888 const char **repos_root_url, 12889 const char *source_path_or_url, 12890 const svn_opt_revision_t *source_revision, 12891 const char *target_path_or_url, 12892 const svn_opt_revision_t *target_revision, 12893 svn_client_ctx_t *ctx, 12894 apr_pool_t *result_pool, 12895 apr_pool_t *scratch_pool) 12896{ 12897 svn_boolean_t target_is_wc; 12898 automatic_merge_t *merge; 12899 12900 target_is_wc = (! svn_path_is_url(target_path_or_url)) 12901 && (target_revision->kind == svn_opt_revision_unspecified 12902 || target_revision->kind == svn_opt_revision_working 12903 || target_revision->kind == svn_opt_revision_base); 12904 if (target_is_wc) 12905 { 12906 const char *target_abspath; 12907 12908 SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_path_or_url, 12909 scratch_pool)); 12910 SVN_ERR(client_find_automatic_merge( 12911 &merge, 12912 source_path_or_url, source_revision, 12913 target_abspath, 12914 TRUE, TRUE, TRUE, /* allow_* */ 12915 ctx, scratch_pool, scratch_pool)); 12916 } 12917 else 12918 SVN_ERR(find_automatic_merge_no_wc( 12919 &merge, 12920 source_path_or_url, source_revision, 12921 target_path_or_url, target_revision, 12922 ctx, scratch_pool, scratch_pool)); 12923 12924 if (needs_reintegration) 12925 *needs_reintegration = merge->is_reintegrate_like; 12926 if (yca_url) 12927 *yca_url = apr_pstrdup(result_pool, merge->yca->url); 12928 if (yca_rev) 12929 *yca_rev = merge->yca->rev; 12930 if (base_url) 12931 *base_url = apr_pstrdup(result_pool, merge->base->url); 12932 if (base_rev) 12933 *base_rev = merge->base->rev; 12934 if (right_url) 12935 *right_url = apr_pstrdup(result_pool, merge->right->url); 12936 if (right_rev) 12937 *right_rev = merge->right->rev; 12938 if (target_url) 12939 *target_url = apr_pstrdup(result_pool, merge->target->url); 12940 if (target_rev) 12941 *target_rev = merge->target->rev; 12942 if (repos_root_url) 12943 *repos_root_url = apr_pstrdup(result_pool, merge->yca->repos_root_url); 12944 12945 return SVN_NO_ERROR; 12946} 12947