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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* ==================================================================== */
31 #include <apr_strings.h>
32 #include <apr_tables.h>
34 #include "svn_types.h"
37 #include "svn_delta.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"
47 #include "svn_pools.h"
48 #include "svn_config.h"
49 #include "svn_props.h"
51 #include "svn_sorts.h"
52 #include "svn_subst.h"
55 #include "mergeinfo.h"
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"
64 #include "svn_private_config.h"
67 /*-----------------------------------------------------------------------*/
69 /* MERGEINFO MERGE SOURCE NORMALIZATION
71 * Nearly any helper function herein that accepts two URL/revision
72 * pairs (or equivalent struct merge_source_t) expects one of two things
75 * 1. that mergeinfo is not being recorded at all for this
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.
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):
92 * A /branches/1.4.x (from /trunk:859597)
95 * A /tags/1.4.4 (from /branches/1.4.x:865262)
96 * # Notice that this copy leaves a gap between 865262 and 865417.
99 * A /branches/1.4.5 (from /tags/1.4.4:866419)
103 * A /tags/1.4.5 (from /branches/1.4.5:866424)
107 * 859500 859597 865262 866419 866424 866500
109 * trunk ------------------------------------------------
111 * branches/1.4.x A-------------------------------------
114 * tags/1.4.4 . A-----------------------
116 * branches/1.4.5 . . A------D
118 * tags/1.4.5 . . . A---------
120 * 859598 865417 866420 866425
122 * A merge of the difference between r859500 and r866500 of this directory
123 * gets split into sequential merges of the following location pairs.
125 * 859500 859597 865262 865416 866419 866424 866500
127 * trunk (======] . . . . .
130 * branches/1.4.x ======] . . . .
132 * branches/1.4.x ( . . . .
133 * tags/1.4.4 =============] . .
134 * implicit_src_gap (======] . . .
137 * branches/1.4.5 ======] .
142 * which are represented in merge_source_t as:
144 * [/trunk:859500, /trunk:859597]
145 * (recorded in svn:mergeinfo as /trunk:859501-859597)
147 * [/trunk:859597, /branches/1.4.x:865262]
148 * (recorded in svn:mergeinfo as /branches/1.4.x:859598-865262)
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])
154 * [/tags/1.4.4@866419, /branches/1.4.5@866424]
155 * (recorded in svn:mergeinfo as /branches/1.4.5:866420-866424)
157 * [/branches/1.4.5@866424, /tags/1.4.5@866500]
158 * (recorded in svn:mergeinfo as /tags/1.4.5:866425-866500)
160 * Our helper functions would then operate on one of these location
164 /* WHICH SVN_CLIENT_MERGE* API DO I WANT?
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.
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 * +----+--------------------------------+---------------------+
192 /* THE CHILDREN_WITH_MERGEINFO ARRAY
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.
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.
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.
209 * For clarification on mergeinfo aware vs. mergeinfo unaware merges, see
210 * the doc string for HONOR_MERGEINFO().
214 /*-----------------------------------------------------------------------*/
216 /*** Repos-Diff Editor Callbacks ***/
219 typedef struct merge_source_t
221 /* "left" side URL and revision (inclusive iff youngest) */
222 const svn_client__pathrev_t *loc1;
224 /* "right" side URL and revision (inclusive iff youngest) */
225 const svn_client__pathrev_t *loc2;
227 /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */
228 svn_boolean_t ancestral;
231 /* Description of the merge target root node (a WC working node) */
232 typedef struct merge_target_t
234 /* Absolute path to the WC node */
237 /* The repository location of the base node of the target WC. If the node
238 * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM.
239 * REPOS_ROOT_URL and REPOS_UUID are always valid. */
240 svn_client__pathrev_t loc;
244 typedef struct merge_cmd_baton_t {
245 svn_boolean_t force_delete; /* Delete a file/dir even if modified */
246 svn_boolean_t dry_run;
247 svn_boolean_t record_only; /* Whether to merge only mergeinfo
249 svn_boolean_t same_repos; /* Whether the merge source repository
250 is the same repository as the
251 target. Defaults to FALSE if DRY_RUN
253 svn_boolean_t mergeinfo_capable; /* Whether the merge source server
254 is capable of Merge Tracking. */
255 svn_boolean_t ignore_mergeinfo; /* Don't honor mergeinfo; see
256 doc string of do_merge(). FALSE if
257 MERGE_SOURCE->ancestral is FALSE. */
258 svn_boolean_t diff_ignore_ancestry; /* Diff unrelated nodes as if related; see
259 doc string of do_merge(). FALSE if
260 MERGE_SOURCE->ancestral is FALSE. */
261 svn_boolean_t reintegrate_merge; /* Whether this is a --reintegrate
263 const merge_target_t *target; /* Description of merge target node */
265 /* The left and right URLs and revs. The value of this field changes to
266 reflect the merge_source_t *currently* being merged by do_merge(). */
267 merge_source_t merge_source;
269 /* Rangelist containing single range which describes the gap, if any,
270 in the natural history of the merge source currently being processed.
271 See http://subversion.tigris.org/issues/show_bug.cgi?id=3432.
272 Updated during each call to do_directory_merge(). May be NULL if there
274 svn_rangelist_t *implicit_src_gap;
276 svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */
278 /* The list of any paths which remained in conflict after a
279 resolution attempt was made. We track this in-memory, rather
280 than just using WC entry state, since the latter doesn't help us
281 when in dry_run mode.
282 ### And because we only want to resolve conflicts that were
283 generated by this merge, not pre-existing ones? */
284 apr_hash_t *conflicted_paths;
286 /* A list of absolute paths which had no explicit mergeinfo prior to the
287 merge but got explicit mergeinfo added by the merge. This is populated
288 by merge_change_props() and is allocated in POOL so it is subject to the
289 lifetime limitations of POOL. Is NULL if no paths are found which
290 meet the criteria or DRY_RUN is true. */
291 apr_hash_t *paths_with_new_mergeinfo;
293 /* A list of absolute paths whose mergeinfo doesn't need updating after
294 the merge. This can be caused by the removal of mergeinfo by the merge
295 or by deleting the node itself. This is populated by merge_change_props()
296 and the delete callbacks and is allocated in POOL so it is subject to the
297 lifetime limitations of POOL. Is NULL if no paths are found which
298 meet the criteria or DRY_RUN is true. */
299 apr_hash_t *paths_with_deleted_mergeinfo;
301 /* The list of absolute skipped paths, which should be examined and
302 cleared after each invocation of the callback. The paths
303 are absolute. Is NULL if MERGE_B->MERGE_SOURCE->ancestral and
304 MERGE_B->REINTEGRATE_MERGE are both false. */
305 apr_hash_t *skipped_abspaths;
307 /* The list of absolute merged paths. Unused if MERGE_B->MERGE_SOURCE->ancestral
308 and MERGE_B->REINTEGRATE_MERGE are both false. */
309 apr_hash_t *merged_abspaths;
311 /* A hash of (const char *) absolute WC paths mapped to the same which
312 represent the roots of subtrees added by the merge. */
313 apr_hash_t *added_abspaths;
315 /* A list of tree conflict victim absolute paths which may be NULL. */
316 apr_hash_t *tree_conflicted_abspaths;
318 /* The diff3_cmd in ctx->config, if any, else null. We could just
319 extract this as needed, but since more than one caller uses it,
320 we just set it up when this baton is created. */
321 const char *diff3_cmd;
322 const apr_array_header_t *merge_options;
324 /* Array of file extension patterns to preserve as extensions in
325 generated conflict files. */
326 const apr_array_header_t *ext_patterns;
328 /* RA sessions used throughout a merge operation. Opened/re-parented
331 NOTE: During the actual merge editor drive, RA_SESSION1 is used
332 for the primary editing and RA_SESSION2 for fetching additional
333 information -- as necessary -- from the repository. So during
334 this phase of the merge, you *must not* reparent RA_SESSION1; use
335 (temporarily reparenting if you must) RA_SESSION2 instead. */
336 svn_ra_session_t *ra_session1;
337 svn_ra_session_t *ra_session2;
339 /* During the merge, *USE_SLEEP is set to TRUE if a sleep will be required
340 afterwards to ensure timestamp integrity, or unchanged if not. */
341 svn_boolean_t *use_sleep;
343 /* Pool which has a lifetime limited to one iteration over a given
344 merge source, i.e. it is cleared on every call to do_directory_merge()
345 or do_file_merge() in do_merge(). */
349 /* State for notify_merge_begin() */
350 struct notify_begin_state_t
352 /* Cache of which abspath was last notified. */
353 const char *last_abspath;
355 /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
356 comment) or a similar list for single-file-merges */
357 const apr_array_header_t *nodes_with_mergeinfo;
363 /* Return TRUE iff we should be taking account of mergeinfo in deciding what
364 changes to merge, for the merge described by MERGE_B. Specifically, that
365 is if the merge source server is capable of merge tracking, the left-side
366 merge source is an ancestor of the right-side (or vice-versa), the merge
367 source is in the same repository as the merge target, and we are not
368 ignoring mergeinfo. */
369 #define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable \
370 && (merge_b)->merge_source.ancestral \
371 && (merge_b)->same_repos \
372 && (! (merge_b)->ignore_mergeinfo))
375 /* Return TRUE iff we should be recording mergeinfo for the merge described
376 by MERGE_B. Specifically, that is if we are honoring mergeinfo and the
377 merge is not a dry run. */
378 #define RECORD_MERGEINFO(merge_b) (HONOR_MERGEINFO(merge_b) \
379 && !(merge_b)->dry_run)
382 /*-----------------------------------------------------------------------*/
386 /* Return TRUE iff the session URL of RA_SESSION is equal to URL. Useful in
387 * asserting preconditions. */
389 session_url_is(svn_ra_session_t *ra_session,
391 apr_pool_t *scratch_pool)
393 const char *session_url;
395 = svn_ra_get_session_url(ra_session, &session_url, scratch_pool);
397 SVN_ERR_ASSERT_NO_RETURN(! err);
398 return strcmp(url, session_url) == 0;
401 /* Return a new merge_source_t structure, allocated in RESULT_POOL,
402 * initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */
403 static merge_source_t *
404 merge_source_create(const svn_client__pathrev_t *loc1,
405 const svn_client__pathrev_t *loc2,
406 svn_boolean_t ancestral,
407 apr_pool_t *result_pool)
410 = apr_palloc(result_pool, sizeof(*s));
412 s->loc1 = svn_client__pathrev_dup(loc1, result_pool);
413 s->loc2 = svn_client__pathrev_dup(loc2, result_pool);
414 s->ancestral = ancestral;
418 /* Return a deep copy of SOURCE, allocated in RESULT_POOL. */
419 static merge_source_t *
420 merge_source_dup(const merge_source_t *source,
421 apr_pool_t *result_pool)
423 merge_source_t *s = apr_palloc(result_pool, sizeof(*s));
425 s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool);
426 s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool);
427 s->ancestral = source->ancestral;
431 /* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository
432 of LOCAL_ABSPATH. Use SCRATCH_POOL for temporary allocations. */
434 check_repos_match(const merge_target_t *target,
435 const char *local_abspath,
437 apr_pool_t *scratch_pool)
439 if (!svn_uri__is_ancestor(target->loc.repos_root_url, url))
440 return svn_error_createf(
441 SVN_ERR_UNSUPPORTED_FEATURE, NULL,
442 _("URL '%s' of '%s' is not in repository '%s'"),
443 url, svn_dirent_local_style(local_abspath, scratch_pool),
444 target->loc.repos_root_url);
449 /* Return TRUE iff the repository of LOCATION1 is the same as
450 * that of LOCATION2. If STRICT_URLS is true, the URLs must
451 * match (and the UUIDs, just to be sure), otherwise just the UUIDs must
452 * match and the URLs can differ (a common case is http versus https). */
454 is_same_repos(const svn_client__pathrev_t *location1,
455 const svn_client__pathrev_t *location2,
456 svn_boolean_t strict_urls)
459 return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0
460 && strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
462 return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
465 /* If the repository identified of LOCATION1 is not the same as that
466 * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES
467 * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos().
470 check_same_repos(const svn_client__pathrev_t *location1,
472 const svn_client__pathrev_t *location2,
474 svn_boolean_t strict_urls,
475 apr_pool_t *scratch_pool)
477 if (! is_same_repos(location1, location2, strict_urls))
478 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
479 _("'%s' must be from the same repository as "
480 "'%s'"), path1, path2);
484 /* Store LOCAL_ABSPATH in PATH_HASH after duplicating it into the pool
485 containing PATH_HASH. */
486 static APR_INLINE void
487 store_path(apr_hash_t *path_hash, const char *local_abspath)
489 const char *dup_path = apr_pstrdup(apr_hash_pool_get(path_hash),
492 svn_hash_sets(path_hash, dup_path, dup_path);
495 /* Store LOCAL_ABSPATH in *PATH_HASH_P after duplicating it into the pool
496 containing *PATH_HASH_P. If *PATH_HASH_P is NULL, then first set
497 *PATH_HASH_P to a new hash allocated from POOL. */
498 static APR_INLINE void
499 alloc_and_store_path(apr_hash_t **path_hash_p,
500 const char *local_abspath,
504 *path_hash_p = apr_hash_make(pool);
505 store_path(*path_hash_p, local_abspath);
508 /* Return whether any WC path was put in conflict by the merge
509 operation corresponding to MERGE_B. */
510 static APR_INLINE svn_boolean_t
511 is_path_conflicted_by_merge(merge_cmd_baton_t *merge_b)
513 return (merge_b->conflicted_paths &&
514 apr_hash_count(merge_b->conflicted_paths) > 0);
517 /* Return a state indicating whether the WC metadata matches the
518 * node kind on disk of the local path LOCAL_ABSPATH.
519 * Use MERGE_B to determine the dry-run details; particularly, if a dry run
520 * noted that it deleted this path, assume matching node kinds (as if both
521 * kinds were svn_node_none).
523 * - Return svn_wc_notify_state_inapplicable if the node kind matches.
524 * - Return 'obstructed' if there is a node on disk where none or a
525 * different kind is expected, or if the disk node cannot be read.
526 * - Return 'missing' if there is no node on disk but one is expected.
527 * Also return 'missing' for server-excluded nodes (not here due to
528 * authz or other reasons determined by the server).
530 * Optionally return a bit more info for interested users.
533 perform_obstruction_check(svn_wc_notify_state_t *obstruction_state,
534 svn_boolean_t *deleted,
535 svn_boolean_t *excluded,
536 svn_node_kind_t *kind,
537 svn_depth_t *parent_depth,
538 const merge_cmd_baton_t *merge_b,
539 const char *local_abspath,
540 apr_pool_t *scratch_pool)
542 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx;
543 svn_node_kind_t wc_kind;
544 svn_boolean_t check_root;
546 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
548 *obstruction_state = svn_wc_notify_state_inapplicable;
553 *kind = svn_node_none;
558 check_root = ! strcmp(local_abspath, merge_b->target->abspath);
560 SVN_ERR(svn_wc__check_for_obstructions(obstruction_state,
565 wc_ctx, local_abspath,
571 /* Create *LEFT and *RIGHT conflict versions for conflict victim
572 * at VICTIM_ABSPATH, with merge-left node kind MERGE_LEFT_NODE_KIND
573 * and merge-right node kind MERGE_RIGHT_NODE_KIND, using information
574 * obtained from MERGE_SOURCE and TARGET.
575 * Allocate returned conflict versions in RESULT_POOL. */
577 make_conflict_versions(const svn_wc_conflict_version_t **left,
578 const svn_wc_conflict_version_t **right,
579 const char *victim_abspath,
580 svn_node_kind_t merge_left_node_kind,
581 svn_node_kind_t merge_right_node_kind,
582 const merge_source_t *merge_source,
583 const merge_target_t *target,
584 apr_pool_t *result_pool,
585 apr_pool_t *scratch_pool)
587 const char *child = svn_dirent_skip_ancestor(target->abspath,
589 const char *left_relpath, *right_relpath;
591 SVN_ERR_ASSERT(child != NULL);
592 left_relpath = svn_client__pathrev_relpath(merge_source->loc1,
594 right_relpath = svn_client__pathrev_relpath(merge_source->loc2,
597 *left = svn_wc_conflict_version_create2(
598 merge_source->loc1->repos_root_url,
599 merge_source->loc1->repos_uuid,
600 svn_relpath_join(left_relpath, child, scratch_pool),
601 merge_source->loc1->rev,
602 merge_left_node_kind, result_pool);
604 *right = svn_wc_conflict_version_create2(
605 merge_source->loc2->repos_root_url,
606 merge_source->loc2->repos_uuid,
607 svn_relpath_join(right_relpath, child, scratch_pool),
608 merge_source->loc2->rev,
609 merge_right_node_kind, result_pool);
614 /* Helper for filter_self_referential_mergeinfo()
616 *MERGEINFO is a non-empty, non-null collection of mergeinfo.
618 Remove all mergeinfo from *MERGEINFO that describes revision ranges
619 greater than REVISION. Put a copy of any removed mergeinfo, allocated
620 in POOL, into *YOUNGER_MERGEINFO.
622 If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set
623 to NULL. If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is
627 split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo,
628 svn_mergeinfo_t *mergeinfo,
629 svn_revnum_t revision,
632 apr_hash_index_t *hi;
633 apr_pool_t *iterpool = svn_pool_create(pool);
635 *younger_mergeinfo = NULL;
636 for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi))
639 const char *merge_source_path = apr_hash_this_key(hi);
640 svn_rangelist_t *rangelist = apr_hash_this_val(hi);
642 svn_pool_clear(iterpool);
644 for (i = 0; i < rangelist->nelts; i++)
646 svn_merge_range_t *range =
647 APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
648 if (range->end <= revision)
650 /* This entirely of this range is as old or older than
651 REVISION, so leave it in *MERGEINFO. */
656 /* Since the rangelists in svn_mergeinfo_t's are sorted in
657 increasing order we know that part or all of *this* range
658 and *all* of the remaining ranges in *RANGELIST are younger
659 than REVISION. Remove the younger rangelists from
660 *MERGEINFO and put them in *YOUNGER_MERGEINFO. */
662 svn_rangelist_t *younger_rangelist =
663 apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
665 for (j = i; j < rangelist->nelts; j++)
667 svn_merge_range_t *younger_range = svn_merge_range_dup(
668 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool);
670 /* REVISION might intersect with the first range where
671 range->end > REVISION. If that is the case then split
672 the current range into two, putting the younger half
673 into *YOUNGER_MERGEINFO and leaving the older half in
675 if (j == i && range->start + 1 <= revision)
676 younger_range->start = range->end = revision;
678 APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) =
682 /* So far we've only been manipulating rangelists, now we
683 actually create *YOUNGER_MERGEINFO and then remove the older
684 ranges from *MERGEINFO */
685 if (!(*younger_mergeinfo))
686 *younger_mergeinfo = apr_hash_make(pool);
687 svn_hash_sets(*younger_mergeinfo, merge_source_path,
689 SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo,
690 *mergeinfo, TRUE, pool, iterpool));
691 break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */
696 svn_pool_destroy(iterpool);
702 /* Make a copy of PROPCHANGES (array of svn_prop_t) into *TRIMMED_PROPCHANGES,
703 omitting any svn:mergeinfo changes. */
705 omit_mergeinfo_changes(apr_array_header_t **trimmed_propchanges,
706 const apr_array_header_t *propchanges,
707 apr_pool_t *result_pool)
711 *trimmed_propchanges = apr_array_make(result_pool,
715 for (i = 0; i < propchanges->nelts; ++i)
717 const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
719 /* If this property is not svn:mergeinfo, then copy it. */
720 if (strcmp(change->name, SVN_PROP_MERGEINFO) != 0)
721 APR_ARRAY_PUSH(*trimmed_propchanges, svn_prop_t) = *change;
728 /* Helper for merge_props_changed().
730 *PROPS is an array of svn_prop_t structures representing regular properties
731 to be added to the working copy TARGET_ABSPATH.
733 The merge source and target are assumed to be in the same repository.
735 Filter out mergeinfo property additions to TARGET_ABSPATH when
736 those additions refer to the same line of history as TARGET_ABSPATH as
739 Examine the added mergeinfo, looking at each range (or single rev)
740 of each source path. If a source_path/range refers to the same line of
741 history as TARGET_ABSPATH (pegged at its base revision), then filter out
742 that range. If the entire rangelist for a given path is filtered then
743 filter out the path as well.
745 RA_SESSION is an open RA session to the repository
746 in which both the source and target live, else RA_SESSION is not used. It
747 may be temporarily reparented as needed by this function.
749 Use CTX for any further client operations.
751 If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated
752 in POOL) of incoming *PROPS minus the filtered mergeinfo. */
754 filter_self_referential_mergeinfo(apr_array_header_t **props,
755 const char *target_abspath,
756 svn_ra_session_t *ra_session,
757 svn_client_ctx_t *ctx,
760 apr_array_header_t *adjusted_props;
762 apr_pool_t *iterpool;
763 svn_boolean_t is_copy;
764 const char *repos_relpath;
765 svn_client__pathrev_t target_base;
767 /* If PATH itself has been added there is no need to filter. */
768 SVN_ERR(svn_wc__node_get_origin(&is_copy, &target_base.rev, &repos_relpath,
769 &target_base.repos_root_url,
770 &target_base.repos_uuid, NULL, NULL,
771 ctx->wc_ctx, target_abspath, FALSE,
774 if (is_copy || !repos_relpath)
775 return SVN_NO_ERROR; /* A copy or a local addition */
777 target_base.url = svn_path_url_add_component2(target_base.repos_root_url,
778 repos_relpath, pool);
780 adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
781 iterpool = svn_pool_create(pool);
782 for (i = 0; i < (*props)->nelts; ++i)
784 svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t);
786 svn_mergeinfo_t mergeinfo, younger_mergeinfo;
787 svn_mergeinfo_t filtered_mergeinfo = NULL;
788 svn_mergeinfo_t filtered_younger_mergeinfo = NULL;
791 /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal)
792 or empty mergeinfo it does not require any special handling. There
793 is nothing to filter out of empty mergeinfo and the concept of
794 filtering doesn't apply if we are trying to remove mergeinfo
796 if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0)
797 || (! prop->value) /* Removal of mergeinfo */
798 || (! prop->value->len)) /* Empty mergeinfo */
800 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
804 svn_pool_clear(iterpool);
806 /* Non-empty mergeinfo; filter self-referential mergeinfo out. */
808 /* Parse the incoming mergeinfo to allow easier manipulation. */
809 err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool);
813 /* Issue #3896: If we can't parse it, we certainly can't
815 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
817 svn_error_clear(err);
818 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
823 return svn_error_trace(err);
827 /* The working copy target PATH is at BASE_REVISION. Divide the
828 incoming mergeinfo into two groups. One where all revision ranges
829 are as old or older than BASE_REVISION and one where all revision
832 Note: You may be wondering why we do this.
834 For the incoming mergeinfo "older" than target's base revision we
835 can filter out self-referential mergeinfo efficiently using
836 svn_client__get_history_as_mergeinfo(). We simply look at PATH's
837 natural history as mergeinfo and remove that from any incoming
840 For mergeinfo "younger" than the base revision we can't use
841 svn_ra_get_location_segments() to look into PATH's future
842 history. Instead we must use svn_client__repos_locations() and
843 look at each incoming source/range individually and see if PATH
844 at its base revision and PATH at the start of the incoming range
845 exist on the same line of history. If they do then we can filter
846 out the incoming range. But since we have to do this for each
847 range there is a substantial performance penalty to pay if the
848 incoming ranges are not contiguous, i.e. we call
849 svn_client__repos_locations for each discrete range and incur
850 the cost of a roundtrip communication with the repository. */
851 SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo,
856 /* Filter self-referential mergeinfo from younger_mergeinfo. */
857 if (younger_mergeinfo)
859 apr_hash_index_t *hi;
860 const char *merge_source_root_url;
862 SVN_ERR(svn_ra_get_repos_root2(ra_session,
863 &merge_source_root_url, iterpool));
865 for (hi = apr_hash_first(iterpool, younger_mergeinfo);
866 hi; hi = apr_hash_next(hi))
869 const char *source_path = apr_hash_this_key(hi);
870 svn_rangelist_t *rangelist = apr_hash_this_val(hi);
871 const char *merge_source_url;
872 svn_rangelist_t *adjusted_rangelist =
873 apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
876 svn_path_url_add_component2(merge_source_root_url,
877 source_path + 1, iterpool);
879 for (j = 0; j < rangelist->nelts; j++)
882 svn_client__pathrev_t *start_loc;
883 svn_merge_range_t *range =
884 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *);
886 /* Because the merge source normalization code
887 ensures mergeinfo refers to real locations on
888 the same line of history, there's no need to
889 look at the whole range, just the start. */
891 /* Check if PATH@BASE_REVISION exists at
892 RANGE->START on the same line of history.
893 (start+1 because RANGE->start is not inclusive.) */
894 err2 = svn_client__repos_location(&start_loc, ra_session,
897 ctx, iterpool, iterpool);
900 if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES
901 || err2->apr_err == SVN_ERR_FS_NOT_FOUND
902 || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
904 /* PATH@BASE_REVISION didn't exist at
905 RANGE->START + 1 or is unrelated to the
906 resource PATH@RANGE->START. Some of the
907 requested revisions may not even exist in
908 the repository; a real possibility since
909 mergeinfo is hand editable. In all of these
910 cases clear and ignore the error and don't
913 Note: In this last case it is possible that
914 we will allow self-referential mergeinfo to
915 be applied, but fixing it here is potentially
916 very costly in terms of finding what part of
917 a range is actually valid. Simply allowing
918 the merge to proceed without filtering the
919 offending range seems the least worst
921 svn_error_clear(err2);
923 APR_ARRAY_PUSH(adjusted_rangelist,
924 svn_merge_range_t *) = range;
928 return svn_error_trace(err2);
933 /* PATH@BASE_REVISION exists on the same
934 line of history at RANGE->START and RANGE->END.
935 Now check that PATH@BASE_REVISION's path
936 names at RANGE->START and RANGE->END are the same.
937 If the names are not the same then the mergeinfo
938 describing PATH@RANGE->START through
939 PATH@RANGE->END actually belong to some other
940 line of history and we want to record this
941 mergeinfo, not filter it. */
942 if (strcmp(start_loc->url, merge_source_url) != 0)
944 APR_ARRAY_PUSH(adjusted_rangelist,
945 svn_merge_range_t *) = range;
948 /* else no need to add, this mergeinfo is
949 all on the same line of history. */
950 } /* for (j = 0; j < rangelist->nelts; j++) */
952 /* Add any rangelists for source_path that are not
954 if (adjusted_rangelist->nelts)
956 if (!filtered_younger_mergeinfo)
957 filtered_younger_mergeinfo = apr_hash_make(iterpool);
958 svn_hash_sets(filtered_younger_mergeinfo, source_path,
962 } /* Iteration over each merge source in younger_mergeinfo. */
963 } /* if (younger_mergeinfo) */
965 /* Filter self-referential mergeinfo from "older" mergeinfo. */
968 svn_mergeinfo_t implicit_mergeinfo;
970 SVN_ERR(svn_client__get_history_as_mergeinfo(
971 &implicit_mergeinfo, NULL,
972 &target_base, target_base.rev, SVN_INVALID_REVNUM,
973 ra_session, ctx, iterpool));
975 /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
976 SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
978 mergeinfo, TRUE, iterpool, iterpool));
981 /* Combine whatever older and younger filtered mergeinfo exists
982 into filtered_mergeinfo. */
983 if (filtered_mergeinfo && filtered_younger_mergeinfo)
984 SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo,
985 filtered_younger_mergeinfo, iterpool,
987 else if (filtered_younger_mergeinfo)
988 filtered_mergeinfo = filtered_younger_mergeinfo;
990 /* If there is any incoming mergeinfo remaining after filtering
991 then put it in adjusted_props. */
992 if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo))
994 /* Convert filtered_mergeinfo to a svn_prop_t and put it
995 back in the array. */
996 svn_string_t *filtered_mergeinfo_str;
997 svn_prop_t *adjusted_prop = apr_pcalloc(pool,
998 sizeof(*adjusted_prop));
999 SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str,
1002 adjusted_prop->name = SVN_PROP_MERGEINFO;
1003 adjusted_prop->value = filtered_mergeinfo_str;
1004 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop;
1007 svn_pool_destroy(iterpool);
1009 *props = adjusted_props;
1010 return SVN_NO_ERROR;
1013 /* Prepare a set of property changes PROPCHANGES to be used for a merge
1014 operation on LOCAL_ABSPATH.
1016 Remove all non-regular prop-changes (entry-props and WC-props).
1017 Remove all non-mergeinfo prop-changes if it's a record-only merge.
1018 Remove self-referential mergeinfo (### in some cases...)
1019 Remove foreign-repository mergeinfo (### in some cases...)
1021 Store the resulting property changes in *PROP_UPDATES.
1022 Store information on where mergeinfo is updated in MERGE_B.
1024 Used for both file and directory property merges. */
1025 static svn_error_t *
1026 prepare_merge_props_changed(const apr_array_header_t **prop_updates,
1027 const char *local_abspath,
1028 const apr_array_header_t *propchanges,
1029 merge_cmd_baton_t *merge_b,
1030 apr_pool_t *result_pool,
1031 apr_pool_t *scratch_pool)
1033 apr_array_header_t *props;
1035 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
1037 /* We only want to merge "regular" version properties: by
1038 definition, 'svn merge' shouldn't touch any data within .svn/ */
1039 SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
1042 /* If we are only applying mergeinfo changes then we need to do
1043 additional filtering of PROPS so it contains only mergeinfo changes. */
1044 if (merge_b->record_only && props->nelts)
1046 apr_array_header_t *mergeinfo_props =
1047 apr_array_make(result_pool, 1, sizeof(svn_prop_t));
1050 for (i = 0; i < props->nelts; i++)
1052 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
1054 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
1056 APR_ARRAY_PUSH(mergeinfo_props, svn_prop_t) = *prop;
1060 props = mergeinfo_props;
1065 /* Issue #3383: We don't want mergeinfo from a foreign repos.
1067 If this is a merge from a foreign repository we must strip all
1068 incoming mergeinfo (including mergeinfo deletions). */
1069 if (! merge_b->same_repos)
1070 SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool));
1072 /* If this is a forward merge then don't add new mergeinfo to
1073 PATH that is already part of PATH's own history, see
1074 http://svn.haxx.se/dev/archive-2008-09/0006.shtml. If the
1075 merge sources are not ancestral then there is no concept of a
1076 'forward' or 'reverse' merge and we filter unconditionally. */
1077 if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev
1078 || !merge_b->merge_source.ancestral)
1080 if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge)
1081 SVN_ERR(filter_self_referential_mergeinfo(&props,
1083 merge_b->ra_session2,
1088 *prop_updates = props;
1090 /* Make a record in BATON if we find a PATH where mergeinfo is added
1091 where none existed previously or PATH is having its existing
1092 mergeinfo deleted. */
1097 for (i = 0; i < props->nelts; ++i)
1099 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
1101 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
1103 /* Does LOCAL_ABSPATH have any pristine mergeinfo? */
1104 svn_boolean_t has_pristine_mergeinfo = FALSE;
1105 apr_hash_t *pristine_props;
1107 SVN_ERR(svn_wc_get_pristine_props(&pristine_props,
1108 merge_b->ctx->wc_ctx,
1114 && svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO))
1115 has_pristine_mergeinfo = TRUE;
1117 if (!has_pristine_mergeinfo && prop->value)
1119 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
1120 local_abspath, merge_b->pool);
1122 else if (has_pristine_mergeinfo && !prop->value)
1124 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
1125 local_abspath, merge_b->pool);
1131 return SVN_NO_ERROR;
1134 #define CONFLICT_REASON_NONE ((svn_wc_conflict_reason_t)-1)
1135 #define CONFLICT_REASON_SKIP ((svn_wc_conflict_reason_t)-2)
1136 #define CONFLICT_REASON_SKIP_WC ((svn_wc_conflict_reason_t)-3)
1138 /* Baton used for testing trees for being editted while performing tree
1139 conflict detection for incoming deletes */
1140 struct dir_delete_baton_t
1142 /* Reference to dir baton of directory that is the root of the deletion */
1143 struct merge_dir_baton_t *del_root;
1145 /* Boolean indicating that some edit is found. Allows avoiding more work */
1146 svn_boolean_t found_edit;
1148 /* A list of paths that are compared. Kept up to date until FOUND_EDIT is
1150 apr_hash_t *compared_abspaths;
1153 /* Baton for the merge_dir_*() functions. Initialized in merge_dir_opened() */
1154 struct merge_dir_baton_t
1156 /* Reference to the parent baton, unless the parent is the anchor, in which
1157 case PARENT_BATON is NULL */
1158 struct merge_dir_baton_t *parent_baton;
1160 /* The pool containing this baton. Use for RESULT_POOL for storing in this
1164 /* This directory doesn't have a representation in the working copy, so any
1165 operation on it will be skipped and possibly cause a tree conflict on the
1167 svn_boolean_t shadowed;
1169 /* This node or one of its descendants received operational changes from the
1170 merge. If this node is the shadow root its tree conflict status has been
1172 svn_boolean_t edited;
1174 /* If a tree conflict will be installed once edited, it's reason. If a skip
1175 should be produced its reason. Otherwise CONFLICT_REASON_NONE for no tree
1179 CONFLICT_REASON_SKIP:
1180 The node will be skipped with content and property state as stored in
1183 CONFLICT_REASON_SKIP_WC:
1184 The node will be skipped as an obstructing working copy.
1186 svn_wc_conflict_reason_t tree_conflict_reason;
1187 svn_wc_conflict_action_t tree_conflict_action;
1188 svn_node_kind_t tree_conflict_local_node_kind;
1189 svn_node_kind_t tree_conflict_merge_left_node_kind;
1190 svn_node_kind_t tree_conflict_merge_right_node_kind;
1192 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to
1193 add to the notification */
1194 svn_wc_notify_state_t skip_reason;
1196 /* TRUE if the node was added by this merge. Otherwise FALSE */
1197 svn_boolean_t added;
1198 svn_boolean_t add_is_replace; /* Add is second part of replace */
1200 /* TRUE if we are taking over an existing directory as addition, otherwise
1202 svn_boolean_t add_existing;
1204 /* NULL, or an hashtable mapping const char * local_abspaths to
1205 const char *kind mapping, containing deleted nodes that still need a delete
1206 notification (which may be a replaced notification if the node is not just
1208 apr_hash_t *pending_deletes;
1210 /* NULL, or an hashtable mapping const char * LOCAL_ABSPATHs to
1211 a const svn_wc_conflict_description2_t * instance, describing the just
1212 installed conflict */
1213 apr_hash_t *new_tree_conflicts;
1215 /* If not NULL, a reference to the information of the delete test that is
1216 currently in progress. Allocated in the root-directory baton, referenced
1217 from all descendants */
1218 struct dir_delete_baton_t *delete_state;
1221 /* Baton for the merge_dir_*() functions. Initialized in merge_file_opened() */
1222 struct merge_file_baton_t
1224 /* Reference to the parent baton, unless the parent is the anchor, in which
1225 case PARENT_BATON is NULL */
1226 struct merge_dir_baton_t *parent_baton;
1228 /* This file doesn't have a representation in the working copy, so any
1229 operation on it will be skipped and possibly cause a tree conflict
1230 on the shadow root */
1231 svn_boolean_t shadowed;
1233 /* This node received operational changes from the merge. If this node
1234 is the shadow root its tree conflict status has been applied */
1235 svn_boolean_t edited;
1237 /* If a tree conflict will be installed once edited, it's reason. If a skip
1238 should be produced its reason. Some special values are defined. See the
1239 merge_tree_baton_t for an explanation. */
1240 svn_wc_conflict_reason_t tree_conflict_reason;
1241 svn_wc_conflict_action_t tree_conflict_action;
1242 svn_node_kind_t tree_conflict_local_node_kind;
1243 svn_node_kind_t tree_conflict_merge_left_node_kind;
1244 svn_node_kind_t tree_conflict_merge_right_node_kind;
1246 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to
1247 add to the notification */
1248 svn_wc_notify_state_t skip_reason;
1250 /* TRUE if the node was added by this merge. Otherwise FALSE */
1251 svn_boolean_t added;
1252 svn_boolean_t add_is_replace; /* Add is second part of replace */
1255 /* Forward declaration */
1256 static svn_error_t *
1257 notify_merge_begin(merge_cmd_baton_t *merge_b,
1258 const char *local_abspath,
1259 svn_boolean_t delete_action,
1260 apr_pool_t *scratch_pool);
1262 /* Record the skip for future processing and (later) produce the
1263 skip notification */
1264 static svn_error_t *
1265 record_skip(merge_cmd_baton_t *merge_b,
1266 const char *local_abspath,
1267 svn_node_kind_t kind,
1268 svn_wc_notify_action_t action,
1269 svn_wc_notify_state_t state,
1270 struct merge_dir_baton_t *pdb,
1271 apr_pool_t *scratch_pool)
1273 if (merge_b->record_only)
1274 return SVN_NO_ERROR; /* ### Why? - Legacy compatibility */
1276 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
1277 && !(pdb && pdb->shadowed))
1279 store_path(merge_b->skipped_abspaths, local_abspath);
1282 if (merge_b->ctx->notify_func2)
1284 svn_wc_notify_t *notify;
1286 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1288 notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
1289 notify->kind = kind;
1290 notify->content_state = notify->prop_state = state;
1292 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
1295 return SVN_NO_ERROR;
1298 /* Forward declaration */
1299 static svn_client__merge_path_t *
1300 find_nearest_ancestor_with_intersecting_ranges(
1301 svn_revnum_t *start,
1303 const apr_array_header_t *children_with_mergeinfo,
1304 svn_boolean_t path_is_own_ancestor,
1305 const char *local_abspath);
1307 /* Record a tree conflict in the WC, unless this is a dry run or a record-
1308 * only merge, or if a tree conflict is already flagged for the VICTIM_PATH.
1309 * (The latter can happen if a merge-tracking-aware merge is doing multiple
1310 * editor drives because of a gap in the range of eligible revisions.)
1312 * The tree conflict, with its victim specified by VICTIM_PATH, is
1313 * assumed to have happened during a merge using merge baton MERGE_B.
1315 * ACTION and REASON correspond to the fields
1316 * of the same names in svn_wc_tree_conflict_description_t.
1318 static svn_error_t *
1319 record_tree_conflict(merge_cmd_baton_t *merge_b,
1320 const char *local_abspath,
1321 struct merge_dir_baton_t *parent_baton,
1322 svn_node_kind_t local_node_kind,
1323 svn_node_kind_t merge_left_node_kind,
1324 svn_node_kind_t merge_right_node_kind,
1325 svn_wc_conflict_action_t action,
1326 svn_wc_conflict_reason_t reason,
1327 const svn_wc_conflict_description2_t *existing_conflict,
1328 svn_boolean_t notify_tc,
1329 apr_pool_t *scratch_pool)
1331 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx;
1333 if (merge_b->record_only)
1334 return SVN_NO_ERROR;
1336 if (merge_b->merge_source.ancestral
1337 || merge_b->reintegrate_merge)
1339 store_path(merge_b->tree_conflicted_abspaths, local_abspath);
1342 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
1345 if (!merge_b->dry_run)
1347 svn_wc_conflict_description2_t *conflict;
1348 const svn_wc_conflict_version_t *left;
1349 const svn_wc_conflict_version_t *right;
1350 apr_pool_t *result_pool = parent_baton ? parent_baton->pool
1353 if (reason == svn_wc_conflict_reason_deleted)
1355 const char *moved_to_abspath;
1357 SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
1358 wc_ctx, local_abspath,
1359 scratch_pool, scratch_pool));
1361 if (moved_to_abspath)
1363 /* Local abspath itself has been moved away. If only a
1364 descendant is moved away, we call the node itself deleted */
1365 reason = svn_wc_conflict_reason_moved_away;
1368 else if (reason == svn_wc_conflict_reason_added)
1370 const char *moved_from_abspath;
1371 SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL,
1372 wc_ctx, local_abspath,
1373 scratch_pool, scratch_pool));
1374 if (moved_from_abspath)
1375 reason = svn_wc_conflict_reason_moved_here;
1378 if (HONOR_MERGEINFO(merge_b) && merge_b->merge_source.ancestral)
1380 struct merge_source_t *source;
1381 svn_client__pathrev_t *loc1;
1382 svn_client__pathrev_t *loc2;
1383 svn_merge_range_t range =
1384 {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE};
1386 /* We are honoring mergeinfo so do not blindly record
1387 * a conflict describing the merge of
1388 * SOURCE->LOC1->URL@SOURCE->LOC1->REV through
1389 * SOURCE->LOC2->URL@SOURCE->LOC2->REV
1390 * but figure out the actual revision range merged. */
1391 (void)find_nearest_ancestor_with_intersecting_ranges(
1392 &(range.start), &(range.end),
1393 merge_b->notify_begin.nodes_with_mergeinfo,
1394 action != svn_wc_conflict_action_delete,
1396 loc1 = svn_client__pathrev_dup(merge_b->merge_source.loc1,
1398 loc2 = svn_client__pathrev_dup(merge_b->merge_source.loc2,
1400 loc1->rev = range.start;
1401 loc2->rev = range.end;
1402 source = merge_source_create(loc1, loc2,
1403 merge_b->merge_source.ancestral,
1405 SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
1406 merge_left_node_kind,
1407 merge_right_node_kind,
1408 source, merge_b->target,
1409 result_pool, scratch_pool));
1412 SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
1413 merge_left_node_kind,
1414 merge_right_node_kind,
1415 &merge_b->merge_source, merge_b->target,
1416 result_pool, scratch_pool));
1418 /* Fix up delete of file, add of dir replacement (or other way around) */
1419 if (existing_conflict != NULL && existing_conflict->src_left_version)
1420 left = existing_conflict->src_left_version;
1422 conflict = svn_wc_conflict_description_create_tree2(
1423 local_abspath, local_node_kind,
1424 svn_wc_operation_merge,
1425 left, right, result_pool);
1427 conflict->action = action;
1428 conflict->reason = reason;
1430 /* May return SVN_ERR_WC_PATH_UNEXPECTED_STATUS */
1431 if (existing_conflict)
1432 SVN_ERR(svn_wc__del_tree_conflict(wc_ctx, local_abspath,
1435 SVN_ERR(svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict,
1440 if (! parent_baton->new_tree_conflicts)
1441 parent_baton->new_tree_conflicts = apr_hash_make(result_pool);
1443 svn_hash_sets(parent_baton->new_tree_conflicts,
1444 apr_pstrdup(result_pool, local_abspath),
1448 /* ### TODO: Store in parent baton */
1451 /* On a replacement we currently get two tree conflicts */
1452 if (merge_b->ctx->notify_func2 && notify_tc)
1454 svn_wc_notify_t *notify;
1456 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1458 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict,
1460 notify->kind = local_node_kind;
1462 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
1466 return SVN_NO_ERROR;
1469 /* Record the add for future processing and produce the
1470 update_add notification
1472 static svn_error_t *
1473 record_update_add(merge_cmd_baton_t *merge_b,
1474 const char *local_abspath,
1475 svn_node_kind_t kind,
1476 svn_boolean_t notify_replaced,
1477 apr_pool_t *scratch_pool)
1479 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
1481 store_path(merge_b->merged_abspaths, local_abspath);
1484 if (merge_b->ctx->notify_func2)
1486 svn_wc_notify_t *notify;
1487 svn_wc_notify_action_t action = svn_wc_notify_update_add;
1489 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1491 if (notify_replaced)
1492 action = svn_wc_notify_update_replace;
1494 notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
1495 notify->kind = kind;
1497 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
1501 return SVN_NO_ERROR;
1504 /* Record the update for future processing and produce the
1505 update_update notification */
1506 static svn_error_t *
1507 record_update_update(merge_cmd_baton_t *merge_b,
1508 const char *local_abspath,
1509 svn_node_kind_t kind,
1510 svn_wc_notify_state_t content_state,
1511 svn_wc_notify_state_t prop_state,
1512 apr_pool_t *scratch_pool)
1514 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
1516 store_path(merge_b->merged_abspaths, local_abspath);
1519 if (merge_b->ctx->notify_func2)
1521 svn_wc_notify_t *notify;
1523 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1525 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update,
1527 notify->kind = kind;
1528 notify->content_state = content_state;
1529 notify->prop_state = prop_state;
1531 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
1535 return SVN_NO_ERROR;
1538 /* Record the delete for future processing and for (later) producing the
1539 update_delete notification */
1540 static svn_error_t *
1541 record_update_delete(merge_cmd_baton_t *merge_b,
1542 struct merge_dir_baton_t *parent_db,
1543 const char *local_abspath,
1544 svn_node_kind_t kind,
1545 apr_pool_t *scratch_pool)
1547 /* Update the lists of merged, skipped, tree-conflicted and added paths. */
1548 if (merge_b->merge_source.ancestral
1549 || merge_b->reintegrate_merge)
1551 /* Issue #4166: If a previous merge added NOTIFY_ABSPATH, but we
1552 are now deleting it, then remove it from the list of added
1554 svn_hash_sets(merge_b->added_abspaths, local_abspath, NULL);
1555 store_path(merge_b->merged_abspaths, local_abspath);
1558 SVN_ERR(notify_merge_begin(merge_b, local_abspath, TRUE, scratch_pool));
1562 const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath);
1564 if (!parent_db->pending_deletes)
1565 parent_db->pending_deletes = apr_hash_make(parent_db->pool);
1567 svn_hash_sets(parent_db->pending_deletes, dup_abspath,
1568 svn_node_kind_to_word(kind));
1571 return SVN_NO_ERROR;
1574 /* Notify the pending 'D'eletes, that were waiting to see if a matching 'A'dd
1575 might make them a 'R'eplace. */
1576 static svn_error_t *
1577 handle_pending_notifications(merge_cmd_baton_t *merge_b,
1578 struct merge_dir_baton_t *db,
1579 apr_pool_t *scratch_pool)
1581 if (merge_b->ctx->notify_func2 && db->pending_deletes)
1583 apr_hash_index_t *hi;
1585 for (hi = apr_hash_first(scratch_pool, db->pending_deletes);
1587 hi = apr_hash_next(hi))
1589 const char *del_abspath = apr_hash_this_key(hi);
1590 svn_wc_notify_t *notify;
1592 notify = svn_wc_create_notify(del_abspath,
1593 svn_wc_notify_update_delete,
1595 notify->kind = svn_node_kind_from_word(
1596 apr_hash_this_val(hi));
1598 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
1599 notify, scratch_pool);
1602 db->pending_deletes = NULL;
1604 return SVN_NO_ERROR;
1607 /* Helper function for the merge_dir_*() and merge_file_*() functions.
1609 Installs and notifies pre-recorded tree conflicts and skips for
1610 ancestors of operational merges
1612 static svn_error_t *
1613 mark_dir_edited(merge_cmd_baton_t *merge_b,
1614 struct merge_dir_baton_t *db,
1615 const char *local_abspath,
1616 apr_pool_t *scratch_pool)
1618 /* ### Too much common code with mark_file_edited */
1620 return SVN_NO_ERROR;
1622 if (db->parent_baton && !db->parent_baton->edited)
1624 const char *dir_abspath = svn_dirent_dirname(local_abspath,
1627 SVN_ERR(mark_dir_edited(merge_b, db->parent_baton, dir_abspath,
1634 return SVN_NO_ERROR; /* Easy out */
1636 if (db->parent_baton
1637 && db->parent_baton->delete_state
1638 && db->tree_conflict_reason != CONFLICT_REASON_NONE)
1640 db->parent_baton->delete_state->found_edit = TRUE;
1642 else if (db->tree_conflict_reason == CONFLICT_REASON_SKIP
1643 || db->tree_conflict_reason == CONFLICT_REASON_SKIP_WC)
1645 /* open_directory() decided not to flag a tree conflict, but
1646 for clarity we produce a skip for this node that
1647 most likely isn't touched by the merge itself */
1649 if (merge_b->ctx->notify_func2)
1651 svn_wc_notify_t *notify;
1653 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
1656 notify = svn_wc_create_notify(
1658 (db->tree_conflict_reason == CONFLICT_REASON_SKIP)
1659 ? svn_wc_notify_skip
1660 : svn_wc_notify_update_skip_obstruction,
1662 notify->kind = svn_node_dir;
1663 notify->content_state = notify->prop_state = db->skip_reason;
1665 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
1670 if (merge_b->merge_source.ancestral
1671 || merge_b->reintegrate_merge)
1673 store_path(merge_b->skipped_abspaths, local_abspath);
1676 else if (db->tree_conflict_reason != CONFLICT_REASON_NONE)
1678 /* open_directory() decided that a tree conflict should be raised */
1680 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton,
1681 db->tree_conflict_local_node_kind,
1682 db->tree_conflict_merge_left_node_kind,
1683 db->tree_conflict_merge_right_node_kind,
1684 db->tree_conflict_action,
1685 db->tree_conflict_reason,
1690 return SVN_NO_ERROR;
1693 /* Helper function for the merge_file_*() functions.
1695 Installs and notifies pre-recorded tree conflicts and skips for
1696 ancestors of operational merges
1698 static svn_error_t *
1699 mark_file_edited(merge_cmd_baton_t *merge_b,
1700 struct merge_file_baton_t *fb,
1701 const char *local_abspath,
1702 apr_pool_t *scratch_pool)
1704 /* ### Too much common code with mark_dir_edited */
1706 return SVN_NO_ERROR;
1708 if (fb->parent_baton && !fb->parent_baton->edited)
1710 const char *dir_abspath = svn_dirent_dirname(local_abspath,
1713 SVN_ERR(mark_dir_edited(merge_b, fb->parent_baton, dir_abspath,
1720 return SVN_NO_ERROR; /* Easy out */
1722 if (fb->parent_baton
1723 && fb->parent_baton->delete_state
1724 && fb->tree_conflict_reason != CONFLICT_REASON_NONE)
1726 fb->parent_baton->delete_state->found_edit = TRUE;
1728 else if (fb->tree_conflict_reason == CONFLICT_REASON_SKIP
1729 || fb->tree_conflict_reason == CONFLICT_REASON_SKIP_WC)
1731 /* open_directory() decided not to flag a tree conflict, but
1732 for clarity we produce a skip for this node that
1733 most likely isn't touched by the merge itself */
1735 if (merge_b->ctx->notify_func2)
1737 svn_wc_notify_t *notify;
1739 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
1742 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip,
1744 notify->kind = svn_node_file;
1745 notify->content_state = notify->prop_state = fb->skip_reason;
1747 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
1752 if (merge_b->merge_source.ancestral
1753 || merge_b->reintegrate_merge)
1755 store_path(merge_b->skipped_abspaths, local_abspath);
1758 else if (fb->tree_conflict_reason != CONFLICT_REASON_NONE)
1760 /* open_file() decided that a tree conflict should be raised */
1762 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton,
1763 fb->tree_conflict_local_node_kind,
1764 fb->tree_conflict_merge_left_node_kind,
1765 fb->tree_conflict_merge_right_node_kind,
1766 fb->tree_conflict_action,
1767 fb->tree_conflict_reason,
1772 return SVN_NO_ERROR;
1775 /* An svn_diff_tree_processor_t function.
1777 Called before either merge_file_changed(), merge_file_added(),
1778 merge_file_deleted() or merge_file_closed(), unless it sets *SKIP to TRUE.
1780 When *SKIP is TRUE, the diff driver avoids work on getting the details
1781 for the closing callbacks.
1783 static svn_error_t *
1784 merge_file_opened(void **new_file_baton,
1785 svn_boolean_t *skip,
1786 const char *relpath,
1787 const svn_diff_source_t *left_source,
1788 const svn_diff_source_t *right_source,
1789 const svn_diff_source_t *copyfrom_source,
1791 const struct svn_diff_tree_processor_t *processor,
1792 apr_pool_t *result_pool,
1793 apr_pool_t *scratch_pool)
1795 merge_cmd_baton_t *merge_b = processor->baton;
1796 struct merge_dir_baton_t *pdb = dir_baton;
1797 struct merge_file_baton_t *fb;
1798 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
1799 relpath, scratch_pool);
1801 fb = apr_pcalloc(result_pool, sizeof(*fb));
1802 fb->tree_conflict_reason = CONFLICT_REASON_NONE;
1803 fb->tree_conflict_action = svn_wc_conflict_action_edit;
1804 fb->skip_reason = svn_wc_notify_state_unknown;
1807 fb->tree_conflict_merge_left_node_kind = svn_node_file;
1809 fb->tree_conflict_merge_left_node_kind = svn_node_none;
1812 fb->tree_conflict_merge_right_node_kind = svn_node_file;
1814 fb->tree_conflict_merge_right_node_kind = svn_node_none;
1816 *new_file_baton = fb;
1820 fb->parent_baton = pdb;
1821 fb->shadowed = pdb->shadowed;
1822 fb->skip_reason = pdb->skip_reason;
1827 /* An ancestor is tree conflicted. Nothing to do here. */
1829 else if (left_source != NULL)
1831 /* Node is expected to be a file, which will be changed or deleted. */
1832 svn_boolean_t is_deleted;
1833 svn_boolean_t excluded;
1834 svn_depth_t parent_depth;
1837 fb->tree_conflict_action = svn_wc_conflict_action_delete;
1840 svn_wc_notify_state_t obstr_state;
1842 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded,
1843 &fb->tree_conflict_local_node_kind,
1845 merge_b, local_abspath,
1848 if (obstr_state != svn_wc_notify_state_inapplicable)
1850 fb->shadowed = TRUE;
1851 fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1852 fb->skip_reason = obstr_state;
1853 return SVN_NO_ERROR;
1857 fb->tree_conflict_local_node_kind = svn_node_none;
1860 if (fb->tree_conflict_local_node_kind == svn_node_none)
1862 fb->shadowed = TRUE;
1864 /* If this is not the merge target and the parent is too shallow to
1865 contain this directory, and the directory is not present
1866 via exclusion or depth filtering, skip it instead of recording
1869 Non-inheritable mergeinfo will be recorded, allowing
1870 future merges into non-shallow working copies to merge
1871 changes we missed this time around. */
1872 if (pdb && (excluded
1873 || (parent_depth != svn_depth_unknown &&
1874 parent_depth < svn_depth_files)))
1876 fb->shadowed = TRUE;
1878 fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1879 fb->skip_reason = svn_wc_notify_state_missing;
1880 return SVN_NO_ERROR;
1884 fb->tree_conflict_reason = svn_wc_conflict_reason_deleted;
1886 fb->tree_conflict_reason = svn_wc_conflict_reason_missing;
1888 /* ### Similar to directory */
1890 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1891 return SVN_NO_ERROR;
1894 else if (fb->tree_conflict_local_node_kind != svn_node_file)
1896 svn_boolean_t added;
1897 fb->shadowed = TRUE;
1899 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx,
1900 local_abspath, scratch_pool));
1902 fb->tree_conflict_reason = added ? svn_wc_conflict_reason_added
1903 : svn_wc_conflict_reason_obstructed;
1905 /* ### Similar to directory */
1907 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1908 return SVN_NO_ERROR;
1914 /* We want to delete the directory */
1915 fb->tree_conflict_action = svn_wc_conflict_action_delete;
1916 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1920 return SVN_NO_ERROR; /* Already set a tree conflict */
1923 /* Comparison mode to verify for delete tree conflicts? */
1924 if (pdb && pdb->delete_state
1925 && pdb->delete_state->found_edit)
1927 /* Earlier nodes found a conflict. Done. */
1934 const svn_wc_conflict_description2_t *old_tc = NULL;
1936 /* The node doesn't exist pre-merge: We have an addition */
1938 fb->tree_conflict_action = svn_wc_conflict_action_add;
1940 if (pdb && pdb->pending_deletes
1941 && svn_hash_gets(pdb->pending_deletes, local_abspath))
1943 fb->add_is_replace = TRUE;
1944 fb->tree_conflict_action = svn_wc_conflict_action_replace;
1946 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL);
1950 && pdb->new_tree_conflicts
1951 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath)))
1953 fb->tree_conflict_action = svn_wc_conflict_action_replace;
1954 fb->tree_conflict_reason = old_tc->reason;
1956 /* Update the tree conflict to store that this is a replace */
1957 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
1959 old_tc->src_left_version->node_kind,
1961 fb->tree_conflict_action,
1962 fb->tree_conflict_reason,
1966 if (old_tc->reason == svn_wc_conflict_reason_deleted
1967 || old_tc->reason == svn_wc_conflict_reason_moved_away)
1969 /* Issue #3806: Incoming replacements on local deletes produce
1970 inconsistent result.
1972 In this specific case we can continue applying the add part
1973 of the replacement. */
1979 return SVN_NO_ERROR;
1982 else if (! (merge_b->dry_run
1983 && ((pdb && pdb->added) || fb->add_is_replace)))
1985 svn_wc_notify_state_t obstr_state;
1986 svn_boolean_t is_deleted;
1988 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL,
1989 &fb->tree_conflict_local_node_kind,
1990 NULL, merge_b, local_abspath,
1993 if (obstr_state != svn_wc_notify_state_inapplicable)
1995 /* Skip the obstruction */
1996 fb->shadowed = TRUE;
1997 fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1998 fb->skip_reason = obstr_state;
2000 else if (fb->tree_conflict_local_node_kind != svn_node_none
2003 /* Set a tree conflict */
2004 svn_boolean_t added;
2006 fb->shadowed = TRUE;
2007 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx,
2008 local_abspath, scratch_pool));
2010 fb->tree_conflict_reason = added ? svn_wc_conflict_reason_added
2011 : svn_wc_conflict_reason_obstructed;
2015 /* Handle pending conflicts */
2016 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2019 return SVN_NO_ERROR;
2022 /* An svn_diff_tree_processor_t function.
2024 * Called after merge_file_opened() when a node receives only text and/or
2025 * property changes between LEFT_SOURCE and RIGHT_SOURCE.
2027 * left_file and right_file can be NULL when the file is not modified.
2028 * left_props and right_props are always available.
2030 static svn_error_t *
2031 merge_file_changed(const char *relpath,
2032 const svn_diff_source_t *left_source,
2033 const svn_diff_source_t *right_source,
2034 const char *left_file,
2035 const char *right_file,
2036 /*const*/ apr_hash_t *left_props,
2037 /*const*/ apr_hash_t *right_props,
2038 svn_boolean_t file_modified,
2039 const apr_array_header_t *prop_changes,
2041 const struct svn_diff_tree_processor_t *processor,
2042 apr_pool_t *scratch_pool)
2044 merge_cmd_baton_t *merge_b = processor->baton;
2045 struct merge_file_baton_t *fb = file_baton;
2046 svn_client_ctx_t *ctx = merge_b->ctx;
2047 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2048 relpath, scratch_pool);
2049 const svn_wc_conflict_version_t *left;
2050 const svn_wc_conflict_version_t *right;
2051 svn_wc_notify_state_t text_state;
2052 svn_wc_notify_state_t property_state;
2054 SVN_ERR_ASSERT(local_abspath && svn_dirent_is_absolute(local_abspath));
2055 SVN_ERR_ASSERT(!left_file || svn_dirent_is_absolute(left_file));
2056 SVN_ERR_ASSERT(!right_file || svn_dirent_is_absolute(right_file));
2058 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2062 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
2064 /* We haven't notified for this node yet: report a skip */
2065 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
2066 svn_wc_notify_update_shadowed_update,
2067 fb->skip_reason, fb->parent_baton,
2071 return SVN_NO_ERROR;
2074 /* This callback is essentially no more than a wrapper around
2075 svn_wc_merge5(). Thank goodness that all the
2076 diff-editor-mechanisms are doing the hard work of getting the
2079 property_state = svn_wc_notify_state_unchanged;
2080 text_state = svn_wc_notify_state_unchanged;
2082 SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath,
2083 prop_changes, merge_b,
2084 scratch_pool, scratch_pool));
2086 SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
2087 svn_node_file, svn_node_file,
2088 &merge_b->merge_source, merge_b->target,
2089 scratch_pool, scratch_pool));
2091 /* Do property merge now, if we are not going to perform a text merge */
2092 if ((merge_b->record_only || !left_file) && prop_changes->nelts)
2094 SVN_ERR(svn_wc_merge_props3(&property_state, ctx->wc_ctx, local_abspath,
2096 left_props, prop_changes,
2099 ctx->cancel_func, ctx->cancel_baton,
2101 if (property_state == svn_wc_notify_state_conflicted)
2103 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
2108 /* Easy out: We are only applying mergeinfo differences. */
2109 if (merge_b->record_only)
2115 svn_boolean_t has_local_mods;
2116 enum svn_wc_merge_outcome_t content_outcome;
2117 const char *target_label;
2118 const char *left_label;
2119 const char *right_label;
2120 const char *path_ext = "";
2122 if (merge_b->ext_patterns && merge_b->ext_patterns->nelts)
2124 svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool);
2126 && svn_cstring_match_glob_list(path_ext,
2127 merge_b->ext_patterns)))
2133 /* xgettext: the '.working', '.merge-left.r%ld' and
2134 '.merge-right.r%ld' strings are used to tag onto a file
2135 name in case of a merge conflict */
2137 target_label = apr_psprintf(scratch_pool, _(".working%s%s"),
2138 *path_ext ? "." : "", path_ext);
2139 left_label = apr_psprintf(scratch_pool,
2140 _(".merge-left.r%ld%s%s"),
2141 left_source->revision,
2142 *path_ext ? "." : "", path_ext);
2143 right_label = apr_psprintf(scratch_pool,
2144 _(".merge-right.r%ld%s%s"),
2145 right_source->revision,
2146 *path_ext ? "." : "", path_ext);
2148 SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx,
2149 local_abspath, FALSE, scratch_pool));
2151 /* Do property merge and text merge in one step so that keyword expansion
2152 takes into account the new property values. */
2153 SVN_ERR(svn_wc_merge5(&content_outcome, &property_state, ctx->wc_ctx,
2154 left_file, right_file, local_abspath,
2155 left_label, right_label, target_label,
2157 merge_b->dry_run, merge_b->diff3_cmd,
2158 merge_b->merge_options,
2159 left_props, prop_changes,
2165 if (content_outcome == svn_wc_merge_conflict
2166 || property_state == svn_wc_notify_state_conflicted)
2168 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
2172 if (content_outcome == svn_wc_merge_conflict)
2173 text_state = svn_wc_notify_state_conflicted;
2174 else if (has_local_mods
2175 && content_outcome != svn_wc_merge_unchanged)
2176 text_state = svn_wc_notify_state_merged;
2177 else if (content_outcome == svn_wc_merge_merged)
2178 text_state = svn_wc_notify_state_changed;
2179 else if (content_outcome == svn_wc_merge_no_merge)
2180 text_state = svn_wc_notify_state_missing;
2181 else /* merge_outcome == svn_wc_merge_unchanged */
2182 text_state = svn_wc_notify_state_unchanged;
2185 if (text_state == svn_wc_notify_state_conflicted
2186 || text_state == svn_wc_notify_state_merged
2187 || text_state == svn_wc_notify_state_changed
2188 || property_state == svn_wc_notify_state_conflicted
2189 || property_state == svn_wc_notify_state_merged
2190 || property_state == svn_wc_notify_state_changed)
2192 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
2193 text_state, property_state,
2197 return SVN_NO_ERROR;
2200 /* An svn_diff_tree_processor_t function.
2202 * Called after merge_file_opened() when a node doesn't exist in LEFT_SOURCE,
2203 * but does in RIGHT_SOURCE.
2205 * When a node is replaced instead of just added a separate opened+deleted will
2206 * be invoked before the current open+added.
2208 static svn_error_t *
2209 merge_file_added(const char *relpath,
2210 const svn_diff_source_t *copyfrom_source,
2211 const svn_diff_source_t *right_source,
2212 const char *copyfrom_file,
2213 const char *right_file,
2214 /*const*/ apr_hash_t *copyfrom_props,
2215 /*const*/ apr_hash_t *right_props,
2217 const struct svn_diff_tree_processor_t *processor,
2218 apr_pool_t *scratch_pool)
2220 merge_cmd_baton_t *merge_b = processor->baton;
2221 struct merge_file_baton_t *fb = file_baton;
2222 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2223 relpath, scratch_pool);
2224 apr_hash_t *pristine_props;
2225 apr_hash_t *new_props;
2227 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
2229 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2233 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
2235 /* We haven't notified for this node yet: report a skip */
2236 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
2237 svn_wc_notify_update_shadowed_add,
2238 fb->skip_reason, fb->parent_baton,
2242 return SVN_NO_ERROR;
2245 /* Easy out: We are only applying mergeinfo differences. */
2246 if (merge_b->record_only)
2248 return SVN_NO_ERROR;
2251 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
2252 && ( !fb->parent_baton || !fb->parent_baton->added))
2254 /* Store the roots of added subtrees */
2255 store_path(merge_b->added_abspaths, local_abspath);
2258 if (!merge_b->dry_run)
2260 const char *copyfrom_url;
2261 svn_revnum_t copyfrom_rev;
2262 svn_stream_t *new_contents, *pristine_contents;
2264 /* If this is a merge from the same repository as our
2265 working copy, we handle adds as add-with-history.
2266 Otherwise, we'll use a pure add. */
2267 if (merge_b->same_repos)
2270 svn_dirent_skip_ancestor(merge_b->target->abspath,
2272 SVN_ERR_ASSERT(child != NULL);
2273 copyfrom_url = svn_path_url_add_component2(
2274 merge_b->merge_source.loc2->url,
2275 child, scratch_pool);
2276 copyfrom_rev = right_source->revision;
2277 SVN_ERR(check_repos_match(merge_b->target, local_abspath,
2278 copyfrom_url, scratch_pool));
2279 SVN_ERR(svn_stream_open_readonly(&pristine_contents,
2283 new_contents = NULL; /* inherit from new_base_contents */
2285 pristine_props = right_props; /* Includes last_* information */
2286 new_props = NULL; /* No local changes */
2288 if (svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO))
2290 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
2291 local_abspath, merge_b->pool);
2296 apr_array_header_t *regular_props;
2298 copyfrom_url = NULL;
2299 copyfrom_rev = SVN_INVALID_REVNUM;
2301 pristine_contents = svn_stream_empty(scratch_pool);
2302 SVN_ERR(svn_stream_open_readonly(&new_contents, right_file,
2303 scratch_pool, scratch_pool));
2305 pristine_props = apr_hash_make(scratch_pool); /* Local addition */
2307 /* We don't want any foreign properties */
2308 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props,
2310 NULL, NULL, ®ular_props,
2313 new_props = svn_prop_array_to_hash(regular_props, scratch_pool);
2315 /* Issue #3383: We don't want mergeinfo from a foreign repository. */
2316 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
2319 /* Do everything like if we had called 'svn cp PATH1 PATH2'. */
2320 SVN_ERR(svn_wc_add_repos_file4(merge_b->ctx->wc_ctx,
2324 pristine_props, new_props,
2325 copyfrom_url, copyfrom_rev,
2326 merge_b->ctx->cancel_func,
2327 merge_b->ctx->cancel_baton,
2330 /* Caller must call svn_sleep_for_timestamps() */
2331 *merge_b->use_sleep = TRUE;
2334 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_file,
2335 fb->add_is_replace, scratch_pool));
2337 return SVN_NO_ERROR;
2340 /* Compare the two sets of properties PROPS1 and PROPS2, ignoring the
2341 * "svn:mergeinfo" property, and noticing only "normal" props. Set *SAME to
2342 * true if the rest of the properties are identical or false if they differ.
2344 static svn_error_t *
2345 properties_same_p(svn_boolean_t *same,
2348 apr_pool_t *scratch_pool)
2350 apr_array_header_t *prop_changes;
2353 /* Examine the properties that differ */
2354 SVN_ERR(svn_prop_diffs(&prop_changes, props1, props2, scratch_pool));
2356 for (i = 0; i < prop_changes->nelts; i++)
2358 const char *pname = APR_ARRAY_IDX(prop_changes, i, svn_prop_t).name;
2360 /* Count the properties we're interested in; ignore the rest */
2361 if (svn_wc_is_normal_prop(pname)
2362 && strcmp(pname, SVN_PROP_MERGEINFO) != 0)
2365 *same = (diffs == 0);
2366 return SVN_NO_ERROR;
2369 /* Compare the file OLDER_ABSPATH (together with its normal properties in
2370 * ORIGINAL_PROPS which may also contain WC props and entry props) with the
2371 * versioned file MINE_ABSPATH (together with its versioned properties).
2372 * Set *SAME to true if they are the same or false if they differ, ignoring
2373 * the "svn:mergeinfo" property, and ignoring differences in keyword
2374 * expansion and end-of-line style. */
2375 static svn_error_t *
2376 files_same_p(svn_boolean_t *same,
2377 const char *older_abspath,
2378 apr_hash_t *original_props,
2379 const char *mine_abspath,
2380 svn_wc_context_t *wc_ctx,
2381 apr_pool_t *scratch_pool)
2383 apr_hash_t *working_props;
2385 SVN_ERR(svn_wc_prop_list2(&working_props, wc_ctx, mine_abspath,
2386 scratch_pool, scratch_pool));
2388 /* Compare the properties */
2389 SVN_ERR(properties_same_p(same, original_props, working_props,
2393 svn_stream_t *mine_stream;
2394 svn_stream_t *older_stream;
2395 svn_string_t *special = svn_hash_gets(working_props, SVN_PROP_SPECIAL);
2396 svn_string_t *eol_style = svn_hash_gets(working_props, SVN_PROP_EOL_STYLE);
2397 svn_string_t *keywords = svn_hash_gets(working_props, SVN_PROP_KEYWORDS);
2399 /* Compare the file content, translating 'mine' to 'normal' form. */
2400 if (special != NULL)
2401 SVN_ERR(svn_subst_read_specialfile(&mine_stream, mine_abspath,
2402 scratch_pool, scratch_pool));
2404 SVN_ERR(svn_stream_open_readonly(&mine_stream, mine_abspath,
2405 scratch_pool, scratch_pool));
2407 if (!special && (eol_style || keywords))
2409 apr_hash_t *kw = NULL;
2410 const char *eol = NULL;
2411 svn_subst_eol_style_t style;
2413 /* We used to use svn_client__get_normalized_stream() here, but
2414 that doesn't work in 100% of the cases because it doesn't
2415 convert EOLs to the repository form; just to '\n'.
2420 svn_subst_eol_style_from_value(&style, &eol, eol_style->data);
2422 if (style == svn_subst_eol_style_native)
2423 eol = SVN_SUBST_NATIVE_EOL_STR;
2424 else if (style != svn_subst_eol_style_fixed
2425 && style != svn_subst_eol_style_none)
2426 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
2430 SVN_ERR(svn_subst_build_keywords3(&kw, keywords->data, "", "",
2431 "", 0, "", scratch_pool));
2433 mine_stream = svn_subst_stream_translated(
2434 mine_stream, eol, FALSE, kw, FALSE, scratch_pool);
2437 SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath,
2438 scratch_pool, scratch_pool));
2440 SVN_ERR(svn_stream_contents_same2(same, mine_stream, older_stream,
2445 return SVN_NO_ERROR;
2448 /* An svn_diff_tree_processor_t function.
2450 * Called after merge_file_opened() when a node does exist in LEFT_SOURCE, but
2451 * no longer exists (or is replaced) in RIGHT_SOURCE.
2453 * When a node is replaced instead of just added a separate opened+added will
2454 * be invoked after the current open+deleted.
2456 static svn_error_t *
2457 merge_file_deleted(const char *relpath,
2458 const svn_diff_source_t *left_source,
2459 const char *left_file,
2460 /*const*/ apr_hash_t *left_props,
2462 const struct svn_diff_tree_processor_t *processor,
2463 apr_pool_t *scratch_pool)
2465 merge_cmd_baton_t *merge_b = processor->baton;
2466 struct merge_file_baton_t *fb = file_baton;
2467 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2468 relpath, scratch_pool);
2471 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2475 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
2477 /* We haven't notified for this node yet: report a skip */
2478 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
2479 svn_wc_notify_update_shadowed_delete,
2480 fb->skip_reason, fb->parent_baton,
2484 return SVN_NO_ERROR;
2487 /* Easy out: We are only applying mergeinfo differences. */
2488 if (merge_b->record_only)
2490 return SVN_NO_ERROR;
2493 /* If the files are identical, attempt deletion */
2494 if (merge_b->force_delete)
2497 SVN_ERR(files_same_p(&same, left_file, left_props,
2498 local_abspath, merge_b->ctx->wc_ctx,
2501 if (fb->parent_baton
2502 && fb->parent_baton->delete_state)
2506 /* Note that we checked this file */
2507 store_path(fb->parent_baton->delete_state->compared_abspaths,
2512 /* We found some modification. Parent should raise a tree conflict */
2513 fb->parent_baton->delete_state->found_edit = TRUE;
2516 return SVN_NO_ERROR;
2520 if (!merge_b->dry_run)
2521 SVN_ERR(svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath,
2522 FALSE /* keep_local */, FALSE /* unversioned */,
2523 merge_b->ctx->cancel_func,
2524 merge_b->ctx->cancel_baton,
2525 NULL, NULL /* no notify */,
2528 /* Record that we might have deleted mergeinfo */
2529 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
2530 local_abspath, merge_b->pool);
2532 /* And notify the deletion */
2533 SVN_ERR(record_update_delete(merge_b, fb->parent_baton, local_abspath,
2534 svn_node_file, scratch_pool));
2538 /* The files differ, so raise a conflict instead of deleting */
2540 /* This is use case 5 described in the paper attached to issue
2541 * #2282. See also notes/tree-conflicts/detection.txt
2543 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton,
2547 svn_wc_conflict_action_delete,
2548 svn_wc_conflict_reason_edited,
2553 return SVN_NO_ERROR;
2556 /* An svn_diff_tree_processor_t function.
2558 Called before either merge_dir_changed(), merge_dir_added(),
2559 merge_dir_deleted() or merge_dir_closed(), unless it sets *SKIP to TRUE.
2561 After this call and before the close call, all descendants will receive
2562 their changes, unless *SKIP_CHILDREN is set to TRUE.
2564 When *SKIP is TRUE, the diff driver avoids work on getting the details
2565 for the closing callbacks.
2567 The SKIP and SKIP_DESCENDANTS work independently.
2569 static svn_error_t *
2570 merge_dir_opened(void **new_dir_baton,
2571 svn_boolean_t *skip,
2572 svn_boolean_t *skip_children,
2573 const char *relpath,
2574 const svn_diff_source_t *left_source,
2575 const svn_diff_source_t *right_source,
2576 const svn_diff_source_t *copyfrom_source,
2577 void *parent_dir_baton,
2578 const struct svn_diff_tree_processor_t *processor,
2579 apr_pool_t *result_pool,
2580 apr_pool_t *scratch_pool)
2582 merge_cmd_baton_t *merge_b = processor->baton;
2583 struct merge_dir_baton_t *db;
2584 struct merge_dir_baton_t *pdb = parent_dir_baton;
2586 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2587 relpath, scratch_pool);
2589 db = apr_pcalloc(result_pool, sizeof(*db));
2590 db->pool = result_pool;
2591 db->tree_conflict_reason = CONFLICT_REASON_NONE;
2592 db->tree_conflict_action = svn_wc_conflict_action_edit;
2593 db->skip_reason = svn_wc_notify_state_unknown;
2595 *new_dir_baton = db;
2598 db->tree_conflict_merge_left_node_kind = svn_node_dir;
2600 db->tree_conflict_merge_left_node_kind = svn_node_none;
2603 db->tree_conflict_merge_right_node_kind = svn_node_dir;
2605 db->tree_conflict_merge_right_node_kind = svn_node_none;
2609 db->parent_baton = pdb;
2610 db->shadowed = pdb->shadowed;
2611 db->skip_reason = pdb->skip_reason;
2616 /* An ancestor is tree conflicted. Nothing to do here. */
2620 else if (left_source != NULL)
2622 /* Node is expected to be a directory. */
2623 svn_boolean_t is_deleted;
2624 svn_boolean_t excluded;
2625 svn_depth_t parent_depth;
2628 db->tree_conflict_action = svn_wc_conflict_action_delete;
2630 /* Check for an obstructed or missing node on disk. */
2632 svn_wc_notify_state_t obstr_state;
2633 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded,
2634 &db->tree_conflict_local_node_kind,
2635 &parent_depth, merge_b,
2636 local_abspath, scratch_pool));
2638 if (obstr_state != svn_wc_notify_state_inapplicable)
2640 db->shadowed = TRUE;
2642 if (obstr_state == svn_wc_notify_state_obstructed)
2644 svn_boolean_t is_wcroot;
2646 SVN_ERR(svn_wc_check_root(&is_wcroot, NULL, NULL,
2647 merge_b->ctx->wc_ctx,
2648 local_abspath, scratch_pool));
2652 db->tree_conflict_reason = CONFLICT_REASON_SKIP_WC;
2653 return SVN_NO_ERROR;
2657 db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2658 db->skip_reason = obstr_state;
2662 *skip = *skip_children = TRUE;
2663 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath,
2667 return SVN_NO_ERROR;
2671 db->tree_conflict_local_node_kind = svn_node_none;
2674 if (db->tree_conflict_local_node_kind == svn_node_none)
2676 db->shadowed = TRUE;
2678 /* If this is not the merge target and the parent is too shallow to
2679 contain this directory, and the directory is not presen
2680 via exclusion or depth filtering, skip it instead of recording
2683 Non-inheritable mergeinfo will be recorded, allowing
2684 future merges into non-shallow working copies to merge
2685 changes we missed this time around. */
2686 if (pdb && (excluded
2687 || (parent_depth != svn_depth_unknown &&
2688 parent_depth < svn_depth_immediates)))
2690 db->shadowed = TRUE;
2692 db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2693 db->skip_reason = svn_wc_notify_state_missing;
2695 return SVN_NO_ERROR;
2699 db->tree_conflict_reason = svn_wc_conflict_reason_deleted;
2701 db->tree_conflict_reason = svn_wc_conflict_reason_missing;
2703 /* ### To avoid breaking tests */
2705 *skip_children = TRUE;
2706 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2707 return SVN_NO_ERROR;
2708 /* ### /avoid breaking tests */
2710 else if (db->tree_conflict_local_node_kind != svn_node_dir)
2712 svn_boolean_t added;
2714 db->shadowed = TRUE;
2715 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx,
2716 local_abspath, scratch_pool));
2718 db->tree_conflict_reason = added ? svn_wc_conflict_reason_added
2719 : svn_wc_conflict_reason_obstructed;
2721 /* ### To avoid breaking tests */
2723 *skip_children = TRUE;
2724 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2725 return SVN_NO_ERROR;
2726 /* ### /avoid breaking tests */
2731 /* We want to delete the directory */
2732 /* Mark PB edited now? */
2733 db->tree_conflict_action = svn_wc_conflict_action_delete;
2734 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2738 *skip_children = TRUE;
2739 return SVN_NO_ERROR; /* Already set a tree conflict */
2742 db->delete_state = (pdb != NULL) ? pdb->delete_state : NULL;
2744 if (db->delete_state && db->delete_state->found_edit)
2746 /* A sibling found a conflict. Done. */
2748 *skip_children = TRUE;
2750 else if (merge_b->force_delete)
2752 /* No comparison necessary */
2753 *skip_children = TRUE;
2755 else if (! db->delete_state)
2757 /* Start descendant comparison */
2758 db->delete_state = apr_pcalloc(db->pool,
2759 sizeof(*db->delete_state));
2761 db->delete_state->del_root = db;
2762 db->delete_state->compared_abspaths = apr_hash_make(db->pool);
2768 const svn_wc_conflict_description2_t *old_tc = NULL;
2770 /* The node doesn't exist pre-merge: We have an addition */
2772 db->tree_conflict_action = svn_wc_conflict_action_add;
2774 if (pdb && pdb->pending_deletes
2775 && svn_hash_gets(pdb->pending_deletes, local_abspath))
2777 db->add_is_replace = TRUE;
2778 db->tree_conflict_action = svn_wc_conflict_action_replace;
2780 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL);
2784 && pdb->new_tree_conflicts
2785 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath)))
2787 db->tree_conflict_action = svn_wc_conflict_action_replace;
2788 db->tree_conflict_reason = old_tc->reason;
2790 if (old_tc->reason == svn_wc_conflict_reason_deleted
2791 || old_tc->reason == svn_wc_conflict_reason_moved_away)
2793 /* Issue #3806: Incoming replacements on local deletes produce
2794 inconsistent result.
2796 In this specific case we can continue applying the add part
2797 of the replacement. */
2802 *skip_children = TRUE;
2804 /* Update the tree conflict to store that this is a replace */
2805 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
2807 old_tc->src_left_version->node_kind,
2809 db->tree_conflict_action,
2810 db->tree_conflict_reason,
2814 return SVN_NO_ERROR;
2818 if (! (merge_b->dry_run
2819 && ((pdb && pdb->added) || db->add_is_replace)))
2821 svn_wc_notify_state_t obstr_state;
2822 svn_boolean_t is_deleted;
2824 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL,
2825 &db->tree_conflict_local_node_kind,
2826 NULL, merge_b, local_abspath,
2829 /* In this case of adding a directory, we have an exception to the
2830 * usual "skip if it's inconsistent" rule. If the directory exists
2831 * on disk unexpectedly, we simply make it versioned, because we can
2832 * do so without risk of destroying data. Only skip if it is
2833 * versioned but unexpectedly missing from disk, or is unversioned
2834 * but obstructed by a node of the wrong kind. */
2835 if (obstr_state == svn_wc_notify_state_obstructed
2837 db->tree_conflict_local_node_kind == svn_node_none))
2839 svn_node_kind_t disk_kind;
2841 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind,
2844 if (disk_kind == svn_node_dir)
2846 obstr_state = svn_wc_notify_state_inapplicable;
2847 db->add_existing = TRUE; /* Take over existing directory */
2851 if (obstr_state != svn_wc_notify_state_inapplicable)
2853 /* Skip the obstruction */
2854 db->shadowed = TRUE;
2855 db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2856 db->skip_reason = obstr_state;
2858 else if (db->tree_conflict_local_node_kind != svn_node_none
2861 /* Set a tree conflict */
2862 svn_boolean_t added;
2863 db->shadowed = TRUE;
2865 SVN_ERR(svn_wc__node_is_added(&added, merge_b->ctx->wc_ctx,
2866 local_abspath, scratch_pool));
2868 db->tree_conflict_reason = added ? svn_wc_conflict_reason_added
2869 : svn_wc_conflict_reason_obstructed;
2873 /* Handle pending conflicts */
2874 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2878 /* Notified and done. Skip children? */
2880 else if (merge_b->record_only)
2882 /* Ok, we are done for this node and its descendants */
2884 *skip_children = TRUE;
2886 else if (! merge_b->dry_run)
2888 /* Create the directory on disk, to allow descendants to be added */
2889 if (! db->add_existing)
2890 SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT,
2895 /* svn_wc_add4 and svn_wc_add_from_disk3 can't add a node
2896 over an existing tree conflict */
2898 /* ### These functions should take some tree conflict argument
2899 and allow overwriting the tc when one is passed */
2901 SVN_ERR(svn_wc__del_tree_conflict(merge_b->ctx->wc_ctx,
2906 if (merge_b->same_repos)
2908 const char *original_url;
2910 original_url = svn_path_url_add_component2(
2911 merge_b->merge_source.loc2->url,
2912 relpath, scratch_pool);
2914 /* Limitation (aka HACK):
2915 We create a newly added directory with an original URL and
2916 revision as that in the repository, but without its properties
2919 When the merge is cancelled before the final dir_added(), the
2920 copy won't really represent the in-repository state of the node.
2922 SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath,
2925 right_source->revision,
2926 merge_b->ctx->cancel_func,
2927 merge_b->ctx->cancel_baton,
2928 NULL, NULL /* no notify! */,
2933 SVN_ERR(svn_wc_add_from_disk3(merge_b->ctx->wc_ctx, local_abspath,
2934 apr_hash_make(scratch_pool),
2935 FALSE /* skip checks */,
2936 NULL, NULL /* no notify! */,
2942 /* ### Should be atomic with svn_wc_add(4|_from_disk2)() */
2943 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
2947 db->tree_conflict_action,
2948 db->tree_conflict_reason,
2954 if (! db->shadowed && !merge_b->record_only)
2955 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_dir,
2956 db->add_is_replace, scratch_pool));
2958 return SVN_NO_ERROR;
2961 /* An svn_diff_tree_processor_t function.
2963 * Called after merge_dir_opened() when a node exists in both the left and
2964 * right source, but has its properties changed inbetween.
2966 * After the merge_dir_opened() but before the call to this merge_dir_changed()
2967 * function all descendants will have been updated.
2969 static svn_error_t *
2970 merge_dir_changed(const char *relpath,
2971 const svn_diff_source_t *left_source,
2972 const svn_diff_source_t *right_source,
2973 /*const*/ apr_hash_t *left_props,
2974 /*const*/ apr_hash_t *right_props,
2975 const apr_array_header_t *prop_changes,
2977 const struct svn_diff_tree_processor_t *processor,
2978 apr_pool_t *scratch_pool)
2980 merge_cmd_baton_t *merge_b = processor->baton;
2981 struct merge_dir_baton_t *db = dir_baton;
2982 const apr_array_header_t *props;
2983 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2984 relpath, scratch_pool);
2986 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
2988 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2992 if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
2994 /* We haven't notified for this node yet: report a skip */
2995 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
2996 svn_wc_notify_update_shadowed_update,
2997 db->skip_reason, db->parent_baton,
3001 return SVN_NO_ERROR;
3004 SVN_ERR(prepare_merge_props_changed(&props, local_abspath, prop_changes,
3005 merge_b, scratch_pool, scratch_pool));
3009 const svn_wc_conflict_version_t *left;
3010 const svn_wc_conflict_version_t *right;
3011 svn_client_ctx_t *ctx = merge_b->ctx;
3012 svn_wc_notify_state_t prop_state;
3014 SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
3015 svn_node_dir, svn_node_dir,
3016 &merge_b->merge_source,
3018 scratch_pool, scratch_pool));
3020 SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath,
3025 ctx->cancel_func, ctx->cancel_baton,
3028 if (prop_state == svn_wc_notify_state_conflicted)
3030 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
3034 if (prop_state == svn_wc_notify_state_conflicted
3035 || prop_state == svn_wc_notify_state_merged
3036 || prop_state == svn_wc_notify_state_changed)
3038 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
3039 svn_wc_notify_state_inapplicable,
3040 prop_state, scratch_pool));
3044 return SVN_NO_ERROR;
3048 /* An svn_diff_tree_processor_t function.
3050 * Called after merge_dir_opened() when a node doesn't exist in LEFT_SOURCE,
3051 * but does in RIGHT_SOURCE. After the merge_dir_opened() but before the call
3052 * to this merge_dir_added() function all descendants will have been added.
3054 * When a node is replaced instead of just added a separate opened+deleted will
3055 * be invoked before the current open+added.
3057 static svn_error_t *
3058 merge_dir_added(const char *relpath,
3059 const svn_diff_source_t *copyfrom_source,
3060 const svn_diff_source_t *right_source,
3061 /*const*/ apr_hash_t *copyfrom_props,
3062 /*const*/ apr_hash_t *right_props,
3064 const struct svn_diff_tree_processor_t *processor,
3065 apr_pool_t *scratch_pool)
3067 merge_cmd_baton_t *merge_b = processor->baton;
3068 struct merge_dir_baton_t *db = dir_baton;
3069 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
3070 relpath, scratch_pool);
3072 /* For consistency; usually a no-op from _dir_added() */
3073 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
3074 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
3078 if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
3080 /* We haven't notified for this node yet: report a skip */
3081 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
3082 svn_wc_notify_update_shadowed_add,
3083 db->skip_reason, db->parent_baton,
3087 return SVN_NO_ERROR;
3091 db->edited /* Marked edited from merge_open_dir() */
3092 && ! merge_b->record_only /* Skip details from merge_open_dir() */
3095 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
3096 && ( !db->parent_baton || !db->parent_baton->added))
3098 /* Store the roots of added subtrees */
3099 store_path(merge_b->added_abspaths, local_abspath);
3102 if (merge_b->same_repos)
3104 /* When the directory was added in merge_dir_added() we didn't update its
3105 pristine properties. Instead we receive the property changes later and
3106 apply them in this function.
3108 If we would apply them as changes (such as before fixing issue #3405),
3109 we would see the unmodified properties as local changes, and the
3110 pristine properties would be out of sync with what the repository
3111 expects for this directory.
3113 Instead of doing that we now simply set the properties as the pristine
3114 properties via a private libsvn_wc api.
3117 const char *copyfrom_url;
3118 svn_revnum_t copyfrom_rev;
3119 const char *parent_abspath;
3122 /* Creating a hash containing regular and entry props */
3123 apr_hash_t *new_pristine_props = right_props;
3125 parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
3126 child = svn_dirent_is_child(merge_b->target->abspath, local_abspath, NULL);
3127 SVN_ERR_ASSERT(child != NULL);
3129 copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2->url,
3130 child, scratch_pool);
3131 copyfrom_rev = right_source->revision;
3133 SVN_ERR(check_repos_match(merge_b->target, parent_abspath, copyfrom_url,
3136 if (!merge_b->dry_run)
3138 SVN_ERR(svn_wc__complete_directory_add(merge_b->ctx->wc_ctx,
3141 copyfrom_url, copyfrom_rev,
3145 if (svn_hash_gets(new_pristine_props, SVN_PROP_MERGEINFO))
3147 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
3148 local_abspath, merge_b->pool);
3153 apr_array_header_t *regular_props;
3154 apr_hash_t *new_props;
3155 svn_wc_notify_state_t prop_state;
3157 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props,
3159 NULL, NULL, ®ular_props, scratch_pool));
3161 new_props = svn_prop_array_to_hash(regular_props, scratch_pool);
3163 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
3165 /* ### What is the easiest way to set new_props on LOCAL_ABSPATH?
3167 ### This doesn't need a merge as we just added the node
3168 ### (or installed a tree conflict and skipped this node)*/
3170 SVN_ERR(svn_wc_merge_props3(&prop_state, merge_b->ctx->wc_ctx,
3173 apr_hash_make(scratch_pool),
3174 svn_prop_hash_to_array(new_props,
3178 merge_b->ctx->cancel_func,
3179 merge_b->ctx->cancel_baton,
3181 if (prop_state == svn_wc_notify_state_conflicted)
3183 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
3188 return SVN_NO_ERROR;
3191 /* Helper for merge_dir_deleted. Implement svn_wc_status_func4_t */
3192 static svn_error_t *
3193 verify_touched_by_del_check(void *baton,
3194 const char *local_abspath,
3195 const svn_wc_status3_t *status,
3196 apr_pool_t *scratch_pool)
3198 struct dir_delete_baton_t *delb = baton;
3200 if (svn_hash_gets(delb->compared_abspaths, local_abspath))
3201 return SVN_NO_ERROR;
3203 switch (status->node_status)
3205 case svn_wc_status_deleted:
3206 case svn_wc_status_ignored:
3207 case svn_wc_status_none:
3208 return SVN_NO_ERROR;
3211 delb->found_edit = TRUE;
3212 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
3216 /* An svn_diff_tree_processor_t function.
3218 * Called after merge_dir_opened() when a node existed only in the left source.
3220 * After the merge_dir_opened() but before the call to this merge_dir_deleted()
3221 * function all descendants that existed in left_source will have been deleted.
3223 * If this node is replaced, an _opened() followed by a matching _add() will
3224 * be invoked after this function.
3226 static svn_error_t *
3227 merge_dir_deleted(const char *relpath,
3228 const svn_diff_source_t *left_source,
3229 /*const*/ apr_hash_t *left_props,
3231 const struct svn_diff_tree_processor_t *processor,
3232 apr_pool_t *scratch_pool)
3234 merge_cmd_baton_t *merge_b = processor->baton;
3235 struct merge_dir_baton_t *db = dir_baton;
3236 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
3237 relpath, scratch_pool);
3239 apr_hash_t *working_props;
3241 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
3242 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
3246 if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
3248 /* We haven't notified for this node yet: report a skip */
3249 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
3250 svn_wc_notify_update_shadowed_delete,
3251 db->skip_reason, db->parent_baton,
3255 return SVN_NO_ERROR;
3258 /* Easy out: We are only applying mergeinfo differences. */
3259 if (merge_b->record_only)
3261 return SVN_NO_ERROR;
3264 SVN_ERR(svn_wc_prop_list2(&working_props,
3265 merge_b->ctx->wc_ctx, local_abspath,
3266 scratch_pool, scratch_pool));
3268 if (merge_b->force_delete)
3270 /* In this legacy mode we just assume that a directory delete
3271 matches any directory. db->delete_state is NULL */
3276 struct dir_delete_baton_t *delb;
3278 /* Compare the properties */
3279 SVN_ERR(properties_same_p(&same, left_props, working_props,
3281 delb = db->delete_state;
3282 assert(delb != NULL);
3286 delb->found_edit = TRUE;
3290 store_path(delb->compared_abspaths, local_abspath);
3293 if (delb->del_root != db)
3294 return SVN_NO_ERROR;
3296 if (delb->found_edit)
3300 apr_array_header_t *ignores;
3304 SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config,
3307 /* None of the descendants was modified, but maybe there are
3308 descendants we haven't walked?
3310 Note that we aren't interested in changes, as we already verified
3311 changes in the paths touched by the merge. And the existence of
3312 other paths is enough to mark the directory edited */
3313 err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath,
3314 svn_depth_infinity, TRUE /* get-all */,
3315 FALSE /* no-ignore */,
3316 TRUE /* ignore-text-mods */, ignores,
3317 verify_touched_by_del_check, delb,
3318 merge_b->ctx->cancel_func,
3319 merge_b->ctx->cancel_baton,
3324 if (err->apr_err != SVN_ERR_CEASE_INVOCATION)
3325 return svn_error_trace(err);
3327 svn_error_clear(err);
3330 same = ! delb->found_edit;
3334 if (same && !merge_b->dry_run)
3338 err = svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath,
3339 FALSE /* keep_local */, FALSE /* unversioned */,
3340 merge_b->ctx->cancel_func,
3341 merge_b->ctx->cancel_baton,
3342 NULL, NULL /* no notify */,
3347 if (err->apr_err != SVN_ERR_WC_LEFT_LOCAL_MOD)
3348 return svn_error_trace(err);
3350 svn_error_clear(err);
3357 /* If the attempt to delete an existing directory failed,
3358 * the directory has local modifications (e.g. locally added
3359 * files, or property changes). Flag a tree conflict. */
3361 /* This handles use case 5 described in the paper attached to issue
3362 * #2282. See also notes/tree-conflicts/detection.txt
3364 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton,
3368 svn_wc_conflict_action_delete,
3369 svn_wc_conflict_reason_edited,
3375 /* Record that we might have deleted mergeinfo */
3377 && svn_hash_gets(working_props, SVN_PROP_MERGEINFO))
3379 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
3380 local_abspath, merge_b->pool);
3383 SVN_ERR(record_update_delete(merge_b, db->parent_baton, local_abspath,
3384 svn_node_dir, scratch_pool));
3387 return SVN_NO_ERROR;
3390 /* An svn_diff_tree_processor_t function.
3392 * Called after merge_dir_opened() when a node itself didn't change between
3393 * the left and right source.
3395 * After the merge_dir_opened() but before the call to this merge_dir_closed()
3396 * function all descendants will have been processed.
3398 static svn_error_t *
3399 merge_dir_closed(const char *relpath,
3400 const svn_diff_source_t *left_source,
3401 const svn_diff_source_t *right_source,
3403 const struct svn_diff_tree_processor_t *processor,
3404 apr_pool_t *scratch_pool)
3406 merge_cmd_baton_t *merge_b = processor->baton;
3407 struct merge_dir_baton_t *db = dir_baton;
3409 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
3411 return SVN_NO_ERROR;
3414 /* An svn_diff_tree_processor_t function.
3416 Called when the diff driver wants to report an absent path.
3418 In case of merges this happens when the diff encounters a server-excluded
3421 We register a skipped path, which will make parent mergeinfo non-
3422 inheritable. This ensures that a future merge might see these skipped
3423 changes as eligable for merging.
3425 For legacy reasons we also notify the path as skipped.
3427 static svn_error_t *
3428 merge_node_absent(const char *relpath,
3430 const svn_diff_tree_processor_t *processor,
3431 apr_pool_t *scratch_pool)
3433 merge_cmd_baton_t *merge_b = processor->baton;
3434 struct merge_dir_baton_t *db = dir_baton;
3436 const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
3437 relpath, scratch_pool);
3439 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_unknown,
3440 svn_wc_notify_skip, svn_wc_notify_state_missing,
3443 return SVN_NO_ERROR;
3446 /*-----------------------------------------------------------------------*/
3448 /*** Merge Notification ***/
3451 /* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for LOCAL_ABSPATH. If
3452 PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO
3453 where child->abspath == PATH is considered PATH's ancestor. If FALSE,
3454 then child->abspath must be a proper ancestor of PATH.
3456 CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first
3458 static svn_client__merge_path_t *
3459 find_nearest_ancestor(const apr_array_header_t *children_with_mergeinfo,
3460 svn_boolean_t path_is_own_ancestor,
3461 const char *local_abspath)
3465 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL);
3467 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--)
3469 svn_client__merge_path_t *child =
3470 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
3472 if (svn_dirent_is_ancestor(child->abspath, local_abspath)
3473 && (path_is_own_ancestor
3474 || strcmp(child->abspath, local_abspath) != 0))
3480 /* Find the highest level path in a merge target (possibly the merge target
3481 itself) to use in a merge notification header.
3483 Return the svn_client__merge_path_t * representing the most distant
3484 ancestor in CHILDREN_WITH_MERGEINFO of LOCAL_ABSPATH where said
3485 ancestor's first remaining ranges element (per the REMAINING_RANGES
3486 member of the ancestor) intersect with the first remaining ranges element
3487 for every intermediate ancestor svn_client__merge_path_t * of
3488 LOCAL_ABSPATH. If no such ancestor is found return NULL.
3490 If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO
3491 represent a forward merge, then set *START to the oldest revision found
3492 in any of the intersecting ancestors and *END to the youngest revision
3493 found. If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO
3494 represent a reverse merge, then set *START to the youngest revision
3495 found and *END to the oldest revision found. If no ancestors are found
3496 then set *START and *END to SVN_INVALID_REVNUM.
3498 If PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO
3499 where child->abspath == PATH is considered PATH's ancestor. If FALSE,
3500 then child->abspath must be a proper ancestor of PATH.
3502 See the CHILDREN_WITH_MERGEINFO ARRAY global comment for more
3504 static svn_client__merge_path_t *
3505 find_nearest_ancestor_with_intersecting_ranges(
3506 svn_revnum_t *start,
3508 const apr_array_header_t *children_with_mergeinfo,
3509 svn_boolean_t path_is_own_ancestor,
3510 const char *local_abspath)
3513 svn_client__merge_path_t *nearest_ancestor = NULL;
3515 *start = SVN_INVALID_REVNUM;
3516 *end = SVN_INVALID_REVNUM;
3518 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL);
3520 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--)
3522 svn_client__merge_path_t *child =
3523 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
3525 if (svn_dirent_is_ancestor(child->abspath, local_abspath)
3526 && (path_is_own_ancestor
3527 || strcmp(child->abspath, local_abspath) != 0))
3529 if (nearest_ancestor == NULL)
3531 /* Found an ancestor. */
3532 nearest_ancestor = child;
3534 if (child->remaining_ranges)
3536 svn_merge_range_t *r1 = APR_ARRAY_IDX(
3537 child->remaining_ranges, 0, svn_merge_range_t *);
3543 /* If CHILD->REMAINING_RANGES is null then LOCAL_ABSPATH
3544 is inside an absent subtree in the merge target. */
3545 *start = SVN_INVALID_REVNUM;
3546 *end = SVN_INVALID_REVNUM;
3552 /* We'e found another ancestor for LOCAL_ABSPATH. Do its
3553 first remaining range intersect with the previously
3555 svn_merge_range_t *r1 =
3556 APR_ARRAY_IDX(nearest_ancestor->remaining_ranges, 0,
3557 svn_merge_range_t *);
3558 svn_merge_range_t *r2 =
3559 APR_ARRAY_IDX(child->remaining_ranges, 0,
3560 svn_merge_range_t *);
3564 svn_merge_range_t range1;
3565 svn_merge_range_t range2;
3566 svn_boolean_t reverse_merge = r1->start > r2->end;
3568 /* Flip endpoints if this is a reverse merge. */
3571 range1.start = r1->end;
3572 range1.end = r1->start;
3573 range2.start = r2->end;
3574 range2.end = r2->start;
3578 range1.start = r1->start;
3579 range1.end = r1->end;
3580 range2.start = r2->start;
3581 range2.end = r2->end;
3584 if (range1.start < range2.end && range2.start < range1.end)
3586 *start = reverse_merge ?
3587 MAX(r1->start, r2->start) : MIN(r1->start, r2->start);
3588 *end = reverse_merge ?
3589 MIN(r1->end, r2->end) : MAX(r1->end, r2->end);
3590 nearest_ancestor = child;
3596 return nearest_ancestor;
3599 /* Notify that we're starting to record mergeinfo for the merge of the
3600 * revision range RANGE into TARGET_ABSPATH. RANGE should be null if the
3601 * merge sources are not from the same URL.
3603 * This calls the client's notification receiver (as found in the client
3604 * context), with a WC abspath.
3607 notify_mergeinfo_recording(const char *target_abspath,
3608 const svn_merge_range_t *range,
3609 svn_client_ctx_t *ctx,
3612 if (ctx->notify_func2)
3614 svn_wc_notify_t *n = svn_wc_create_notify(
3615 target_abspath, svn_wc_notify_merge_record_info_begin, pool);
3617 n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL;
3618 ctx->notify_func2(ctx->notify_baton2, n, pool);
3622 /* Notify that we're completing the merge into TARGET_ABSPATH.
3624 * This calls the client's notification receiver (as found in the client
3625 * context), with a WC abspath.
3628 notify_merge_completed(const char *target_abspath,
3629 svn_client_ctx_t *ctx,
3632 if (ctx->notify_func2)
3635 = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed,
3637 ctx->notify_func2(ctx->notify_baton2, n, pool);
3641 /* Is the notification the result of a real operative merge? */
3642 #define IS_OPERATIVE_NOTIFICATION(notify) \
3643 (notify->content_state == svn_wc_notify_state_conflicted \
3644 || notify->content_state == svn_wc_notify_state_merged \
3645 || notify->content_state == svn_wc_notify_state_changed \
3646 || notify->prop_state == svn_wc_notify_state_conflicted \
3647 || notify->prop_state == svn_wc_notify_state_merged \
3648 || notify->prop_state == svn_wc_notify_state_changed \
3649 || notify->action == svn_wc_notify_update_add \
3650 || notify->action == svn_wc_notify_tree_conflict)
3653 /* Remove merge source gaps from range used for merge notifications.
3654 See http://subversion.tigris.org/issues/show_bug.cgi?id=4138
3656 If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a
3657 single range (see the implicit_src_gap member of merge_cmd_baton_t).
3658 RANGE describes a (possibly reverse) merge.
3660 If IMPLICIT_SRC_GAP is not NULL and it's sole range intersects with
3661 the older revision in *RANGE, then remove IMPLICIT_SRC_GAP's range
3664 remove_source_gap(svn_merge_range_t *range,
3665 apr_array_header_t *implicit_src_gap)
3667 if (implicit_src_gap)
3669 svn_merge_range_t *gap_range =
3670 APR_ARRAY_IDX(implicit_src_gap, 0, svn_merge_range_t *);
3671 if (range->start < range->end)
3673 if (gap_range->start == range->start)
3674 range->start = gap_range->end;
3676 else /* Reverse merge */
3678 if (gap_range->start == range->end)
3679 range->end = gap_range->end;
3684 /* Notify that we're starting a merge
3686 * This calls the client's notification receiver (as found in the client
3687 * context), with a WC abspath.
3689 static svn_error_t *
3690 notify_merge_begin(merge_cmd_baton_t *merge_b,
3691 const char *local_abspath,
3692 svn_boolean_t delete_action,
3693 apr_pool_t *scratch_pool)
3695 svn_wc_notify_t *notify;
3696 svn_merge_range_t n_range =
3697 {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE};
3698 const char *notify_abspath;
3700 if (! merge_b->ctx->notify_func2)
3701 return SVN_NO_ERROR;
3703 /* If our merge sources are ancestors of one another... */
3704 if (merge_b->merge_source.ancestral)
3706 const svn_client__merge_path_t *child;
3707 /* Find NOTIFY->PATH's nearest ancestor in
3708 NOTIFY->CHILDREN_WITH_MERGEINFO. Normally we consider a child in
3709 NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an
3710 ancestor of PATH, but if this is a deletion of PATH then the
3711 notification must be for a proper ancestor of PATH. This ensures
3712 we don't get notifications like:
3714 --- Merging rX into 'PARENT/CHILD'
3719 --- Merging rX into 'PARENT'
3723 child = find_nearest_ancestor_with_intersecting_ranges(
3724 &(n_range.start), &(n_range.end),
3725 merge_b->notify_begin.nodes_with_mergeinfo,
3726 ! delete_action, local_abspath);
3728 if (!child && delete_action)
3730 /* Triggered by file replace in single-file-merge */
3731 child = find_nearest_ancestor(merge_b->notify_begin.nodes_with_mergeinfo,
3732 TRUE, local_abspath);
3735 assert(child != NULL); /* Should always find the merge anchor */
3738 return SVN_NO_ERROR;
3740 if (merge_b->notify_begin.last_abspath != NULL
3741 && strcmp(child->abspath, merge_b->notify_begin.last_abspath) == 0)
3743 /* Don't notify the same merge again */
3744 return SVN_NO_ERROR;
3747 merge_b->notify_begin.last_abspath = child->abspath;
3749 if (child->absent || child->remaining_ranges->nelts == 0
3750 || !SVN_IS_VALID_REVNUM(n_range.start))
3752 /* No valid information for an header */
3753 return SVN_NO_ERROR;
3756 notify_abspath = child->abspath;
3760 if (merge_b->notify_begin.last_abspath)
3761 return SVN_NO_ERROR; /* already notified */
3763 notify_abspath = merge_b->target->abspath;
3764 /* Store something in last_abspath. Any value would do */
3765 merge_b->notify_begin.last_abspath = merge_b->target->abspath;
3768 notify = svn_wc_create_notify(notify_abspath,
3770 ? svn_wc_notify_merge_begin
3771 : svn_wc_notify_foreign_merge_begin,
3774 if (SVN_IS_VALID_REVNUM(n_range.start))
3776 /* If the merge source has a gap, then don't mention
3777 those gap revisions in the notification. */
3778 remove_source_gap(&n_range, merge_b->implicit_src_gap);
3779 notify->merge_range = &n_range;
3783 notify->merge_range = NULL;
3786 merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
3789 return SVN_NO_ERROR;
3792 /* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple
3793 * (inheritable) revision range REV1:REV2, according to CONSIDER_INHERITANCE.
3794 * If REV1 is equal to REV2, the result is an empty rangelist, otherwise
3795 * REV1 must be less than REV2.
3797 * Note: If CONSIDER_INHERITANCE is FALSE, the effect is to treat any non-
3798 * inheritable input ranges as if they were inheritable. If it is TRUE, the
3799 * effect is to discard any non-inheritable input ranges. Therefore the
3800 * ranges in *OUT_RANGELIST will always be inheritable. */
3801 static svn_error_t *
3802 rangelist_intersect_range(svn_rangelist_t **out_rangelist,
3803 const svn_rangelist_t *in_rangelist,
3806 svn_boolean_t consider_inheritance,
3807 apr_pool_t *result_pool,
3808 apr_pool_t *scratch_pool)
3810 SVN_ERR_ASSERT(rev1 <= rev2);
3814 svn_rangelist_t *simple_rangelist =
3815 svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool);
3817 SVN_ERR(svn_rangelist_intersect(out_rangelist,
3818 simple_rangelist, in_rangelist,
3819 consider_inheritance, result_pool));
3823 *out_rangelist = apr_array_make(result_pool, 0,
3824 sizeof(svn_merge_range_t *));
3826 return SVN_NO_ERROR;
3829 /* Helper for fix_deleted_subtree_ranges(). Like fix_deleted_subtree_ranges()
3830 this function should only be called when honoring mergeinfo.
3832 CHILD, PARENT, REVISION1, REVISION2, and RA_SESSION are all cascaded from
3833 fix_deleted_subtree_ranges() -- see that function for more information on
3836 If PARENT is not the merge target then PARENT must have already have been
3837 processed by this function as a child. Specifically, this means that
3838 PARENT->REMAINING_RANGES must already be populated -- it can be an empty
3839 rangelist but cannot be NULL.
3841 PRIMARY_URL is the merge source url of CHILD at the younger of REVISION1
3844 Since this function is only invoked for subtrees of the merge target, the
3845 guarantees afforded by normalize_merge_sources() don't apply - see the
3846 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file.
3847 Therefore it is possible that PRIMARY_URL@REVISION1 and
3848 PRIMARY_URL@REVISION2 don't describe the endpoints of an unbroken line of
3849 history. The purpose of this helper is to identify these cases of broken
3850 history and adjust CHILD->REMAINING_RANGES in such a way we don't later try
3851 to describe nonexistent path/revisions to the merge report editor -- see
3852 drive_merge_report_editor().
3854 If PRIMARY_URL@REVISION1 and PRIMARY_URL@REVISION2 describe an unbroken
3855 line of history then do nothing and leave CHILD->REMAINING_RANGES as-is.
3857 If neither PRIMARY_URL@REVISION1 nor PRIMARY_URL@REVISION2 exist then
3858 there is nothing to merge to CHILD->ABSPATH so set CHILD->REMAINING_RANGES
3859 equal to PARENT->REMAINING_RANGES. This will cause the subtree to
3860 effectively ignore CHILD -- see 'Note: If the first svn_merge_range_t...'
3861 in drive_merge_report_editor()'s doc string.
3863 If PRIMARY_URL@REVISION1 *xor* PRIMARY_URL@REVISION2 exist then we take the
3864 subset of REVISION1:REVISION2 in CHILD->REMAINING_RANGES at which
3865 PRIMARY_URL doesn't exist and set that subset equal to
3866 PARENT->REMAINING_RANGES' intersection with that non-existent range. Why?
3867 Because this causes CHILD->REMAINING_RANGES to be identical to
3868 PARENT->REMAINING_RANGES for revisions between REVISION1 and REVISION2 at
3869 which PRIMARY_URL doesn't exist. As mentioned above this means that
3870 drive_merge_report_editor() won't attempt to describe these non-existent
3871 subtree path/ranges to the reporter (which would break the merge).
3873 If the preceding paragraph wasn't terribly clear then what follows spells
3874 out this function's behavior a bit more explicitly:
3876 For forward merges (REVISION1 < REVISION2)
3878 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
3879 find the revision 'N' in which PRIMARY_URL@REVISION1 was deleted. Leave
3880 the subset of CHILD->REMAINING_RANGES that intersects with
3881 REVISION1:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3882 that intersects with (N - 1):REVISION2 equal to PARENT->REMAINING_RANGES'
3883 intersection with (N - 1):REVISION2.
3885 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
3886 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
3887 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with
3888 (M - 1):REVISION2 as-is and set the subset of CHILD->REMAINING_RANGES
3889 that intersects with REVISION1:(M - 1) equal to PARENT->REMAINING_RANGES'
3890 intersection with REVISION1:(M - 1).
3892 For reverse merges (REVISION1 > REVISION2)
3894 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
3895 find the revision 'N' in which PRIMARY_URL@REVISION1 came into existence.
3896 Leave the subset of CHILD->REMAINING_RANGES that intersects with
3897 REVISION2:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3898 that intersects with (N - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
3899 intersection with (N - 1):REVISION1.
3901 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
3902 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
3903 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with
3904 REVISION2:(M - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3905 that intersects with (M - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
3906 intersection with REVISION1:(M - 1).
3908 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD are
3909 allocated in RESULT_POOL. */
3910 static svn_error_t *
3911 adjust_deleted_subtree_ranges(svn_client__merge_path_t *child,
3912 svn_client__merge_path_t *parent,
3913 svn_revnum_t revision1,
3914 svn_revnum_t revision2,
3915 const char *primary_url,
3916 svn_ra_session_t *ra_session,
3917 svn_client_ctx_t *ctx,
3918 apr_pool_t *result_pool,
3919 apr_pool_t *scratch_pool)
3921 svn_boolean_t is_rollback = revision2 < revision1;
3922 svn_revnum_t younger_rev = is_rollback ? revision1 : revision2;
3923 svn_revnum_t peg_rev = younger_rev;
3924 svn_revnum_t older_rev = is_rollback ? revision2 : revision1;
3925 apr_array_header_t *segments;
3928 SVN_ERR_ASSERT(parent->remaining_ranges);
3930 err = svn_client__repos_location_segments(&segments, ra_session,
3931 primary_url, peg_rev,
3932 younger_rev, older_rev, ctx,
3937 const char *rel_source_path; /* PRIMARY_URL relative to RA_SESSION */
3938 svn_node_kind_t kind;
3940 if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
3941 return svn_error_trace(err);
3943 svn_error_clear(err);
3945 /* PRIMARY_URL@peg_rev doesn't exist. Check if PRIMARY_URL@older_rev
3946 exists, if neither exist then the editor can simply ignore this
3949 SVN_ERR(svn_ra_get_path_relative_to_session(
3950 ra_session, &rel_source_path, primary_url, scratch_pool));
3952 SVN_ERR(svn_ra_check_path(ra_session, rel_source_path,
3953 older_rev, &kind, scratch_pool));
3954 if (kind == svn_node_none)
3956 /* Neither PRIMARY_URL@peg_rev nor PRIMARY_URL@older_rev exist,
3957 so there is nothing to merge. Set CHILD->REMAINING_RANGES
3958 identical to PARENT's. */
3959 child->remaining_ranges =
3960 svn_rangelist_dup(parent->remaining_ranges, scratch_pool);
3964 svn_rangelist_t *deleted_rangelist;
3965 svn_revnum_t rev_primary_url_deleted;
3967 /* PRIMARY_URL@older_rev exists, so it was deleted at some
3968 revision prior to peg_rev, find that revision. */
3969 SVN_ERR(svn_ra_get_deleted_rev(ra_session, rel_source_path,
3970 older_rev, younger_rev,
3971 &rev_primary_url_deleted,
3974 /* PRIMARY_URL@older_rev exists and PRIMARY_URL@peg_rev doesn't,
3975 so svn_ra_get_deleted_rev() should always find the revision
3976 PRIMARY_URL@older_rev was deleted. */
3977 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev_primary_url_deleted));
3979 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and
3980 PARENT->REMAINING_RANGES so both will work with the
3981 svn_rangelist_* APIs below. */
3984 /* svn_rangelist_reverse operates in place so it's safe
3985 to use our scratch_pool. */
3986 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
3988 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
3992 /* Find the intersection of CHILD->REMAINING_RANGES with the
3993 range over which PRIMARY_URL@older_rev exists (ending at
3994 the youngest revision at which it still exists). */
3995 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges,
3996 child->remaining_ranges,
3998 rev_primary_url_deleted - 1,
4000 scratch_pool, scratch_pool));
4002 /* Merge into CHILD->REMAINING_RANGES the intersection of
4003 PARENT->REMAINING_RANGES with the range beginning when
4004 PRIMARY_URL@older_rev was deleted until younger_rev. */
4005 SVN_ERR(rangelist_intersect_range(&deleted_rangelist,
4006 parent->remaining_ranges,
4007 rev_primary_url_deleted - 1,
4010 scratch_pool, scratch_pool));
4011 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
4012 deleted_rangelist, scratch_pool,
4015 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES
4016 to reverse order if necessary. */
4019 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
4021 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
4026 else /* PRIMARY_URL@peg_rev exists. */
4028 svn_rangelist_t *non_existent_rangelist;
4029 svn_location_segment_t *segment =
4030 APR_ARRAY_IDX(segments, (segments->nelts - 1),
4031 svn_location_segment_t *);
4033 /* We know PRIMARY_URL@peg_rev exists as the call to
4034 svn_client__repos_location_segments() succeeded. If there is only
4035 one segment that starts at oldest_rev then we know that
4036 PRIMARY_URL@oldest_rev:PRIMARY_URL@peg_rev describes an unbroken
4037 line of history, so there is nothing more to adjust in
4038 CHILD->REMAINING_RANGES. */
4039 if (segment->range_start == older_rev)
4041 return SVN_NO_ERROR;
4044 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and
4045 PARENT->REMAINING_RANGES so both will work with the
4046 svn_rangelist_* APIs below. */
4049 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
4051 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
4055 /* Intersect CHILD->REMAINING_RANGES with the range where PRIMARY_URL
4056 exists. Since segment doesn't span older_rev:peg_rev we know
4057 PRIMARY_URL@peg_rev didn't come into existence until
4058 segment->range_start + 1. */
4059 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges,
4060 child->remaining_ranges,
4061 segment->range_start, peg_rev,
4062 FALSE, scratch_pool, scratch_pool));
4064 /* Merge into CHILD->REMAINING_RANGES the intersection of
4065 PARENT->REMAINING_RANGES with the range before PRIMARY_URL@peg_rev
4066 came into existence. */
4067 SVN_ERR(rangelist_intersect_range(&non_existent_rangelist,
4068 parent->remaining_ranges,
4069 older_rev, segment->range_start,
4070 FALSE, scratch_pool, scratch_pool));
4071 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
4072 non_existent_rangelist, scratch_pool,
4075 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES
4076 to reverse order if necessary. */
4079 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
4081 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
4086 /* Make a lasting copy of CHILD->REMAINING_RANGES using POOL. */
4087 child->remaining_ranges = svn_rangelist_dup(child->remaining_ranges,
4089 return SVN_NO_ERROR;
4092 /* Helper for do_directory_merge().
4094 SOURCE is cascaded from the argument of the same name in
4095 do_directory_merge(). TARGET is the merge target. RA_SESSION is the
4096 session for the younger of SOURCE->loc1 and SOURCE->loc2.
4098 Adjust the subtrees in CHILDREN_WITH_MERGEINFO so that we don't
4099 later try to describe invalid paths in drive_merge_report_editor().
4100 This function is just a thin wrapper around
4101 adjust_deleted_subtree_ranges(), which see for further details.
4103 SCRATCH_POOL is used for all temporary allocations. Changes to
4104 CHILDREN_WITH_MERGEINFO are allocated in RESULT_POOL.
4106 static svn_error_t *
4107 fix_deleted_subtree_ranges(const merge_source_t *source,
4108 const merge_target_t *target,
4109 svn_ra_session_t *ra_session,
4110 apr_array_header_t *children_with_mergeinfo,
4111 svn_client_ctx_t *ctx,
4112 apr_pool_t *result_pool,
4113 apr_pool_t *scratch_pool)
4116 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
4117 svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev;
4119 assert(session_url_is(ra_session,
4120 (is_rollback ? source->loc1 : source->loc2)->url,
4123 /* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so
4124 start at index 1 to examine only subtrees. */
4125 for (i = 1; i < children_with_mergeinfo->nelts; i++)
4127 svn_client__merge_path_t *child =
4128 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
4129 svn_client__merge_path_t *parent;
4130 svn_rangelist_t *deleted_rangelist, *added_rangelist;
4132 SVN_ERR_ASSERT(child);
4136 svn_pool_clear(iterpool);
4138 /* Find CHILD's parent. */
4139 parent = find_nearest_ancestor(children_with_mergeinfo,
4140 FALSE, child->abspath);
4142 /* Since CHILD is a subtree then its parent must be in
4143 CHILDREN_WITH_MERGEINFO, see the global comment
4144 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
4145 SVN_ERR_ASSERT(parent);
4147 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
4148 so it will work with the svn_rangelist_diff API. */
4151 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
4152 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool));
4155 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
4156 child->remaining_ranges,
4157 parent->remaining_ranges,
4162 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
4163 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool));
4166 /* If CHILD is the merge target we then know that SOURCE is provided
4167 by normalize_merge_sources() -- see 'MERGEINFO MERGE SOURCE
4168 NORMALIZATION'. Due to this normalization we know that SOURCE
4169 describes an unbroken line of history such that the entire range
4170 described by SOURCE can potentially be merged to CHILD.
4172 But if CHILD is a subtree we don't have the same guarantees about
4173 SOURCE as we do for the merge target. SOURCE->loc1 and/or
4174 SOURCE->loc2 might not exist.
4176 If one or both doesn't exist, then adjust CHILD->REMAINING_RANGES
4177 such that we don't later try to describe invalid subtrees in
4178 drive_merge_report_editor(), as that will break the merge.
4179 If CHILD has the same remaining ranges as PARENT however, then
4180 there is no need to make these adjustments, since
4181 drive_merge_report_editor() won't attempt to describe CHILD in this
4182 case, see the 'Note' in drive_merge_report_editor's docstring. */
4183 if (deleted_rangelist->nelts || added_rangelist->nelts)
4185 const char *child_primary_source_url;
4186 const char *child_repos_src_path =
4187 svn_dirent_is_child(target->abspath, child->abspath, iterpool);
4189 /* This loop is only processing subtrees, so CHILD->ABSPATH
4190 better be a proper child of the merge target. */
4191 SVN_ERR_ASSERT(child_repos_src_path);
4193 child_primary_source_url =
4194 svn_path_url_add_component2((source->loc1->rev < source->loc2->rev)
4195 ? source->loc2->url : source->loc1->url,
4196 child_repos_src_path, iterpool);
4198 SVN_ERR(adjust_deleted_subtree_ranges(child, parent,
4201 child_primary_source_url,
4203 ctx, result_pool, iterpool));
4207 svn_pool_destroy(iterpool);
4208 return SVN_NO_ERROR;
4211 /*-----------------------------------------------------------------------*/
4213 /*** Determining What Remains To Be Merged ***/
4215 /* Get explicit and/or implicit mergeinfo for the working copy path
4218 If RECORDED_MERGEINFO is not NULL then set *RECORDED_MERGEINFO
4219 to TARGET_ABSPATH's explicit or inherited mergeinfo as dictated by
4222 If IMPLICIT_MERGEINFO is not NULL then set *IMPLICIT_MERGEINFO
4223 to TARGET_ABSPATH's implicit mergeinfo (a.k.a. natural history).
4225 If both RECORDED_MERGEINFO and IMPLICIT_MERGEINFO are not NULL and
4226 *RECORDED_MERGEINFO is inherited, then *IMPLICIT_MERGEINFO will be
4227 removed from *RECORDED_MERGEINFO.
4229 If INHERITED is not NULL set *INHERITED to TRUE if *RECORDED_MERGEINFO
4230 is inherited rather than explicit. If RECORDED_MERGEINFO is NULL then
4231 INHERITED is ignored.
4234 If IMPLICIT_MERGEINFO is not NULL then START and END are limits on
4235 the natural history sought, must both be valid revision numbers, and
4236 START must be greater than END. If TARGET_ABSPATH's base revision
4237 is older than START, then the base revision is used as the younger
4238 bound in place of START.
4240 RA_SESSION is an RA session open to the repository in which TARGET_ABSPATH
4241 lives. It may be temporarily reparented as needed by this function.
4243 Allocate *RECORDED_MERGEINFO and *IMPLICIT_MERGEINFO in RESULT_POOL.
4244 Use SCRATCH_POOL for any temporary allocations. */
4245 static svn_error_t *
4246 get_full_mergeinfo(svn_mergeinfo_t *recorded_mergeinfo,
4247 svn_mergeinfo_t *implicit_mergeinfo,
4248 svn_boolean_t *inherited,
4249 svn_mergeinfo_inheritance_t inherit,
4250 svn_ra_session_t *ra_session,
4251 const char *target_abspath,
4254 svn_client_ctx_t *ctx,
4255 apr_pool_t *result_pool,
4256 apr_pool_t *scratch_pool)
4258 /* First, we get the real mergeinfo. */
4259 if (recorded_mergeinfo)
4261 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(recorded_mergeinfo,
4263 NULL /* from_repos */,
4265 inherit, ra_session,
4270 if (implicit_mergeinfo)
4272 svn_client__pathrev_t *target;
4274 /* Assert that we have sane input. */
4275 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start) && SVN_IS_VALID_REVNUM(end)
4278 /* Retrieve the origin (original_*) of the node, or just the
4279 url if the node was not copied. */
4280 SVN_ERR(svn_client__wc_node_get_origin(&target, target_abspath, ctx,
4281 scratch_pool, scratch_pool));
4285 /* We've been asked to operate on a locally added target, so its
4286 * implicit mergeinfo is empty. */
4287 *implicit_mergeinfo = apr_hash_make(result_pool);
4289 else if (target->rev <= end)
4291 /* We're asking about a range outside our natural history
4292 altogether. That means our implicit mergeinfo is empty. */
4293 *implicit_mergeinfo = apr_hash_make(result_pool);
4297 /* Fetch so-called "implicit mergeinfo" (that is, natural
4300 /* Do not ask for implicit mergeinfo from TARGET_ABSPATH's future.
4301 TARGET_ABSPATH might not even exist, and even if it does the
4302 working copy is *at* TARGET_REV so its implicit history ends
4304 if (target->rev < start)
4305 start = target->rev;
4307 /* Fetch the implicit mergeinfo. */
4308 SVN_ERR(svn_client__get_history_as_mergeinfo(implicit_mergeinfo,
4314 } /*if (implicit_mergeinfo) */
4316 return SVN_NO_ERROR;
4319 /* Helper for ensure_implicit_mergeinfo().
4321 PARENT, CHILD, REVISION1, REVISION2 and CTX
4322 are all cascaded from the arguments of the same names in
4323 ensure_implicit_mergeinfo(). PARENT and CHILD must both exist, i.e.
4324 this function should never be called where CHILD is the merge target.
4326 If PARENT->IMPLICIT_MERGEINFO is NULL, obtain it from the server.
4328 Set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from
4329 PARENT->IMPLICIT_MERGEINFO. CHILD->IMPLICIT_MERGEINFO is allocated
4332 RA_SESSION is an RA session open to the repository that contains CHILD.
4333 It may be temporarily reparented by this function.
4335 static svn_error_t *
4336 inherit_implicit_mergeinfo_from_parent(svn_client__merge_path_t *parent,
4337 svn_client__merge_path_t *child,
4338 svn_revnum_t revision1,
4339 svn_revnum_t revision2,
4340 svn_ra_session_t *ra_session,
4341 svn_client_ctx_t *ctx,
4342 apr_pool_t *result_pool,
4343 apr_pool_t *scratch_pool)
4345 const char *path_diff;
4347 /* This only works on subtrees! */
4348 SVN_ERR_ASSERT(parent);
4349 SVN_ERR_ASSERT(child);
4351 /* While PARENT must exist, it is possible we've deferred
4352 getting its implicit mergeinfo. If so get it now. */
4353 if (!parent->implicit_mergeinfo)
4354 SVN_ERR(get_full_mergeinfo(NULL, &(parent->implicit_mergeinfo),
4355 NULL, svn_mergeinfo_inherited,
4356 ra_session, child->abspath,
4357 MAX(revision1, revision2),
4358 MIN(revision1, revision2),
4359 ctx, result_pool, scratch_pool));
4361 /* Let CHILD inherit PARENT's implicit mergeinfo. */
4363 path_diff = svn_dirent_is_child(parent->abspath, child->abspath,
4365 /* PARENT->PATH better be an ancestor of CHILD->ABSPATH! */
4366 SVN_ERR_ASSERT(path_diff);
4368 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
4369 &child->implicit_mergeinfo, parent->implicit_mergeinfo,
4370 path_diff, result_pool, scratch_pool));
4371 child->implicit_mergeinfo = svn_mergeinfo_dup(child->implicit_mergeinfo,
4373 return SVN_NO_ERROR;
4376 /* Helper of filter_merged_revisions().
4378 If we have deferred obtaining CHILD->IMPLICIT_MERGEINFO, then get
4379 it now, allocating it in RESULT_POOL. If CHILD_INHERITS_PARENT is true
4380 then set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from
4381 PARENT->IMPLICIT_MERGEINFO, otherwise contact the repository. Use
4382 SCRATCH_POOL for all temporary allocations.
4384 RA_SESSION is an RA session open to the repository that contains CHILD.
4385 It may be temporarily reparented by this function.
4387 PARENT, CHILD, REVISION1, REVISION2 and
4388 CTX are all cascaded from the arguments of the same name in
4389 filter_merged_revisions() and the same conditions for that function
4391 static svn_error_t *
4392 ensure_implicit_mergeinfo(svn_client__merge_path_t *parent,
4393 svn_client__merge_path_t *child,
4394 svn_boolean_t child_inherits_parent,
4395 svn_revnum_t revision1,
4396 svn_revnum_t revision2,
4397 svn_ra_session_t *ra_session,
4398 svn_client_ctx_t *ctx,
4399 apr_pool_t *result_pool,
4400 apr_pool_t *scratch_pool)
4402 /* If we haven't already found CHILD->IMPLICIT_MERGEINFO then
4403 contact the server to get it. */
4405 if (child->implicit_mergeinfo)
4406 return SVN_NO_ERROR;
4408 if (child_inherits_parent)
4409 SVN_ERR(inherit_implicit_mergeinfo_from_parent(parent,
4418 SVN_ERR(get_full_mergeinfo(NULL,
4419 &(child->implicit_mergeinfo),
4420 NULL, svn_mergeinfo_inherited,
4421 ra_session, child->abspath,
4422 MAX(revision1, revision2),
4423 MIN(revision1, revision2),
4424 ctx, result_pool, scratch_pool));
4426 return SVN_NO_ERROR;
4429 /* Helper for calculate_remaining_ranges().
4431 Initialize CHILD->REMAINING_RANGES to a rangelist representing the
4432 requested merge of REVISION1:REVISION2 from MERGEINFO_PATH to
4435 For forward merges remove any ranges from CHILD->REMAINING_RANGES that
4436 have already been merged to CHILD->ABSPATH per TARGET_MERGEINFO or
4437 CHILD->IMPLICIT_MERGEINFO. For reverse merges remove any ranges from
4438 CHILD->REMAINING_RANGES that have not already been merged to CHILD->ABSPATH
4439 per TARGET_MERGEINFO or CHILD->IMPLICIT_MERGEINFO. If we have deferred
4440 obtaining CHILD->IMPLICIT_MERGEINFO and it is necessary to use it for
4441 these calculations, then get it from the server, allocating it in
4444 CHILD represents a working copy path which is the merge target or one of
4445 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise
4446 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'.
4448 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
4449 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
4450 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact
4451 the repository for CHILD->IMPLICIT_MERGEINFO.
4453 NOTE: If PARENT is present then this function must have previously been
4454 called for PARENT, i.e. if populate_remaining_ranges() is calling this
4455 function for a set of svn_client__merge_path_t* the calls must be made
4456 in depth-first order.
4458 MERGEINFO_PATH is the merge source relative to the repository root.
4460 REVISION1 and REVISION2 describe the merge range requested from
4463 TARGET_RANGELIST is the portion of CHILD->ABSPATH's explicit or inherited
4464 mergeinfo that intersects with the merge history described by
4465 MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2. TARGET_RANGELIST
4466 should be NULL if there is no explicit or inherited mergeinfo on
4467 CHILD->ABSPATH or an empty list if CHILD->ABSPATH has empty mergeinfo or
4468 explicit mergeinfo that exclusively describes non-intersecting history
4469 with MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.
4471 SCRATCH_POOL is used for all temporary allocations.
4473 NOTE: This should only be called when honoring mergeinfo.
4475 NOTE: Like calculate_remaining_ranges() if PARENT is present then this
4476 function must have previously been called for PARENT.
4478 static svn_error_t *
4479 filter_merged_revisions(svn_client__merge_path_t *parent,
4480 svn_client__merge_path_t *child,
4481 const char *mergeinfo_path,
4482 svn_rangelist_t *target_rangelist,
4483 svn_revnum_t revision1,
4484 svn_revnum_t revision2,
4485 svn_boolean_t child_inherits_implicit,
4486 svn_ra_session_t *ra_session,
4487 svn_client_ctx_t *ctx,
4488 apr_pool_t *result_pool,
4489 apr_pool_t *scratch_pool)
4491 svn_rangelist_t *requested_rangelist,
4492 *target_implicit_rangelist, *explicit_rangelist;
4494 /* Convert REVISION1 and REVISION2 to a rangelist.
4496 Note: Talking about a requested merge range's inheritability
4497 doesn't make much sense, but as we are using svn_merge_range_t
4498 to describe it we need to pick *something*. Since all the
4499 rangelist manipulations in this function either don't consider
4500 inheritance by default or we are requesting that they don't (i.e.
4501 svn_rangelist_remove and svn_rangelist_intersect) then we could
4502 set the inheritability as FALSE, it won't matter either way. */
4503 requested_rangelist = svn_rangelist__initialize(revision1, revision2,
4504 TRUE, scratch_pool);
4506 /* Now filter out revisions that have already been merged to CHILD. */
4508 if (revision1 > revision2) /* This is a reverse merge. */
4510 svn_rangelist_t *added_rangelist, *deleted_rangelist;
4512 /* The revert range and will need to be reversed for
4513 our svn_rangelist_* APIs to work properly. */
4514 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool));
4516 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
4517 already recorded as merged to target. */
4518 if (target_rangelist)
4520 /* Return the intersection of the revs which are both already
4521 represented by CHILD's explicit or inherited mergeinfo.
4523 We don't consider inheritance when determining intersecting
4524 ranges. If we *did* consider inheritance, then our calculation
4525 would be wrong. For example, if the CHILD->REMAINING_RANGES is
4526 5:3 and TARGET_RANGELIST is r5* (non-inheritable) then the
4527 intersection would be r4. And that would be wrong as we clearly
4528 want to reverse merge both r4 and r5 in this case. Ignoring the
4529 ranges' inheritance results in an intersection of r4-5.
4531 You might be wondering about CHILD's children, doesn't the above
4532 imply that we will reverse merge r4-5 from them? Nope, this is
4533 safe to do because any path whose parent has non-inheritable
4534 ranges is always considered a subtree with differing mergeinfo
4535 even if that path has no explicit mergeinfo prior to the
4536 merge -- See condition 3 in the doc string for
4537 merge.c:get_mergeinfo_paths(). */
4538 SVN_ERR(svn_rangelist_intersect(&explicit_rangelist,
4540 requested_rangelist,
4541 FALSE, scratch_pool));
4545 explicit_rangelist =
4546 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *));
4549 /* Was any part of the requested reverse merge not accounted for in
4550 CHILD's explicit or inherited mergeinfo? */
4551 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
4552 requested_rangelist, explicit_rangelist,
4553 FALSE, scratch_pool));
4555 if (deleted_rangelist->nelts == 0)
4557 /* The whole of REVISION1:REVISION2 was represented in CHILD's
4558 explicit/inherited mergeinfo, allocate CHILD's remaining
4559 ranges in POOL and then we are done. */
4560 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool));
4561 child->remaining_ranges = svn_rangelist_dup(requested_rangelist,
4564 else /* We need to check CHILD's implicit mergeinfo. */
4566 svn_rangelist_t *implicit_rangelist;
4568 SVN_ERR(ensure_implicit_mergeinfo(parent,
4570 child_inherits_implicit,
4578 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo,
4581 if (target_implicit_rangelist)
4582 SVN_ERR(svn_rangelist_intersect(&implicit_rangelist,
4583 target_implicit_rangelist,
4584 requested_rangelist,
4585 FALSE, scratch_pool));
4587 implicit_rangelist = apr_array_make(scratch_pool, 0,
4588 sizeof(svn_merge_range_t *));
4590 SVN_ERR(svn_rangelist_merge2(implicit_rangelist,
4591 explicit_rangelist, scratch_pool,
4593 SVN_ERR(svn_rangelist_reverse(implicit_rangelist, scratch_pool));
4594 child->remaining_ranges = svn_rangelist_dup(implicit_rangelist,
4598 else /* This is a forward merge */
4600 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
4601 NOT already recorded as merged to target. */
4602 if (target_rangelist)
4604 /* See earlier comment preceding svn_rangelist_intersect() for
4605 why we don't consider inheritance here. */
4606 SVN_ERR(svn_rangelist_remove(&explicit_rangelist,
4608 requested_rangelist, FALSE,
4613 explicit_rangelist = svn_rangelist_dup(requested_rangelist,
4617 if (explicit_rangelist->nelts == 0)
4619 child->remaining_ranges =
4620 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *));
4623 /* ### TODO: Which evil shall we choose?
4625 ### If we allow all forward-merges not already found in recorded
4626 ### mergeinfo, we destroy the ability to, say, merge the whole of a
4627 ### branch to the trunk while automatically ignoring the revisions
4628 ### common to both. That's bad.
4630 ### If we allow only forward-merges not found in either recorded
4631 ### mergeinfo or implicit mergeinfo (natural history), then the
4632 ### previous scenario works great, but we can't reverse-merge a
4633 ### previous change made to our line of history and then remake it
4634 ### (because the reverse-merge will leave no mergeinfo trace, and
4635 ### the remake-it attempt will still find the original change in
4636 ### natural mergeinfo. But you know, that we happen to use 'merge'
4637 ### for revision undoing is somewhat unnatural anyway, so I'm
4638 ### finding myself having little interest in caring too much about
4639 ### this. That said, if we had a way of storing reverse merge
4640 ### ranges, we'd be in good shape either way.
4642 #ifdef SVN_MERGE__ALLOW_ALL_FORWARD_MERGES_FROM_SELF
4644 /* ### Don't consider implicit mergeinfo. */
4645 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist,
4650 /* Based on CHILD's TARGET_MERGEINFO there are ranges to merge.
4651 Check CHILD's implicit mergeinfo to see if these remaining
4652 ranges are represented there. */
4653 SVN_ERR(ensure_implicit_mergeinfo(parent,
4655 child_inherits_implicit,
4663 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo,
4665 if (target_implicit_rangelist)
4666 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
4667 target_implicit_rangelist,
4669 FALSE, result_pool));
4671 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist,
4677 return SVN_NO_ERROR;
4680 /* Helper for do_file_merge and do_directory_merge (by way of
4681 populate_remaining_ranges() for the latter).
4683 Determine what portions of SOURCE have already
4684 been merged to CHILD->ABSPATH and populate CHILD->REMAINING_RANGES with
4685 the ranges that still need merging.
4687 SOURCE and CTX are all cascaded from the caller's arguments of the same
4688 names. Note that this means SOURCE adheres to the requirements noted in
4689 `MERGEINFO MERGE SOURCE NORMALIZATION'.
4691 CHILD represents a working copy path which is the merge target or one of
4692 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise
4693 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. TARGET_MERGEINFO is
4694 the working mergeinfo on CHILD.
4696 RA_SESSION is the session for the younger of SOURCE->loc1 and
4699 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
4700 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
4701 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact
4702 the repository for CHILD->IMPLICIT_MERGEINFO.
4704 If not null, IMPLICIT_SRC_GAP is the gap, if any, in the natural history
4705 of SOURCE, see merge_cmd_baton_t.implicit_src_gap.
4707 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD and
4708 PARENT are made in RESULT_POOL.
4710 NOTE: This should only be called when honoring mergeinfo.
4712 NOTE: If PARENT is present then this function must have previously been
4713 called for PARENT, i.e. if populate_remaining_ranges() is calling this
4714 function for a set of svn_client__merge_path_t* the calls must be made
4715 in depth-first order.
4717 NOTE: When performing reverse merges, return
4718 SVN_ERR_CLIENT_NOT_READY_TO_MERGE if both locations in SOURCE and
4719 CHILD->ABSPATH are all on the same line of history but CHILD->ABSPATH's
4720 base revision is older than the SOURCE->rev1:rev2 range, see comment re
4723 static svn_error_t *
4724 calculate_remaining_ranges(svn_client__merge_path_t *parent,
4725 svn_client__merge_path_t *child,
4726 const merge_source_t *source,
4727 svn_mergeinfo_t target_mergeinfo,
4728 const apr_array_header_t *implicit_src_gap,
4729 svn_boolean_t child_inherits_implicit,
4730 svn_ra_session_t *ra_session,
4731 svn_client_ctx_t *ctx,
4732 apr_pool_t *result_pool,
4733 apr_pool_t *scratch_pool)
4735 const svn_client__pathrev_t *primary_src
4736 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1;
4737 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
4739 /* Intersection of TARGET_MERGEINFO and the merge history
4740 described by SOURCE. */
4741 svn_rangelist_t *target_rangelist;
4742 svn_revnum_t child_base_revision;
4744 /* Since this function should only be called when honoring mergeinfo and
4745 * SOURCE adheres to the requirements noted in 'MERGEINFO MERGE SOURCE
4746 * NORMALIZATION', SOURCE must be 'ancestral'. */
4747 SVN_ERR_ASSERT(source->ancestral);
4749 /* Determine which of the requested ranges to consider merging... */
4751 /* Set TARGET_RANGELIST to the portion of TARGET_MERGEINFO that refers
4752 to SOURCE (excluding any gap in SOURCE): first get all ranges from
4753 TARGET_MERGEINFO that refer to the path of SOURCE, and then prune
4754 any ranges that lie in the gap in SOURCE.
4756 ### [JAF] In fact, that may still leave some ranges that lie entirely
4757 outside the range of SOURCE; it seems we don't care about that. */
4758 if (target_mergeinfo)
4759 target_rangelist = svn_hash_gets(target_mergeinfo, mergeinfo_path);
4761 target_rangelist = NULL;
4762 if (implicit_src_gap && target_rangelist)
4764 /* Remove any mergeinfo referring to the 'gap' in SOURCE, as that
4765 mergeinfo doesn't really refer to SOURCE at all but instead
4766 refers to locations that are non-existent or on a different
4767 line of history. (Issue #3242.) */
4768 SVN_ERR(svn_rangelist_remove(&target_rangelist,
4769 implicit_src_gap, target_rangelist,
4770 FALSE, result_pool));
4773 /* Initialize CHILD->REMAINING_RANGES and filter out revisions already
4774 merged (or, in the case of reverse merges, ranges not yet merged). */
4775 SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path,
4777 source->loc1->rev, source->loc2->rev,
4778 child_inherits_implicit,
4779 ra_session, ctx, result_pool,
4782 /* Issue #2973 -- from the continuing series of "Why, since the advent of
4783 merge tracking, allowing merges into mixed rev and locally modified
4784 working copies isn't simple and could be considered downright evil".
4786 If reverse merging a range to the WC path represented by CHILD, from
4787 that path's own history, where the path inherits no locally modified
4788 mergeinfo from its WC parents (i.e. there is no uncommitted merge to
4789 the WC), and the path's base revision is older than the range, then
4790 the merge will always be a no-op. This is because we only allow reverse
4791 merges of ranges in the path's explicit or natural mergeinfo and a
4792 reverse merge from the path's future history obviously isn't going to be
4793 in either, hence the no-op.
4795 The problem is two-fold. First, in a mixed rev WC, the change we
4796 want to revert might actually be to some child of the target path
4797 which is at a younger base revision. Sure, we can merge directly
4798 to that child or update the WC or even use --ignore-ancestry and then
4799 successfully run the reverse merge, but that gets to the second
4800 problem: Those courses of action are not very obvious. Before 1.5 if
4801 a user committed a change that didn't touch the commit target, then
4802 immediately decided to revert that change via a reverse merge it would
4803 just DTRT. But with the advent of merge tracking the user gets a no-op.
4805 So in the name of user friendliness, return an error suggesting a helpful
4808 SVN_ERR(svn_wc__node_get_base(NULL, &child_base_revision,
4809 NULL, NULL, NULL, NULL,
4810 ctx->wc_ctx, child->abspath,
4811 TRUE /* ignore_enoent */,
4812 scratch_pool, scratch_pool));
4813 /* If CHILD has no base revision then it hasn't been committed yet, so it
4814 can't have any "future" history. */
4815 if (SVN_IS_VALID_REVNUM(child_base_revision)
4816 && ((child->remaining_ranges)->nelts == 0) /* Inoperative merge */
4817 && (source->loc2->rev < source->loc1->rev) /* Reverse merge */
4818 && (child_base_revision <= source->loc2->rev)) /* From CHILD's future */
4820 /* Hmmm, an inoperative reverse merge from the "future". If it is
4821 from our own future return a helpful error. */
4823 svn_client__pathrev_t *start_loc;
4825 err = svn_client__repos_location(&start_loc,
4828 child_base_revision,
4829 ctx, scratch_pool, scratch_pool);
4832 if (err->apr_err == SVN_ERR_FS_NOT_FOUND
4833 || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES)
4834 svn_error_clear(err);
4836 return svn_error_trace(err);
4842 SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath,
4843 scratch_pool, scratch_pool));
4844 if (strcmp(start_loc->url, url) == 0)
4845 return svn_error_create(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL,
4846 _("Cannot reverse-merge a range from a "
4847 "path's own future history; try "
4852 return SVN_NO_ERROR;
4855 /* Helper for populate_remaining_ranges().
4857 SOURCE is cascaded from the arguments of the same name in
4858 populate_remaining_ranges().
4860 Note: The following comments assume a forward merge, i.e.
4861 SOURCE->loc1->rev < SOURCE->loc2->rev. If this is a reverse merge then
4862 all the following comments still apply, but with SOURCE->loc1 switched
4865 Like populate_remaining_ranges(), SOURCE must adhere to the restrictions
4866 documented in 'MERGEINFO MERGE SOURCE NORMALIZATION'. These restrictions
4867 allow for a *single* gap in SOURCE, GAP_REV1:GAP_REV2 exclusive:inclusive
4868 (where SOURCE->loc1->rev == GAP_REV1 <= GAP_REV2 < SOURCE->loc2->rev),
4869 if SOURCE->loc2->url@(GAP_REV2+1) was copied from SOURCE->loc1. If such
4870 a gap exists, set *GAP_START and *GAP_END to the starting and ending
4871 revisions of the gap. Otherwise set both to SVN_INVALID_REVNUM.
4873 For example, if the natural history of URL@2:URL@9 is 'trunk/:2,7-9' this
4874 would indicate that trunk@7 was copied from trunk@2. This function would
4875 return GAP_START:GAP_END of 2:6 in this case. Note that a path 'trunk'
4876 might exist at r3-6, but it would not be on the same line of history as
4879 ### GAP_START is basically redundant, as (if there is a gap at all) it is
4880 necessarily the older revision of SOURCE.
4882 RA_SESSION is an open RA session to the repository in which SOURCE lives.
4884 static svn_error_t *
4885 find_gaps_in_merge_source_history(svn_revnum_t *gap_start,
4886 svn_revnum_t *gap_end,
4887 const merge_source_t *source,
4888 svn_ra_session_t *ra_session,
4889 svn_client_ctx_t *ctx,
4890 apr_pool_t *scratch_pool)
4892 svn_mergeinfo_t implicit_src_mergeinfo;
4893 svn_revnum_t old_rev = MIN(source->loc1->rev, source->loc2->rev);
4894 const svn_client__pathrev_t *primary_src
4895 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1;
4896 const char *merge_src_fspath = svn_client__pathrev_fspath(primary_src,
4898 svn_rangelist_t *rangelist;
4900 SVN_ERR_ASSERT(source->ancestral);
4902 /* Start by assuming there is no gap. */
4903 *gap_start = *gap_end = SVN_INVALID_REVNUM;
4905 /* Easy out: There can't be a gap between adjacent revisions. */
4906 if (labs(source->loc1->rev - source->loc2->rev) == 1)
4907 return SVN_NO_ERROR;
4909 /* Get SOURCE as mergeinfo. */
4910 SVN_ERR(svn_client__get_history_as_mergeinfo(&implicit_src_mergeinfo, NULL,
4912 primary_src->rev, old_rev,
4914 ctx, scratch_pool));
4916 rangelist = svn_hash_gets(implicit_src_mergeinfo, merge_src_fspath);
4918 if (!rangelist) /* ### Can we ever not find a rangelist? */
4919 return SVN_NO_ERROR;
4921 /* A gap in natural history can result from either a copy or
4922 a rename. If from a copy then history as mergeinfo will look
4923 something like this:
4927 If from a rename it will look like this:
4930 '/trunk_new_name:Y-Z'
4932 In both cases the gap, if it exists, is M-N, where M = X + 1 and
4935 Note that per the rules of 'MERGEINFO MERGE SOURCE NORMALIZATION' we
4936 should never have multiple gaps, e.g. if we see anything like the
4937 following then something is quite wrong:
4939 '/trunk_old_name:A,B-C'
4940 '/trunk_new_name:D-E'
4943 if (rangelist->nelts > 1) /* Copy */
4945 const svn_merge_range_t *gap;
4946 /* As mentioned above, multiple gaps *shouldn't* be possible. */
4947 SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1);
4949 gap = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
4950 const svn_merge_range_t *);
4952 *gap_start = MIN(source->loc1->rev, source->loc2->rev);
4953 *gap_end = gap->start;
4956 ### This assertion triggers in merge_tests.py svnmucc_abuse_1()
4957 ### when a node is replaced by an older copy of itself.
4959 BH: I think we should review this and the 'rename' case to find
4960 out which behavior we really want, and if we can really
4961 determine what happened this way. */
4962 SVN_ERR_ASSERT(*gap_start < *gap_end);
4964 else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */
4966 svn_rangelist_t *requested_rangelist =
4967 svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev),
4968 MAX(source->loc1->rev, source->loc2->rev),
4969 TRUE, scratch_pool);
4970 svn_rangelist_t *implicit_rangelist =
4971 apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *));
4972 svn_rangelist_t *gap_rangelist;
4974 SVN_ERR(svn_rangelist__merge_many(implicit_rangelist,
4975 implicit_src_mergeinfo,
4976 scratch_pool, scratch_pool));
4977 SVN_ERR(svn_rangelist_remove(&gap_rangelist, implicit_rangelist,
4978 requested_rangelist, FALSE,
4981 /* If there is anything left it is the gap. */
4982 if (gap_rangelist->nelts)
4984 svn_merge_range_t *gap_range =
4985 APR_ARRAY_IDX(gap_rangelist, 0, svn_merge_range_t *);
4987 *gap_start = gap_range->start;
4988 *gap_end = gap_range->end;
4992 SVN_ERR_ASSERT(*gap_start == MIN(source->loc1->rev, source->loc2->rev)
4993 || (*gap_start == SVN_INVALID_REVNUM
4994 && *gap_end == SVN_INVALID_REVNUM));
4995 return SVN_NO_ERROR;
4998 /* Helper for do_directory_merge().
5000 For each (svn_client__merge_path_t *) child in CHILDREN_WITH_MERGEINFO,
5001 populate that child's 'remaining_ranges' list with (### ... what?),
5002 and populate that child's 'implicit_mergeinfo' with its implicit
5003 mergeinfo (natural history). CHILDREN_WITH_MERGEINFO is expected
5004 to be sorted in depth first order and each child must be processed in
5005 that order. The inheritability of all calculated ranges is TRUE.
5007 If mergeinfo is being honored (based on MERGE_B -- see HONOR_MERGEINFO()
5008 for how this is determined), this function will actually try to be
5009 intelligent about populating remaining_ranges list. Otherwise, it
5010 will claim that each child has a single remaining range, from
5011 SOURCE->rev1, to SOURCE->rev2.
5012 ### We also take the short-cut if doing record-only. Why?
5014 SCRATCH_POOL is used for all temporary allocations. Changes to
5015 CHILDREN_WITH_MERGEINFO are made in RESULT_POOL.
5017 Note that if SOURCE->rev1 > SOURCE->rev2, then each child's remaining_ranges
5018 member does not adhere to the API rules for rangelists described in
5019 svn_mergeinfo.h -- See svn_client__merge_path_t.
5021 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements
5024 static svn_error_t *
5025 populate_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
5026 const merge_source_t *source,
5027 svn_ra_session_t *ra_session,
5028 merge_cmd_baton_t *merge_b,
5029 apr_pool_t *result_pool,
5030 apr_pool_t *scratch_pool)
5032 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5034 svn_revnum_t gap_start, gap_end;
5036 /* If we aren't honoring mergeinfo or this is a --record-only merge,
5037 we'll make quick work of this by simply adding dummy SOURCE->rev1:rev2
5038 ranges for all children. */
5039 if (! HONOR_MERGEINFO(merge_b) || merge_b->record_only)
5041 for (i = 0; i < children_with_mergeinfo->nelts; i++)
5043 svn_client__merge_path_t *child =
5044 APR_ARRAY_IDX(children_with_mergeinfo, i,
5045 svn_client__merge_path_t *);
5047 svn_pool_clear(iterpool);
5049 /* Issue #3646 'record-only merges create self-referential
5050 mergeinfo'. Get the merge target's implicit mergeinfo (natural
5051 history). We'll use it later to avoid setting self-referential
5052 mergeinfo -- see filter_natural_history_from_mergeinfo(). */
5053 if (i == 0) /* First item is always the merge target. */
5055 SVN_ERR(get_full_mergeinfo(NULL, /* child->pre_merge_mergeinfo */
5056 &(child->implicit_mergeinfo),
5057 NULL, /* child->inherited_mergeinfo */
5058 svn_mergeinfo_inherited, ra_session,
5060 MAX(source->loc1->rev,
5062 MIN(source->loc1->rev,
5064 merge_b->ctx, result_pool,
5069 /* Issue #3443 - Subtrees of the merge target can inherit
5070 their parent's implicit mergeinfo in most cases. */
5071 svn_client__merge_path_t *parent
5072 = find_nearest_ancestor(children_with_mergeinfo,
5073 FALSE, child->abspath);
5074 svn_boolean_t child_inherits_implicit;
5076 /* If CHILD is a subtree then its parent must be in
5077 CHILDREN_WITH_MERGEINFO, see the global comment
5078 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
5079 SVN_ERR_ASSERT(parent);
5081 child_inherits_implicit = (parent && !child->switched);
5082 SVN_ERR(ensure_implicit_mergeinfo(parent, child,
5083 child_inherits_implicit,
5086 ra_session, merge_b->ctx,
5087 result_pool, iterpool));
5090 child->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
5095 svn_pool_destroy(iterpool);
5096 return SVN_NO_ERROR;
5099 /* If, in the merge source's history, there was a copy from an older
5100 revision, then SOURCE->loc2->url won't exist at some range M:N, where
5101 SOURCE->loc1->rev < M < N < SOURCE->loc2->rev. The rules of 'MERGEINFO
5102 MERGE SOURCE NORMALIZATION' allow this, but we must ignore these gaps
5103 when calculating what ranges remain to be merged from SOURCE. If we
5104 don't and try to merge any part of SOURCE->loc2->url@M:N we would
5105 break the editor since no part of that actually exists. See
5106 http://svn.haxx.se/dev/archive-2008-11/0618.shtml.
5108 Find the gaps in the merge target's history, if any. Eventually
5109 we will adjust CHILD->REMAINING_RANGES such that we don't describe
5110 non-existent paths to the editor. */
5111 SVN_ERR(find_gaps_in_merge_source_history(&gap_start, &gap_end,
5113 ra_session, merge_b->ctx,
5116 /* Stash any gap in the merge command baton, we'll need it later when
5117 recording mergeinfo describing this merge. */
5118 if (SVN_IS_VALID_REVNUM(gap_start) && SVN_IS_VALID_REVNUM(gap_end))
5119 merge_b->implicit_src_gap = svn_rangelist__initialize(gap_start, gap_end,
5122 for (i = 0; i < children_with_mergeinfo->nelts; i++)
5124 svn_client__merge_path_t *child =
5125 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5126 const char *child_repos_path
5127 = svn_dirent_skip_ancestor(merge_b->target->abspath, child->abspath);
5128 merge_source_t child_source;
5129 svn_client__merge_path_t *parent = NULL;
5130 svn_boolean_t child_inherits_implicit;
5132 svn_pool_clear(iterpool);
5134 /* If the path is absent don't do subtree merge either. */
5135 SVN_ERR_ASSERT(child);
5139 SVN_ERR_ASSERT(child_repos_path != NULL);
5140 child_source.loc1 = svn_client__pathrev_join_relpath(
5141 source->loc1, child_repos_path, iterpool);
5142 child_source.loc2 = svn_client__pathrev_join_relpath(
5143 source->loc2, child_repos_path, iterpool);
5144 /* ### Is the child 'ancestral' over the same revision range? It's
5145 * not necessarily true that a child is 'ancestral' if the parent is,
5146 * nor that it's not if the parent is not. However, here we claim
5147 * that it is. Before we had this 'ancestral' field that we need to
5148 * set explicitly, the claim was implicit. Either way, the impact is
5149 * that we might pass calculate_remaining_ranges() a source that is
5150 * not in fact 'ancestral' (despite its 'ancestral' field being true),
5151 * contrary to its doc-string. */
5152 child_source.ancestral = source->ancestral;
5154 /* Get the explicit/inherited mergeinfo for CHILD. If CHILD is the
5155 merge target then also get its implicit mergeinfo. Otherwise defer
5156 this until we know it is absolutely necessary, since it requires an
5157 expensive round trip communication with the server. */
5158 SVN_ERR(get_full_mergeinfo(
5159 child->pre_merge_mergeinfo ? NULL : &(child->pre_merge_mergeinfo),
5160 /* Get implicit only for merge target. */
5161 (i == 0) ? &(child->implicit_mergeinfo) : NULL,
5162 &(child->inherited_mergeinfo),
5163 svn_mergeinfo_inherited, ra_session,
5165 MAX(source->loc1->rev, source->loc2->rev),
5166 MIN(source->loc1->rev, source->loc2->rev),
5167 merge_b->ctx, result_pool, iterpool));
5169 /* If CHILD isn't the merge target find its parent. */
5172 parent = find_nearest_ancestor(children_with_mergeinfo,
5173 FALSE, child->abspath);
5174 /* If CHILD is a subtree then its parent must be in
5175 CHILDREN_WITH_MERGEINFO, see the global comment
5176 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
5177 SVN_ERR_ASSERT(parent);
5180 /* Issue #3443 - Can CHILD inherit PARENT's implicit mergeinfo, saving
5181 us from having to ask the repos? The only time we can't do this is if
5182 CHILD is the merge target and so there is no PARENT to inherit from
5183 or if CHILD is the root of a switched subtree, in which case PARENT
5184 exists but is not CHILD's repository parent. */
5185 child_inherits_implicit = (parent && !child->switched);
5187 SVN_ERR(calculate_remaining_ranges(parent, child,
5189 child->pre_merge_mergeinfo,
5190 merge_b->implicit_src_gap,
5191 child_inherits_implicit,
5193 merge_b->ctx, result_pool,
5196 /* Deal with any gap in SOURCE's natural history.
5198 If the gap is a proper subset of CHILD->REMAINING_RANGES then we can
5199 safely ignore it since we won't describe this path/rev pair.
5201 If the gap exactly matches or is a superset of a range in
5202 CHILD->REMAINING_RANGES then we must remove that range so we don't
5203 attempt to describe non-existent paths via the reporter, this will
5204 break the editor and our merge.
5206 If the gap adjoins or overlaps a range in CHILD->REMAINING_RANGES
5207 then we must *add* the gap so we span the missing revisions. */
5208 if (child->remaining_ranges->nelts
5209 && merge_b->implicit_src_gap)
5212 svn_boolean_t proper_subset = FALSE;
5213 svn_boolean_t overlaps_or_adjoins = FALSE;
5215 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
5216 so it will work with the svn_rangelist_* APIs below. */
5217 if (source->loc1->rev > source->loc2->rev)
5218 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
5220 for (j = 0; j < child->remaining_ranges->nelts; j++)
5222 svn_merge_range_t *range
5223 = APR_ARRAY_IDX(child->remaining_ranges, j, svn_merge_range_t *);
5225 if ((range->start <= gap_start && gap_end < range->end)
5226 || (range->start < gap_start && gap_end <= range->end))
5228 proper_subset = TRUE;
5231 else if ((gap_start == range->start) && (range->end == gap_end))
5235 else if (gap_start <= range->end && range->start <= gap_end)
5238 overlaps_or_adjoins = TRUE;
5245 /* We need to make adjustments. Remove from, or add the gap
5246 to, CHILD->REMAINING_RANGES as appropriate. */
5248 if (overlaps_or_adjoins)
5249 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
5250 merge_b->implicit_src_gap,
5251 result_pool, iterpool));
5252 else /* equals == TRUE */
5253 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
5254 merge_b->implicit_src_gap,
5255 child->remaining_ranges, FALSE,
5259 if (source->loc1->rev > source->loc2->rev) /* Reverse merge */
5260 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
5264 svn_pool_destroy(iterpool);
5265 return SVN_NO_ERROR;
5269 /*-----------------------------------------------------------------------*/
5271 /*** Other Helper Functions ***/
5273 /* Calculate the new mergeinfo for the target tree rooted at TARGET_ABSPATH
5274 based on MERGES (a mapping of absolute WC paths to rangelists representing
5275 a merge from the source SOURCE_FSPATH).
5277 If RESULT_CATALOG is NULL, then record the new mergeinfo in the WC (at,
5278 and possibly below, TARGET_ABSPATH).
5280 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
5281 WC, but instead record it in RESULT_CATALOG, where the keys are absolute
5282 working copy paths and the values are the new mergeinfos for each.
5283 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
5285 static svn_error_t *
5286 update_wc_mergeinfo(svn_mergeinfo_catalog_t result_catalog,
5287 const char *target_abspath,
5288 const char *source_fspath,
5290 svn_boolean_t is_rollback,
5291 svn_client_ctx_t *ctx,
5292 apr_pool_t *scratch_pool)
5294 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5295 apr_hash_index_t *hi;
5297 /* Combine the mergeinfo for the revision range just merged into
5298 the WC with its on-disk mergeinfo. */
5299 for (hi = apr_hash_first(scratch_pool, merges); hi; hi = apr_hash_next(hi))
5301 const char *local_abspath = apr_hash_this_key(hi);
5302 svn_rangelist_t *ranges = apr_hash_this_val(hi);
5303 svn_rangelist_t *rangelist;
5305 const char *local_abspath_rel_to_target;
5307 svn_mergeinfo_t mergeinfo;
5309 svn_pool_clear(iterpool);
5311 /* As some of the merges may've changed the WC's mergeinfo, get
5312 a fresh copy before using it to update the WC's mergeinfo. */
5313 err = svn_client__parse_mergeinfo(&mergeinfo, ctx->wc_ctx,
5314 local_abspath, iterpool, iterpool);
5316 /* If a directory PATH was skipped because it is missing or was
5317 obstructed by an unversioned item then there's nothing we can
5318 do with that, so skip it. */
5321 if (err->apr_err == SVN_ERR_WC_NOT_LOCKED
5322 || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
5324 svn_error_clear(err);
5329 return svn_error_trace(err);
5333 /* If we are attempting to set empty revision range override mergeinfo
5334 on a path with no explicit mergeinfo, we first need the
5335 mergeinfo that path inherits. */
5336 if (mergeinfo == NULL && ranges->nelts == 0)
5338 SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, NULL,
5339 svn_mergeinfo_nearest_ancestor,
5340 local_abspath, NULL, NULL,
5341 FALSE, ctx, iterpool, iterpool));
5344 if (mergeinfo == NULL)
5345 mergeinfo = apr_hash_make(iterpool);
5347 local_abspath_rel_to_target = svn_dirent_skip_ancestor(target_abspath,
5349 SVN_ERR_ASSERT(local_abspath_rel_to_target != NULL);
5350 fspath = svn_fspath__join(source_fspath,
5351 local_abspath_rel_to_target,
5353 rangelist = svn_hash_gets(mergeinfo, fspath);
5354 if (rangelist == NULL)
5355 rangelist = apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
5359 ranges = svn_rangelist_dup(ranges, iterpool);
5360 SVN_ERR(svn_rangelist_reverse(ranges, iterpool));
5361 SVN_ERR(svn_rangelist_remove(&rangelist, ranges, rangelist,
5367 SVN_ERR(svn_rangelist_merge2(rangelist, ranges, iterpool, iterpool));
5369 /* Update the mergeinfo by adjusting the path's rangelist. */
5370 svn_hash_sets(mergeinfo, fspath, rangelist);
5372 if (is_rollback && apr_hash_count(mergeinfo) == 0)
5375 svn_mergeinfo__remove_empty_rangelists(mergeinfo, scratch_pool);
5379 svn_mergeinfo_t existing_mergeinfo =
5380 svn_hash_gets(result_catalog, local_abspath);
5381 apr_pool_t *result_catalog_pool = apr_hash_pool_get(result_catalog);
5383 if (existing_mergeinfo)
5384 SVN_ERR(svn_mergeinfo_merge2(mergeinfo, existing_mergeinfo,
5385 result_catalog_pool, scratch_pool));
5386 svn_hash_sets(result_catalog,
5387 apr_pstrdup(result_catalog_pool, local_abspath),
5388 svn_mergeinfo_dup(mergeinfo, result_catalog_pool));
5392 err = svn_client__record_wc_mergeinfo(local_abspath, mergeinfo,
5393 TRUE, ctx, iterpool);
5395 if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
5397 /* PATH isn't just missing, it's not even versioned as far
5398 as this working copy knows. But it was included in
5399 MERGES, which means that the server knows about it.
5400 Likely we don't have access to the source due to authz
5401 restrictions. For now just clear the error and
5404 ### TODO: Set non-inheritable mergeinfo on PATH's immediate
5405 ### parent and normal mergeinfo on PATH's siblings which we
5406 ### do have access to. */
5407 svn_error_clear(err);
5414 svn_pool_destroy(iterpool);
5415 return SVN_NO_ERROR;
5418 /* Helper for record_mergeinfo_for_dir_merge().
5420 Record override mergeinfo on any paths skipped during a merge.
5422 Set empty mergeinfo on each path in MERGE_B->SKIPPED_ABSPATHS so the path
5423 does not incorrectly inherit mergeinfo that will later be describing
5426 MERGEINFO_PATH and MERGE_B are cascaded from
5427 arguments of the same name in the caller.
5429 IS_ROLLBACK is true if the caller is recording a reverse merge and false
5430 otherwise. RANGELIST is the set of revisions being merged from
5431 MERGEINFO_PATH to MERGE_B->target. */
5432 static svn_error_t *
5433 record_skips_in_mergeinfo(const char *mergeinfo_path,
5434 const svn_rangelist_t *rangelist,
5435 svn_boolean_t is_rollback,
5436 merge_cmd_baton_t *merge_b,
5437 apr_pool_t *scratch_pool)
5439 apr_hash_index_t *hi;
5441 apr_size_t nbr_skips = apr_hash_count(merge_b->skipped_abspaths);
5442 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5445 return SVN_NO_ERROR;
5447 merges = apr_hash_make(scratch_pool);
5449 /* Override the mergeinfo for child paths which weren't actually merged. */
5450 for (hi = apr_hash_first(scratch_pool, merge_b->skipped_abspaths); hi;
5451 hi = apr_hash_next(hi))
5453 const char *skipped_abspath = apr_hash_this_key(hi);
5454 svn_wc_notify_state_t obstruction_state;
5456 svn_pool_clear(iterpool);
5458 /* Before we override, make sure this is a versioned path, it might
5459 be an external or missing from disk due to authz restrictions. */
5460 SVN_ERR(perform_obstruction_check(&obstruction_state, NULL, NULL,
5462 merge_b, skipped_abspath,
5464 if (obstruction_state == svn_wc_notify_state_obstructed
5465 || obstruction_state == svn_wc_notify_state_missing)
5468 /* Add an empty range list for this path.
5470 ### TODO: This works fine for a file path skipped because it is
5471 ### missing as long as the file's parent directory is present.
5472 ### But missing directory paths skipped are not handled yet,
5473 ### see issue #2915.
5475 ### TODO: An empty range is fine if the skipped path doesn't
5476 ### inherit any mergeinfo from a parent, but if it does
5477 ### we need to account for that. See issue #3440
5478 ### http://subversion.tigris.org/issues/show_bug.cgi?id=3440. */
5479 svn_hash_sets(merges, skipped_abspath,
5480 apr_array_make(scratch_pool, 0,
5481 sizeof(svn_merge_range_t *)));
5483 /* if (nbr_skips < notify_b->nbr_notifications)
5484 ### Use RANGELIST as the mergeinfo for all children of
5485 ### this path which were not also explicitly
5488 SVN_ERR(update_wc_mergeinfo(NULL, merge_b->target->abspath,
5489 mergeinfo_path, merges,
5490 is_rollback, merge_b->ctx, iterpool));
5491 svn_pool_destroy(iterpool);
5492 return SVN_NO_ERROR;
5495 /* Data for reporting when a merge aborted because of raising conflicts.
5497 typedef struct single_range_conflict_report_t
5499 /* What sub-range of the requested source raised conflicts?
5500 * The 'inheritable' flag is ignored. */
5501 merge_source_t *conflicted_range;
5502 /* What sub-range of the requested source remains to be merged?
5503 * NULL if no more. The 'inheritable' flag is ignored. */
5504 merge_source_t *remaining_source;
5506 } single_range_conflict_report_t;
5508 /* Create a single_range_conflict_report_t, containing deep copies of
5509 * CONFLICTED_RANGE and REMAINING_SOURCE, allocated in RESULT_POOL. */
5510 static single_range_conflict_report_t *
5511 single_range_conflict_report_create(const merge_source_t *conflicted_range,
5512 const merge_source_t *remaining_source,
5513 apr_pool_t *result_pool)
5515 single_range_conflict_report_t *report
5516 = apr_palloc(result_pool, sizeof(*report));
5518 assert(conflicted_range != NULL);
5520 report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
5521 report->remaining_source
5522 = remaining_source ? merge_source_dup(remaining_source, result_pool)
5527 /* Data for reporting when a merge aborted because of raising conflicts.
5529 * ### TODO: More info, including the ranges (or other parameters) the user
5530 * needs to complete the merge.
5532 typedef struct conflict_report_t
5534 const char *target_abspath;
5535 /* The revision range during which conflicts were raised */
5536 const merge_source_t *conflicted_range;
5537 /* Was the conflicted range the last range in the whole requested merge? */
5538 svn_boolean_t was_last_range;
5539 } conflict_report_t;
5541 /* Return a new conflict_report_t containing deep copies of the parameters,
5542 * allocated in RESULT_POOL. */
5543 static conflict_report_t *
5544 conflict_report_create(const char *target_abspath,
5545 const merge_source_t *conflicted_range,
5546 svn_boolean_t was_last_range,
5547 apr_pool_t *result_pool)
5549 conflict_report_t *report = apr_palloc(result_pool, sizeof(*report));
5551 report->target_abspath = apr_pstrdup(result_pool, target_abspath);
5552 report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
5553 report->was_last_range = was_last_range;
5557 /* Return a deep copy of REPORT, allocated in RESULT_POOL. */
5558 static conflict_report_t *
5559 conflict_report_dup(const conflict_report_t *report,
5560 apr_pool_t *result_pool)
5562 conflict_report_t *new = apr_pmemdup(result_pool, report, sizeof(*new));
5564 new->target_abspath = apr_pstrdup(result_pool, report->target_abspath);
5565 new->conflicted_range = merge_source_dup(report->conflicted_range,
5570 /* Create and return an error structure appropriate for the unmerged
5571 revisions range(s). */
5572 static APR_INLINE svn_error_t *
5573 make_merge_conflict_error(conflict_report_t *report,
5574 apr_pool_t *scratch_pool)
5576 assert(!report || svn_dirent_is_absolute(report->target_abspath));
5578 if (report && ! report->was_last_range)
5580 svn_error_t *err = svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
5581 _("One or more conflicts were produced while merging r%ld:%ld into\n"
5583 "resolve all conflicts and rerun the merge to apply the remaining\n"
5584 "unmerged revisions"),
5585 report->conflicted_range->loc1->rev, report->conflicted_range->loc2->rev,
5586 svn_dirent_local_style(report->target_abspath, scratch_pool));
5587 assert(report->conflicted_range->loc1->rev != report->conflicted_range->loc2->rev); /* ### is a valid case in a 2-URL merge */
5590 return SVN_NO_ERROR;
5593 /* Helper for do_directory_merge().
5595 TARGET_WCPATH is a directory and CHILDREN_WITH_MERGEINFO is filled
5596 with paths (svn_client__merge_path_t *) arranged in depth first order,
5597 which have mergeinfo set on them or meet one of the other criteria
5598 defined in get_mergeinfo_paths(). Remove any paths absent from disk
5599 or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to
5600 or are descendants of TARGET_WCPATH by setting those children to NULL. */
5602 remove_absent_children(const char *target_wcpath,
5603 apr_array_header_t *children_with_mergeinfo)
5605 /* Before we try to override mergeinfo for skipped paths, make sure
5606 the path isn't absent due to authz restrictions, because there's
5607 nothing we can do about those. */
5609 for (i = 0; i < children_with_mergeinfo->nelts; i++)
5611 svn_client__merge_path_t *child =
5612 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5613 if ((child->absent || child->scheduled_for_deletion)
5614 && svn_dirent_is_ancestor(target_wcpath, child->abspath))
5616 svn_sort__array_delete(children_with_mergeinfo, i--, 1);
5621 /* Helper for do_directory_merge() to handle the case where a merge editor
5622 drive removes explicit mergeinfo from a subtree of the merge target.
5624 MERGE_B is cascaded from the argument of the same name in
5625 do_directory_merge(). For each path (if any) in
5626 MERGE_B->PATHS_WITH_DELETED_MERGEINFO remove that path from
5627 CHILDREN_WITH_MERGEINFO.
5629 The one exception is for the merge target itself,
5630 MERGE_B->target->abspath, this must always be present in
5631 CHILDREN_WITH_MERGEINFO so this is never removed by this
5634 remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b,
5635 apr_array_header_t *children_with_mergeinfo)
5639 if (!merge_b->paths_with_deleted_mergeinfo)
5642 /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target
5643 so start at the first child. */
5644 for (i = 1; i < children_with_mergeinfo->nelts; i++)
5646 svn_client__merge_path_t *child =
5647 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5649 if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath))
5651 svn_sort__array_delete(children_with_mergeinfo, i--, 1);
5656 /* Helper for do_directory_merge().
5658 Set up the diff editor report to merge the SOURCE diff
5659 into TARGET_ABSPATH and drive it.
5661 If mergeinfo is not being honored (based on MERGE_B -- see the doc
5662 string for HONOR_MERGEINFO() for how this is determined), then ignore
5663 CHILDREN_WITH_MERGEINFO and merge the SOURCE diff to TARGET_ABSPATH.
5665 If mergeinfo is being honored then perform a history-aware merge,
5666 describing TARGET_ABSPATH and its subtrees to the reporter in such as way
5667 as to avoid repeating merges already performed per the mergeinfo and
5668 natural history of TARGET_ABSPATH and its subtrees.
5670 The ranges that still need to be merged to the TARGET_ABSPATH and its
5671 subtrees are described in CHILDREN_WITH_MERGEINFO, an array of
5672 svn_client__merge_path_t * -- see 'THE CHILDREN_WITH_MERGEINFO ARRAY'
5673 comment at the top of this file for more info. Note that it is possible
5674 TARGET_ABSPATH and/or some of its subtrees need only a subset, or no part,
5675 of SOURCE to be merged. Though there is little point to
5676 calling this function if TARGET_ABSPATH and all its subtrees have already
5677 had SOURCE merged, this will work but is a no-op.
5679 SOURCE->rev1 and SOURCE->rev2 must be bound by the set of remaining_ranges
5680 fields in CHILDREN_WITH_MERGEINFO's elements, specifically:
5682 For forward merges (SOURCE->rev1 < SOURCE->rev2):
5684 1) The first svn_merge_range_t * element of each child's remaining_ranges
5685 array must meet one of the following conditions:
5687 a) The range's start field is greater than or equal to SOURCE->rev2.
5689 b) The range's end field is SOURCE->rev2.
5691 2) Among all the ranges that meet condition 'b' the oldest start
5692 revision must equal SOURCE->rev1.
5694 For reverse merges (SOURCE->rev1 > SOURCE->rev2):
5696 1) The first svn_merge_range_t * element of each child's remaining_ranges
5697 array must meet one of the following conditions:
5699 a) The range's start field is less than or equal to SOURCE->rev2.
5701 b) The range's end field is SOURCE->rev2.
5703 2) Among all the ranges that meet condition 'b' the youngest start
5704 revision must equal SOURCE->rev1.
5706 Note: If the first svn_merge_range_t * element of some subtree child's
5707 remaining_ranges array is the same as the first range of that child's
5708 nearest path-wise ancestor, then the subtree child *will not* be described
5711 DEPTH, NOTIFY_B, and MERGE_B are cascaded from do_directory_merge(), see
5712 that function for more info.
5714 MERGE_B->ra_session1 and MERGE_B->ra_session2 are RA sessions open to any
5715 URL in the repository of SOURCE; they may be temporarily reparented within
5718 If SOURCE->ancestral is set, then SOURCE->loc1 must be a
5719 historical ancestor of SOURCE->loc2, or vice-versa (see
5720 `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around
5721 SOURCE in this case).
5723 static svn_error_t *
5724 drive_merge_report_editor(const char *target_abspath,
5725 const merge_source_t *source,
5726 const apr_array_header_t *children_with_mergeinfo,
5727 const svn_diff_tree_processor_t *processor,
5729 merge_cmd_baton_t *merge_b,
5730 apr_pool_t *scratch_pool)
5732 const svn_ra_reporter3_t *reporter;
5733 const svn_delta_editor_t *diff_editor;
5734 void *diff_edit_baton;
5736 svn_revnum_t target_start;
5737 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
5738 const char *old_sess1_url, *old_sess2_url;
5739 svn_boolean_t is_rollback = source->loc1->rev > source->loc2->rev;
5741 /* Start with a safe default starting revision for the editor and the
5743 target_start = source->loc1->rev;
5745 /* If we are honoring mergeinfo the starting revision for the merge target
5746 might not be SOURCE->rev1, in fact the merge target might not need *any*
5747 part of SOURCE merged -- Instead some subtree of the target
5748 needs SOURCE -- So get the right starting revision for the
5750 if (honor_mergeinfo)
5752 svn_client__merge_path_t *child;
5754 /* CHILDREN_WITH_MERGEINFO must always exist if we are honoring
5755 mergeinfo and must have at least one element (describing the
5757 SVN_ERR_ASSERT(children_with_mergeinfo);
5758 SVN_ERR_ASSERT(children_with_mergeinfo->nelts);
5760 /* Get the merge target's svn_client__merge_path_t, which is always
5761 the first in the array due to depth first sorting requirement,
5762 see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
5763 child = APR_ARRAY_IDX(children_with_mergeinfo, 0,
5764 svn_client__merge_path_t *);
5765 SVN_ERR_ASSERT(child);
5766 if (child->remaining_ranges->nelts == 0)
5768 /* The merge target doesn't need anything merged. */
5769 target_start = source->loc2->rev;
5773 /* The merge target has remaining revisions to merge. These
5774 ranges may fully or partially overlap the range described
5775 by SOURCE->rev1:rev2 or may not intersect that range at
5777 svn_merge_range_t *range =
5778 APR_ARRAY_IDX(child->remaining_ranges, 0,
5779 svn_merge_range_t *);
5780 if ((!is_rollback && range->start > source->loc2->rev)
5781 || (is_rollback && range->start < source->loc2->rev))
5783 /* Merge target's first remaining range doesn't intersect. */
5784 target_start = source->loc2->rev;
5788 /* Merge target's first remaining range partially or
5790 target_start = range->start;
5795 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url,
5796 merge_b->ra_session1,
5797 source->loc1->url, scratch_pool));
5798 /* Temporarily point our second RA session to SOURCE->loc1->url, too. We use
5799 this to request individual file contents. */
5800 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url,
5801 merge_b->ra_session2,
5802 source->loc1->url, scratch_pool));
5804 /* Get the diff editor and a reporter with which to, ultimately,
5806 SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton,
5807 merge_b->ra_session2,
5810 TRUE /* text_deltas */,
5812 merge_b->ctx->cancel_func,
5813 merge_b->ctx->cancel_baton,
5815 SVN_ERR(svn_ra_do_diff3(merge_b->ra_session1,
5816 &reporter, &report_baton, source->loc2->rev,
5817 "", depth, merge_b->diff_ignore_ancestry,
5818 TRUE, /* text_deltas */
5819 source->loc2->url, diff_editor, diff_edit_baton,
5822 /* Drive the reporter. */
5823 SVN_ERR(reporter->set_path(report_baton, "", target_start, depth,
5824 FALSE, NULL, scratch_pool));
5825 if (honor_mergeinfo && children_with_mergeinfo)
5827 /* Describe children with mergeinfo overlapping this merge
5828 operation such that no repeated diff is retrieved for them from
5831 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5833 /* Start with CHILDREN_WITH_MERGEINFO[1], CHILDREN_WITH_MERGEINFO[0]
5834 is always the merge target (TARGET_ABSPATH). */
5835 for (i = 1; i < children_with_mergeinfo->nelts; i++)
5837 svn_merge_range_t *range;
5838 const char *child_repos_path;
5839 const svn_client__merge_path_t *parent;
5840 const svn_client__merge_path_t *child =
5841 APR_ARRAY_IDX(children_with_mergeinfo, i,
5842 svn_client__merge_path_t *);
5844 SVN_ERR_ASSERT(child);
5848 svn_pool_clear(iterpool);
5850 /* Find this child's nearest wc ancestor with mergeinfo. */
5851 parent = find_nearest_ancestor(children_with_mergeinfo,
5852 FALSE, child->abspath);
5854 /* If a subtree needs the same range applied as its nearest parent
5855 with mergeinfo or neither the subtree nor this parent need
5856 SOURCE->rev1:rev2 merged, then we don't need to describe the
5857 subtree separately. In the latter case this could break the
5858 editor if child->abspath didn't exist at SOURCE->rev2 and we
5859 attempt to describe it via a reporter set_path call. */
5860 if (child->remaining_ranges->nelts)
5862 range = APR_ARRAY_IDX(child->remaining_ranges, 0,
5863 svn_merge_range_t *);
5864 if ((!is_rollback && range->start > source->loc2->rev)
5865 || (is_rollback && range->start < source->loc2->rev))
5867 /* This child's first remaining range comes after the range
5868 we are currently merging, so skip it. We expect to get
5869 to it in a subsequent call to this function. */
5872 else if (parent->remaining_ranges->nelts)
5874 svn_merge_range_t *parent_range =
5875 APR_ARRAY_IDX(parent->remaining_ranges, 0,
5876 svn_merge_range_t *);
5877 svn_merge_range_t *child_range =
5878 APR_ARRAY_IDX(child->remaining_ranges, 0,
5879 svn_merge_range_t *);
5880 if (parent_range->start == child_range->start)
5881 continue; /* Subtree needs same range as parent. */
5884 else /* child->remaining_ranges->nelts == 0*/
5886 /* If both the subtree and its parent need no ranges applied
5887 consider that as the "same ranges" and don't describe
5889 if (parent->remaining_ranges->nelts == 0)
5893 /* Ok, we really need to describe this subtree as it needs different
5894 ranges applied than its nearest working copy parent. */
5895 child_repos_path = svn_dirent_is_child(target_abspath,
5898 /* This loop is only processing subtrees, so CHILD->ABSPATH
5899 better be a proper child of the merge target. */
5900 SVN_ERR_ASSERT(child_repos_path);
5902 if ((child->remaining_ranges->nelts == 0)
5903 || (is_rollback && (range->start < source->loc2->rev))
5904 || (!is_rollback && (range->start > source->loc2->rev)))
5906 /* Nothing to merge to this child. We'll claim we have
5907 it up to date so the server doesn't send us
5909 SVN_ERR(reporter->set_path(report_baton, child_repos_path,
5910 source->loc2->rev, depth, FALSE,
5915 SVN_ERR(reporter->set_path(report_baton, child_repos_path,
5916 range->start, depth, FALSE,
5920 svn_pool_destroy(iterpool);
5922 SVN_ERR(reporter->finish_report(report_baton, scratch_pool));
5924 /* Point the merge baton's RA sessions back where they were. */
5925 SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess1_url, scratch_pool));
5926 SVN_ERR(svn_ra_reparent(merge_b->ra_session2, old_sess2_url, scratch_pool));
5928 return SVN_NO_ERROR;
5931 /* Iterate over each svn_client__merge_path_t * element in
5932 CHILDREN_WITH_MERGEINFO and, if START_REV is true, find the most inclusive
5933 start revision among those element's first remaining_ranges element. If
5934 START_REV is false, then look for the most inclusive end revision.
5936 If IS_ROLLBACK is true the youngest start or end (as per START_REV)
5937 revision is considered the "most inclusive" otherwise the oldest revision
5940 If none of CHILDREN_WITH_MERGEINFO's elements have any remaining ranges
5941 return SVN_INVALID_REVNUM. */
5943 get_most_inclusive_rev(const apr_array_header_t *children_with_mergeinfo,
5944 svn_boolean_t is_rollback,
5945 svn_boolean_t start_rev)
5948 svn_revnum_t most_inclusive_rev = SVN_INVALID_REVNUM;
5950 for (i = 0; i < children_with_mergeinfo->nelts; i++)
5952 svn_client__merge_path_t *child =
5953 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5955 if ((! child) || child->absent)
5957 if (child->remaining_ranges->nelts > 0)
5959 svn_merge_range_t *range =
5960 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
5962 /* Are we looking for the most inclusive start or end rev? */
5963 svn_revnum_t rev = start_rev ? range->start : range->end;
5965 if ((most_inclusive_rev == SVN_INVALID_REVNUM)
5966 || (is_rollback && (rev > most_inclusive_rev))
5967 || ((! is_rollback) && (rev < most_inclusive_rev)))
5968 most_inclusive_rev = rev;
5971 return most_inclusive_rev;
5975 /* If first item in each child of CHILDREN_WITH_MERGEINFO's
5976 remaining_ranges is inclusive of END_REV, Slice the first range in
5977 to two at END_REV. All the allocations are persistent and allocated
5980 slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
5981 svn_boolean_t is_rollback, svn_revnum_t end_rev,
5985 for (i = 0; i < children_with_mergeinfo->nelts; i++)
5987 svn_client__merge_path_t *child =
5988 APR_ARRAY_IDX(children_with_mergeinfo, i,
5989 svn_client__merge_path_t *);
5990 if (!child || child->absent)
5992 if (child->remaining_ranges->nelts > 0)
5994 svn_merge_range_t *range = APR_ARRAY_IDX(child->remaining_ranges, 0,
5995 svn_merge_range_t *);
5996 if ((is_rollback && (range->start > end_rev)
5997 && (range->end < end_rev))
5998 || (!is_rollback && (range->start < end_rev)
5999 && (range->end > end_rev)))
6001 svn_merge_range_t *split_range1, *split_range2;
6003 split_range1 = svn_merge_range_dup(range, pool);
6004 split_range2 = svn_merge_range_dup(range, pool);
6005 split_range1->end = end_rev;
6006 split_range2->start = end_rev;
6007 APR_ARRAY_IDX(child->remaining_ranges, 0,
6008 svn_merge_range_t *) = split_range1;
6009 svn_sort__array_insert(child->remaining_ranges, &split_range2, 1);
6015 /* Helper for do_directory_merge().
6017 For each child in CHILDREN_WITH_MERGEINFO remove the first remaining_ranges
6018 svn_merge_range_t *element of the child if that range has an end revision
6021 If a range is removed from a child's remaining_ranges array, allocate the
6022 new remaining_ranges array in POOL.
6025 remove_first_range_from_remaining_ranges(svn_revnum_t revision,
6027 *children_with_mergeinfo,
6032 for (i = 0; i < children_with_mergeinfo->nelts; i++)
6034 svn_client__merge_path_t *child =
6035 APR_ARRAY_IDX(children_with_mergeinfo, i,
6036 svn_client__merge_path_t *);
6037 if (!child || child->absent)
6039 if (child->remaining_ranges->nelts > 0)
6041 svn_merge_range_t *first_range =
6042 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
6043 if (first_range->end == revision)
6045 svn_sort__array_delete(child->remaining_ranges, 0, 1);
6051 /* Get a file's content and properties from the repository.
6052 Set *FILENAME to the local path to a new temporary file holding its text,
6053 and set *PROPS to a new hash of its properties.
6055 RA_SESSION is a session open to the correct repository, which will be
6056 temporarily reparented to the URL of the file itself. LOCATION is the
6057 repository location of the file.
6059 The resulting file and the return values live as long as RESULT_POOL, all
6060 other allocations occur in SCRATCH_POOL.
6062 static svn_error_t *
6063 single_file_merge_get_file(const char **filename,
6065 svn_ra_session_t *ra_session,
6066 const svn_client__pathrev_t *location,
6067 const char *wc_target,
6068 apr_pool_t *result_pool,
6069 apr_pool_t *scratch_pool)
6071 svn_stream_t *stream;
6072 const char *old_sess_url;
6075 SVN_ERR(svn_stream_open_unique(&stream, filename, NULL,
6076 svn_io_file_del_on_pool_cleanup,
6077 result_pool, scratch_pool));
6079 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, ra_session, location->url,
6081 err = svn_ra_get_file(ra_session, "", location->rev,
6082 stream, NULL, props, scratch_pool);
6083 SVN_ERR(svn_error_compose_create(
6084 err, svn_ra_reparent(ra_session, old_sess_url, scratch_pool)));
6086 return svn_error_trace(svn_stream_close(stream));
6089 /* Compare two svn_client__merge_path_t elements **A and **B, given the
6090 addresses of pointers to them. Return an integer less than, equal to, or
6091 greater than zero if A sorts before, the same as, or after B, respectively.
6092 This is a helper for qsort() and bsearch() on an array of such elements. */
6094 compare_merge_path_t_as_paths(const void *a,
6097 const svn_client__merge_path_t *child1
6098 = *((const svn_client__merge_path_t * const *) a);
6099 const svn_client__merge_path_t *child2
6100 = *((const svn_client__merge_path_t * const *) b);
6102 return svn_path_compare_paths(child1->abspath, child2->abspath);
6105 /* Return a pointer to the element of CHILDREN_WITH_MERGEINFO whose path
6106 * is PATH, or return NULL if there is no such element. */
6107 static svn_client__merge_path_t *
6108 get_child_with_mergeinfo(const apr_array_header_t *children_with_mergeinfo,
6109 const char *abspath)
6111 svn_client__merge_path_t merge_path;
6112 svn_client__merge_path_t *key;
6113 svn_client__merge_path_t **pchild;
6115 merge_path.abspath = abspath;
6117 pchild = bsearch(&key, children_with_mergeinfo->elts,
6118 children_with_mergeinfo->nelts,
6119 children_with_mergeinfo->elt_size,
6120 compare_merge_path_t_as_paths);
6121 return pchild ? *pchild : NULL;
6124 /* Insert a deep copy of INSERT_ELEMENT into the CHILDREN_WITH_MERGEINFO
6125 array at its correct position. Allocate the new storage in POOL.
6126 CHILDREN_WITH_MERGEINFO is a depth first sorted array of
6127 (svn_client__merge_path_t *).
6129 ### Most callers don't need this to deep-copy the new element.
6130 ### It may be more efficient for some callers to insert a bunch of items
6131 out of order and then sort afterwards. (One caller is doing a qsort
6132 after calling this anyway.)
6135 insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
6136 const svn_client__merge_path_t *insert_element,
6140 const svn_client__merge_path_t *new_element;
6142 /* Find where to insert the new element */
6144 svn_sort__bsearch_lower_bound(children_with_mergeinfo, &insert_element,
6145 compare_merge_path_t_as_paths);
6147 new_element = svn_client__merge_path_dup(insert_element, pool);
6148 svn_sort__array_insert(children_with_mergeinfo, &new_element, insert_index);
6151 /* Helper for get_mergeinfo_paths().
6153 CHILDREN_WITH_MERGEINFO, DEPTH, and POOL are
6154 all cascaded from the arguments of the same name to get_mergeinfo_paths().
6156 TARGET is the merge target.
6158 *CHILD is the element in in CHILDREN_WITH_MERGEINFO that
6159 get_mergeinfo_paths() is iterating over and *CURR_INDEX is index for
6162 If CHILD->ABSPATH is equal to MERGE_CMD_BATON->target->abspath do nothing.
6163 Else if CHILD->ABSPATH is switched or absent then make sure its immediate
6164 (as opposed to nearest) parent in CHILDREN_WITH_MERGEINFO is marked as
6165 missing a child. If the immediate parent does not exist in
6166 CHILDREN_WITH_MERGEINFO then create it (and increment *CURR_INDEX so that
6167 caller doesn't process the inserted element). Also ensure that
6168 CHILD->ABSPATH's siblings which are not already present in
6169 CHILDREN_WITH_MERGEINFO are also added to the array, limited by DEPTH
6170 (e.g. don't add directory siblings of a switched file).
6171 Use POOL for temporary allocations only, any new CHILDREN_WITH_MERGEINFO
6172 elements are allocated in POOL. */
6173 static svn_error_t *
6174 insert_parent_and_sibs_of_sw_absent_del_subtree(
6175 apr_array_header_t *children_with_mergeinfo,
6176 const merge_target_t *target,
6178 svn_client__merge_path_t *child,
6180 svn_client_ctx_t *ctx,
6183 svn_client__merge_path_t *parent;
6184 const char *parent_abspath;
6185 apr_pool_t *iterpool;
6186 const apr_array_header_t *children;
6191 && strcmp(target->abspath,
6192 child->abspath) != 0)))
6193 return SVN_NO_ERROR;
6195 parent_abspath = svn_dirent_dirname(child->abspath, pool);
6196 parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath);
6199 parent->missing_child = child->absent;
6200 parent->switched_child = child->switched;
6204 /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */
6205 parent = svn_client__merge_path_create(parent_abspath, pool);
6206 parent->missing_child = child->absent;
6207 parent->switched_child = child->switched;
6208 /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
6209 insert_child_to_merge(children_with_mergeinfo, parent, pool);
6210 /* Increment for loop index so we don't process the inserted element. */
6212 } /*(parent == NULL) */
6214 /* Add all of PARENT's non-missing children that are not already present.*/
6215 SVN_ERR(svn_wc__node_get_children_of_working_node(&children, ctx->wc_ctx,
6218 iterpool = svn_pool_create(pool);
6219 for (i = 0; i < children->nelts; i++)
6221 const char *child_abspath = APR_ARRAY_IDX(children, i, const char *);
6222 svn_client__merge_path_t *sibling_of_missing;
6224 svn_pool_clear(iterpool);
6226 /* Does this child already exist in CHILDREN_WITH_MERGEINFO? */
6227 sibling_of_missing = get_child_with_mergeinfo(children_with_mergeinfo,
6229 /* Create the missing child and insert it into CHILDREN_WITH_MERGEINFO.*/
6230 if (!sibling_of_missing)
6232 /* Don't add directory children if DEPTH is svn_depth_files. */
6233 if (depth == svn_depth_files)
6235 svn_node_kind_t child_kind;
6237 SVN_ERR(svn_wc_read_kind2(&child_kind,
6238 ctx->wc_ctx, child_abspath,
6239 FALSE, FALSE, iterpool));
6240 if (child_kind != svn_node_file)
6244 sibling_of_missing = svn_client__merge_path_create(child_abspath,
6246 insert_child_to_merge(children_with_mergeinfo, sibling_of_missing,
6251 svn_pool_destroy(iterpool);
6253 return SVN_NO_ERROR;
6256 /* pre_merge_status_cb's baton */
6257 struct pre_merge_status_baton_t
6259 svn_wc_context_t *wc_ctx;
6261 /* const char *absolute_wc_path to svn_depth_t * mapping for depths
6262 of empty, immediates, and files. */
6263 apr_hash_t *shallow_subtrees;
6265 /* const char *absolute_wc_path to the same, for all paths missing
6266 from the working copy. */
6267 apr_hash_t *missing_subtrees;
6269 /* const char *absolute_wc_path const char * repos relative path, describing
6270 the root of each switched subtree in the working copy and the repository
6271 relative path it is switched to. */
6272 apr_hash_t *switched_subtrees;
6274 /* A pool to allocate additions to the above hashes in. */
6278 /* A svn_wc_status_func4_t callback used by get_mergeinfo_paths to gather
6279 all switched, depth filtered and missing subtrees under a merge target.
6281 Note that this doesn't see server and user excluded trees. */
6282 static svn_error_t *
6283 pre_merge_status_cb(void *baton,
6284 const char *local_abspath,
6285 const svn_wc_status3_t *status,
6286 apr_pool_t *scratch_pool)
6288 struct pre_merge_status_baton_t *pmsb = baton;
6290 if (status->switched && !status->file_external)
6292 store_path(pmsb->switched_subtrees, local_abspath);
6295 if (status->depth == svn_depth_empty
6296 || status->depth == svn_depth_files)
6298 const char *dup_abspath;
6299 svn_depth_t *depth = apr_pmemdup(pmsb->pool, &status->depth,
6302 dup_abspath = apr_pstrdup(pmsb->pool, local_abspath);
6304 svn_hash_sets(pmsb->shallow_subtrees, dup_abspath, depth);
6307 if (status->node_status == svn_wc_status_missing)
6309 svn_boolean_t new_missing_root = TRUE;
6310 apr_hash_index_t *hi;
6312 for (hi = apr_hash_first(scratch_pool, pmsb->missing_subtrees);
6314 hi = apr_hash_next(hi))
6316 const char *missing_root_path = apr_hash_this_key(hi);
6318 if (svn_dirent_is_ancestor(missing_root_path,
6321 new_missing_root = FALSE;
6326 if (new_missing_root)
6327 store_path(pmsb->missing_subtrees, local_abspath);
6330 return SVN_NO_ERROR;
6333 /* Find all the subtrees in the working copy tree rooted at TARGET_ABSPATH
6334 * that have explicit mergeinfo.
6335 * Set *SUBTREES_WITH_MERGEINFO to a hash mapping (const char *) absolute
6336 * WC path to (svn_mergeinfo_t *) mergeinfo.
6338 * ### Is this function equivalent to:
6340 * svn_client__get_wc_mergeinfo_catalog(
6341 * subtrees_with_mergeinfo, inherited=NULL, include_descendants=TRUE,
6342 * svn_mergeinfo_explicit, target_abspath, limit_path=NULL,
6343 * walked_path=NULL, ignore_invalid_mergeinfo=FALSE, ...)
6345 * except for the catalog keys being abspaths instead of repo-relpaths?
6347 static svn_error_t *
6348 get_wc_explicit_mergeinfo_catalog(apr_hash_t **subtrees_with_mergeinfo,
6349 const char *target_abspath,
6351 svn_client_ctx_t *ctx,
6352 apr_pool_t *result_pool,
6353 apr_pool_t *scratch_pool)
6355 svn_opt_revision_t working_revision = { svn_opt_revision_working, { 0 } };
6356 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
6357 apr_hash_index_t *hi;
6358 apr_hash_t *externals;
6360 SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL,
6361 SVN_PROP_MERGEINFO, target_abspath,
6362 &working_revision, &working_revision, NULL,
6363 depth, NULL, ctx, result_pool, scratch_pool));
6365 SVN_ERR(svn_wc__externals_defined_below(&externals, ctx->wc_ctx,
6366 target_abspath, scratch_pool,
6369 /* Convert property values to svn_mergeinfo_t. */
6370 for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo);
6372 hi = apr_hash_next(hi))
6374 const char *wc_path = apr_hash_this_key(hi);
6375 svn_string_t *mergeinfo_string = apr_hash_this_val(hi);
6376 svn_mergeinfo_t mergeinfo;
6379 /* svn_client_propget5 picks up file externals with
6380 mergeinfo, but we don't want those. */
6381 if (svn_hash_gets(externals, wc_path))
6383 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, NULL);
6387 svn_pool_clear(iterpool);
6389 err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_string->data,
6393 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
6395 err = svn_error_createf(
6396 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
6397 _("Invalid mergeinfo detected on '%s', "
6398 "merge tracking not possible"),
6399 svn_dirent_local_style(wc_path, scratch_pool));
6401 return svn_error_trace(err);
6403 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, mergeinfo);
6405 svn_pool_destroy(iterpool);
6407 return SVN_NO_ERROR;
6410 /* Helper for do_directory_merge() when performing merge-tracking aware
6413 Walk of the working copy tree rooted at TARGET->abspath to
6414 depth DEPTH. Create an svn_client__merge_path_t * for any path which meets
6415 one or more of the following criteria:
6417 1) Path has working svn:mergeinfo.
6418 2) Path is switched.
6419 3) Path is a subtree of the merge target (i.e. is not equal to
6420 TARGET->abspath) and has no mergeinfo of its own but
6421 its immediate parent has mergeinfo with non-inheritable ranges. If
6422 this isn't a dry-run and the merge is between differences in the same
6423 repository, then this function will set working mergeinfo on the path
6424 equal to the mergeinfo inheritable from its parent.
6425 4) Path has an immediate child (or children) missing from the WC because
6426 the child is switched or absent from the WC, or due to a sparse
6428 5) Path has a sibling (or siblings) missing from the WC because the
6429 sibling is switched, absent, scheduled for deletion, or missing due to
6431 6) Path is absent from disk due to an authz restriction.
6432 7) Path is equal to TARGET->abspath.
6433 8) Path is an immediate *directory* child of
6434 TARGET->abspath and DEPTH is svn_depth_immediates.
6435 9) Path is an immediate *file* child of TARGET->abspath
6436 and DEPTH is svn_depth_files.
6437 10) Path is at a depth of 'empty' or 'files'.
6438 11) Path is missing from disk (e.g. due to an OS-level deletion).
6440 If subtrees within the requested DEPTH are unexpectedly missing disk,
6441 then raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
6443 Store the svn_client__merge_path_t *'s in *CHILDREN_WITH_MERGEINFO in
6444 depth-first order based on the svn_client__merge_path_t *s path member as
6445 sorted by svn_path_compare_paths(). Set the remaining_ranges field of each
6448 Note: Since the walk is rooted at TARGET->abspath, the
6449 latter is guaranteed to be in *CHILDREN_WITH_MERGEINFO and due to the
6450 depth-first ordering it is guaranteed to be the first element in
6451 *CHILDREN_WITH_MERGEINFO.
6453 MERGE_CMD_BATON is cascaded from the argument of the same name in
6454 do_directory_merge().
6456 static svn_error_t *
6457 get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
6458 const merge_target_t *target,
6460 svn_boolean_t dry_run,
6461 svn_boolean_t same_repos,
6462 svn_client_ctx_t *ctx,
6463 apr_pool_t *result_pool,
6464 apr_pool_t *scratch_pool)
6467 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
6468 apr_pool_t *swmi_pool;
6469 apr_hash_t *subtrees_with_mergeinfo;
6470 apr_hash_t *excluded_subtrees;
6471 apr_hash_t *switched_subtrees;
6472 apr_hash_t *shallow_subtrees;
6473 apr_hash_t *missing_subtrees;
6474 struct pre_merge_status_baton_t pre_merge_status_baton;
6476 /* Case 1: Subtrees with explicit mergeinfo. */
6477 /* Use a subpool for subtrees_with_mergeinfo, as it can be very large
6478 and is temporary. */
6479 swmi_pool = svn_pool_create(scratch_pool);
6480 SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
6483 swmi_pool, swmi_pool));
6484 if (subtrees_with_mergeinfo)
6486 apr_hash_index_t *hi;
6488 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo);
6490 hi = apr_hash_next(hi))
6492 const char *wc_path = apr_hash_this_key(hi);
6493 svn_mergeinfo_t mergeinfo = apr_hash_this_val(hi);
6494 svn_client__merge_path_t *mergeinfo_child =
6495 svn_client__merge_path_create(wc_path, result_pool);
6497 svn_pool_clear(iterpool);
6499 /* Stash this child's pre-existing mergeinfo. */
6500 mergeinfo_child->pre_merge_mergeinfo = mergeinfo;
6502 /* Note if this child has non-inheritable mergeinfo */
6503 mergeinfo_child->has_noninheritable
6504 = svn_mergeinfo__is_noninheritable(
6505 mergeinfo_child->pre_merge_mergeinfo, iterpool);
6507 /* Append it. We'll sort below. */
6508 APR_ARRAY_PUSH(children_with_mergeinfo, svn_client__merge_path_t *)
6509 = svn_client__merge_path_dup(mergeinfo_child, result_pool);
6512 /* Sort CHILDREN_WITH_MERGEINFO by each child's path (i.e. as per
6513 compare_merge_path_t_as_paths). Any subsequent insertions of new
6514 children with insert_child_to_merge() require this ordering. */
6515 qsort(children_with_mergeinfo->elts,
6516 children_with_mergeinfo->nelts,
6517 children_with_mergeinfo->elt_size,
6518 compare_merge_path_t_as_paths);
6520 svn_pool_destroy(swmi_pool);
6522 /* Case 2: Switched subtrees
6523 Case 10: Paths at depths of 'empty' or 'files'
6524 Case 11: Paths missing from disk */
6525 pre_merge_status_baton.wc_ctx = ctx->wc_ctx;
6526 switched_subtrees = apr_hash_make(scratch_pool);
6527 pre_merge_status_baton.switched_subtrees = switched_subtrees;
6528 shallow_subtrees = apr_hash_make(scratch_pool);
6529 pre_merge_status_baton.shallow_subtrees = shallow_subtrees;
6530 missing_subtrees = apr_hash_make(scratch_pool);
6531 pre_merge_status_baton.missing_subtrees = missing_subtrees;
6532 pre_merge_status_baton.pool = scratch_pool;
6533 SVN_ERR(svn_wc_walk_status(ctx->wc_ctx,
6537 FALSE /* no_ignore */,
6538 TRUE /* ignore_text_mods */,
6539 NULL /* ingore_patterns */,
6540 pre_merge_status_cb, &pre_merge_status_baton,
6541 ctx->cancel_func, ctx->cancel_baton,
6544 /* Issue #2915: Raise an error describing the roots of any missing
6545 subtrees, i.e. those that the WC thinks are on disk but have been
6546 removed outside of Subversion. */
6547 if (apr_hash_count(missing_subtrees))
6549 apr_hash_index_t *hi;
6550 svn_stringbuf_t *missing_subtree_err_buf =
6551 svn_stringbuf_create(_("Merge tracking not allowed with missing "
6552 "subtrees; try restoring these items "
6553 "first:\n"), scratch_pool);
6555 for (hi = apr_hash_first(scratch_pool, missing_subtrees);
6557 hi = apr_hash_next(hi))
6559 svn_pool_clear(iterpool);
6560 svn_stringbuf_appendcstr(missing_subtree_err_buf,
6561 svn_dirent_local_style(
6562 apr_hash_this_key(hi), iterpool));
6563 svn_stringbuf_appendcstr(missing_subtree_err_buf, "\n");
6566 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
6567 NULL, missing_subtree_err_buf->data);
6570 if (apr_hash_count(switched_subtrees))
6572 apr_hash_index_t *hi;
6574 for (hi = apr_hash_first(scratch_pool, switched_subtrees);
6576 hi = apr_hash_next(hi))
6578 const char *wc_path = apr_hash_this_key(hi);
6579 svn_client__merge_path_t *child = get_child_with_mergeinfo(
6580 children_with_mergeinfo, wc_path);
6584 child->switched = TRUE;
6588 svn_client__merge_path_t *switched_child =
6589 svn_client__merge_path_create(wc_path, result_pool);
6590 switched_child->switched = TRUE;
6591 insert_child_to_merge(children_with_mergeinfo, switched_child,
6597 if (apr_hash_count(shallow_subtrees))
6599 apr_hash_index_t *hi;
6601 for (hi = apr_hash_first(scratch_pool, shallow_subtrees);
6603 hi = apr_hash_next(hi))
6605 svn_boolean_t new_shallow_child = FALSE;
6606 const char *wc_path = apr_hash_this_key(hi);
6607 svn_depth_t *child_depth = apr_hash_this_val(hi);
6608 svn_client__merge_path_t *shallow_child = get_child_with_mergeinfo(
6609 children_with_mergeinfo, wc_path);
6613 if (*child_depth == svn_depth_empty
6614 || *child_depth == svn_depth_files)
6615 shallow_child->missing_child = TRUE;
6619 shallow_child = svn_client__merge_path_create(wc_path,
6621 new_shallow_child = TRUE;
6623 if (*child_depth == svn_depth_empty
6624 || *child_depth == svn_depth_files)
6625 shallow_child->missing_child = TRUE;
6628 /* A little trickery: If PATH doesn't have any mergeinfo or has
6629 only inheritable mergeinfo, we still describe it as having
6630 non-inheritable mergeinfo if it is missing a child due to
6631 a shallow depth. Why? Because the mergeinfo we'll add to PATH
6632 to describe the merge must be non-inheritable, so PATH's missing
6633 children don't inherit it. Marking these PATHs as non-
6634 inheritable allows the logic for case 3 to properly account
6635 for PATH's children. */
6636 if (!shallow_child->has_noninheritable
6637 && (*child_depth == svn_depth_empty
6638 || *child_depth == svn_depth_files))
6640 shallow_child->has_noninheritable = TRUE;
6643 if (new_shallow_child)
6644 insert_child_to_merge(children_with_mergeinfo, shallow_child,
6649 /* Case 6: Paths absent from disk due to server or user exclusion. */
6650 SVN_ERR(svn_wc__get_excluded_subtrees(&excluded_subtrees,
6651 ctx->wc_ctx, target->abspath,
6652 result_pool, scratch_pool));
6653 if (excluded_subtrees)
6655 apr_hash_index_t *hi;
6657 for (hi = apr_hash_first(scratch_pool, excluded_subtrees);
6659 hi = apr_hash_next(hi))
6661 const char *wc_path = apr_hash_this_key(hi);
6662 svn_client__merge_path_t *child = get_child_with_mergeinfo(
6663 children_with_mergeinfo, wc_path);
6667 child->absent = TRUE;
6671 svn_client__merge_path_t *absent_child =
6672 svn_client__merge_path_create(wc_path, result_pool);
6673 absent_child->absent = TRUE;
6674 insert_child_to_merge(children_with_mergeinfo, absent_child,
6680 /* Case 7: The merge target MERGE_CMD_BATON->target->abspath is always
6682 if (!get_child_with_mergeinfo(children_with_mergeinfo,
6685 svn_client__merge_path_t *target_child =
6686 svn_client__merge_path_create(target->abspath,
6688 insert_child_to_merge(children_with_mergeinfo, target_child,
6692 /* Case 8: Path is an immediate *directory* child of
6693 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates.
6695 Case 9: Path is an immediate *file* child of
6696 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_files. */
6697 if (depth == svn_depth_immediates || depth == svn_depth_files)
6700 const apr_array_header_t *immediate_children;
6702 SVN_ERR(svn_wc__node_get_children_of_working_node(
6703 &immediate_children, ctx->wc_ctx,
6704 target->abspath, scratch_pool, scratch_pool));
6706 for (j = 0; j < immediate_children->nelts; j++)
6708 const char *immediate_child_abspath =
6709 APR_ARRAY_IDX(immediate_children, j, const char *);
6710 svn_node_kind_t immediate_child_kind;
6712 svn_pool_clear(iterpool);
6713 SVN_ERR(svn_wc_read_kind2(&immediate_child_kind,
6714 ctx->wc_ctx, immediate_child_abspath,
6715 FALSE, FALSE, iterpool));
6716 if ((immediate_child_kind == svn_node_dir
6717 && depth == svn_depth_immediates)
6718 || (immediate_child_kind == svn_node_file
6719 && depth == svn_depth_files))
6721 if (!get_child_with_mergeinfo(children_with_mergeinfo,
6722 immediate_child_abspath))
6724 svn_client__merge_path_t *immediate_child =
6725 svn_client__merge_path_create(immediate_child_abspath,
6728 if (immediate_child_kind == svn_node_dir
6729 && depth == svn_depth_immediates)
6730 immediate_child->immediate_child_dir = TRUE;
6732 insert_child_to_merge(children_with_mergeinfo,
6733 immediate_child, result_pool);
6739 /* If DEPTH isn't empty then cover cases 3), 4), and 5), possibly adding
6740 elements to CHILDREN_WITH_MERGEINFO. */
6741 if (depth <= svn_depth_empty)
6742 return SVN_NO_ERROR;
6744 for (i = 0; i < children_with_mergeinfo->nelts; i++)
6746 svn_client__merge_path_t *child =
6747 APR_ARRAY_IDX(children_with_mergeinfo, i,
6748 svn_client__merge_path_t *);
6749 svn_pool_clear(iterpool);
6751 /* Case 3) Where merging to a path with a switched child the path
6752 gets non-inheritable mergeinfo for the merge range performed and
6753 the child gets its own set of mergeinfo. If the switched child
6754 later "returns", e.g. a switched path is unswitched, the child
6755 may not have any explicit mergeinfo. If the initial merge is
6756 repeated we don't want to repeat the merge for the path, but we
6757 do want to repeat it for the previously switched child. To
6758 ensure this we check if all of CHILD's non-missing children have
6759 explicit mergeinfo (they should already be present in
6760 CHILDREN_WITH_MERGEINFO if they do). If not,
6761 add the children without mergeinfo to CHILDREN_WITH_MERGEINFO so
6762 do_directory_merge() will merge them independently.
6764 But that's not enough! Since do_directory_merge() performs
6765 the merges on the paths in CHILDREN_WITH_MERGEINFO in a depth
6766 first manner it will merge the previously switched path's parent
6767 first. As part of this merge it will update the parent's
6768 previously non-inheritable mergeinfo and make it inheritable
6769 (since it notices the path has no missing children), then when
6770 do_directory_merge() finally merges the previously missing
6771 child it needs to get mergeinfo from the child's nearest
6772 ancestor, but since do_directory_merge() already tweaked that
6773 mergeinfo, removing the non-inheritable flag, it appears that the
6774 child already has been merged to. To prevent this we set
6775 override mergeinfo on the child now, before any merging is done,
6776 so it has explicit mergeinfo that reflects only CHILD's
6777 inheritable mergeinfo. */
6779 /* If depth is immediates or files then don't add new children if
6780 CHILD is a subtree of the merge target; those children are below
6781 the operational depth of the merge. */
6782 if (child->has_noninheritable
6783 && (i == 0 || depth == svn_depth_infinity))
6785 const apr_array_header_t *children;
6788 SVN_ERR(svn_wc__node_get_children_of_working_node(
6792 iterpool, iterpool));
6793 for (j = 0; j < children->nelts; j++)
6795 svn_client__merge_path_t *child_of_noninheritable;
6796 const char *child_abspath = APR_ARRAY_IDX(children, j,
6799 /* Does this child already exist in CHILDREN_WITH_MERGEINFO?
6800 If not, create it and insert it into
6801 CHILDREN_WITH_MERGEINFO and set override mergeinfo on
6803 child_of_noninheritable =
6804 get_child_with_mergeinfo(children_with_mergeinfo,
6806 if (!child_of_noninheritable)
6808 /* Don't add directory children if DEPTH
6809 is svn_depth_files. */
6810 if (depth == svn_depth_files)
6812 svn_node_kind_t child_kind;
6813 SVN_ERR(svn_wc_read_kind2(&child_kind,
6814 ctx->wc_ctx, child_abspath,
6815 FALSE, FALSE, iterpool));
6816 if (child_kind != svn_node_file)
6819 /* else DEPTH is infinity or immediates so we want both
6820 directory and file children. */
6822 child_of_noninheritable =
6823 svn_client__merge_path_create(child_abspath, result_pool);
6824 child_of_noninheritable->child_of_noninheritable = TRUE;
6825 insert_child_to_merge(children_with_mergeinfo,
6826 child_of_noninheritable,
6828 if (!dry_run && same_repos)
6830 svn_mergeinfo_t mergeinfo;
6832 SVN_ERR(svn_client__get_wc_mergeinfo(
6834 svn_mergeinfo_nearest_ancestor,
6835 child_of_noninheritable->abspath,
6836 target->abspath, NULL, FALSE,
6837 ctx, iterpool, iterpool));
6839 SVN_ERR(svn_client__record_wc_mergeinfo(
6840 child_of_noninheritable->abspath, mergeinfo,
6841 FALSE, ctx, iterpool));
6846 /* Case 4 and 5 are handled by the following function. */
6847 SVN_ERR(insert_parent_and_sibs_of_sw_absent_del_subtree(
6848 children_with_mergeinfo, target, &i, child,
6849 depth, ctx, result_pool));
6850 } /* i < children_with_mergeinfo->nelts */
6851 svn_pool_destroy(iterpool);
6853 return SVN_NO_ERROR;
6857 /* Implements the svn_log_entry_receiver_t interface.
6859 * BATON is an 'apr_array_header_t *' array of 'svn_revnum_t'.
6860 * Push a copy of LOG_ENTRY->revision onto BATON. Thus, a
6861 * series of invocations of this callback accumulates the
6862 * corresponding set of revisions into BATON.
6864 static svn_error_t *
6865 log_changed_revs(void *baton,
6866 svn_log_entry_t *log_entry,
6869 apr_array_header_t *revs = baton;
6871 APR_ARRAY_PUSH(revs, svn_revnum_t) = log_entry->revision;
6872 return SVN_NO_ERROR;
6876 /* Set *MIN_REV_P to the oldest and *MAX_REV_P to the youngest start or end
6877 * revision occurring in RANGELIST, or to SVN_INVALID_REVNUM if RANGELIST
6880 merge_range_find_extremes(svn_revnum_t *min_rev_p,
6881 svn_revnum_t *max_rev_p,
6882 const svn_rangelist_t *rangelist)
6886 *min_rev_p = SVN_INVALID_REVNUM;
6887 *max_rev_p = SVN_INVALID_REVNUM;
6888 for (i = 0; i < rangelist->nelts; i++)
6890 svn_merge_range_t *range
6891 = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
6892 svn_revnum_t range_min = MIN(range->start, range->end);
6893 svn_revnum_t range_max = MAX(range->start, range->end);
6895 if ((! SVN_IS_VALID_REVNUM(*min_rev_p)) || (range_min < *min_rev_p))
6896 *min_rev_p = range_min;
6897 if ((! SVN_IS_VALID_REVNUM(*max_rev_p)) || (range_max > *max_rev_p))
6898 *max_rev_p = range_max;
6902 /* Wrapper around svn_ra_get_log2(). Invoke RECEIVER with RECEIVER_BATON
6903 * on each commit from YOUNGEST_REV to OLDEST_REV in which TARGET_RELPATH
6904 * changed. TARGET_RELPATH is relative to RA_SESSION's URL.
6905 * Important: Revision properties are not retrieved by this function for
6906 * performance reasons.
6908 static svn_error_t *
6909 get_log(svn_ra_session_t *ra_session,
6910 const char *target_relpath,
6911 svn_revnum_t youngest_rev,
6912 svn_revnum_t oldest_rev,
6913 svn_boolean_t discover_changed_paths,
6914 svn_log_entry_receiver_t receiver,
6915 void *receiver_baton,
6918 apr_array_header_t *log_targets;
6919 apr_array_header_t *revprops;
6921 log_targets = apr_array_make(pool, 1, sizeof(const char *));
6922 APR_ARRAY_PUSH(log_targets, const char *) = target_relpath;
6924 revprops = apr_array_make(pool, 0, sizeof(const char *));
6926 SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev,
6927 oldest_rev, 0 /* limit */, discover_changed_paths,
6928 FALSE /* strict_node_history */,
6929 FALSE /* include_merged_revisions */,
6930 revprops, receiver, receiver_baton, pool));
6932 return SVN_NO_ERROR;
6935 /* Set *OPERATIVE_RANGES_P to an array of svn_merge_range_t * merge
6936 range objects copied wholesale from RANGES which have the property
6937 that in some revision within that range the object identified by
6938 RA_SESSION was modified (if by "modified" we mean "'svn log' would
6939 return that revision). *OPERATIVE_RANGES_P is allocated from the
6940 same pool as RANGES, and the ranges within it are shared with
6943 *OPERATIVE_RANGES_P may be the same as RANGES (that is, the output
6944 parameter is set only after the input is no longer used).
6946 Use POOL for temporary allocations. */
6947 static svn_error_t *
6948 remove_noop_merge_ranges(svn_rangelist_t **operative_ranges_p,
6949 svn_ra_session_t *ra_session,
6950 const svn_rangelist_t *ranges,
6954 svn_revnum_t oldest_rev, youngest_rev;
6955 apr_array_header_t *changed_revs =
6956 apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t));
6957 svn_rangelist_t *operative_ranges =
6958 apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size);
6960 /* Find the revision extremes of the RANGES we have. */
6961 merge_range_find_extremes(&oldest_rev, &youngest_rev, ranges);
6962 if (SVN_IS_VALID_REVNUM(oldest_rev))
6963 oldest_rev++; /* make it inclusive */
6965 /* Get logs across those ranges, recording which revisions hold
6966 changes to our object's history. */
6967 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, FALSE,
6968 log_changed_revs, changed_revs, pool));
6970 /* Are there *any* changes? */
6971 if (changed_revs->nelts)
6973 /* Our list of changed revisions should be in youngest-to-oldest
6975 svn_revnum_t youngest_changed_rev
6976 = APR_ARRAY_IDX(changed_revs, 0, svn_revnum_t);
6977 svn_revnum_t oldest_changed_rev
6978 = APR_ARRAY_IDX(changed_revs, changed_revs->nelts - 1, svn_revnum_t);
6980 /* Now, copy from RANGES to *OPERATIVE_RANGES, filtering out ranges
6981 that aren't operative (by virtue of not having any revisions
6982 represented in the CHANGED_REVS array). */
6983 for (i = 0; i < ranges->nelts; i++)
6985 svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i,
6986 svn_merge_range_t *);
6987 svn_revnum_t range_min = MIN(range->start, range->end) + 1;
6988 svn_revnum_t range_max = MAX(range->start, range->end);
6991 /* If the merge range is entirely outside the range of changed
6992 revisions, we've no use for it. */
6993 if ((range_min > youngest_changed_rev)
6994 || (range_max < oldest_changed_rev))
6997 /* Walk through the changed_revs to see if any of them fall
6998 inside our current range. */
6999 for (j = 0; j < changed_revs->nelts; j++)
7001 svn_revnum_t changed_rev
7002 = APR_ARRAY_IDX(changed_revs, j, svn_revnum_t);
7003 if ((changed_rev >= range_min) && (changed_rev <= range_max))
7005 APR_ARRAY_PUSH(operative_ranges, svn_merge_range_t *) =
7013 *operative_ranges_p = operative_ranges;
7014 return SVN_NO_ERROR;
7018 /*-----------------------------------------------------------------------*/
7020 /*** Merge Source Normalization ***/
7022 /* qsort-compatible sort routine, rating merge_source_t * objects to
7023 be in descending (youngest-to-oldest) order based on their ->loc1->rev
7026 compare_merge_source_ts(const void *a,
7029 svn_revnum_t a_rev = (*(const merge_source_t *const *)a)->loc1->rev;
7030 svn_revnum_t b_rev = (*(const merge_source_t *const *)b)->loc1->rev;
7033 return a_rev < b_rev ? 1 : -1;
7036 /* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by
7037 slicing history location SEGMENTS with a given requested merge
7038 RANGE. Use SOURCE_LOC for full source URL calculation.
7040 Order the merge sources in *MERGE_SOURCE_TS_P from oldest to
7042 static svn_error_t *
7043 combine_range_with_segments(apr_array_header_t **merge_source_ts_p,
7044 const svn_merge_range_t *range,
7045 const apr_array_header_t *segments,
7046 const svn_client__pathrev_t *source_loc,
7049 apr_array_header_t *merge_source_ts =
7050 apr_array_make(pool, 1, sizeof(merge_source_t *));
7051 svn_revnum_t minrev = MIN(range->start, range->end) + 1;
7052 svn_revnum_t maxrev = MAX(range->start, range->end);
7053 svn_boolean_t subtractive = (range->start > range->end);
7056 for (i = 0; i < segments->nelts; i++)
7058 svn_location_segment_t *segment =
7059 APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
7060 svn_client__pathrev_t *loc1, *loc2;
7061 merge_source_t *merge_source;
7062 const char *path1 = NULL;
7065 /* If this segment doesn't overlap our range at all, or
7066 represents a gap, ignore it. */
7067 if ((segment->range_end < minrev)
7068 || (segment->range_start > maxrev)
7069 || (! segment->path))
7072 /* If our range spans a segment boundary, we have to point our
7073 merge_source_t's path1 to the path of the immediately older
7074 segment, else it points to the same location as its path2. */
7075 rev1 = MAX(segment->range_start, minrev) - 1;
7076 if (minrev <= segment->range_start)
7080 path1 = (APR_ARRAY_IDX(segments, i - 1,
7081 svn_location_segment_t *))->path;
7083 /* If we've backed PATH1 up into a segment gap, let's back
7084 it up further still to the segment before the gap. We'll
7085 have to adjust rev1, too. */
7086 if ((! path1) && (i > 1))
7088 path1 = (APR_ARRAY_IDX(segments, i - 2,
7089 svn_location_segment_t *))->path;
7090 rev1 = (APR_ARRAY_IDX(segments, i - 2,
7091 svn_location_segment_t *))->range_end;
7096 path1 = apr_pstrdup(pool, segment->path);
7099 /* If we don't have two valid paths, we won't know what to do
7100 when merging. This could happen if someone requested a merge
7101 where the source didn't exist in a particular revision or
7102 something. The merge code would probably bomb out anyway, so
7103 we'll just *not* create a merge source in this case. */
7104 if (! (path1 && segment->path))
7107 /* Build our merge source structure. */
7108 loc1 = svn_client__pathrev_create_with_relpath(
7109 source_loc->repos_root_url, source_loc->repos_uuid,
7111 loc2 = svn_client__pathrev_create_with_relpath(
7112 source_loc->repos_root_url, source_loc->repos_uuid,
7113 MIN(segment->range_end, maxrev), segment->path, pool);
7114 /* If this is subtractive, reverse the whole calculation. */
7116 merge_source = merge_source_create(loc2, loc1, TRUE /* ancestral */,
7119 merge_source = merge_source_create(loc1, loc2, TRUE /* ancestral */,
7122 APR_ARRAY_PUSH(merge_source_ts, merge_source_t *) = merge_source;
7125 /* If this was a subtractive merge, and we created more than one
7126 merge source, we need to reverse the sort ordering of our sources. */
7127 if (subtractive && (merge_source_ts->nelts > 1))
7128 qsort(merge_source_ts->elts, merge_source_ts->nelts,
7129 merge_source_ts->elt_size, compare_merge_source_ts);
7131 *merge_source_ts_p = merge_source_ts;
7132 return SVN_NO_ERROR;
7135 /* Similar to normalize_merge_sources() except the input MERGE_RANGE_TS is a
7138 static svn_error_t *
7139 normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
7140 const svn_client__pathrev_t *source_loc,
7141 const svn_rangelist_t *merge_range_ts,
7142 svn_ra_session_t *ra_session,
7143 svn_client_ctx_t *ctx,
7144 apr_pool_t *result_pool,
7145 apr_pool_t *scratch_pool)
7147 svn_revnum_t source_peg_revnum = source_loc->rev;
7148 svn_revnum_t oldest_requested, youngest_requested;
7149 svn_revnum_t trim_revision = SVN_INVALID_REVNUM;
7150 apr_array_header_t *segments;
7153 /* Initialize our return variable. */
7154 *merge_sources_p = apr_array_make(result_pool, 1, sizeof(merge_source_t *));
7156 /* No ranges to merge? No problem. */
7157 if (merge_range_ts->nelts == 0)
7158 return SVN_NO_ERROR;
7160 /* Find the extremes of the revisions across our set of ranges. */
7161 merge_range_find_extremes(&oldest_requested, &youngest_requested,
7164 /* ### FIXME: Our underlying APIs can't yet handle the case where
7165 the peg revision isn't the youngest of the three revisions. So
7166 we'll just verify that the source in the peg revision is related
7167 to the source in the youngest requested revision (which is
7168 all the underlying APIs would do in this case right now anyway). */
7169 if (source_peg_revnum < youngest_requested)
7171 svn_client__pathrev_t *start_loc;
7173 SVN_ERR(svn_client__repos_location(&start_loc,
7174 ra_session, source_loc,
7176 ctx, scratch_pool, scratch_pool));
7177 source_peg_revnum = youngest_requested;
7180 /* Fetch the locations for our merge range span. */
7181 SVN_ERR(svn_client__repos_location_segments(&segments,
7182 ra_session, source_loc->url,
7188 /* See if we fetched enough history to do the job. "Surely we did,"
7189 you say. "After all, we covered the entire requested merge
7190 range." Yes, that's true, but if our first segment doesn't
7191 extend back to the oldest request revision, we've got a special
7192 case to deal with. Or if the first segment represents a gap,
7193 that's another special case. */
7194 trim_revision = SVN_INVALID_REVNUM;
7195 if (segments->nelts)
7197 svn_location_segment_t *first_segment =
7198 APR_ARRAY_IDX(segments, 0, svn_location_segment_t *);
7200 /* If the first segment doesn't start with the OLDEST_REQUESTED
7201 revision, we'll need to pass a trim revision to our range
7203 if (first_segment->range_start != oldest_requested)
7205 trim_revision = first_segment->range_start;
7208 /* Else, if the first segment has no path (and therefore is a
7209 gap), then we'll fetch the copy source revision from the
7210 second segment (provided there is one, of course) and use it
7211 to prepend an extra pathful segment to our list.
7213 ### We could avoid this bit entirely if we'd passed
7214 ### SVN_INVALID_REVNUM instead of OLDEST_REQUESTED to
7215 ### svn_client__repos_location_segments(), but that would
7216 ### really penalize clients hitting pre-1.5 repositories with
7217 ### the typical small merge range request (because of the
7218 ### lack of a node-origins cache in the repository). */
7219 else if (! first_segment->path)
7221 if (segments->nelts > 1)
7223 svn_location_segment_t *second_segment =
7224 APR_ARRAY_IDX(segments, 1, svn_location_segment_t *);
7225 const char *segment_url;
7226 const char *original_repos_relpath;
7227 svn_revnum_t original_revision;
7228 svn_opt_revision_t range_start_rev;
7229 range_start_rev.kind = svn_opt_revision_number;
7230 range_start_rev.value.number = second_segment->range_start;
7232 segment_url = svn_path_url_add_component2(
7233 source_loc->repos_root_url, second_segment->path,
7235 SVN_ERR(svn_client__get_copy_source(&original_repos_relpath,
7240 result_pool, scratch_pool));
7241 /* Got copyfrom data? Fix up the first segment to cover
7242 back to COPYFROM_REV + 1, and then prepend a new
7243 segment covering just COPYFROM_REV. */
7244 if (original_repos_relpath)
7246 svn_location_segment_t *new_segment =
7247 apr_pcalloc(result_pool, sizeof(*new_segment));
7249 new_segment->path = original_repos_relpath;
7250 new_segment->range_start = original_revision;
7251 new_segment->range_end = original_revision;
7252 svn_sort__array_insert(segments, &new_segment, 0);
7258 /* For each range in our requested range set, try to determine the
7259 path(s) associated with that range. */
7260 for (i = 0; i < merge_range_ts->nelts; i++)
7262 svn_merge_range_t *range =
7263 APR_ARRAY_IDX(merge_range_ts, i, svn_merge_range_t *);
7264 apr_array_header_t *merge_sources;
7266 if (SVN_IS_VALID_REVNUM(trim_revision))
7268 /* If the range predates the trim revision, discard it. */
7269 if (MAX(range->start, range->end) < trim_revision)
7272 /* If the range overlaps the trim revision, trim it. */
7273 if (range->start < trim_revision)
7274 range->start = trim_revision;
7275 if (range->end < trim_revision)
7276 range->end = trim_revision;
7279 /* Copy the resulting merge sources into master list thereof. */
7280 SVN_ERR(combine_range_with_segments(&merge_sources, range,
7281 segments, source_loc,
7283 apr_array_cat(*merge_sources_p, merge_sources);
7286 return SVN_NO_ERROR;
7289 /* Determine the normalized ranges to merge from a given line of history.
7291 Calculate the result by intersecting the list of location segments at
7292 which SOURCE_LOC existed along its line of history with the requested
7293 revision ranges in RANGES_TO_MERGE. RANGES_TO_MERGE is an array of
7294 (svn_opt_revision_range_t *) revision ranges. Use SOURCE_PATH_OR_URL to
7295 resolve any WC-relative revision specifiers (such as 'base') in
7298 Set *MERGE_SOURCES_P to an array of merge_source_t * objects, each
7299 describing a normalized range of revisions to be merged from the line
7300 history of SOURCE_LOC. Order the objects from oldest to youngest.
7302 RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may
7303 be temporarily reparented within this function. Use RA_SESSION to find
7304 the location segments along the line of history of SOURCE_LOC.
7306 Allocate MERGE_SOURCES_P and its contents in RESULT_POOL.
7308 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more on the
7309 background of this function.
7311 static svn_error_t *
7312 normalize_merge_sources(apr_array_header_t **merge_sources_p,
7313 const char *source_path_or_url,
7314 const svn_client__pathrev_t *source_loc,
7315 const apr_array_header_t *ranges_to_merge,
7316 svn_ra_session_t *ra_session,
7317 svn_client_ctx_t *ctx,
7318 apr_pool_t *result_pool,
7319 apr_pool_t *scratch_pool)
7321 const char *source_abspath_or_url;
7322 svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
7323 svn_rangelist_t *merge_range_ts;
7325 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
7327 if(!svn_path_is_url(source_path_or_url))
7328 SVN_ERR(svn_dirent_get_absolute(&source_abspath_or_url, source_path_or_url,
7331 source_abspath_or_url = source_path_or_url;
7333 /* Create a list to hold svn_merge_range_t's. */
7334 merge_range_ts = apr_array_make(scratch_pool, ranges_to_merge->nelts,
7335 sizeof(svn_merge_range_t *));
7337 for (i = 0; i < ranges_to_merge->nelts; i++)
7339 svn_opt_revision_range_t *range
7340 = APR_ARRAY_IDX(ranges_to_merge, i, svn_opt_revision_range_t *);
7341 svn_merge_range_t mrange;
7343 svn_pool_clear(iterpool);
7345 /* Resolve revisions to real numbers, validating as we go. */
7346 if ((range->start.kind == svn_opt_revision_unspecified)
7347 || (range->end.kind == svn_opt_revision_unspecified))
7348 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
7349 _("Not all required revisions are specified"));
7351 SVN_ERR(svn_client__get_revision_number(&mrange.start, &youngest_rev,
7353 source_abspath_or_url,
7354 ra_session, &range->start,
7356 SVN_ERR(svn_client__get_revision_number(&mrange.end, &youngest_rev,
7358 source_abspath_or_url,
7359 ra_session, &range->end,
7362 /* If this isn't a no-op range... */
7363 if (mrange.start != mrange.end)
7365 /* ...then add it to the list. */
7366 mrange.inheritable = TRUE;
7367 APR_ARRAY_PUSH(merge_range_ts, svn_merge_range_t *)
7368 = svn_merge_range_dup(&mrange, scratch_pool);
7372 SVN_ERR(normalize_merge_sources_internal(
7373 merge_sources_p, source_loc,
7374 merge_range_ts, ra_session, ctx, result_pool, scratch_pool));
7376 svn_pool_destroy(iterpool);
7377 return SVN_NO_ERROR;
7381 /*-----------------------------------------------------------------------*/
7383 /*** Merge Workhorse Functions ***/
7385 /* Helper for do_directory_merge() and do_file_merge() which filters out a
7386 path's own natural history from the mergeinfo describing a merge.
7388 Given the natural history IMPLICIT_MERGEINFO of some wc merge target path,
7389 the repository-relative merge source path SOURCE_REL_PATH, and the
7390 requested merge range REQUESTED_RANGE from SOURCE_REL_PATH, remove any
7391 portion of REQUESTED_RANGE which is already described in
7392 IMPLICIT_MERGEINFO. Store the result in *FILTERED_RANGELIST.
7394 This function only filters natural history for mergeinfo that will be
7395 *added* during a forward merge. Removing natural history from explicit
7396 mergeinfo is harmless. If REQUESTED_RANGE describes a reverse merge,
7397 then *FILTERED_RANGELIST is simply populated with one range described
7398 by REQUESTED_RANGE. *FILTERED_RANGELIST is never NULL.
7400 Allocate *FILTERED_RANGELIST in POOL. */
7401 static svn_error_t *
7402 filter_natural_history_from_mergeinfo(svn_rangelist_t **filtered_rangelist,
7403 const char *source_rel_path,
7404 svn_mergeinfo_t implicit_mergeinfo,
7405 svn_merge_range_t *requested_range,
7408 /* Make the REQUESTED_RANGE into a rangelist. */
7409 svn_rangelist_t *requested_rangelist =
7410 svn_rangelist__initialize(requested_range->start, requested_range->end,
7411 requested_range->inheritable, pool);
7413 *filtered_rangelist = NULL;
7415 /* For forward merges: If the IMPLICIT_MERGEINFO already describes ranges
7416 associated with SOURCE_REL_PATH then filter those ranges out. */
7417 if (implicit_mergeinfo
7418 && (requested_range->start < requested_range->end))
7420 svn_rangelist_t *implied_rangelist =
7421 svn_hash_gets(implicit_mergeinfo, source_rel_path);
7423 if (implied_rangelist)
7424 SVN_ERR(svn_rangelist_remove(filtered_rangelist,
7426 requested_rangelist,
7430 /* If no filtering was performed the filtered rangelist is
7431 simply the requested rangelist.*/
7432 if (! (*filtered_rangelist))
7433 *filtered_rangelist = requested_rangelist;
7435 return SVN_NO_ERROR;
7438 /* Return a merge source representing the sub-range from START_REV to
7439 END_REV of SOURCE. SOURCE obeys the rules described in the
7440 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file.
7441 The younger of START_REV and END_REV is inclusive while the older is
7444 Allocate the result structure in POOL but leave the URLs in it as shallow
7445 copies of the URLs in SOURCE.
7447 static merge_source_t *
7448 subrange_source(const merge_source_t *source,
7449 svn_revnum_t start_rev,
7450 svn_revnum_t end_rev,
7453 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
7454 svn_boolean_t same_urls = (strcmp(source->loc1->url, source->loc2->url) == 0);
7455 svn_client__pathrev_t loc1 = *source->loc1;
7456 svn_client__pathrev_t loc2 = *source->loc2;
7458 /* For this function we require that the input source is 'ancestral'. */
7459 SVN_ERR_ASSERT_NO_RETURN(source->ancestral);
7460 SVN_ERR_ASSERT_NO_RETURN(start_rev != end_rev);
7462 loc1.rev = start_rev;
7466 if (is_rollback && (end_rev != source->loc2->rev))
7468 loc2.url = source->loc1->url;
7470 if ((! is_rollback) && (start_rev != source->loc1->rev))
7472 loc1.url = source->loc2->url;
7475 return merge_source_create(&loc1, &loc2, source->ancestral, pool);
7478 /* The single-file, simplified version of do_directory_merge(), which see for
7479 parameter descriptions.
7481 Additional parameters:
7483 If SOURCES_RELATED is set, the "left" and "right" sides of SOURCE are
7484 historically related (ancestors, uncles, second
7485 cousins thrice removed, etc...). (This is used to simulate the
7486 history checks that the repository logic does in the directory case.)
7488 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
7489 is not NULL, then don't record the new mergeinfo on the TARGET_ABSPATH,
7490 but instead record it in RESULT_CATALOG, where the key is TARGET_ABSPATH
7491 and the value is the new mergeinfo for that path. Allocate additions
7492 to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
7494 CONFLICTED_RANGE is as documented for do_directory_merge().
7496 Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->loc1->url and
7497 MERGE_B->RA_SESSION2 with SOURCE->loc2->url.
7499 static svn_error_t *
7500 do_file_merge(svn_mergeinfo_catalog_t result_catalog,
7501 single_range_conflict_report_t **conflict_report,
7502 const merge_source_t *source,
7503 const char *target_abspath,
7504 const svn_diff_tree_processor_t *processor,
7505 svn_boolean_t sources_related,
7506 svn_boolean_t squelch_mergeinfo_notifications,
7507 merge_cmd_baton_t *merge_b,
7508 apr_pool_t *result_pool,
7509 apr_pool_t *scratch_pool)
7511 svn_rangelist_t *remaining_ranges;
7512 svn_client_ctx_t *ctx = merge_b->ctx;
7513 svn_merge_range_t range;
7514 svn_mergeinfo_t target_mergeinfo;
7515 svn_boolean_t inherited = FALSE;
7516 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
7517 const svn_client__pathrev_t *primary_src
7518 = is_rollback ? source->loc1 : source->loc2;
7519 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
7520 svn_client__merge_path_t *merge_target = NULL;
7521 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
7523 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
7525 *conflict_report = NULL;
7527 /* Note that this is a single-file merge. */
7528 range.start = source->loc1->rev;
7529 range.end = source->loc2->rev;
7530 range.inheritable = TRUE;
7532 merge_target = svn_client__merge_path_create(target_abspath, scratch_pool);
7534 if (honor_mergeinfo)
7538 /* Fetch mergeinfo. */
7539 err = get_full_mergeinfo(&target_mergeinfo,
7540 &(merge_target->implicit_mergeinfo),
7541 &inherited, svn_mergeinfo_inherited,
7542 merge_b->ra_session1, target_abspath,
7543 MAX(source->loc1->rev, source->loc2->rev),
7544 MIN(source->loc1->rev, source->loc2->rev),
7545 ctx, scratch_pool, iterpool);
7549 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
7551 err = svn_error_createf(
7552 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
7553 _("Invalid mergeinfo detected on merge target '%s', "
7554 "merge tracking not possible"),
7555 svn_dirent_local_style(target_abspath, scratch_pool));
7557 return svn_error_trace(err);
7560 /* Calculate remaining merges unless this is a record only merge.
7561 In that case the remaining range is the whole range described
7562 by SOURCE->rev1:rev2. */
7563 if (!merge_b->record_only)
7565 /* ### Bug? calculate_remaining_ranges() needs 'source' to adhere
7566 * to the requirements of 'MERGEINFO MERGE SOURCE NORMALIZATION'
7567 * here, but it doesn't appear to be guaranteed so. */
7568 SVN_ERR(calculate_remaining_ranges(NULL, merge_target,
7571 merge_b->implicit_src_gap, FALSE,
7572 merge_b->ra_session1,
7575 remaining_ranges = merge_target->remaining_ranges;
7577 /* We are honoring mergeinfo and this is not a simple record only
7578 merge which blindly records mergeinfo describing the merge of
7579 SOURCE->LOC1->URL@SOURCE->LOC1->REV through
7580 SOURCE->LOC2->URL@SOURCE->LOC2->REV. This means that the oldest
7581 and youngest revisions merged (as determined above by
7582 calculate_remaining_ranges) might differ from those described
7583 in SOURCE. To keep the '--- Merging *' notifications consistent
7584 with the '--- Recording mergeinfo *' notifications, we adjust
7585 RANGE to account for such changes. */
7586 if (remaining_ranges->nelts)
7588 svn_merge_range_t *adj_start_range =
7589 APR_ARRAY_IDX(remaining_ranges, 0, svn_merge_range_t *);
7590 svn_merge_range_t *adj_end_range =
7591 APR_ARRAY_IDX(remaining_ranges, remaining_ranges->nelts - 1,
7592 svn_merge_range_t *);
7593 range.start = adj_start_range->start;
7594 range.end = adj_end_range->end;
7599 /* The simple cases where our remaining range is SOURCE->rev1:rev2. */
7600 if (!honor_mergeinfo || merge_b->record_only)
7602 remaining_ranges = apr_array_make(scratch_pool, 1, sizeof(&range));
7603 APR_ARRAY_PUSH(remaining_ranges, svn_merge_range_t *) = ⦥
7606 if (!merge_b->record_only)
7608 svn_rangelist_t *ranges_to_merge = apr_array_copy(scratch_pool,
7610 const char *target_relpath = ""; /* relative to root of merge */
7612 if (source->ancestral)
7614 apr_array_header_t *child_with_mergeinfo;
7615 svn_client__merge_path_t *target_info;
7617 /* If we have ancestrally related sources and more than one
7618 range to merge, eliminate no-op ranges before going through
7619 the effort of downloading the many copies of the file
7620 required to do these merges (two copies per range). */
7621 if (remaining_ranges->nelts > 1)
7623 const char *old_sess_url;
7626 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url,
7627 merge_b->ra_session1,
7630 err = remove_noop_merge_ranges(&ranges_to_merge,
7631 merge_b->ra_session1,
7632 remaining_ranges, scratch_pool);
7633 SVN_ERR(svn_error_compose_create(
7634 err, svn_ra_reparent(merge_b->ra_session1,
7635 old_sess_url, iterpool)));
7638 /* To support notify_merge_begin() initialize our
7639 CHILD_WITH_MERGEINFO. See the comment
7640 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */
7642 child_with_mergeinfo = apr_array_make(scratch_pool, 1,
7643 sizeof(svn_client__merge_path_t *));
7645 /* ### Create a fake copy of merge_target as we don't keep
7646 remaining_ranges in sync (yet). */
7647 target_info = apr_pcalloc(scratch_pool, sizeof(*target_info));
7649 target_info->abspath = merge_target->abspath;
7650 target_info->remaining_ranges = ranges_to_merge;
7652 APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *)
7655 /* And store in baton to allow using it from notify_merge_begin() */
7656 merge_b->notify_begin.nodes_with_mergeinfo = child_with_mergeinfo;
7659 while (ranges_to_merge->nelts > 0)
7661 svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, 0,
7662 svn_merge_range_t *);
7663 const merge_source_t *real_source;
7664 const char *left_file, *right_file;
7665 apr_hash_t *left_props, *right_props;
7666 const svn_diff_source_t *left_source;
7667 const svn_diff_source_t *right_source;
7669 svn_pool_clear(iterpool);
7671 /* Ensure any subsequent drives gets their own notification. */
7672 merge_b->notify_begin.last_abspath = NULL;
7674 /* While we currently don't allow it, in theory we could be
7675 fetching two fulltexts from two different repositories here. */
7676 if (source->ancestral)
7677 real_source = subrange_source(source, r->start, r->end, iterpool);
7679 real_source = source;
7680 SVN_ERR(single_file_merge_get_file(&left_file, &left_props,
7681 merge_b->ra_session1,
7684 iterpool, iterpool));
7685 SVN_ERR(single_file_merge_get_file(&right_file, &right_props,
7686 merge_b->ra_session2,
7689 iterpool, iterpool));
7690 /* Calculate sources for the diff processor */
7691 left_source = svn_diff__source_create(r->start, iterpool);
7692 right_source = svn_diff__source_create(r->end, iterpool);
7695 /* If the sources are related or we're ignoring ancestry in diffs,
7696 do a text-n-props merge; otherwise, do a delete-n-add merge. */
7697 if (! (merge_b->diff_ignore_ancestry || sources_related))
7699 struct merge_dir_baton_t dir_baton;
7703 /* Initialize minimal dir baton to allow calculating 'R'eplace
7704 from 'D'elete + 'A'dd. */
7706 memset(&dir_baton, 0, sizeof(dir_baton));
7707 dir_baton.pool = iterpool;
7708 dir_baton.tree_conflict_reason = CONFLICT_REASON_NONE;
7709 dir_baton.tree_conflict_action = svn_wc_conflict_action_edit;
7710 dir_baton.skip_reason = svn_wc_notify_state_unknown;
7715 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7717 NULL /* right_source */,
7718 NULL /* copyfrom_source */,
7721 iterpool, iterpool));
7723 SVN_ERR(processor->file_deleted(target_relpath,
7731 /* ...plus add... */
7734 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7735 NULL /* left_source */,
7737 NULL /* copyfrom_source */,
7740 iterpool, iterpool));
7742 SVN_ERR(processor->file_added(target_relpath,
7743 NULL /* copyfrom_source */,
7745 NULL /* copyfrom_file */,
7747 NULL /* copyfrom_props */,
7752 /* ... equals replace. */
7756 void *file_baton = NULL;
7757 svn_boolean_t skip = FALSE;
7758 apr_array_header_t *propchanges;
7761 /* Deduce property diffs. */
7762 SVN_ERR(svn_prop_diffs(&propchanges, right_props, left_props,
7765 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7768 NULL /* copyfrom_source */,
7769 NULL /* dir_baton */,
7771 iterpool, iterpool));
7773 SVN_ERR(processor->file_changed(target_relpath,
7780 TRUE /* file changed */,
7787 if (is_path_conflicted_by_merge(merge_b))
7789 merge_source_t *remaining_range = NULL;
7791 if (real_source->loc2->rev != source->loc2->rev)
7792 remaining_range = subrange_source(source,
7793 real_source->loc2->rev,
7796 *conflict_report = single_range_conflict_report_create(
7797 real_source, remaining_range, result_pool);
7799 /* Only record partial mergeinfo if only a partial merge was
7800 performed before a conflict was encountered. */
7805 /* Now delete the just merged range from the hash
7806 (This list is used from notify_merge_begin)
7808 Directory merges use remove_first_range_from_remaining_ranges() */
7809 svn_sort__array_delete(ranges_to_merge, 0, 1);
7811 merge_b->notify_begin.last_abspath = NULL;
7812 } /* !merge_b->record_only */
7814 /* Record updated WC mergeinfo to account for our new merges, minus
7815 any unresolved conflicts and skips. We use the original
7816 REMAINING_RANGES here because we want to record all the requested
7817 merge ranges, include the noop ones. */
7818 if (RECORD_MERGEINFO(merge_b) && remaining_ranges->nelts)
7820 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
7822 svn_rangelist_t *filtered_rangelist;
7824 /* Filter any ranges from TARGET_WCPATH's own history, there is no
7825 need to record this explicitly in mergeinfo, it is already part
7826 of TARGET_WCPATH's natural history (implicit mergeinfo). */
7827 SVN_ERR(filter_natural_history_from_mergeinfo(
7828 &filtered_rangelist,
7830 merge_target->implicit_mergeinfo,
7834 /* Only record mergeinfo if there is something other than
7835 self-referential mergeinfo, but don't record mergeinfo if
7836 TARGET_WCPATH was skipped. */
7837 if (filtered_rangelist->nelts
7838 && (apr_hash_count(merge_b->skipped_abspaths) == 0))
7840 apr_hash_t *merges = apr_hash_make(iterpool);
7842 /* If merge target has inherited mergeinfo set it before
7843 recording the first merge range. */
7845 SVN_ERR(svn_client__record_wc_mergeinfo(target_abspath,
7850 svn_hash_sets(merges, target_abspath, filtered_rangelist);
7852 if (!squelch_mergeinfo_notifications)
7854 /* Notify that we are recording mergeinfo describing a merge. */
7855 svn_merge_range_t n_range;
7857 SVN_ERR(svn_mergeinfo__get_range_endpoints(
7858 &n_range.end, &n_range.start, merges, iterpool));
7859 n_range.inheritable = TRUE;
7860 notify_mergeinfo_recording(target_abspath, &n_range,
7861 merge_b->ctx, iterpool);
7864 SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath,
7865 mergeinfo_path, merges, is_rollback,
7870 merge_b->notify_begin.nodes_with_mergeinfo = NULL;
7872 svn_pool_destroy(iterpool);
7874 return SVN_NO_ERROR;
7877 /* Helper for do_directory_merge() to handle the case where a merge editor
7878 drive adds explicit mergeinfo to a path which didn't have any explicit
7879 mergeinfo previously.
7881 MERGE_B is cascaded from the argument of the same
7882 name in do_directory_merge(). Should be called only after
7883 do_directory_merge() has called populate_remaining_ranges() and populated
7884 the remaining_ranges field of each child in
7885 CHILDREN_WITH_MERGEINFO (i.e. the remaining_ranges fields can be
7886 empty but never NULL).
7888 If MERGE_B->DRY_RUN is true do nothing, if it is false then
7889 for each path (if any) in MERGE_B->PATHS_WITH_NEW_MERGEINFO merge that
7890 path's inherited mergeinfo (if any) with its working explicit mergeinfo
7891 and set that as the path's new explicit mergeinfo. Then add an
7892 svn_client__merge_path_t * element representing the path to
7893 CHILDREN_WITH_MERGEINFO if it isn't already present. All fields
7894 in any elements added to CHILDREN_WITH_MERGEINFO are initialized
7895 to FALSE/NULL with the exception of 'path' and 'remaining_ranges'. The
7896 latter is set to a rangelist equal to the remaining_ranges of the path's
7897 nearest path-wise ancestor in CHILDREN_WITH_MERGEINFO.
7899 Any elements added to CHILDREN_WITH_MERGEINFO are allocated
7901 static svn_error_t *
7902 process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b,
7903 apr_array_header_t *children_with_mergeinfo,
7906 apr_pool_t *iterpool;
7907 apr_hash_index_t *hi;
7909 if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run)
7910 return SVN_NO_ERROR;
7912 /* Iterate over each path with explicit mergeinfo added by the merge. */
7913 iterpool = svn_pool_create(pool);
7914 for (hi = apr_hash_first(pool, merge_b->paths_with_new_mergeinfo);
7916 hi = apr_hash_next(hi))
7918 const char *abspath_with_new_mergeinfo = apr_hash_this_key(hi);
7919 svn_mergeinfo_t path_inherited_mergeinfo;
7920 svn_mergeinfo_t path_explicit_mergeinfo;
7921 svn_client__merge_path_t *new_child;
7923 svn_pool_clear(iterpool);
7925 /* Note: We could skip recording inherited mergeinfo here if this path
7926 was added (with preexisting mergeinfo) by the merge. That's actually
7927 more correct, since the inherited mergeinfo likely describes
7928 non-existent or unrelated merge history, but it's not quite so simple
7929 as that, see http://subversion.tigris.org/issues/show_bug.cgi?id=4309
7932 /* Get the path's new explicit mergeinfo... */
7933 SVN_ERR(svn_client__get_wc_mergeinfo(&path_explicit_mergeinfo, NULL,
7934 svn_mergeinfo_explicit,
7935 abspath_with_new_mergeinfo,
7938 iterpool, iterpool));
7939 /* ...there *should* always be explicit mergeinfo at this point
7940 but you can't be too careful. */
7941 if (path_explicit_mergeinfo)
7943 /* Get the mergeinfo the path would have inherited before
7945 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(
7946 &path_inherited_mergeinfo,
7949 svn_mergeinfo_nearest_ancestor, /* We only want inherited MI */
7950 merge_b->ra_session2,
7951 abspath_with_new_mergeinfo,
7955 /* If the path inherited any mergeinfo then merge that with the
7956 explicit mergeinfo and record the result as the path's new
7957 explicit mergeinfo. */
7958 if (path_inherited_mergeinfo)
7960 SVN_ERR(svn_mergeinfo_merge2(path_explicit_mergeinfo,
7961 path_inherited_mergeinfo,
7962 iterpool, iterpool));
7963 SVN_ERR(svn_client__record_wc_mergeinfo(
7964 abspath_with_new_mergeinfo,
7965 path_explicit_mergeinfo,
7966 FALSE, merge_b->ctx, iterpool));
7969 /* If the path is not in CHILDREN_WITH_MERGEINFO then add it. */
7971 get_child_with_mergeinfo(children_with_mergeinfo,
7972 abspath_with_new_mergeinfo);
7975 const svn_client__merge_path_t *parent
7976 = find_nearest_ancestor(children_with_mergeinfo,
7977 FALSE, abspath_with_new_mergeinfo);
7979 = svn_client__merge_path_create(abspath_with_new_mergeinfo,
7982 /* If path_with_new_mergeinfo is the merge target itself
7983 then it should already be in
7984 CHILDREN_WITH_MERGEINFO per the criteria of
7985 get_mergeinfo_paths() and we shouldn't be in this block.
7986 If path_with_new_mergeinfo is a subtree then it must have
7987 a parent in CHILDREN_WITH_MERGEINFO if only
7988 the merge target itself...so if we don't find a parent
7989 the caller has done something quite wrong. */
7990 SVN_ERR_ASSERT(parent);
7991 SVN_ERR_ASSERT(parent->remaining_ranges);
7993 /* Set the path's remaining_ranges equal to its parent's. */
7994 new_child->remaining_ranges = svn_rangelist_dup(
7995 parent->remaining_ranges, pool);
7996 insert_child_to_merge(children_with_mergeinfo, new_child, pool);
8000 svn_pool_destroy(iterpool);
8002 return SVN_NO_ERROR;
8005 /* Return true if any path in SUBTREES is equal to, or is a subtree of,
8006 LOCAL_ABSPATH. Return false otherwise. The keys of SUBTREES are
8007 (const char *) absolute paths and its values are irrelevant.
8008 If SUBTREES is NULL return false. */
8009 static svn_boolean_t
8010 path_is_subtree(const char *local_abspath,
8011 apr_hash_t *subtrees,
8016 apr_hash_index_t *hi;
8018 for (hi = apr_hash_first(pool, subtrees);
8019 hi; hi = apr_hash_next(hi))
8021 const char *path_touched_by_merge = apr_hash_this_key(hi);
8022 if (svn_dirent_is_ancestor(local_abspath, path_touched_by_merge))
8029 /* Return true if any merged, skipped, added or tree-conflicted path
8030 recorded in MERGE_B is equal to, or is a subtree of LOCAL_ABSPATH. Return
8033 ### Why not text- or prop-conflicted paths? Are such paths guaranteed
8034 to be recorded as 'merged' or 'skipped' or 'added', perhaps?
8036 static svn_boolean_t
8037 subtree_touched_by_merge(const char *local_abspath,
8038 merge_cmd_baton_t *merge_b,
8041 return (path_is_subtree(local_abspath, merge_b->merged_abspaths, pool)
8042 || path_is_subtree(local_abspath, merge_b->skipped_abspaths, pool)
8043 || path_is_subtree(local_abspath, merge_b->added_abspaths, pool)
8044 || path_is_subtree(local_abspath, merge_b->tree_conflicted_abspaths,
8048 /* Helper for do_directory_merge() when performing mergeinfo unaware merges.
8050 Merge the SOURCE diff into TARGET_DIR_WCPATH.
8052 SOURCE, DEPTH, NOTIFY_B, and MERGE_B
8053 are all cascaded from do_directory_merge's arguments of the same names.
8055 CONFLICT_REPORT is as documented for do_directory_merge().
8057 NOTE: This is a very thin wrapper around drive_merge_report_editor() and
8058 exists only to populate CHILDREN_WITH_MERGEINFO with the single element
8059 expected during mergeinfo unaware merges.
8061 static svn_error_t *
8062 do_mergeinfo_unaware_dir_merge(single_range_conflict_report_t **conflict_report,
8063 const merge_source_t *source,
8064 const char *target_dir_wcpath,
8065 apr_array_header_t *children_with_mergeinfo,
8066 const svn_diff_tree_processor_t *processor,
8068 merge_cmd_baton_t *merge_b,
8069 apr_pool_t *result_pool,
8070 apr_pool_t *scratch_pool)
8072 /* Initialize CHILDREN_WITH_MERGEINFO and populate it with
8073 one element describing the merge of SOURCE->rev1:rev2 to
8074 TARGET_DIR_WCPATH. */
8075 svn_client__merge_path_t *item
8076 = svn_client__merge_path_create(target_dir_wcpath, scratch_pool);
8078 *conflict_report = NULL;
8079 item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
8081 TRUE, scratch_pool);
8082 APR_ARRAY_PUSH(children_with_mergeinfo,
8083 svn_client__merge_path_t *) = item;
8084 SVN_ERR(drive_merge_report_editor(target_dir_wcpath,
8086 NULL, processor, depth,
8087 merge_b, scratch_pool));
8088 if (is_path_conflicted_by_merge(merge_b))
8090 *conflict_report = single_range_conflict_report_create(
8091 source, NULL, result_pool);
8093 return SVN_NO_ERROR;
8096 /* A svn_log_entry_receiver_t baton for log_find_operative_subtree_revs(). */
8097 typedef struct log_find_operative_subtree_baton_t
8099 /* Mapping of const char * absolute working copy paths to those
8100 path's const char * repos absolute paths. */
8101 apr_hash_t *operative_children;
8103 /* As per the arguments of the same name to
8104 get_operative_immediate_children(). */
8105 const char *merge_source_fspath;
8106 const char *merge_target_abspath;
8108 svn_wc_context_t *wc_ctx;
8110 /* A pool to allocate additions to the hashes in. */
8111 apr_pool_t *result_pool;
8112 } log_find_operative_subtree_baton_t;
8114 /* A svn_log_entry_receiver_t callback for
8115 get_inoperative_immediate_children(). */
8116 static svn_error_t *
8117 log_find_operative_subtree_revs(void *baton,
8118 svn_log_entry_t *log_entry,
8121 log_find_operative_subtree_baton_t *log_baton = baton;
8122 apr_hash_index_t *hi;
8123 apr_pool_t *iterpool;
8125 /* It's possible that authz restrictions on the merge source prevent us
8126 from knowing about any of the changes for LOG_ENTRY->REVISION. */
8127 if (!log_entry->changed_paths2)
8128 return SVN_NO_ERROR;
8130 iterpool = svn_pool_create(pool);
8132 for (hi = apr_hash_first(pool, log_entry->changed_paths2);
8134 hi = apr_hash_next(hi))
8136 const char *path = apr_hash_this_key(hi);
8137 svn_log_changed_path2_t *change = apr_hash_this_val(hi);
8141 const char *potential_child;
8142 const char *rel_path =
8143 svn_fspath__skip_ancestor(log_baton->merge_source_fspath, path);
8145 /* Some affected paths might be the root of the merge source or
8146 entirely outside our subtree of interest. In either case they
8147 are not operative *immediate* children. */
8148 if (rel_path == NULL
8149 || rel_path[0] == '\0')
8152 svn_pool_clear(iterpool);
8154 child = svn_relpath_dirname(rel_path, iterpool);
8155 if (child[0] == '\0')
8157 /* The svn_log_changed_path2_t.node_kind members in
8158 LOG_ENTRY->CHANGED_PATHS2 may be set to
8159 svn_node_unknown, see svn_log_changed_path2_t and
8160 svn_fs_paths_changed2. In that case we check the
8161 type of the corresponding subtree in the merge
8163 svn_node_kind_t node_kind;
8165 if (change->node_kind == svn_node_unknown)
8167 const char *wc_child_abspath =
8168 svn_dirent_join(log_baton->merge_target_abspath,
8169 rel_path, iterpool);
8171 SVN_ERR(svn_wc_read_kind2(&node_kind, log_baton->wc_ctx,
8172 wc_child_abspath, FALSE, FALSE,
8177 node_kind = change->node_kind;
8180 /* We only care about immediate directory children if
8181 DEPTH is svn_depth_files. */
8182 if (log_baton->depth == svn_depth_files
8183 && node_kind != svn_node_dir)
8186 /* If depth is svn_depth_immediates, then we only care
8187 about changes to proper subtrees of PATH. If the change
8188 is to PATH itself then PATH is within the operational
8189 depth of the merge. */
8190 if (log_baton->depth == svn_depth_immediates)
8196 potential_child = svn_dirent_join(log_baton->merge_target_abspath,
8199 if (change->action == 'A'
8200 || !svn_hash_gets(log_baton->operative_children,
8203 svn_hash_sets(log_baton->operative_children,
8204 apr_pstrdup(log_baton->result_pool,
8206 apr_pstrdup(log_baton->result_pool, path));
8210 svn_pool_destroy(iterpool);
8211 return SVN_NO_ERROR;
8214 /* Find immediate subtrees of MERGE_TARGET_ABSPATH which would have
8215 additional differences applied if record_mergeinfo_for_dir_merge() were
8216 recording mergeinfo describing a merge at svn_depth_infinity, rather
8217 than at DEPTH (which is assumed to be shallow; if
8218 DEPTH == svn_depth_infinity then this function does nothing beyond
8219 setting *OPERATIVE_CHILDREN to an empty hash).
8221 MERGE_SOURCE_FSPATH is the absolute repository path of the merge
8222 source. OLDEST_REV and YOUNGEST_REV are the revisions merged from
8223 MERGE_SOURCE_FSPATH to MERGE_TARGET_ABSPATH.
8225 RA_SESSION points to MERGE_SOURCE_FSPATH.
8227 Set *OPERATIVE_CHILDREN to a hash (mapping const char * absolute
8228 working copy paths to those path's const char * repos absolute paths)
8229 containing all the immediate subtrees of MERGE_TARGET_ABSPATH which would
8230 have a different diff applied if MERGE_SOURCE_FSPATH
8231 -r(OLDEST_REV - 1):YOUNGEST_REV were merged to MERGE_TARGET_ABSPATH at
8232 svn_depth_infinity rather than DEPTH.
8234 RESULT_POOL is used to allocate the contents of *OPERATIVE_CHILDREN.
8235 SCRATCH_POOL is used for temporary allocations. */
8236 static svn_error_t *
8237 get_operative_immediate_children(apr_hash_t **operative_children,
8238 const char *merge_source_fspath,
8239 svn_revnum_t oldest_rev,
8240 svn_revnum_t youngest_rev,
8241 const char *merge_target_abspath,
8243 svn_wc_context_t *wc_ctx,
8244 svn_ra_session_t *ra_session,
8245 apr_pool_t *result_pool,
8246 apr_pool_t *scratch_pool)
8248 log_find_operative_subtree_baton_t log_baton;
8250 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
8251 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
8252 SVN_ERR_ASSERT(oldest_rev <= youngest_rev);
8254 *operative_children = apr_hash_make(result_pool);
8256 if (depth == svn_depth_infinity)
8257 return SVN_NO_ERROR;
8259 /* Now remove any paths from *OPERATIVE_CHILDREN that are inoperative when
8260 merging MERGE_SOURCE_REPOS_PATH -r(OLDEST_REV - 1):YOUNGEST_REV to
8261 MERGE_TARGET_ABSPATH at --depth infinity. */
8262 log_baton.operative_children = *operative_children;
8263 log_baton.merge_source_fspath = merge_source_fspath;
8264 log_baton.merge_target_abspath = merge_target_abspath;
8265 log_baton.depth = depth;
8266 log_baton.wc_ctx = wc_ctx;
8267 log_baton.result_pool = result_pool;
8269 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev,
8270 TRUE, /* discover_changed_paths */
8271 log_find_operative_subtree_revs,
8272 &log_baton, scratch_pool));
8274 return SVN_NO_ERROR;
8277 /* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of
8278 CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately
8279 describe a merge, what inheritance type such new mergeinfo should have,
8280 and what subtrees can be ignored altogether.
8282 For each svn_client__merge_path_t CHILD in CHILDREN_WITH_MERGEINFO,
8283 set CHILD->RECORD_MERGEINFO and CHILD->RECORD_NONINHERITABLE to true
8284 if the subtree needs mergeinfo to describe the merge and if that
8285 mergeinfo should be non-inheritable respectively.
8287 If OPERATIVE_MERGE is true, then the merge being described is operative
8288 as per subtree_touched_by_merge(). OPERATIVE_MERGE is false otherwise.
8290 MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all
8291 cascaded from record_mergeinfo_for_dir_merge's arguments of the same
8294 SCRATCH_POOL is used for temporary allocations.
8296 static svn_error_t *
8297 flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
8298 const svn_merge_range_t *merged_range,
8299 apr_array_header_t *children_with_mergeinfo,
8300 const char *mergeinfo_fspath,
8302 merge_cmd_baton_t *merge_b,
8303 apr_pool_t *scratch_pool)
8305 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
8307 apr_hash_t *operative_immediate_children = NULL;
8309 assert(! merge_b->dry_run);
8311 if (!merge_b->record_only
8312 && merged_range->start <= merged_range->end
8313 && (depth < svn_depth_infinity))
8314 SVN_ERR(get_operative_immediate_children(
8315 &operative_immediate_children,
8316 mergeinfo_fspath, merged_range->start + 1, merged_range->end,
8317 merge_b->target->abspath, depth, merge_b->ctx->wc_ctx,
8318 merge_b->ra_session1, scratch_pool, iterpool));
8320 /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
8321 order. This way each child knows if it has operative missing/switched
8322 children which necessitates non-inheritable mergeinfo. */
8323 for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--)
8325 svn_client__merge_path_t *child =
8326 APR_ARRAY_IDX(children_with_mergeinfo, i,
8327 svn_client__merge_path_t *);
8329 /* Can't record mergeinfo on something that isn't here. */
8333 /* Verify that remove_children_with_deleted_mergeinfo() did its job */
8335 ||! merge_b->paths_with_deleted_mergeinfo
8336 || !svn_hash_gets(merge_b->paths_with_deleted_mergeinfo,
8339 /* Don't record mergeinfo on skipped paths. */
8340 if (svn_hash_gets(merge_b->skipped_abspaths, child->abspath))
8343 /* ### ptb: Yes, we could combine the following into a single
8344 ### conditional, but clarity would suffer (even more than
8345 ### it does now). */
8348 /* Always record mergeinfo on the merge target. */
8349 child->record_mergeinfo = TRUE;
8351 else if (merge_b->record_only && !merge_b->reintegrate_merge)
8353 /* Always record mergeinfo for --record-only merges. */
8354 child->record_mergeinfo = TRUE;
8356 else if (child->immediate_child_dir
8357 && !child->pre_merge_mergeinfo
8358 && operative_immediate_children
8359 && svn_hash_gets(operative_immediate_children, child->abspath))
8361 /* We must record mergeinfo on those issue #3642 children
8362 that are operative at a greater depth. */
8363 child->record_mergeinfo = TRUE;
8367 && subtree_touched_by_merge(child->abspath, merge_b, iterpool))
8369 svn_pool_clear(iterpool);
8371 /* This subtree was affected by the merge. */
8372 child->record_mergeinfo = TRUE;
8374 /* Were any CHILD's missing children skipped by the merge?
8375 If not, then CHILD's missing children don't need to be
8376 considered when recording mergeinfo describing the merge. */
8377 if (! merge_b->reintegrate_merge
8378 && child->missing_child
8379 && !path_is_subtree(child->abspath,
8380 merge_b->skipped_abspaths,
8383 child->missing_child = FALSE;
8386 /* If CHILD has an immediate switched child or children and
8387 none of these were touched by the merge, then we don't need
8388 need to do any special handling of those switched subtrees
8389 (e.g. record non-inheritable mergeinfo) when recording
8390 mergeinfo describing the merge. */
8391 if (child->switched_child)
8394 svn_boolean_t operative_switched_child = FALSE;
8397 j < children_with_mergeinfo->nelts;
8400 svn_client__merge_path_t *potential_child =
8401 APR_ARRAY_IDX(children_with_mergeinfo, j,
8402 svn_client__merge_path_t *);
8403 if (!svn_dirent_is_ancestor(child->abspath,
8404 potential_child->abspath))
8407 /* POTENTIAL_CHILD is a subtree of CHILD, but is it
8408 an immediate child? */
8409 if (strcmp(child->abspath,
8410 svn_dirent_dirname(potential_child->abspath,
8414 if (potential_child->switched
8415 && potential_child->record_mergeinfo)
8417 operative_switched_child = TRUE;
8422 /* Can we treat CHILD as if it has no switched children? */
8423 if (! operative_switched_child)
8424 child->switched_child = FALSE;
8428 if (child->record_mergeinfo)
8430 /* We need to record mergeinfo, but should that mergeinfo be
8432 svn_node_kind_t path_kind;
8433 SVN_ERR(svn_wc_read_kind2(&path_kind, merge_b->ctx->wc_ctx,
8434 child->abspath, FALSE, FALSE, iterpool));
8436 /* Only directories can have non-inheritable mergeinfo. */
8437 if (path_kind == svn_node_dir)
8439 /* There are two general cases where non-inheritable mergeinfo
8442 1) There merge target has missing subtrees (due to authz
8443 restrictions, switched subtrees, or a shallow working
8446 2) The operational depth of the merge itself is shallow. */
8448 /* We've already determined the first case. */
8449 child->record_noninheritable =
8450 child->missing_child || child->switched_child;
8452 /* The second case requires a bit more work. */
8455 /* If CHILD is the root of the merge target and the
8456 operational depth is empty or files, then the mere
8457 existence of operative immediate children means we
8458 must record non-inheritable mergeinfo.
8460 ### What about svn_depth_immediates? In that case
8461 ### the merge target needs only normal inheritable
8462 ### mergeinfo and the target's immediate children will
8463 ### get non-inheritable mergeinfo, assuming they
8464 ### need even that. */
8465 if (depth < svn_depth_immediates
8466 && operative_immediate_children
8467 && apr_hash_count(operative_immediate_children))
8468 child->record_noninheritable = TRUE;
8470 else if (depth == svn_depth_immediates)
8472 /* An immediate directory child of the merge target, which
8473 was affected by a --depth=immediates merge, needs
8474 non-inheritable mergeinfo. */
8475 if (svn_hash_gets(operative_immediate_children,
8477 child->record_noninheritable = TRUE;
8481 else /* child->record_mergeinfo */
8483 /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
8484 because it had no explicit mergeinfo of its own at the
8485 start of the merge but is the child of of some path with
8486 non-inheritable mergeinfo, then the explicit mergeinfo it
8487 has *now* was set by get_mergeinfo_paths() -- see criteria
8488 3 in that function's doc string. So since CHILD->ABSPATH
8489 was not touched by the merge we can remove the
8491 if (child->child_of_noninheritable)
8492 SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
8499 svn_pool_destroy(iterpool);
8500 return SVN_NO_ERROR;
8503 /* Helper for do_directory_merge().
8505 If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
8506 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
8507 MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described
8508 by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment
8509 'THE CHILDREN_WITH_MERGEINFO ARRAY'. Obviously this should only
8510 be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO().
8512 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
8513 WC, but instead record it in RESULT_CATALOG, where the keys are absolute
8514 working copy paths and the values are the new mergeinfos for each.
8515 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
8518 DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS are all
8519 cascaded from do_directory_merge's arguments of the same names.
8521 SCRATCH_POOL is used for temporary allocations.
8523 static svn_error_t *
8524 record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog,
8525 const svn_merge_range_t *merged_range,
8526 const char *mergeinfo_fspath,
8527 apr_array_header_t *children_with_mergeinfo,
8529 svn_boolean_t squelch_mergeinfo_notifications,
8530 merge_cmd_baton_t *merge_b,
8531 apr_pool_t *scratch_pool)
8534 svn_boolean_t is_rollback = (merged_range->start > merged_range->end);
8535 svn_boolean_t operative_merge;
8537 /* Update the WC mergeinfo here to account for our new
8538 merges, minus any unresolved conflicts and skips. */
8540 /* We need a scratch pool for iterations below. */
8541 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
8543 svn_merge_range_t range = *merged_range;
8545 assert(! merge_b->dry_run);
8547 /* Regardless of what subtrees in MERGE_B->target->abspath might be missing
8548 could this merge have been operative? */
8549 operative_merge = subtree_touched_by_merge(merge_b->target->abspath,
8552 /* If this couldn't be an operative merge then don't bother with
8553 the added complexity (and user confusion) of non-inheritable ranges.
8554 There is no harm in subtrees inheriting inoperative mergeinfo. */
8555 if (!operative_merge)
8556 range.inheritable = TRUE;
8558 /* Remove absent children at or under MERGE_B->target->abspath from
8559 NOTIFY_B->CHILDREN_WITH_MERGEINFO
8560 before we calculate the merges performed. */
8561 remove_absent_children(merge_b->target->abspath,
8562 children_with_mergeinfo);
8564 /* Determine which subtrees of interest need mergeinfo recorded... */
8565 SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
8566 children_with_mergeinfo,
8567 mergeinfo_fspath, depth,
8568 merge_b, iterpool));
8570 /* ...and then record it. */
8571 for (i = 0; i < children_with_mergeinfo->nelts; i++)
8573 const char *child_repos_path;
8574 const char *child_merge_src_fspath;
8575 svn_rangelist_t *child_merge_rangelist;
8576 apr_hash_t *child_merges;
8577 svn_client__merge_path_t *child =
8578 APR_ARRAY_IDX(children_with_mergeinfo, i,
8579 svn_client__merge_path_t *);
8580 SVN_ERR_ASSERT(child);
8582 svn_pool_clear(iterpool);
8584 if (child->record_mergeinfo)
8586 child_repos_path = svn_dirent_skip_ancestor(merge_b->target->abspath,
8588 SVN_ERR_ASSERT(child_repos_path != NULL);
8589 child_merge_src_fspath = svn_fspath__join(mergeinfo_fspath,
8592 /* Filter any ranges from each child's natural history before
8593 setting mergeinfo describing the merge. */
8594 SVN_ERR(filter_natural_history_from_mergeinfo(
8595 &child_merge_rangelist, child_merge_src_fspath,
8596 child->implicit_mergeinfo, &range, iterpool));
8598 if (child_merge_rangelist->nelts == 0)
8601 if (!squelch_mergeinfo_notifications)
8603 /* If the merge source has a gap, then don't mention
8604 those gap revisions in the notification. */
8605 remove_source_gap(&range, merge_b->implicit_src_gap);
8606 notify_mergeinfo_recording(child->abspath, &range,
8607 merge_b->ctx, iterpool);
8610 /* If we are here we know we will be recording some mergeinfo, but
8611 before we do, set override mergeinfo on skipped paths so they
8612 don't incorrectly inherit the mergeinfo we are about to set. */
8614 SVN_ERR(record_skips_in_mergeinfo(mergeinfo_fspath,
8615 child_merge_rangelist,
8616 is_rollback, merge_b, iterpool));
8618 /* We may need to record non-inheritable mergeinfo that applies
8619 only to CHILD->ABSPATH. */
8620 if (child->record_noninheritable)
8621 svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
8623 /* If CHILD has inherited mergeinfo set it before
8624 recording the first merge range. */
8625 if (child->inherited_mergeinfo)
8626 SVN_ERR(svn_client__record_wc_mergeinfo(
8628 child->pre_merge_mergeinfo,
8629 FALSE, merge_b->ctx,
8631 if (merge_b->implicit_src_gap)
8633 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
8634 so it will work with the svn_rangelist_remove API. */
8636 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist,
8639 SVN_ERR(svn_rangelist_remove(&child_merge_rangelist,
8640 merge_b->implicit_src_gap,
8641 child_merge_rangelist, FALSE,
8644 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist,
8648 child_merges = apr_hash_make(iterpool);
8652 If we are describing a forward merge, then the naive mergeinfo
8653 defined by MERGE_SOURCE_PATH:MERGED_RANGE->START:
8654 MERGE_SOURCE_PATH:MERGED_RANGE->END may contain non-existent
8655 path-revs or may describe other lines of history. We must
8656 remove these invalid portion(s) before recording mergeinfo
8657 describing the merge.
8661 If CHILD is the merge target we know that
8662 MERGE_SOURCE_PATH:MERGED_RANGE->END exists. Further, if there
8663 were no copies in MERGE_SOURCE_PATH's history going back to
8664 RANGE->START then we know that
8665 MERGE_SOURCE_PATH:MERGED_RANGE->START exists too and the two
8666 describe an unbroken line of history, and thus
8667 MERGE_SOURCE_PATH:MERGED_RANGE->START:
8668 MERGE_SOURCE_PATH:MERGED_RANGE->END is a valid description of
8669 the merge -- see normalize_merge_sources() and the global comment
8670 'MERGEINFO MERGE SOURCE NORMALIZATION'.
8672 However, if there *was* a copy, then
8673 MERGE_SOURCE_PATH:MERGED_RANGE->START doesn't exist or is
8674 unrelated to MERGE_SOURCE_PATH:MERGED_RANGE->END. Also, we
8675 don't know if (MERGE_SOURCE_PATH:MERGED_RANGE->START)+1 through
8676 (MERGE_SOURCE_PATH:MERGED_RANGE->END)-1 actually exist.
8678 If CHILD is a subtree of the merge target, then nothing is
8679 guaranteed beyond the fact that MERGE_SOURCE_PATH exists at
8680 MERGED_RANGE->END. */
8681 if ((!merge_b->record_only || merge_b->reintegrate_merge)
8685 svn_mergeinfo_t subtree_history_as_mergeinfo;
8686 svn_rangelist_t *child_merge_src_rangelist;
8687 svn_client__pathrev_t *subtree_mergeinfo_pathrev
8688 = svn_client__pathrev_create_with_relpath(
8689 merge_b->target->loc.repos_root_url,
8690 merge_b->target->loc.repos_uuid,
8691 merged_range->end, child_merge_src_fspath + 1,
8694 /* Confirm that the naive mergeinfo we want to set on
8695 CHILD->ABSPATH both exists and is part of
8696 (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's
8698 /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START
8699 because we only do this for forward merges. */
8700 err = svn_client__get_history_as_mergeinfo(
8701 &subtree_history_as_mergeinfo, NULL,
8702 subtree_mergeinfo_pathrev,
8703 merged_range->end, merged_range->start,
8704 merge_b->ra_session2, merge_b->ctx, iterpool);
8706 /* If CHILD is a subtree it may have been deleted prior to
8707 MERGED_RANGE->END so the above call to get its history
8711 if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
8712 return svn_error_trace(err);
8713 svn_error_clear(err);
8717 child_merge_src_rangelist = svn_hash_gets(
8718 subtree_history_as_mergeinfo,
8719 child_merge_src_fspath);
8720 SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist,
8721 child_merge_rangelist,
8722 child_merge_src_rangelist,
8724 if (child->record_noninheritable)
8725 svn_rangelist__set_inheritance(child_merge_rangelist,
8730 svn_hash_sets(child_merges, child->abspath, child_merge_rangelist);
8731 SVN_ERR(update_wc_mergeinfo(result_catalog,
8733 child_merge_src_fspath,
8734 child_merges, is_rollback,
8735 merge_b->ctx, iterpool));
8737 /* Once is enough: We don't need to record mergeinfo describing
8738 the merge a second. If CHILD->ABSPATH is in
8739 MERGE_B->ADDED_ABSPATHS, we'll do just that, so remove the
8740 former from the latter. */
8741 svn_hash_sets(merge_b->added_abspaths, child->abspath, NULL);
8744 /* Elide explicit subtree mergeinfo whether or not we updated it. */
8747 svn_boolean_t in_switched_subtree = FALSE;
8749 if (child->switched)
8750 in_switched_subtree = TRUE;
8753 /* Check if CHILD is part of a switched subtree */
8754 svn_client__merge_path_t *parent;
8758 parent = APR_ARRAY_IDX(children_with_mergeinfo,
8759 j, svn_client__merge_path_t *);
8762 && svn_dirent_is_ancestor(parent->abspath,
8765 in_switched_subtree = TRUE;
8771 /* Allow mergeinfo on switched subtrees to elide to the
8772 repository. Otherwise limit elision to the merge target
8773 for now. do_merge() will eventually try to
8774 elide that when the merge is complete. */
8775 SVN_ERR(svn_client__elide_mergeinfo(
8777 in_switched_subtree ? NULL : merge_b->target->abspath,
8778 merge_b->ctx, iterpool));
8780 } /* (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++) */
8782 svn_pool_destroy(iterpool);
8783 return SVN_NO_ERROR;
8786 /* Helper for do_directory_merge().
8788 Record mergeinfo describing a merge of
8789 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
8790 MERGEINFO_FSPATH to each path in ADDED_ABSPATHS which has explicit
8791 mergeinfo or is the immediate child of a parent with explicit
8792 non-inheritable mergeinfo.
8794 DEPTH, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS, are
8795 cascaded from do_directory_merge's arguments of the same names.
8797 Note: This is intended to support forward merges only, i.e.
8798 MERGED_RANGE->START must be older than MERGED_RANGE->END.
8800 static svn_error_t *
8801 record_mergeinfo_for_added_subtrees(
8802 svn_merge_range_t *merged_range,
8803 const char *mergeinfo_fspath,
8805 svn_boolean_t squelch_mergeinfo_notifications,
8806 apr_hash_t *added_abspaths,
8807 merge_cmd_baton_t *merge_b,
8810 apr_pool_t *iterpool;
8811 apr_hash_index_t *hi;
8813 /* If no paths were added by the merge then we have nothing to do. */
8814 if (!added_abspaths)
8815 return SVN_NO_ERROR;
8817 SVN_ERR_ASSERT(merged_range->start < merged_range->end);
8819 iterpool = svn_pool_create(pool);
8820 for (hi = apr_hash_first(pool, added_abspaths); hi; hi = apr_hash_next(hi))
8822 const char *added_abspath = apr_hash_this_key(hi);
8823 const char *dir_abspath;
8824 svn_mergeinfo_t parent_mergeinfo;
8825 svn_mergeinfo_t added_path_mergeinfo;
8827 svn_pool_clear(iterpool);
8828 dir_abspath = svn_dirent_dirname(added_abspath, iterpool);
8830 /* Grab the added path's explicit mergeinfo. */
8831 SVN_ERR(svn_client__get_wc_mergeinfo(&added_path_mergeinfo, NULL,
8832 svn_mergeinfo_explicit,
8833 added_abspath, NULL, NULL, FALSE,
8834 merge_b->ctx, iterpool, iterpool));
8836 /* If the added path doesn't have explicit mergeinfo, does its immediate
8837 parent have non-inheritable mergeinfo? */
8838 if (!added_path_mergeinfo)
8839 SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, NULL,
8840 svn_mergeinfo_explicit,
8841 dir_abspath, NULL, NULL, FALSE,
8843 iterpool, iterpool));
8845 if (added_path_mergeinfo
8846 || svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool))
8848 svn_node_kind_t added_path_kind;
8849 svn_mergeinfo_t merge_mergeinfo;
8850 svn_mergeinfo_t adds_history_as_mergeinfo;
8851 svn_rangelist_t *rangelist;
8852 const char *rel_added_path;
8853 const char *added_path_mergeinfo_fspath;
8854 svn_client__pathrev_t *added_path_pathrev;
8856 SVN_ERR(svn_wc_read_kind2(&added_path_kind, merge_b->ctx->wc_ctx,
8857 added_abspath, FALSE, FALSE, iterpool));
8859 /* Calculate the naive mergeinfo describing the merge. */
8860 merge_mergeinfo = apr_hash_make(iterpool);
8861 rangelist = svn_rangelist__initialize(
8862 merged_range->start, merged_range->end,
8863 ((added_path_kind == svn_node_file)
8864 || (!(depth == svn_depth_infinity
8865 || depth == svn_depth_immediates))),
8868 /* Create the new mergeinfo path for added_path's mergeinfo.
8869 (added_abspath had better be a child of MERGE_B->target->abspath
8870 or something is *really* wrong.) */
8871 rel_added_path = svn_dirent_is_child(merge_b->target->abspath,
8872 added_abspath, iterpool);
8873 SVN_ERR_ASSERT(rel_added_path);
8874 added_path_mergeinfo_fspath = svn_fspath__join(mergeinfo_fspath,
8877 svn_hash_sets(merge_mergeinfo, added_path_mergeinfo_fspath,
8880 /* Don't add new mergeinfo to describe the merge if that mergeinfo
8881 contains non-existent merge sources.
8883 We know that MERGEINFO_PATH/rel_added_path's history does not
8884 span MERGED_RANGE->START:MERGED_RANGE->END but rather that it
8885 was added at some revions greater than MERGED_RANGE->START
8886 (assuming this is a forward merge). It may have been added,
8887 deleted, and re-added many times. The point is that we cannot
8888 blindly apply the naive mergeinfo calculated above because it
8889 will describe non-existent merge sources. To avoid this we get
8890 take the intersection of the naive mergeinfo with
8891 MERGEINFO_PATH/rel_added_path's history. */
8892 added_path_pathrev = svn_client__pathrev_create_with_relpath(
8893 merge_b->target->loc.repos_root_url,
8894 merge_b->target->loc.repos_uuid,
8895 MAX(merged_range->start, merged_range->end),
8896 added_path_mergeinfo_fspath + 1, iterpool);
8897 SVN_ERR(svn_client__get_history_as_mergeinfo(
8898 &adds_history_as_mergeinfo, NULL,
8900 MAX(merged_range->start, merged_range->end),
8901 MIN(merged_range->start, merged_range->end),
8902 merge_b->ra_session2, merge_b->ctx, iterpool));
8904 SVN_ERR(svn_mergeinfo_intersect2(&merge_mergeinfo,
8906 adds_history_as_mergeinfo,
8907 FALSE, iterpool, iterpool));
8909 /* Combine the explicit mergeinfo on the added path (if any)
8910 with the mergeinfo describing this merge. */
8911 if (added_path_mergeinfo)
8912 SVN_ERR(svn_mergeinfo_merge2(merge_mergeinfo,
8913 added_path_mergeinfo,
8914 iterpool, iterpool));
8915 SVN_ERR(svn_client__record_wc_mergeinfo(
8916 added_abspath, merge_mergeinfo,
8917 !squelch_mergeinfo_notifications, merge_b->ctx, iterpool));
8920 svn_pool_destroy(iterpool);
8922 return SVN_NO_ERROR;
8924 /* Baton structure for log_noop_revs. */
8925 typedef struct log_noop_baton_t
8927 /* See the comment 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start
8929 apr_array_header_t *children_with_mergeinfo;
8931 /* Absolute repository path of younger of the two merge sources
8933 const char *source_fspath;
8935 /* The merge target. */
8936 const merge_target_t *target;
8938 /* Initially empty rangelists allocated in POOL. The rangelists are
8939 * populated across multiple invocations of log_noop_revs(). */
8940 svn_rangelist_t *operative_ranges;
8941 svn_rangelist_t *merged_ranges;
8943 /* Pool to store the rangelists. */
8947 /* Helper for log_noop_revs: Merge a svn_merge_range_t representation of
8948 REVISION into RANGELIST. New elements added to rangelist are allocated
8951 This is *not* a general purpose rangelist merge but a special replacement
8952 for svn_rangelist_merge when REVISION is guaranteed to be younger than any
8953 element in RANGELIST. svn_rangelist_merge is O(n) worst-case (i.e. when
8954 all the ranges in output rangelist are older than the incoming changes).
8955 This turns the special case of a single incoming younger range into O(1).
8957 static svn_error_t *
8958 rangelist_merge_revision(svn_rangelist_t *rangelist,
8959 svn_revnum_t revision,
8960 apr_pool_t *result_pool)
8962 svn_merge_range_t *new_range;
8963 if (rangelist->nelts)
8965 svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
8966 svn_merge_range_t *);
8967 if (range->end == revision - 1)
8969 /* REVISION is adjacent to the youngest range in RANGELIST
8970 so we can simply expand that range to encompass REVISION. */
8971 range->end = revision;
8972 return SVN_NO_ERROR;
8975 new_range = apr_palloc(result_pool, sizeof(*new_range));
8976 new_range->start = revision - 1;
8977 new_range->end = revision;
8978 new_range->inheritable = TRUE;
8980 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = new_range;
8982 return SVN_NO_ERROR;
8985 /* Implements the svn_log_entry_receiver_t interface.
8987 BATON is an log_noop_baton_t *.
8989 Add LOG_ENTRY->REVISION to BATON->OPERATIVE_RANGES.
8991 If LOG_ENTRY->REVISION has already been fully merged to
8992 BATON->target->abspath per the mergeinfo in BATON->CHILDREN_WITH_MERGEINFO,
8993 then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES.
8995 Use SCRATCH_POOL for temporary allocations. Allocate additions to
8996 BATON->MERGED_RANGES and BATON->OPERATIVE_RANGES in BATON->POOL.
8998 Note: This callback must be invoked from oldest LOG_ENTRY->REVISION
8999 to youngest LOG_ENTRY->REVISION -- see rangelist_merge_revision().
9001 static svn_error_t *
9002 log_noop_revs(void *baton,
9003 svn_log_entry_t *log_entry,
9004 apr_pool_t *scratch_pool)
9006 log_noop_baton_t *log_gap_baton = baton;
9007 apr_hash_index_t *hi;
9008 svn_revnum_t revision;
9009 svn_boolean_t log_entry_rev_required = FALSE;
9011 revision = log_entry->revision;
9013 /* It's possible that authz restrictions on the merge source prevent us
9014 from knowing about any of the changes for LOG_ENTRY->REVISION. */
9015 if (!log_entry->changed_paths2)
9016 return SVN_NO_ERROR;
9018 /* Unconditionally add LOG_ENTRY->REVISION to BATON->OPERATIVE_MERGES. */
9019 SVN_ERR(rangelist_merge_revision(log_gap_baton->operative_ranges,
9021 log_gap_baton->pool));
9023 /* Examine each path affected by LOG_ENTRY->REVISION. If the explicit or
9024 inherited mergeinfo for *all* of the corresponding paths under
9025 BATON->target->abspath reflects that LOG_ENTRY->REVISION has been
9026 merged, then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. */
9027 for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2);
9029 hi = apr_hash_next(hi))
9031 const char *fspath = apr_hash_this_key(hi);
9032 const char *rel_path;
9033 const char *cwmi_abspath;
9034 svn_rangelist_t *paths_explicit_rangelist = NULL;
9035 svn_boolean_t mergeinfo_inherited = FALSE;
9037 /* Adjust REL_PATH so it is relative to the merge source then use it to
9038 calculate what path in the merge target would be affected by this
9040 rel_path = svn_fspath__skip_ancestor(log_gap_baton->source_fspath,
9042 /* Is PATH even within the merge target? If it isn't we
9043 can disregard it altogether. */
9044 if (rel_path == NULL)
9046 cwmi_abspath = svn_dirent_join(log_gap_baton->target->abspath,
9047 rel_path, scratch_pool);
9049 /* Find any explicit or inherited mergeinfo for PATH. */
9050 while (!log_entry_rev_required)
9052 svn_client__merge_path_t *child = get_child_with_mergeinfo(
9053 log_gap_baton->children_with_mergeinfo, cwmi_abspath);
9055 if (child && child->pre_merge_mergeinfo)
9057 /* Found some explicit mergeinfo, grab any ranges
9059 paths_explicit_rangelist =
9060 svn_hash_gets(child->pre_merge_mergeinfo, fspath);
9064 if (cwmi_abspath[0] == '\0'
9065 || svn_dirent_is_root(cwmi_abspath, strlen(cwmi_abspath))
9066 || strcmp(log_gap_baton->target->abspath, cwmi_abspath) == 0)
9068 /* Can't crawl any higher. */
9072 /* Didn't find anything so crawl up to the parent. */
9073 cwmi_abspath = svn_dirent_dirname(cwmi_abspath, scratch_pool);
9074 fspath = svn_fspath__dirname(fspath, scratch_pool);
9076 /* At this point *if* we find mergeinfo it will be inherited. */
9077 mergeinfo_inherited = TRUE;
9080 if (paths_explicit_rangelist)
9082 svn_rangelist_t *intersecting_range;
9083 svn_rangelist_t *rangelist;
9085 rangelist = svn_rangelist__initialize(revision - 1, revision, TRUE,
9088 /* If PATH inherited mergeinfo we must consider inheritance in the
9089 event the inherited mergeinfo is actually non-inheritable. */
9090 SVN_ERR(svn_rangelist_intersect(&intersecting_range,
9091 paths_explicit_rangelist,
9093 mergeinfo_inherited, scratch_pool));
9095 if (intersecting_range->nelts == 0)
9096 log_entry_rev_required = TRUE;
9100 log_entry_rev_required = TRUE;
9104 if (!log_entry_rev_required)
9105 SVN_ERR(rangelist_merge_revision(log_gap_baton->merged_ranges,
9107 log_gap_baton->pool));
9109 return SVN_NO_ERROR;
9112 /* Helper for do_directory_merge().
9114 SOURCE is cascaded from the argument of the same name in
9115 do_directory_merge(). TARGET is the merge target. RA_SESSION is the
9116 session for SOURCE->loc2.
9118 Find all the ranges required by subtrees in
9119 CHILDREN_WITH_MERGEINFO that are *not* required by
9120 TARGET->abspath (i.e. CHILDREN_WITH_MERGEINFO[0]). If such
9121 ranges exist, then find any subset of ranges which, if merged, would be
9122 inoperative. Finally, if any inoperative ranges are found then remove
9123 these ranges from all of the subtree's REMAINING_RANGES.
9125 This function should only be called when honoring mergeinfo during
9126 forward merges (i.e. SOURCE->rev1 < SOURCE->rev2).
9128 static svn_error_t *
9129 remove_noop_subtree_ranges(const merge_source_t *source,
9130 const merge_target_t *target,
9131 svn_ra_session_t *ra_session,
9132 apr_array_header_t *children_with_mergeinfo,
9133 apr_pool_t *result_pool,
9134 apr_pool_t *scratch_pool)
9136 /* ### Do we need to check that we are at a uniform working revision? */
9138 svn_client__merge_path_t *root_child =
9139 APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *);
9140 svn_rangelist_t *requested_ranges;
9141 svn_rangelist_t *subtree_gap_ranges;
9142 svn_rangelist_t *subtree_remaining_ranges;
9143 log_noop_baton_t log_gap_baton;
9144 svn_merge_range_t *oldest_gap_rev;
9145 svn_merge_range_t *youngest_gap_rev;
9146 svn_rangelist_t *inoperative_ranges;
9147 apr_pool_t *iterpool;
9148 const char *longest_common_subtree_ancestor = NULL;
9151 assert(session_url_is(ra_session, source->loc2->url, scratch_pool));
9153 /* This function is only intended to work with forward merges. */
9154 if (source->loc1->rev > source->loc2->rev)
9155 return SVN_NO_ERROR;
9157 /* Another easy out: There are no subtrees. */
9158 if (children_with_mergeinfo->nelts < 2)
9159 return SVN_NO_ERROR;
9161 subtree_remaining_ranges = apr_array_make(scratch_pool, 1,
9162 sizeof(svn_merge_range_t *));
9164 /* Given the requested merge of SOURCE->rev1:rev2 might there be any
9165 part of this range required for subtrees but not for the target? */
9166 requested_ranges = svn_rangelist__initialize(MIN(source->loc1->rev,
9168 MAX(source->loc1->rev,
9170 TRUE, scratch_pool);
9171 SVN_ERR(svn_rangelist_remove(&subtree_gap_ranges,
9172 root_child->remaining_ranges,
9173 requested_ranges, FALSE, scratch_pool));
9175 /* Early out, nothing to operate on */
9176 if (!subtree_gap_ranges->nelts)
9177 return SVN_NO_ERROR;
9179 /* Create a rangelist describing every range required across all subtrees. */
9180 iterpool = svn_pool_create(scratch_pool);
9181 for (i = 1; i < children_with_mergeinfo->nelts; i++)
9183 svn_client__merge_path_t *child =
9184 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
9186 svn_pool_clear(iterpool);
9188 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */
9189 if (child->remaining_ranges && child->remaining_ranges->nelts)
9191 /* Issue #4269: Keep track of the longest common ancestor of all the
9192 subtrees which require merges. This may be a child of
9193 TARGET->ABSPATH, which will allow us to narrow the log request
9195 if (longest_common_subtree_ancestor)
9196 longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor(
9197 longest_common_subtree_ancestor, child->abspath, scratch_pool);
9199 longest_common_subtree_ancestor = child->abspath;
9201 SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges,
9202 child->remaining_ranges,
9203 scratch_pool, iterpool));
9206 svn_pool_destroy(iterpool);
9208 /* It's possible that none of the subtrees had any remaining ranges. */
9209 if (!subtree_remaining_ranges->nelts)
9210 return SVN_NO_ERROR;
9212 /* Ok, *finally* we can answer what part(s) of SOURCE->rev1:rev2 are
9213 required for the subtrees but not the target. */
9214 SVN_ERR(svn_rangelist_intersect(&subtree_gap_ranges,
9216 subtree_remaining_ranges, FALSE,
9219 /* Another early out */
9220 if (!subtree_gap_ranges->nelts)
9221 return SVN_NO_ERROR;
9223 /* One or more subtrees need some revisions that the target doesn't need.
9224 Use log to determine if any of these revisions are inoperative. */
9225 oldest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 0, svn_merge_range_t *);
9226 youngest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges,
9227 subtree_gap_ranges->nelts - 1, svn_merge_range_t *);
9229 /* Set up the log baton. */
9230 log_gap_baton.children_with_mergeinfo = children_with_mergeinfo;
9231 log_gap_baton.source_fspath
9232 = svn_client__pathrev_fspath(source->loc2, result_pool);
9233 log_gap_baton.target = target;
9234 log_gap_baton.merged_ranges = apr_array_make(scratch_pool, 0,
9235 sizeof(svn_revnum_t *));
9236 log_gap_baton.operative_ranges = apr_array_make(scratch_pool, 0,
9237 sizeof(svn_revnum_t *));
9238 log_gap_baton.pool = svn_pool_create(scratch_pool);
9240 /* Find the longest common ancestor of all subtrees relative to
9241 RA_SESSION's URL. */
9242 if (longest_common_subtree_ancestor)
9243 longest_common_subtree_ancestor =
9244 svn_dirent_skip_ancestor(target->abspath,
9245 longest_common_subtree_ancestor);
9247 longest_common_subtree_ancestor = "";
9249 /* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from
9250 oldest to youngest. The receiver is optimized to add ranges to
9251 log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but
9252 requires that the revs arrive oldest to youngest -- see log_noop_revs()
9253 and rangelist_merge_revision(). */
9254 err = get_log(ra_session, longest_common_subtree_ancestor,
9255 oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE,
9256 log_noop_revs, &log_gap_baton, scratch_pool);
9258 /* It's possible that the only subtrees with mergeinfo in TARGET don't have
9259 any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2.
9260 So it's also possible that we may ask for the logs of non-existent paths.
9261 If we do, then assume that no subtree requires any ranges that are not
9262 already required by the TARGET. */
9265 if (err->apr_err != SVN_ERR_FS_NOT_FOUND
9266 && longest_common_subtree_ancestor[0] != '\0')
9267 return svn_error_trace(err);
9269 /* Asked about a non-existent subtree in SOURCE. */
9270 svn_error_clear(err);
9271 log_gap_baton.merged_ranges =
9272 svn_rangelist__initialize(oldest_gap_rev->start,
9273 youngest_gap_rev->end,
9274 TRUE, scratch_pool);
9278 inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
9279 youngest_gap_rev->end,
9280 TRUE, scratch_pool);
9281 SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
9282 log_gap_baton.operative_ranges,
9283 inoperative_ranges, FALSE, scratch_pool));
9284 SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
9285 scratch_pool, scratch_pool));
9288 for (i = 1; i < children_with_mergeinfo->nelts; i++)
9290 svn_client__merge_path_t *child =
9291 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
9293 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */
9294 if (child->remaining_ranges && child->remaining_ranges->nelts)
9296 /* Remove inoperative ranges from all children so we don't perform
9297 inoperative editor drives. */
9298 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
9299 log_gap_baton.merged_ranges,
9300 child->remaining_ranges,
9301 FALSE, result_pool));
9305 svn_pool_destroy(log_gap_baton.pool);
9307 return SVN_NO_ERROR;
9310 /* Perform a merge of changes in SOURCE to the working copy path
9311 TARGET_ABSPATH. Both URLs in SOURCE, and TARGET_ABSPATH all represent
9312 directories -- for the single file case, the caller should use
9315 CHILDREN_WITH_MERGEINFO and MERGE_B describe the merge being performed
9316 As this function is for a mergeinfo-aware merge, SOURCE->ancestral
9317 should be TRUE, and SOURCE->loc1 must be a historical ancestor of
9318 SOURCE->loc2, or vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION'
9319 for more requirements around SOURCE).
9321 Mergeinfo changes will be recorded unless MERGE_B->dry_run is true.
9323 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE,
9324 and MERGE_B->CTX->NOTIFY_FUNC2 is not NULL, then call
9325 MERGE_B->CTX->NOTIFY_FUNC2 with MERGE_B->CTX->NOTIFY_BATON2 and a
9326 svn_wc_notify_merge_record_info_begin notification before any mergeinfo
9327 changes are made to describe the merge performed.
9329 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
9330 is not NULL, then don't record the new mergeinfo on the WC, but instead
9331 record it in RESULT_CATALOG, where the keys are absolute working copy
9332 paths and the values are the new mergeinfos for each. Allocate additions
9333 to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
9335 Handle DEPTH as documented for svn_client_merge5().
9337 CONFLICT_REPORT is as documented for do_directory_merge().
9339 Perform any temporary allocations in SCRATCH_POOL.
9341 NOTE: This is a wrapper around drive_merge_report_editor() which
9342 handles the complexities inherent to situations where a given
9343 directory's children may have intersecting merges (because they
9344 meet one or more of the criteria described in get_mergeinfo_paths()).
9346 static svn_error_t *
9347 do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
9348 single_range_conflict_report_t **conflict_report,
9349 const merge_source_t *source,
9350 const char *target_abspath,
9351 apr_array_header_t *children_with_mergeinfo,
9352 const svn_diff_tree_processor_t *processor,
9354 svn_boolean_t squelch_mergeinfo_notifications,
9355 merge_cmd_baton_t *merge_b,
9356 apr_pool_t *result_pool,
9357 apr_pool_t *scratch_pool)
9359 /* The range defining the mergeinfo we will record to describe the merge
9360 (assuming we are recording mergeinfo
9362 Note: This may be a subset of SOURCE->rev1:rev2 if
9363 populate_remaining_ranges() determines that some part of
9364 SOURCE->rev1:rev2 has already been wholly merged to TARGET_ABSPATH.
9365 Also, the actual editor drive(s) may be a subset of RANGE, if
9366 remove_noop_subtree_ranges() and/or fix_deleted_subtree_ranges()
9367 further tweak things. */
9368 svn_merge_range_t range;
9370 svn_ra_session_t *ra_session;
9371 svn_client__merge_path_t *target_merge_path;
9372 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
9374 SVN_ERR_ASSERT(source->ancestral);
9376 /*** If we get here, we're dealing with related sources from the
9377 same repository as the target -- merge tracking might be
9380 *conflict_report = NULL;
9382 /* Point our RA_SESSION to the URL of our youngest merge source side. */
9383 ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2;
9385 /* Fill NOTIFY_B->CHILDREN_WITH_MERGEINFO with child paths (const
9386 svn_client__merge_path_t *) which might have intersecting merges
9387 because they meet one or more of the criteria described in
9388 get_mergeinfo_paths(). Here the paths are arranged in a depth
9390 SVN_ERR(get_mergeinfo_paths(children_with_mergeinfo,
9391 merge_b->target, depth,
9392 merge_b->dry_run, merge_b->same_repos,
9393 merge_b->ctx, scratch_pool, scratch_pool));
9395 /* The first item from the NOTIFY_B->CHILDREN_WITH_MERGEINFO is always
9396 the target thanks to depth-first ordering. */
9397 target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0,
9398 svn_client__merge_path_t *);
9400 /* If we are honoring mergeinfo, then for each item in
9401 NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
9402 merged, and then merge it. Otherwise, we just merge what we were asked
9403 to merge across the whole tree. */
9404 SVN_ERR(populate_remaining_ranges(children_with_mergeinfo,
9406 merge_b, scratch_pool, scratch_pool));
9408 /* Always start with a range which describes the most inclusive merge
9409 possible, i.e. SOURCE->rev1:rev2. */
9410 range.start = source->loc1->rev;
9411 range.end = source->loc2->rev;
9412 range.inheritable = TRUE;
9414 if (!merge_b->reintegrate_merge)
9416 svn_revnum_t new_range_start, start_rev;
9417 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
9419 /* The merge target TARGET_ABSPATH and/or its subtrees may not need all
9420 of SOURCE->rev1:rev2 applied. So examine
9421 NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting
9422 revision that actually needs to be merged (for reverse merges this is
9423 the youngest starting revision).
9425 We'll do this twice, right now for the start of the mergeinfo we will
9426 ultimately record to describe this merge and then later for the
9427 start of the actual editor drive. */
9428 new_range_start = get_most_inclusive_rev(
9429 children_with_mergeinfo, is_rollback, TRUE);
9430 if (SVN_IS_VALID_REVNUM(new_range_start))
9431 range.start = new_range_start;
9433 /* Remove inoperative ranges from any subtrees' remaining_ranges
9434 to spare the expense of noop editor drives. */
9436 SVN_ERR(remove_noop_subtree_ranges(source, merge_b->target,
9438 children_with_mergeinfo,
9439 scratch_pool, iterpool));
9441 /* Adjust subtrees' remaining_ranges to deal with issue #3067:
9442 * "subtrees that don't exist at the start or end of a merge range
9443 * shouldn't break the merge". */
9444 SVN_ERR(fix_deleted_subtree_ranges(source, merge_b->target,
9446 children_with_mergeinfo,
9447 merge_b->ctx, scratch_pool, iterpool));
9449 /* remove_noop_subtree_ranges() and/or fix_deleted_subtree_range()
9450 may have further refined the starting revision for our editor
9453 get_most_inclusive_rev(children_with_mergeinfo,
9456 /* Is there anything to merge? */
9457 if (SVN_IS_VALID_REVNUM(start_rev))
9459 /* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest
9460 ending revision that actually needs to be merged (for reverse
9461 merges this is the youngest ending revision). */
9462 svn_revnum_t end_rev =
9463 get_most_inclusive_rev(children_with_mergeinfo,
9464 is_rollback, FALSE);
9466 /* While END_REV is valid, do the following:
9468 1. Tweak each NOTIFY_B->CHILDREN_WITH_MERGEINFO element so that
9469 the element's remaining_ranges member has as its first element
9470 a range that ends with end_rev.
9472 2. Starting with start_rev, call drive_merge_report_editor()
9473 on MERGE_B->target->abspath for start_rev:end_rev.
9475 3. Remove the first element from each
9476 NOTIFY_B->CHILDREN_WITH_MERGEINFO element's remaining_ranges
9479 4. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
9480 inclusive starting revision that actually needs to be merged and
9481 update start_rev. This prevents us from needlessly contacting the
9482 repository and doing a diff where we describe the entire target
9483 tree as *not* needing any of the requested range. This can happen
9484 whenever we have mergeinfo with gaps in it for the merge source.
9486 5. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
9487 inclusive ending revision that actually needs to be merged and
9490 6. Lather, rinse, repeat.
9493 while (end_rev != SVN_INVALID_REVNUM)
9495 merge_source_t *real_source;
9496 svn_merge_range_t *first_target_range
9497 = (target_merge_path->remaining_ranges->nelts == 0 ? NULL
9498 : APR_ARRAY_IDX(target_merge_path->remaining_ranges, 0,
9499 svn_merge_range_t *));
9501 /* Issue #3324: Stop editor abuse! Don't call
9502 drive_merge_report_editor() in such a way that we request an
9503 editor with svn_client__get_diff_editor() for some rev X,
9504 then call svn_ra_do_diff3() for some revision Y, and then
9505 call reporter->set_path(PATH=="") to set the root revision
9506 for the editor drive to revision Z where
9507 (X != Z && X < Z < Y). This is bogus because the server will
9508 send us the diff between X:Y but the client is expecting the
9509 diff between Y:Z. See issue #3324 for full details on the
9510 problems this can cause. */
9511 if (first_target_range
9512 && start_rev != first_target_range->start)
9516 if (end_rev < first_target_range->start)
9517 end_rev = first_target_range->start;
9521 if (end_rev > first_target_range->start)
9522 end_rev = first_target_range->start;
9526 svn_pool_clear(iterpool);
9528 slice_remaining_ranges(children_with_mergeinfo,
9529 is_rollback, end_rev, scratch_pool);
9531 /* Reset variables that must be reset for every drive */
9532 merge_b->notify_begin.last_abspath = NULL;
9534 real_source = subrange_source(source, start_rev, end_rev, iterpool);
9535 SVN_ERR(drive_merge_report_editor(
9536 merge_b->target->abspath,
9538 children_with_mergeinfo,
9544 /* If any paths picked up explicit mergeinfo as a result of
9545 the merge we need to make sure any mergeinfo those paths
9546 inherited is recorded and then add these paths to
9547 NOTIFY_B->CHILDREN_WITH_MERGEINFO.*/
9548 SVN_ERR(process_children_with_new_mergeinfo(
9549 merge_b, children_with_mergeinfo,
9552 /* If any subtrees had their explicit mergeinfo deleted as a
9553 result of the merge then remove these paths from
9554 NOTIFY_B->CHILDREN_WITH_MERGEINFO since there is no need
9555 to consider these subtrees for subsequent editor drives
9556 nor do we want to record mergeinfo on them describing
9557 the merge itself. */
9558 remove_children_with_deleted_mergeinfo(
9559 merge_b, children_with_mergeinfo);
9561 /* Prepare for the next iteration (if any). */
9562 remove_first_range_from_remaining_ranges(
9563 end_rev, children_with_mergeinfo, scratch_pool);
9565 /* If we raised any conflicts, break out and report how much
9567 if (is_path_conflicted_by_merge(merge_b))
9569 merge_source_t *remaining_range = NULL;
9571 if (real_source->loc2->rev != source->loc2->rev)
9572 remaining_range = subrange_source(source,
9573 real_source->loc2->rev,
9576 *conflict_report = single_range_conflict_report_create(
9577 real_source, remaining_range,
9580 range.end = end_rev;
9585 get_most_inclusive_rev(children_with_mergeinfo,
9588 get_most_inclusive_rev(children_with_mergeinfo,
9589 is_rollback, FALSE);
9592 svn_pool_destroy(iterpool);
9596 if (!merge_b->record_only)
9598 /* Reset the last notification path so that subsequent cherry
9599 picked revision ranges will be notified upon subsequent
9601 merge_b->notify_begin.last_abspath = NULL;
9603 SVN_ERR(drive_merge_report_editor(merge_b->target->abspath,
9613 /* Record mergeinfo where appropriate.*/
9614 if (RECORD_MERGEINFO(merge_b))
9616 const svn_client__pathrev_t *primary_src
9617 = is_rollback ? source->loc1 : source->loc2;
9618 const char *mergeinfo_path
9619 = svn_client__pathrev_fspath(primary_src, scratch_pool);
9621 SVN_ERR(record_mergeinfo_for_dir_merge(result_catalog,
9624 children_with_mergeinfo,
9626 squelch_mergeinfo_notifications,
9630 /* If a path has an immediate parent with non-inheritable mergeinfo at
9631 this point, then it meets criteria 3 or 5 described in
9632 get_mergeinfo_paths' doc string. For paths which exist prior to a
9633 merge explicit mergeinfo has already been set. But for paths added
9634 during the merge this is not the case. The path might have explicit
9635 mergeinfo from the merge source, but no mergeinfo yet exists
9636 describing *this* merge. So the added path has either incomplete
9637 explicit mergeinfo or inherits incomplete mergeinfo from its
9638 immediate parent (if any, the parent might have only non-inheritable
9639 ranges in which case the path simply inherits empty mergeinfo).
9641 So here we look at the root path of each subtree added during the
9642 merge and set explicit mergeinfo on it if it meets the aforementioned
9644 if (range.start < range.end) /* Nothing to record on added subtrees
9645 resulting from reverse merges. */
9647 SVN_ERR(record_mergeinfo_for_added_subtrees(
9648 &range, mergeinfo_path, depth,
9649 squelch_mergeinfo_notifications,
9650 merge_b->added_abspaths, merge_b, scratch_pool));
9654 return SVN_NO_ERROR;
9657 /* Helper for do_merge() when the merge target is a directory.
9659 * If any conflict is raised during the merge, set *CONFLICTED_RANGE to
9660 * the revision sub-range that raised the conflict. In this case, the
9661 * merge will have ended at revision CONFLICTED_RANGE and mergeinfo will
9662 * have been recorded for all revision sub-ranges up to and including
9663 * CONFLICTED_RANGE. Otherwise, set *CONFLICTED_RANGE to NULL.
9665 static svn_error_t *
9666 do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
9667 single_range_conflict_report_t **conflict_report,
9668 const merge_source_t *source,
9669 const char *target_abspath,
9670 const svn_diff_tree_processor_t *processor,
9672 svn_boolean_t squelch_mergeinfo_notifications,
9673 merge_cmd_baton_t *merge_b,
9674 apr_pool_t *result_pool,
9675 apr_pool_t *scratch_pool)
9677 apr_array_header_t *children_with_mergeinfo;
9679 /* Initialize CHILDREN_WITH_MERGEINFO. See the comment
9680 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */
9681 children_with_mergeinfo =
9682 apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *));
9684 /* And make it read-only accessible from the baton */
9685 merge_b->notify_begin.nodes_with_mergeinfo = children_with_mergeinfo;
9687 /* If we are not honoring mergeinfo we can skip right to the
9688 business of merging changes! */
9689 if (HONOR_MERGEINFO(merge_b))
9690 SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflict_report,
9691 source, target_abspath,
9692 children_with_mergeinfo,
9694 squelch_mergeinfo_notifications,
9695 merge_b, result_pool, scratch_pool));
9697 SVN_ERR(do_mergeinfo_unaware_dir_merge(conflict_report,
9698 source, target_abspath,
9699 children_with_mergeinfo,
9701 merge_b, result_pool, scratch_pool));
9703 merge_b->notify_begin.nodes_with_mergeinfo = NULL;
9705 return SVN_NO_ERROR;
9708 /** Ensure that *RA_SESSION is opened to URL, either by reusing
9709 * *RA_SESSION if it is non-null and already opened to URL's
9710 * repository, or by allocating a new *RA_SESSION in POOL.
9711 * (RA_SESSION itself cannot be null, of course.)
9713 * CTX is used as for svn_client_open_ra_session().
9715 static svn_error_t *
9716 ensure_ra_session_url(svn_ra_session_t **ra_session,
9718 const char *wri_abspath,
9719 svn_client_ctx_t *ctx,
9722 svn_error_t *err = SVN_NO_ERROR;
9726 err = svn_ra_reparent(*ra_session, url, pool);
9729 /* SVN_ERR_RA_ILLEGAL_URL is raised when url doesn't point to the same
9730 repository as ra_session. */
9731 if (! *ra_session || (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL))
9733 svn_error_clear(err);
9734 err = svn_client_open_ra_session2(ra_session, url, wri_abspath,
9739 return SVN_NO_ERROR;
9742 /* Drive a merge of MERGE_SOURCES into working copy node TARGET
9743 and possibly record mergeinfo describing the merge -- see
9746 If MODIFIED_SUBTREES is not NULL and all the MERGE_SOURCES are 'ancestral'
9747 or REINTEGRATE_MERGE is true, then replace *MODIFIED_SUBTREES with a new
9748 hash containing all the paths that *MODIFIED_SUBTREES contained before,
9749 and also every path modified, skipped, added, or tree-conflicted
9750 by the merge. Keys and values of the hash are both (const char *)
9751 absolute paths. The contents of the hash are allocated in RESULT_POOL.
9753 If the merge raises any conflicts while merging a revision range, return
9754 early and set *CONFLICT_REPORT to describe the details. (In this case,
9755 notify that the merge is complete if and only if this was the last
9756 revision range of the merge.) If there are no conflicts, set
9757 *CONFLICT_REPORT to NULL. A revision range here can be one specified
9758 in MERGE_SOURCES or an internally generated sub-range of one of those
9759 when merge tracking is in use.
9761 For every (const merge_source_t *) merge source in MERGE_SOURCES, if
9762 SOURCE->ANCESTRAL is set, then the "left" and "right" side are
9763 ancestrally related. (See 'MERGEINFO MERGE SOURCE NORMALIZATION'
9764 for more on what that means and how it matters.)
9766 If SOURCES_RELATED is set, the "left" and "right" sides of the
9767 merge source are historically related (ancestors, uncles, second
9768 cousins thrice removed, etc...). (This is passed through to
9769 do_file_merge() to simulate the history checks that the repository
9770 logic does in the directory case.)
9772 SAME_REPOS is TRUE iff the merge sources live in the same
9773 repository as the one from which the target working copy has been
9776 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE,
9777 and CTX->NOTIFY_FUNC2 is not NULL, then call CTX->NOTIFY_FUNC2 with
9778 CTX->NOTIFY_BATON2 and a svn_wc_notify_merge_record_info_begin
9779 notification before any mergeinfo changes are made to describe the merge
9782 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
9783 is not NULL, then don't record the new mergeinfo on the WC, but instead
9784 record it in RESULT_CATALOG, where the keys are absolute working copy
9785 paths and the values are the new mergeinfos for each. Allocate additions
9786 to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
9788 FORCE_DELETE, DRY_RUN, RECORD_ONLY, DEPTH, MERGE_OPTIONS,
9789 and CTX are as described in the docstring for svn_client_merge_peg3().
9791 If IGNORE_MERGEINFO is true, disable merge tracking, by treating the two
9792 sources as unrelated even if they actually have a common ancestor. See
9793 the macro HONOR_MERGEINFO().
9795 If DIFF_IGNORE_ANCESTRY is true, diff the 'left' and 'right' versions
9796 of a node (if they are the same kind) as if they were related, even if
9797 they are not related. Otherwise, diff unrelated items as a deletion
9798 of one thing and the addition of another.
9800 If not NULL, RECORD_ONLY_PATHS is a hash of (const char *) paths mapped
9801 to the same. If RECORD_ONLY is true and RECORD_ONLY_PATHS is not NULL,
9802 then record mergeinfo describing the merge only on subtrees which contain
9803 items from RECORD_ONLY_PATHS. If RECORD_ONLY is true and RECORD_ONLY_PATHS
9804 is NULL, then record mergeinfo on every subtree with mergeinfo in
9807 REINTEGRATE_MERGE is TRUE if this is a reintegrate merge.
9809 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp
9810 integrity, *USE_SLEEP will be unchanged if no sleep is required.
9812 SCRATCH_POOL is used for all temporary allocations.
9814 static svn_error_t *
9815 do_merge(apr_hash_t **modified_subtrees,
9816 svn_mergeinfo_catalog_t result_catalog,
9817 conflict_report_t **conflict_report,
9818 svn_boolean_t *use_sleep,
9819 const apr_array_header_t *merge_sources,
9820 const merge_target_t *target,
9821 svn_ra_session_t *src_session,
9822 svn_boolean_t sources_related,
9823 svn_boolean_t same_repos,
9824 svn_boolean_t ignore_mergeinfo,
9825 svn_boolean_t diff_ignore_ancestry,
9826 svn_boolean_t force_delete,
9827 svn_boolean_t dry_run,
9828 svn_boolean_t record_only,
9829 apr_hash_t *record_only_paths,
9830 svn_boolean_t reintegrate_merge,
9831 svn_boolean_t squelch_mergeinfo_notifications,
9833 const apr_array_header_t *merge_options,
9834 svn_client_ctx_t *ctx,
9835 apr_pool_t *result_pool,
9836 apr_pool_t *scratch_pool)
9838 merge_cmd_baton_t merge_cmd_baton = { 0 };
9840 const char *diff3_cmd;
9841 const char *preserved_exts_str;
9843 svn_boolean_t checked_mergeinfo_capability = FALSE;
9844 svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL;
9845 const char *old_src_session_url = NULL;
9846 apr_pool_t *iterpool;
9847 const svn_diff_tree_processor_t *processor;
9849 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
9851 *conflict_report = NULL;
9853 /* Check from some special conditions when in record-only mode
9854 (which is a merge-tracking thing). */
9857 svn_boolean_t sources_ancestral = TRUE;
9860 /* Find out whether all of the sources are 'ancestral'. */
9861 for (j = 0; j < merge_sources->nelts; j++)
9862 if (! APR_ARRAY_IDX(merge_sources, j, merge_source_t *)->ancestral)
9864 sources_ancestral = FALSE;
9868 /* We can't do a record-only merge if the sources aren't related. */
9869 if (! sources_ancestral)
9870 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
9871 _("Use of two URLs is not compatible with "
9872 "mergeinfo modification"));
9874 /* We can't do a record-only merge if the sources aren't from
9875 the same repository as the target. */
9877 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
9878 _("Merge from foreign repository is not "
9879 "compatible with mergeinfo modification"));
9881 /* If this is a dry-run record-only merge, there's nothing to do. */
9883 return SVN_NO_ERROR;
9886 iterpool = svn_pool_create(scratch_pool);
9888 /* Ensure a known depth. */
9889 if (depth == svn_depth_unknown)
9890 depth = svn_depth_infinity;
9892 /* Set up the diff3 command, so various callers don't have to. */
9894 ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
9896 svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
9897 SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
9899 if (diff3_cmd != NULL)
9900 SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool));
9902 /* See which files the user wants to preserve the extension of when
9903 conflict files are made. */
9904 svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
9905 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
9907 /* Build the merge context baton (or at least the parts of it that
9908 don't need to be reset for each merge source). */
9909 merge_cmd_baton.force_delete = force_delete;
9910 merge_cmd_baton.dry_run = dry_run;
9911 merge_cmd_baton.record_only = record_only;
9912 merge_cmd_baton.ignore_mergeinfo = ignore_mergeinfo;
9913 merge_cmd_baton.diff_ignore_ancestry = diff_ignore_ancestry;
9914 merge_cmd_baton.same_repos = same_repos;
9915 merge_cmd_baton.mergeinfo_capable = FALSE;
9916 merge_cmd_baton.ctx = ctx;
9917 merge_cmd_baton.reintegrate_merge = reintegrate_merge;
9918 merge_cmd_baton.target = target;
9919 merge_cmd_baton.pool = iterpool;
9920 merge_cmd_baton.merge_options = merge_options;
9921 merge_cmd_baton.diff3_cmd = diff3_cmd;
9922 merge_cmd_baton.ext_patterns = *preserved_exts_str
9923 ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ",
9924 FALSE, scratch_pool)
9927 merge_cmd_baton.use_sleep = use_sleep;
9929 /* Do we already know the specific subtrees with mergeinfo we want
9930 to record-only mergeinfo on? */
9931 if (record_only && record_only_paths)
9932 merge_cmd_baton.merged_abspaths = record_only_paths;
9934 merge_cmd_baton.merged_abspaths = apr_hash_make(result_pool);
9936 merge_cmd_baton.skipped_abspaths = apr_hash_make(result_pool);
9937 merge_cmd_baton.added_abspaths = apr_hash_make(result_pool);
9938 merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool);
9941 svn_diff_tree_processor_t *merge_processor;
9943 merge_processor = svn_diff__tree_processor_create(&merge_cmd_baton,
9946 merge_processor->dir_opened = merge_dir_opened;
9947 merge_processor->dir_changed = merge_dir_changed;
9948 merge_processor->dir_added = merge_dir_added;
9949 merge_processor->dir_deleted = merge_dir_deleted;
9950 merge_processor->dir_closed = merge_dir_closed;
9952 merge_processor->file_opened = merge_file_opened;
9953 merge_processor->file_changed = merge_file_changed;
9954 merge_processor->file_added = merge_file_added;
9955 merge_processor->file_deleted = merge_file_deleted;
9956 /* Not interested in file_closed() */
9958 merge_processor->node_absent = merge_node_absent;
9960 processor = merge_processor;
9965 SVN_ERR(svn_ra_get_session_url(src_session, &old_src_session_url,
9967 ra_session1 = src_session;
9970 for (i = 0; i < merge_sources->nelts; i++)
9972 svn_node_kind_t src1_kind;
9973 merge_source_t *source =
9974 APR_ARRAY_IDX(merge_sources, i, merge_source_t *);
9975 single_range_conflict_report_t *conflicted_range_report;
9977 svn_pool_clear(iterpool);
9979 /* Sanity check: if our left- and right-side merge sources are
9980 the same, there's nothing to here. */
9981 if ((strcmp(source->loc1->url, source->loc2->url) == 0)
9982 && (source->loc1->rev == source->loc2->rev))
9985 /* Establish RA sessions to our URLs, reuse where possible. */
9986 SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url,
9987 target->abspath, ctx, scratch_pool));
9988 SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2->url,
9989 target->abspath, ctx, scratch_pool));
9991 /* Populate the portions of the merge context baton that need to
9992 be reset for each merge source iteration. */
9993 merge_cmd_baton.merge_source = *source;
9994 merge_cmd_baton.implicit_src_gap = NULL;
9995 merge_cmd_baton.conflicted_paths = NULL;
9996 merge_cmd_baton.paths_with_new_mergeinfo = NULL;
9997 merge_cmd_baton.paths_with_deleted_mergeinfo = NULL;
9998 merge_cmd_baton.ra_session1 = ra_session1;
9999 merge_cmd_baton.ra_session2 = ra_session2;
10001 merge_cmd_baton.notify_begin.last_abspath = NULL;
10003 /* Populate the portions of the merge context baton that require
10004 an RA session to set, but shouldn't be reset for each iteration. */
10005 if (! checked_mergeinfo_capability)
10007 SVN_ERR(svn_ra_has_capability(ra_session1,
10008 &merge_cmd_baton.mergeinfo_capable,
10009 SVN_RA_CAPABILITY_MERGEINFO,
10011 checked_mergeinfo_capability = TRUE;
10014 SVN_ERR(svn_ra_check_path(ra_session1, "", source->loc1->rev,
10015 &src1_kind, iterpool));
10017 /* Run the merge; if there are conflicts, allow the callback to
10018 * resolve them, and if it resolves all of them, then run the
10019 * merge again with the remaining revision range, until it is all
10023 /* Merge as far as possible without resolving any conflicts */
10024 if (src1_kind != svn_node_dir)
10026 SVN_ERR(do_file_merge(result_catalog, &conflicted_range_report,
10027 source, target->abspath,
10030 squelch_mergeinfo_notifications,
10031 &merge_cmd_baton, iterpool, iterpool));
10033 else /* Directory */
10035 SVN_ERR(do_directory_merge(result_catalog, &conflicted_range_report,
10036 source, target->abspath,
10038 depth, squelch_mergeinfo_notifications,
10039 &merge_cmd_baton, iterpool, iterpool));
10042 /* Give the conflict resolver callback the opportunity to
10043 * resolve any conflicts that were raised. If it resolves all
10044 * of them, go around again to merge the next sub-range (if any). */
10045 if (conflicted_range_report && ctx->conflict_func2 && ! dry_run)
10047 svn_boolean_t conflicts_remain;
10049 SVN_ERR(svn_client__resolve_conflicts(
10050 &conflicts_remain, merge_cmd_baton.conflicted_paths,
10052 if (conflicts_remain)
10055 merge_cmd_baton.conflicted_paths = NULL;
10056 /* Caution: this source is in iterpool */
10057 source = conflicted_range_report->remaining_source;
10058 conflicted_range_report = NULL;
10065 /* The final mergeinfo on TARGET_WCPATH may itself elide. */
10067 SVN_ERR(svn_client__elide_mergeinfo(target->abspath, NULL,
10070 /* If conflicts occurred while merging any but the very last
10071 * range of a multi-pass merge, we raise an error that aborts
10072 * the merge. The user will be asked to resolve conflicts
10073 * before merging subsequent revision ranges. */
10074 if (conflicted_range_report)
10076 *conflict_report = conflict_report_create(
10077 target->abspath, conflicted_range_report->conflicted_range,
10078 (i == merge_sources->nelts - 1
10079 && ! conflicted_range_report->remaining_source),
10085 if (! *conflict_report || (*conflict_report)->was_last_range)
10087 /* Let everyone know we're finished here. */
10088 notify_merge_completed(target->abspath, ctx, iterpool);
10091 /* Does the caller want to know what the merge has done? */
10092 if (modified_subtrees)
10094 *modified_subtrees =
10095 apr_hash_overlay(result_pool, *modified_subtrees,
10096 merge_cmd_baton.merged_abspaths);
10097 *modified_subtrees =
10098 apr_hash_overlay(result_pool, *modified_subtrees,
10099 merge_cmd_baton.added_abspaths);
10100 *modified_subtrees =
10101 apr_hash_overlay(result_pool, *modified_subtrees,
10102 merge_cmd_baton.skipped_abspaths);
10103 *modified_subtrees =
10104 apr_hash_overlay(result_pool, *modified_subtrees,
10105 merge_cmd_baton.tree_conflicted_abspaths);
10109 SVN_ERR(svn_ra_reparent(src_session, old_src_session_url, iterpool));
10111 svn_pool_destroy(iterpool);
10112 return SVN_NO_ERROR;
10115 /* Perform a two-URL merge between URLs which are related, but neither
10116 is a direct ancestor of the other. This first does a real two-URL
10117 merge (unless this is record-only), followed by record-only merges
10118 to represent the changed mergeinfo.
10120 Set *CONFLICT_REPORT to indicate if there were any conflicts, as in
10123 The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1)
10124 and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest
10127 SAME_REPOS must be true if and only if the source URLs are in the same
10128 repository as the target working copy.
10130 DIFF_IGNORE_ANCESTRY is as in do_merge().
10132 Other arguments are as in all of the public merge APIs.
10134 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp
10135 integrity, *USE_SLEEP will be unchanged if no sleep is required.
10137 SCRATCH_POOL is used for all temporary allocations.
10139 static svn_error_t *
10140 merge_cousins_and_supplement_mergeinfo(conflict_report_t **conflict_report,
10141 svn_boolean_t *use_sleep,
10142 const merge_target_t *target,
10143 svn_ra_session_t *URL1_ra_session,
10144 svn_ra_session_t *URL2_ra_session,
10145 const merge_source_t *source,
10146 const svn_client__pathrev_t *yca,
10147 svn_boolean_t same_repos,
10149 svn_boolean_t diff_ignore_ancestry,
10150 svn_boolean_t force_delete,
10151 svn_boolean_t record_only,
10152 svn_boolean_t dry_run,
10153 const apr_array_header_t *merge_options,
10154 svn_client_ctx_t *ctx,
10155 apr_pool_t *result_pool,
10156 apr_pool_t *scratch_pool)
10158 apr_array_header_t *remove_sources, *add_sources;
10159 apr_hash_t *modified_subtrees = NULL;
10161 /* Sure we could use SCRATCH_POOL throughout this function, but since this
10162 is a wrapper around three separate merges we'll create a subpool we can
10163 clear between each of the three. If the merge target has a lot of
10164 subtree mergeinfo, then this will help keep memory use in check. */
10165 apr_pool_t *subpool = svn_pool_create(scratch_pool);
10167 assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool));
10168 assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool));
10170 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
10171 SVN_ERR_ASSERT(! source->ancestral);
10173 SVN_ERR(normalize_merge_sources_internal(
10174 &remove_sources, source->loc1,
10175 svn_rangelist__initialize(source->loc1->rev, yca->rev, TRUE,
10177 URL1_ra_session, ctx, scratch_pool, subpool));
10179 SVN_ERR(normalize_merge_sources_internal(
10180 &add_sources, source->loc2,
10181 svn_rangelist__initialize(yca->rev, source->loc2->rev, TRUE,
10183 URL2_ra_session, ctx, scratch_pool, subpool));
10185 *conflict_report = NULL;
10187 /* If this isn't a record-only merge, we'll first do a stupid
10188 point-to-point merge... */
10191 apr_array_header_t *faux_sources =
10192 apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
10194 modified_subtrees = apr_hash_make(scratch_pool);
10195 APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source;
10196 SVN_ERR(do_merge(&modified_subtrees, NULL, conflict_report, use_sleep,
10197 faux_sources, target,
10198 URL1_ra_session, TRUE, same_repos,
10199 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10200 force_delete, dry_run, FALSE, NULL, TRUE,
10201 FALSE, depth, merge_options, ctx,
10202 scratch_pool, subpool));
10203 if (*conflict_report)
10205 *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10206 if (! (*conflict_report)->was_last_range)
10207 return SVN_NO_ERROR;
10210 else if (! same_repos)
10212 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
10213 _("Merge from foreign repository is not "
10214 "compatible with mergeinfo modification"));
10217 /* ... and now, if we're doing the mergeinfo thang, we execute a
10218 pair of record-only merges using the real sources we've
10221 Issue #3648: We don't actually perform these two record-only merges
10222 on the WC at first, but rather see what each would do and store that
10223 in two mergeinfo catalogs. We then merge the catalogs together and
10224 then record the result in the WC. This prevents the second record
10225 only merge from removing legitimate mergeinfo history, from the same
10226 source, that was made in prior merges. */
10227 if (same_repos && !dry_run)
10229 svn_mergeinfo_catalog_t add_result_catalog =
10230 apr_hash_make(scratch_pool);
10231 svn_mergeinfo_catalog_t remove_result_catalog =
10232 apr_hash_make(scratch_pool);
10234 notify_mergeinfo_recording(target->abspath, NULL, ctx, scratch_pool);
10235 svn_pool_clear(subpool);
10236 SVN_ERR(do_merge(NULL, add_result_catalog, conflict_report, use_sleep,
10237 add_sources, target,
10238 URL1_ra_session, TRUE, same_repos,
10239 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10240 force_delete, dry_run, TRUE,
10241 modified_subtrees, TRUE,
10242 TRUE, depth, merge_options, ctx,
10243 scratch_pool, subpool));
10244 if (*conflict_report)
10246 *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10247 if (! (*conflict_report)->was_last_range)
10248 return SVN_NO_ERROR;
10250 svn_pool_clear(subpool);
10251 SVN_ERR(do_merge(NULL, remove_result_catalog, conflict_report, use_sleep,
10252 remove_sources, target,
10253 URL1_ra_session, TRUE, same_repos,
10254 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10255 force_delete, dry_run, TRUE,
10256 modified_subtrees, TRUE,
10257 TRUE, depth, merge_options, ctx,
10258 scratch_pool, subpool));
10259 if (*conflict_report)
10261 *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10262 if (! (*conflict_report)->was_last_range)
10263 return SVN_NO_ERROR;
10265 SVN_ERR(svn_mergeinfo_catalog_merge(add_result_catalog,
10266 remove_result_catalog,
10267 scratch_pool, scratch_pool));
10268 SVN_ERR(svn_client__record_wc_mergeinfo_catalog(add_result_catalog,
10269 ctx, scratch_pool));
10272 svn_pool_destroy(subpool);
10273 return SVN_NO_ERROR;
10276 /* Perform checks to determine whether the working copy at TARGET_ABSPATH
10277 * can safely be used as a merge target. Checks are performed according to
10278 * the ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, and ALLOW_SWITCHED_SUBTREES
10279 * parameters. If any checks fail, raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
10281 * E.g. if all the ALLOW_* parameters are FALSE, TARGET_ABSPATH must
10282 * be a single-revision, pristine, unswitched working copy.
10283 * In other words, it must reflect a subtree of the repository as found
10284 * at single revision -- although sparse checkouts are permitted. */
10285 static svn_error_t *
10286 ensure_wc_is_suitable_merge_target(const char *target_abspath,
10287 svn_client_ctx_t *ctx,
10288 svn_boolean_t allow_mixed_rev,
10289 svn_boolean_t allow_local_mods,
10290 svn_boolean_t allow_switched_subtrees,
10291 apr_pool_t *scratch_pool)
10293 svn_node_kind_t target_kind;
10295 /* Check the target exists. */
10296 SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool));
10297 if (target_kind == svn_node_none)
10298 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
10299 _("Path '%s' does not exist"),
10300 svn_dirent_local_style(target_abspath,
10302 SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, target_abspath,
10303 FALSE, FALSE, scratch_pool));
10304 if (target_kind != svn_node_dir && target_kind != svn_node_file)
10305 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
10306 _("Merge target '%s' does not exist in the "
10307 "working copy"), target_abspath);
10309 /* Perform the mixed-revision check first because it's the cheapest one. */
10310 if (! allow_mixed_rev)
10312 svn_revnum_t min_rev;
10313 svn_revnum_t max_rev;
10315 SVN_ERR(svn_client_min_max_revisions(&min_rev, &max_rev, target_abspath,
10316 FALSE, ctx, scratch_pool));
10318 if (!(SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev)))
10320 svn_boolean_t is_added;
10322 /* Allow merge into added nodes. */
10323 SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath,
10326 return SVN_NO_ERROR;
10328 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10329 _("Cannot determine revision of working "
10333 if (min_rev != max_rev)
10334 return svn_error_createf(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL,
10335 _("Cannot merge into mixed-revision working "
10336 "copy [%ld:%ld]; try updating first"),
10340 /* Next, check for switched subtrees. */
10341 if (! allow_switched_subtrees)
10343 svn_boolean_t is_switched;
10345 SVN_ERR(svn_wc__has_switched_subtrees(&is_switched, ctx->wc_ctx,
10346 target_abspath, NULL,
10349 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10350 _("Cannot merge into a working copy "
10351 "with a switched subtree"));
10354 /* This is the most expensive check, so it is performed last.*/
10355 if (! allow_local_mods)
10357 svn_boolean_t is_modified;
10359 SVN_ERR(svn_wc__has_local_mods(&is_modified, ctx->wc_ctx,
10360 target_abspath, TRUE,
10365 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10366 _("Cannot merge into a working copy "
10367 "that has local modifications"));
10370 return SVN_NO_ERROR;
10373 /* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository
10375 static svn_error_t *
10376 ensure_wc_path_has_repo_revision(const char *path_or_url,
10377 const svn_opt_revision_t *revision,
10378 apr_pool_t *scratch_pool)
10380 if (revision->kind != svn_opt_revision_number
10381 && revision->kind != svn_opt_revision_date
10382 && revision->kind != svn_opt_revision_head
10383 && ! svn_path_is_url(path_or_url))
10384 return svn_error_createf(
10385 SVN_ERR_CLIENT_BAD_REVISION, NULL,
10386 _("Invalid merge source '%s'; a working copy path can only be "
10387 "used with a repository revision (a number, a date, or head)"),
10388 svn_dirent_local_style(path_or_url, scratch_pool));
10389 return SVN_NO_ERROR;
10392 /* "Open" the target WC for a merge. That means:
10393 * - find out its exact repository location
10394 * - check the WC for suitability (throw an error if unsuitable)
10396 * Set *TARGET_P to a new, fully initialized, target description structure.
10398 * ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, ALLOW_SWITCHED_SUBTREES determine
10399 * whether the WC is deemed suitable; see ensure_wc_is_suitable_merge_target()
10402 * If the node is locally added, the rev and URL will be null/invalid. Some
10403 * kinds of merge can use such a target; others can't.
10405 static svn_error_t *
10406 open_target_wc(merge_target_t **target_p,
10407 const char *wc_abspath,
10408 svn_boolean_t allow_mixed_rev,
10409 svn_boolean_t allow_local_mods,
10410 svn_boolean_t allow_switched_subtrees,
10411 svn_client_ctx_t *ctx,
10412 apr_pool_t *result_pool,
10413 apr_pool_t *scratch_pool)
10415 merge_target_t *target = apr_palloc(result_pool, sizeof(*target));
10416 svn_client__pathrev_t *origin;
10418 target->abspath = apr_pstrdup(result_pool, wc_abspath);
10420 SVN_ERR(svn_client__wc_node_get_origin(&origin, wc_abspath, ctx,
10421 result_pool, scratch_pool));
10424 target->loc = *origin;
10429 /* The node has no location in the repository. It's unversioned or
10430 * locally added or locally deleted.
10432 * If it's locally added or deleted, find the repository root
10433 * URL and UUID anyway, and leave the node URL and revision as NULL
10434 * and INVALID. If it's unversioned, this will throw an error. */
10435 err = svn_wc__node_get_repos_info(NULL, NULL,
10436 &target->loc.repos_root_url,
10437 &target->loc.repos_uuid,
10438 ctx->wc_ctx, wc_abspath,
10439 result_pool, scratch_pool);
10443 if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
10444 && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY
10445 && err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
10446 return svn_error_trace(err);
10448 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, err,
10449 _("Merge target '%s' does not exist in the "
10451 svn_dirent_local_style(wc_abspath,
10455 target->loc.rev = SVN_INVALID_REVNUM;
10456 target->loc.url = NULL;
10459 SVN_ERR(ensure_wc_is_suitable_merge_target(
10461 allow_mixed_rev, allow_local_mods, allow_switched_subtrees,
10464 *target_p = target;
10465 return SVN_NO_ERROR;
10468 /*-----------------------------------------------------------------------*/
10470 /*** Public APIs ***/
10472 /* The body of svn_client_merge5(), which see for details.
10474 * If SOURCE1 @ REVISION1 is related to SOURCE2 @ REVISION2 then use merge
10475 * tracking (subject to other constraints -- see HONOR_MERGEINFO());
10476 * otherwise disable merge tracking.
10478 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge().
10480 static svn_error_t *
10481 merge_locked(conflict_report_t **conflict_report,
10482 const char *source1,
10483 const svn_opt_revision_t *revision1,
10484 const char *source2,
10485 const svn_opt_revision_t *revision2,
10486 const char *target_abspath,
10488 svn_boolean_t ignore_mergeinfo,
10489 svn_boolean_t diff_ignore_ancestry,
10490 svn_boolean_t force_delete,
10491 svn_boolean_t record_only,
10492 svn_boolean_t dry_run,
10493 svn_boolean_t allow_mixed_rev,
10494 const apr_array_header_t *merge_options,
10495 svn_client_ctx_t *ctx,
10496 apr_pool_t *result_pool,
10497 apr_pool_t *scratch_pool)
10499 merge_target_t *target;
10500 svn_client__pathrev_t *source1_loc, *source2_loc;
10501 svn_boolean_t sources_related = FALSE;
10502 svn_ra_session_t *ra_session1, *ra_session2;
10503 apr_array_header_t *merge_sources;
10505 svn_boolean_t use_sleep = FALSE;
10506 svn_client__pathrev_t *yca = NULL;
10507 apr_pool_t *sesspool;
10508 svn_boolean_t same_repos;
10510 /* ### FIXME: This function really ought to do a history check on
10511 the left and right sides of the merge source, and -- if one is an
10512 ancestor of the other -- just call svn_client_merge_peg3() with
10513 the appropriate args. */
10515 SVN_ERR(open_target_wc(&target, target_abspath,
10516 allow_mixed_rev, TRUE, TRUE,
10517 ctx, scratch_pool, scratch_pool));
10519 /* Open RA sessions to both sides of our merge source, and resolve URLs
10520 * and revisions. */
10521 sesspool = svn_pool_create(scratch_pool);
10522 SVN_ERR(svn_client__ra_session_from_path2(
10523 &ra_session1, &source1_loc,
10524 source1, NULL, revision1, revision1, ctx, sesspool));
10525 SVN_ERR(svn_client__ra_session_from_path2(
10526 &ra_session2, &source2_loc,
10527 source2, NULL, revision2, revision2, ctx, sesspool));
10529 /* We can't do a diff between different repositories. */
10530 /* ### We should also insist that the root URLs of the two sources match,
10531 * as we are only carrying around a single source-repos-root from now
10532 * on, and URL calculations will go wrong if they differ.
10533 * Alternatively, teach the code to cope with differing root URLs. */
10534 SVN_ERR(check_same_repos(source1_loc, source1_loc->url,
10535 source2_loc, source2_loc->url,
10536 FALSE /* strict_urls */, scratch_pool));
10538 /* Do our working copy and sources come from the same repository? */
10539 same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */);
10541 /* Unless we're ignoring ancestry, see if the two sources are related. */
10542 if (! ignore_mergeinfo)
10543 SVN_ERR(svn_client__get_youngest_common_ancestor(
10544 &yca, source1_loc, source2_loc, ra_session1, ctx,
10545 scratch_pool, scratch_pool));
10547 /* Check for a youngest common ancestor. If we have one, we'll be
10548 doing merge tracking.
10550 So, given a requested merge of the differences between A and
10551 B, and a common ancestor of C, we will find ourselves in one of
10552 four positions, and four different approaches:
10554 A == B == C there's nothing to merge
10556 A == C != B we merge the changes between A (or C) and B
10558 B == C != A we merge the changes between B (or C) and A
10560 A != B != C we merge the changes between A and B without
10561 merge recording, then record-only two merges:
10562 from A to C, and from C to B
10566 /* Note that our merge sources are related. */
10567 sources_related = TRUE;
10569 /* If the common ancestor matches the right side of our merge,
10570 then we only need to reverse-merge the left side. */
10571 if ((strcmp(yca->url, source2_loc->url) == 0)
10572 && (yca->rev == source2_loc->rev))
10574 SVN_ERR(normalize_merge_sources_internal(
10575 &merge_sources, source1_loc,
10576 svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE,
10578 ra_session1, ctx, scratch_pool, scratch_pool));
10580 /* If the common ancestor matches the left side of our merge,
10581 then we only need to merge the right side. */
10582 else if ((strcmp(yca->url, source1_loc->url) == 0)
10583 && (yca->rev == source1_loc->rev))
10585 SVN_ERR(normalize_merge_sources_internal(
10586 &merge_sources, source2_loc,
10587 svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE,
10589 ra_session2, ctx, scratch_pool, scratch_pool));
10591 /* And otherwise, we need to do both: reverse merge the left
10592 side, and merge the right. */
10595 merge_source_t source;
10597 source.loc1 = source1_loc;
10598 source.loc2 = source2_loc;
10599 source.ancestral = FALSE;
10601 err = merge_cousins_and_supplement_mergeinfo(conflict_report,
10610 diff_ignore_ancestry,
10612 record_only, dry_run,
10617 /* Close our temporary RA sessions (this could've happened
10618 after the second call to normalize_merge_sources() inside
10619 the merge_cousins_and_supplement_mergeinfo() routine). */
10620 svn_pool_destroy(sesspool);
10623 svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
10626 return SVN_NO_ERROR;
10631 /* Build a single-item merge_source_t array. */
10632 merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
10633 APR_ARRAY_PUSH(merge_sources, merge_source_t *)
10634 = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool);
10637 err = do_merge(NULL, NULL, conflict_report, &use_sleep,
10638 merge_sources, target,
10639 ra_session1, sources_related, same_repos,
10640 ignore_mergeinfo, diff_ignore_ancestry, force_delete, dry_run,
10641 record_only, NULL, FALSE, FALSE, depth, merge_options,
10642 ctx, result_pool, scratch_pool);
10644 /* Close our temporary RA sessions. */
10645 svn_pool_destroy(sesspool);
10648 svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
10651 return SVN_NO_ERROR;
10654 /* Set *TARGET_ABSPATH to the absolute path of, and *LOCK_ABSPATH to
10655 the absolute path to lock for, TARGET_WCPATH. */
10656 static svn_error_t *
10657 get_target_and_lock_abspath(const char **target_abspath,
10658 const char **lock_abspath,
10659 const char *target_wcpath,
10660 svn_client_ctx_t *ctx,
10661 apr_pool_t *result_pool)
10663 svn_node_kind_t kind;
10664 SVN_ERR(svn_dirent_get_absolute(target_abspath, target_wcpath,
10666 SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, *target_abspath,
10667 FALSE, FALSE, result_pool));
10668 if (kind == svn_node_dir)
10669 *lock_abspath = *target_abspath;
10671 *lock_abspath = svn_dirent_dirname(*target_abspath, result_pool);
10673 return SVN_NO_ERROR;
10677 svn_client_merge5(const char *source1,
10678 const svn_opt_revision_t *revision1,
10679 const char *source2,
10680 const svn_opt_revision_t *revision2,
10681 const char *target_wcpath,
10683 svn_boolean_t ignore_mergeinfo,
10684 svn_boolean_t diff_ignore_ancestry,
10685 svn_boolean_t force_delete,
10686 svn_boolean_t record_only,
10687 svn_boolean_t dry_run,
10688 svn_boolean_t allow_mixed_rev,
10689 const apr_array_header_t *merge_options,
10690 svn_client_ctx_t *ctx,
10693 const char *target_abspath, *lock_abspath;
10694 conflict_report_t *conflict_report;
10696 /* Sanity check our input -- we require specified revisions,
10697 * and either 2 paths or 2 URLs. */
10698 if ((revision1->kind == svn_opt_revision_unspecified)
10699 || (revision2->kind == svn_opt_revision_unspecified))
10700 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
10701 _("Not all required revisions are specified"));
10702 if (svn_path_is_url(source1) != svn_path_is_url(source2))
10703 return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
10704 _("Merge sources must both be "
10705 "either paths or URLs"));
10706 /* A WC path must be used with a repository revision, as we can't
10707 * (currently) use the WC itself as a source, we can only read the URL
10708 * from it and use that. */
10709 SVN_ERR(ensure_wc_path_has_repo_revision(source1, revision1, pool));
10710 SVN_ERR(ensure_wc_path_has_repo_revision(source2, revision2, pool));
10712 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
10713 target_wcpath, ctx, pool));
10716 SVN_WC__CALL_WITH_WRITE_LOCK(
10717 merge_locked(&conflict_report,
10718 source1, revision1, source2, revision2,
10719 target_abspath, depth, ignore_mergeinfo,
10720 diff_ignore_ancestry,
10721 force_delete, record_only, dry_run,
10722 allow_mixed_rev, merge_options, ctx, pool, pool),
10723 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
10725 SVN_ERR(merge_locked(&conflict_report,
10726 source1, revision1, source2, revision2,
10727 target_abspath, depth, ignore_mergeinfo,
10728 diff_ignore_ancestry,
10729 force_delete, record_only, dry_run,
10730 allow_mixed_rev, merge_options, ctx, pool, pool));
10732 SVN_ERR(make_merge_conflict_error(conflict_report, pool));
10733 return SVN_NO_ERROR;
10737 /* Check if mergeinfo for a given path is described explicitly or via
10738 inheritance in a mergeinfo catalog.
10740 If REPOS_REL_PATH exists in CATALOG and has mergeinfo containing
10741 MERGEINFO, then set *IN_CATALOG to TRUE. If REPOS_REL_PATH does
10742 not exist in CATALOG, then find its nearest parent which does exist.
10743 If the mergeinfo REPOS_REL_PATH would inherit from that parent
10744 contains MERGEINFO then set *IN_CATALOG to TRUE. Set *IN_CATALOG
10745 to FALSE in all other cases.
10747 Set *CAT_KEY_PATH to the key path in CATALOG for REPOS_REL_PATH's
10748 explicit or inherited mergeinfo. If no explicit or inherited mergeinfo
10749 is found for REPOS_REL_PATH then set *CAT_KEY_PATH to NULL.
10751 User RESULT_POOL to allocate *CAT_KEY_PATH. Use SCRATCH_POOL for
10752 temporary allocations. */
10753 static svn_error_t *
10754 mergeinfo_in_catalog(svn_boolean_t *in_catalog,
10755 const char **cat_key_path,
10756 const char *repos_rel_path,
10757 svn_mergeinfo_t mergeinfo,
10758 svn_mergeinfo_catalog_t catalog,
10759 apr_pool_t *result_pool,
10760 apr_pool_t *scratch_pool)
10762 const char *walk_path = NULL;
10764 *in_catalog = FALSE;
10765 *cat_key_path = NULL;
10767 if (mergeinfo && catalog && apr_hash_count(catalog))
10769 const char *path = repos_rel_path;
10771 /* Start with the assumption there is no explicit or inherited
10772 mergeinfo for REPOS_REL_PATH in CATALOG. */
10773 svn_mergeinfo_t mergeinfo_in_cat = NULL;
10777 mergeinfo_in_cat = svn_hash_gets(catalog, path);
10779 if (mergeinfo_in_cat) /* Found it! */
10781 *cat_key_path = apr_pstrdup(result_pool, path);
10784 else /* Look for inherited mergeinfo. */
10786 walk_path = svn_relpath_join(svn_relpath_basename(path,
10788 walk_path ? walk_path : "",
10790 path = svn_relpath_dirname(path, scratch_pool);
10792 if (path[0] == '\0') /* No mergeinfo to inherit. */
10797 if (mergeinfo_in_cat)
10800 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(&mergeinfo_in_cat,
10805 SVN_ERR(svn_mergeinfo_intersect2(&mergeinfo_in_cat,
10806 mergeinfo_in_cat, mergeinfo,
10808 scratch_pool, scratch_pool));
10809 SVN_ERR(svn_mergeinfo__equals(in_catalog, mergeinfo_in_cat,
10810 mergeinfo, TRUE, scratch_pool));
10814 return SVN_NO_ERROR;
10817 /* A svn_log_entry_receiver_t baton for log_find_operative_revs(). */
10818 typedef struct log_find_operative_baton_t
10820 /* The catalog of explicit mergeinfo on a reintegrate source. */
10821 svn_mergeinfo_catalog_t merged_catalog;
10823 /* The catalog of unmerged history from the reintegrate target to
10824 the source which we will create. Allocated in RESULT_POOL. */
10825 svn_mergeinfo_catalog_t unmerged_catalog;
10827 /* The repository absolute path of the reintegrate target. */
10828 const char *target_fspath;
10830 /* The path of the reintegrate source relative to the repository root. */
10831 const char *source_repos_rel_path;
10833 apr_pool_t *result_pool;
10834 } log_find_operative_baton_t;
10836 /* A svn_log_entry_receiver_t callback for find_unsynced_ranges(). */
10837 static svn_error_t *
10838 log_find_operative_revs(void *baton,
10839 svn_log_entry_t *log_entry,
10842 log_find_operative_baton_t *log_baton = baton;
10843 apr_hash_index_t *hi;
10844 svn_revnum_t revision;
10846 /* It's possible that authz restrictions on the merge source prevent us
10847 from knowing about any of the changes for LOG_ENTRY->REVISION. */
10848 if (!log_entry->changed_paths2)
10849 return SVN_NO_ERROR;
10851 revision = log_entry->revision;
10853 for (hi = apr_hash_first(pool, log_entry->changed_paths2);
10855 hi = apr_hash_next(hi))
10857 const char *subtree_missing_this_rev;
10858 const char *path = apr_hash_this_key(hi);
10859 const char *rel_path;
10860 const char *source_rel_path;
10861 svn_boolean_t in_catalog;
10862 svn_mergeinfo_t log_entry_as_mergeinfo;
10864 rel_path = svn_fspath__skip_ancestor(log_baton->target_fspath, path);
10865 /* Easy out: The path is not within the tree of interest. */
10866 if (rel_path == NULL)
10869 source_rel_path = svn_relpath_join(log_baton->source_repos_rel_path,
10872 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo,
10873 apr_psprintf(pool, "%s:%ld",
10877 SVN_ERR(mergeinfo_in_catalog(&in_catalog, &subtree_missing_this_rev,
10878 source_rel_path, log_entry_as_mergeinfo,
10879 log_baton->merged_catalog,
10884 svn_mergeinfo_t unmerged_for_key;
10885 const char *suffix, *missing_path;
10887 /* If there is no mergeinfo on the source tree we'll say
10888 the "subtree" missing this revision is the root of the
10890 if (!subtree_missing_this_rev)
10891 subtree_missing_this_rev = log_baton->source_repos_rel_path;
10893 suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev,
10895 if (suffix && suffix[0] != '\0')
10897 missing_path = apr_pstrmemdup(pool, path,
10898 strlen(path) - strlen(suffix) - 1);
10902 missing_path = path;
10905 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo,
10906 apr_psprintf(pool, "%s:%ld",
10907 missing_path, revision),
10908 log_baton->result_pool));
10909 unmerged_for_key = svn_hash_gets(log_baton->unmerged_catalog,
10910 subtree_missing_this_rev);
10912 if (unmerged_for_key)
10914 SVN_ERR(svn_mergeinfo_merge2(unmerged_for_key,
10915 log_entry_as_mergeinfo,
10916 log_baton->result_pool,
10921 svn_hash_sets(log_baton->unmerged_catalog,
10922 apr_pstrdup(log_baton->result_pool,
10923 subtree_missing_this_rev),
10924 log_entry_as_mergeinfo);
10929 return SVN_NO_ERROR;
10932 /* Determine if the mergeinfo on a reintegrate source SOURCE_LOC,
10933 reflects that the source is fully synced with the reintegrate target
10934 TARGET_LOC, even if a naive interpretation of the source's
10935 mergeinfo says otherwise -- See issue #3577.
10937 UNMERGED_CATALOG represents the history (as mergeinfo) from
10938 TARGET_LOC that is not represented in SOURCE_LOC's
10939 explicit/inherited mergeinfo as represented by MERGED_CATALOG.
10940 MERGED_CATALOG may be empty if the source has no explicit or inherited
10943 Check that all of the unmerged revisions in UNMERGED_CATALOG's
10944 mergeinfos are "phantoms", that is, one of the following conditions holds:
10946 1) The revision affects no corresponding paths in SOURCE_LOC.
10948 2) The revision affects corresponding paths in SOURCE_LOC,
10949 but based on the mergeinfo in MERGED_CATALOG, the change was
10952 Make a deep copy, allocated in RESULT_POOL, of any portions of
10953 UNMERGED_CATALOG that are not phantoms, to TRUE_UNMERGED_CATALOG.
10955 Note: The keys in all mergeinfo catalogs used here are relative to the
10956 root of the repository.
10958 RA_SESSION is an RA session open to the repository of TARGET_LOC; it may
10959 be temporarily reparented within this function.
10961 Use SCRATCH_POOL for all temporary allocations. */
10962 static svn_error_t *
10963 find_unsynced_ranges(const svn_client__pathrev_t *source_loc,
10964 const svn_client__pathrev_t *target_loc,
10965 svn_mergeinfo_catalog_t unmerged_catalog,
10966 svn_mergeinfo_catalog_t merged_catalog,
10967 svn_mergeinfo_catalog_t true_unmerged_catalog,
10968 svn_ra_session_t *ra_session,
10969 apr_pool_t *result_pool,
10970 apr_pool_t *scratch_pool)
10972 svn_rangelist_t *potentially_unmerged_ranges = NULL;
10974 /* Convert all the unmerged history to a rangelist. */
10975 if (apr_hash_count(unmerged_catalog))
10977 apr_hash_index_t *hi_catalog;
10979 potentially_unmerged_ranges =
10980 apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *));
10982 for (hi_catalog = apr_hash_first(scratch_pool, unmerged_catalog);
10984 hi_catalog = apr_hash_next(hi_catalog))
10986 svn_mergeinfo_t mergeinfo = apr_hash_this_val(hi_catalog);
10988 SVN_ERR(svn_rangelist__merge_many(potentially_unmerged_ranges,
10990 scratch_pool, scratch_pool));
10994 /* Find any unmerged revisions which both affect the source and
10995 are not yet merged to it. */
10996 if (potentially_unmerged_ranges)
10998 svn_revnum_t oldest_rev =
10999 (APR_ARRAY_IDX(potentially_unmerged_ranges,
11001 svn_merge_range_t *))->start + 1;
11002 svn_revnum_t youngest_rev =
11003 (APR_ARRAY_IDX(potentially_unmerged_ranges,
11004 potentially_unmerged_ranges->nelts - 1,
11005 svn_merge_range_t *))->end;
11006 log_find_operative_baton_t log_baton;
11007 const char *old_session_url = NULL;
11010 log_baton.merged_catalog = merged_catalog;
11011 log_baton.unmerged_catalog = true_unmerged_catalog;
11012 log_baton.source_repos_rel_path
11013 = svn_client__pathrev_relpath(source_loc, scratch_pool);
11014 log_baton.target_fspath
11015 = svn_client__pathrev_fspath(target_loc, scratch_pool);
11016 log_baton.result_pool = result_pool;
11018 /* Reparent the session to TARGET_LOC if this target location
11019 * exists within the unmerged revision range. */
11020 if (target_loc->rev <= youngest_rev && target_loc->rev >= oldest_rev)
11021 SVN_ERR(svn_client__ensure_ra_session_url(
11022 &old_session_url, ra_session, target_loc->url, scratch_pool));
11024 err = get_log(ra_session, "", youngest_rev, oldest_rev,
11025 TRUE, /* discover_changed_paths */
11026 log_find_operative_revs, &log_baton,
11028 if (old_session_url)
11029 err = svn_error_compose_create(err,
11030 svn_ra_reparent(ra_session,
11036 return SVN_NO_ERROR;
11040 /* Find the youngest revision that has been merged from target to source.
11042 * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in
11043 * SOURCE_MERGEINFO, then we know that at least one merge was done from the
11044 * target to the source. In that case, set *YOUNGEST_MERGED_REV to the
11045 * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is
11046 * already younger than that). Otherwise, leave *YOUNGEST_MERGED_REV alone.
11048 static svn_error_t *
11049 find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev,
11050 svn_mergeinfo_t target_history_as_mergeinfo,
11051 svn_mergeinfo_t source_mergeinfo,
11052 apr_pool_t *scratch_pool)
11054 svn_mergeinfo_t explicit_source_target_history_intersection;
11056 SVN_ERR(svn_mergeinfo_intersect2(
11057 &explicit_source_target_history_intersection,
11058 source_mergeinfo, target_history_as_mergeinfo, TRUE,
11059 scratch_pool, scratch_pool));
11060 if (apr_hash_count(explicit_source_target_history_intersection))
11062 svn_revnum_t old_rev, young_rev;
11064 /* Keep track of the youngest revision merged from target to source. */
11065 SVN_ERR(svn_mergeinfo__get_range_endpoints(
11066 &young_rev, &old_rev,
11067 explicit_source_target_history_intersection, scratch_pool));
11068 if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
11069 || (young_rev > *youngest_merged_rev))
11070 *youngest_merged_rev = young_rev;
11073 return SVN_NO_ERROR;
11076 /* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO
11077 * that are not present in the source branch.
11079 * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source
11080 * branch SOURCE_PATHREV. Extend SOURCE_MERGEINFO, modifying it in
11081 * place, to include the natural history (implicit mergeinfo) of
11082 * SOURCE_PATHREV. ### But make these additions in SCRATCH_POOL.
11084 * SOURCE_RA_SESSION is an RA session open to the repository containing
11085 * SOURCE_PATHREV; it may be temporarily reparented within this function.
11087 * ### [JAF] This function is named '..._subroutine' simply because I
11088 * factored it out based on code similarity, without knowing what it's
11089 * purpose is. We should clarify its purpose and choose a better name.
11091 static svn_error_t *
11092 find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p,
11093 svn_mergeinfo_t target_history_as_mergeinfo,
11094 svn_mergeinfo_t source_mergeinfo,
11095 const svn_client__pathrev_t *source_pathrev,
11096 svn_ra_session_t *source_ra_session,
11097 svn_client_ctx_t *ctx,
11098 apr_pool_t *result_pool,
11099 apr_pool_t *scratch_pool)
11101 svn_mergeinfo_t source_history_as_mergeinfo;
11103 /* Get the source path's natural history and merge it into source
11104 path's explicit or inherited mergeinfo. */
11105 SVN_ERR(svn_client__get_history_as_mergeinfo(
11106 &source_history_as_mergeinfo, NULL /* has_rev_zero_history */,
11107 source_pathrev, source_pathrev->rev, SVN_INVALID_REVNUM,
11108 source_ra_session, ctx, scratch_pool));
11109 SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
11110 source_history_as_mergeinfo,
11111 scratch_pool, scratch_pool));
11113 /* Now source_mergeinfo represents everything we know about
11114 source_path's history. Now we need to know what part, if any, of the
11115 corresponding target's history is *not* part of source_path's total
11116 history; because it is neither shared history nor was it ever merged
11117 from the target to the source. */
11118 SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p,
11120 target_history_as_mergeinfo, TRUE,
11121 result_pool, scratch_pool));
11122 return SVN_NO_ERROR;
11125 /* Helper for calculate_left_hand_side() which produces a mergeinfo catalog
11126 describing what parts of of the reintegrate target have not previously been
11127 merged to the reintegrate source.
11129 SOURCE_CATALOG is the collection of explicit mergeinfo on SOURCE_LOC and
11130 all its children, i.e. the mergeinfo catalog for the reintegrate source.
11132 TARGET_HISTORY_HASH is a hash of (const char *) paths mapped to
11133 svn_mergeinfo_t representing the location history. Each of these
11134 path keys represent a path in the reintegrate target, relative to the
11135 repository root, which has explicit mergeinfo and/or is the reintegrate
11136 target itself. The svn_mergeinfo_t's contain the natural history of each
11137 path@TARGET_REV. Effectively this is the mergeinfo catalog on the
11138 reintegrate target.
11140 YC_ANCESTOR_REV is the revision of the youngest common ancestor of the
11141 reintegrate source and the reintegrate target.
11143 SOURCE_LOC is the reintegrate source.
11145 SOURCE_RA_SESSION is a session opened to the URL of SOURCE_LOC
11146 and TARGET_RA_SESSION is open to TARGET->loc.url.
11148 For each entry in TARGET_HISTORY_HASH check that the history it
11149 represents is contained in either the explicit mergeinfo for the
11150 corresponding path in SOURCE_CATALOG, the corresponding path's inherited
11151 mergeinfo (if no explicit mergeinfo for the path is found in
11152 SOURCE_CATALOG), or the corresponding path's natural history. Populate
11153 *UNMERGED_TO_SOURCE_CATALOG with the corresponding source paths mapped to
11154 the mergeinfo from the target's natural history which is *not* found. Also
11155 include any mergeinfo from SOURCE_CATALOG which explicitly describes the
11156 target's history but for which *no* entry was found in
11157 TARGET_HISTORY_HASH.
11159 If no part of TARGET_HISTORY_HASH is found in SOURCE_CATALOG set
11160 *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM; otherwise set it to the youngest
11161 revision previously merged from the target to the source, and filter
11162 *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than
11163 *YOUNGEST_MERGED_REV.
11165 *UNMERGED_TO_SOURCE_CATALOG is (deeply) allocated in RESULT_POOL.
11166 SCRATCH_POOL is used for all temporary allocations. */
11167 static svn_error_t *
11168 find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
11169 svn_revnum_t *youngest_merged_rev,
11170 svn_revnum_t yc_ancestor_rev,
11171 svn_mergeinfo_catalog_t source_catalog,
11172 apr_hash_t *target_history_hash,
11173 const svn_client__pathrev_t *source_loc,
11174 const merge_target_t *target,
11175 svn_ra_session_t *source_ra_session,
11176 svn_ra_session_t *target_ra_session,
11177 svn_client_ctx_t *ctx,
11178 apr_pool_t *result_pool,
11179 apr_pool_t *scratch_pool)
11181 const char *source_repos_rel_path
11182 = svn_client__pathrev_relpath(source_loc, scratch_pool);
11183 const char *target_repos_rel_path
11184 = svn_client__pathrev_relpath(&target->loc, scratch_pool);
11185 apr_hash_index_t *hi;
11186 svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool);
11187 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
11189 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11190 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11192 *youngest_merged_rev = SVN_INVALID_REVNUM;
11194 /* Examine the natural history of each path in the reintegrate target
11195 with explicit mergeinfo. */
11196 for (hi = apr_hash_first(scratch_pool, target_history_hash);
11198 hi = apr_hash_next(hi))
11200 const char *target_path = apr_hash_this_key(hi);
11201 svn_mergeinfo_t target_history_as_mergeinfo = apr_hash_this_val(hi);
11202 const char *path_rel_to_session
11203 = svn_relpath_skip_ancestor(target_repos_rel_path, target_path);
11204 const char *source_path;
11205 svn_client__pathrev_t *source_pathrev;
11206 svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
11208 svn_pool_clear(iterpool);
11210 source_path = svn_relpath_join(source_repos_rel_path,
11211 path_rel_to_session, iterpool);
11212 source_pathrev = svn_client__pathrev_join_relpath(
11213 source_loc, path_rel_to_session, iterpool);
11215 /* Remove any target history that is also part of the source's history,
11216 i.e. their common ancestry. By definition this has already been
11217 "merged" from the target to the source. If the source has explicit
11218 self referential mergeinfo it would intersect with the target's
11219 history below, making it appear that some merges had been done from
11220 the target to the source, when this might not actually be the case. */
11221 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
11222 &target_history_as_mergeinfo, target_history_as_mergeinfo,
11223 source_loc->rev, yc_ancestor_rev, TRUE, iterpool, iterpool));
11225 /* Look for any explicit mergeinfo on the source path corresponding to
11226 the target path. If we find any remove that from SOURCE_CATALOG.
11227 When this iteration over TARGET_HISTORY_HASH is complete all that
11228 should be left in SOURCE_CATALOG are subtrees that have explicit
11229 mergeinfo on the reintegrate source where there is no corresponding
11230 explicit mergeinfo on the reintegrate target. */
11231 source_mergeinfo = svn_hash_gets(source_catalog, source_path);
11232 if (source_mergeinfo)
11234 svn_hash_sets(source_catalog, source_path, NULL);
11236 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
11237 target_history_as_mergeinfo,
11243 /* There is no mergeinfo on source_path *or* source_path doesn't
11244 exist at all. If simply doesn't exist we can ignore it
11246 svn_node_kind_t kind;
11248 SVN_ERR(svn_ra_check_path(source_ra_session,
11249 path_rel_to_session,
11250 source_loc->rev, &kind, iterpool));
11251 if (kind == svn_node_none)
11253 /* Else source_path does exist though it has no explicit mergeinfo.
11254 Find its inherited mergeinfo. If it doesn't have any then simply
11255 set source_mergeinfo to an empty hash. */
11256 SVN_ERR(svn_client__get_repos_mergeinfo(
11257 &source_mergeinfo, source_ra_session,
11258 source_pathrev->url, source_pathrev->rev,
11259 svn_mergeinfo_inherited, FALSE /*squelch_incapable*/,
11261 if (!source_mergeinfo)
11262 source_mergeinfo = apr_hash_make(iterpool);
11265 /* Use scratch_pool rather than iterpool because filtered_mergeinfo
11266 is going into new_catalog below and needs to last to the end of
11268 SVN_ERR(find_unmerged_mergeinfo_subroutine(
11269 &filtered_mergeinfo, target_history_as_mergeinfo,
11270 source_mergeinfo, source_pathrev,
11271 source_ra_session, ctx, scratch_pool, iterpool));
11272 svn_hash_sets(new_catalog, apr_pstrdup(scratch_pool, source_path),
11273 filtered_mergeinfo);
11276 /* Are there any subtrees with explicit mergeinfo still left in the merge
11277 source where there was no explicit mergeinfo for the corresponding path
11278 in the merge target? If so, add the intersection of those path's
11279 mergeinfo and the corresponding target path's mergeinfo to
11281 for (hi = apr_hash_first(scratch_pool, source_catalog);
11283 hi = apr_hash_next(hi))
11285 const char *source_path = apr_hash_this_key(hi);
11286 const char *path_rel_to_session =
11287 svn_relpath_skip_ancestor(source_repos_rel_path, source_path);
11288 const char *source_url;
11289 svn_mergeinfo_t source_mergeinfo = apr_hash_this_val(hi);
11290 svn_mergeinfo_t filtered_mergeinfo;
11291 svn_client__pathrev_t *target_pathrev;
11292 svn_mergeinfo_t target_history_as_mergeinfo;
11295 svn_pool_clear(iterpool);
11297 source_url = svn_path_url_add_component2(source_loc->url,
11298 path_rel_to_session, iterpool);
11299 target_pathrev = svn_client__pathrev_join_relpath(
11300 &target->loc, path_rel_to_session, iterpool);
11301 err = svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo,
11302 NULL /* has_rev_zero_history */,
11305 SVN_INVALID_REVNUM,
11310 if (err->apr_err == SVN_ERR_FS_NOT_FOUND
11311 || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
11313 /* This path with explicit mergeinfo in the source doesn't
11314 exist on the target. */
11315 svn_error_clear(err);
11320 return svn_error_trace(err);
11325 svn_client__pathrev_t *pathrev;
11327 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
11328 target_history_as_mergeinfo,
11332 /* Use scratch_pool rather than iterpool because filtered_mergeinfo
11333 is going into new_catalog below and needs to last to the end of
11335 /* ### Why looking at SOURCE_url at TARGET_rev? */
11336 SVN_ERR(svn_client__pathrev_create_with_session(
11337 &pathrev, source_ra_session, target->loc.rev, source_url,
11339 SVN_ERR(find_unmerged_mergeinfo_subroutine(
11340 &filtered_mergeinfo, target_history_as_mergeinfo,
11341 source_mergeinfo, pathrev,
11342 source_ra_session, ctx, scratch_pool, iterpool));
11343 if (apr_hash_count(filtered_mergeinfo))
11344 svn_hash_sets(new_catalog,
11345 apr_pstrdup(scratch_pool, source_path),
11346 filtered_mergeinfo);
11350 /* Limit new_catalog to the youngest revisions previously merged from
11351 the target to the source. */
11352 if (SVN_IS_VALID_REVNUM(*youngest_merged_rev))
11353 SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog,
11355 *youngest_merged_rev,
11356 0, /* No oldest bound. */
11361 /* Make a shiny new copy before blowing away all the temporary pools. */
11362 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(new_catalog,
11364 svn_pool_destroy(iterpool);
11365 return SVN_NO_ERROR;
11368 /* Helper for svn_client_merge_reintegrate() which calculates the
11369 'left hand side' of the underlying two-URL merge that a --reintegrate
11370 merge actually performs. If no merge should be performed, set
11373 TARGET->abspath is the absolute working copy path of the reintegrate
11376 SOURCE_LOC is the reintegrate source.
11378 SUBTREES_WITH_MERGEINFO is a hash of (const char *) absolute paths mapped
11379 to (svn_mergeinfo_t *) mergeinfo values for each working copy path with
11380 explicit mergeinfo in TARGET->abspath. Actually we only need to know the
11381 paths, not the mergeinfo.
11383 TARGET->loc.rev is the working revision the entire WC tree rooted at
11386 Populate *UNMERGED_TO_SOURCE_CATALOG with the mergeinfo describing what
11387 parts of TARGET->loc have not been merged to SOURCE_LOC, up to the
11388 youngest revision ever merged from the TARGET->abspath to the source if
11389 such exists, see doc string for find_unmerged_mergeinfo().
11391 SOURCE_RA_SESSION is a session opened to the SOURCE_LOC
11392 and TARGET_RA_SESSION is open to TARGET->loc.url.
11394 *LEFT_P, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are
11395 allocated in RESULT_POOL. SCRATCH_POOL is used for all temporary
11397 static svn_error_t *
11398 calculate_left_hand_side(svn_client__pathrev_t **left_p,
11399 svn_mergeinfo_catalog_t *merged_to_source_catalog,
11400 svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
11401 const merge_target_t *target,
11402 apr_hash_t *subtrees_with_mergeinfo,
11403 const svn_client__pathrev_t *source_loc,
11404 svn_ra_session_t *source_ra_session,
11405 svn_ra_session_t *target_ra_session,
11406 svn_client_ctx_t *ctx,
11407 apr_pool_t *result_pool,
11408 apr_pool_t *scratch_pool)
11410 svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog;
11411 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
11412 apr_hash_index_t *hi;
11413 /* hash of paths mapped to arrays of svn_mergeinfo_t. */
11414 apr_hash_t *target_history_hash = apr_hash_make(scratch_pool);
11415 svn_revnum_t youngest_merged_rev;
11416 svn_client__pathrev_t *yc_ancestor;
11418 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11419 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11421 /* Initialize our return variables. */
11424 /* TARGET->abspath may not have explicit mergeinfo and thus may not be
11425 contained within SUBTREES_WITH_MERGEINFO. If this is the case then
11426 add a dummy item for TARGET->abspath so we get its history (i.e. implicit
11427 mergeinfo) below. */
11428 if (!svn_hash_gets(subtrees_with_mergeinfo, target->abspath))
11429 svn_hash_sets(subtrees_with_mergeinfo, target->abspath,
11430 apr_hash_make(result_pool));
11432 /* Get the history segments (as mergeinfo) for TARGET->abspath and any of
11433 its subtrees with explicit mergeinfo. */
11434 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo);
11436 hi = apr_hash_next(hi))
11438 const char *local_abspath = apr_hash_this_key(hi);
11439 svn_client__pathrev_t *target_child;
11440 const char *repos_relpath;
11441 svn_mergeinfo_t target_history_as_mergeinfo;
11443 svn_pool_clear(iterpool);
11445 /* Convert the absolute path with mergeinfo on it to a path relative
11446 to the session root. */
11447 SVN_ERR(svn_wc__node_get_repos_info(NULL, &repos_relpath, NULL, NULL,
11448 ctx->wc_ctx, local_abspath,
11449 scratch_pool, iterpool));
11450 target_child = svn_client__pathrev_create_with_relpath(
11451 target->loc.repos_root_url, target->loc.repos_uuid,
11452 target->loc.rev, repos_relpath, iterpool);
11453 SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo,
11454 NULL /* has_rev_zero_hist */,
11457 SVN_INVALID_REVNUM,
11459 ctx, scratch_pool));
11461 svn_hash_sets(target_history_hash, repos_relpath,
11462 target_history_as_mergeinfo);
11465 /* Check that SOURCE_LOC and TARGET->loc are
11466 actually related, we can't reintegrate if they are not. Also
11467 get an initial value for the YCA revision number. */
11468 SVN_ERR(svn_client__get_youngest_common_ancestor(
11469 &yc_ancestor, source_loc, &target->loc, target_ra_session, ctx,
11470 iterpool, iterpool));
11472 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11473 _("'%s@%ld' must be ancestrally related to "
11474 "'%s@%ld'"), source_loc->url, source_loc->rev,
11475 target->loc.url, target->loc.rev);
11477 /* If the source revision is the same as the youngest common
11478 revision, then there can't possibly be any unmerged revisions
11479 that we need to apply to target. */
11480 if (source_loc->rev == yc_ancestor->rev)
11482 svn_pool_destroy(iterpool);
11483 return SVN_NO_ERROR;
11486 /* Get the mergeinfo from the source, including its descendants
11487 with differing explicit mergeinfo. */
11488 SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
11489 &mergeinfo_catalog, source_ra_session,
11490 source_loc->url, source_loc->rev,
11491 svn_mergeinfo_inherited, FALSE /* squelch_incapable */,
11492 TRUE /* include_descendants */, iterpool, iterpool));
11494 if (!mergeinfo_catalog)
11495 mergeinfo_catalog = apr_hash_make(iterpool);
11497 *merged_to_source_catalog = svn_mergeinfo_catalog_dup(mergeinfo_catalog,
11500 /* Filter the source's mergeinfo catalog so that we are left with
11501 mergeinfo that describes what has *not* previously been merged from
11502 TARGET->loc to SOURCE_LOC. */
11503 SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
11504 &youngest_merged_rev,
11507 target_history_hash,
11513 iterpool, iterpool));
11515 /* Simplify unmerged_catalog through elision then make a copy in POOL. */
11516 SVN_ERR(svn_client__elide_mergeinfo_catalog(unmerged_catalog,
11518 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(unmerged_catalog,
11521 if (youngest_merged_rev == SVN_INVALID_REVNUM)
11523 /* We never merged to the source. Just return the branch point. */
11524 *left_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
11528 /* We've previously merged some or all of the target, up to
11529 youngest_merged_rev, to the source. Set
11530 *LEFT_P to cover the youngest part of this range. */
11531 SVN_ERR(svn_client__repos_location(left_p, target_ra_session,
11532 &target->loc, youngest_merged_rev,
11533 ctx, result_pool, iterpool));
11536 svn_pool_destroy(iterpool);
11537 return SVN_NO_ERROR;
11540 /* Determine the URLs and revisions needed to perform a reintegrate merge
11541 * from SOURCE_LOC into the working copy at TARGET.
11543 * SOURCE_RA_SESSION and TARGET_RA_SESSION are RA sessions opened to the
11544 * URLs of SOURCE_LOC and TARGET->loc respectively.
11547 * the source-left and source-right locations of the required merge. Set
11548 * *YC_ANCESTOR_P to the location of the youngest ancestor.
11549 * Any of these output pointers may be NULL if not wanted.
11551 * See svn_client_find_reintegrate_merge() for other details.
11553 static svn_error_t *
11554 find_reintegrate_merge(merge_source_t **source_p,
11555 svn_client__pathrev_t **yc_ancestor_p,
11556 svn_ra_session_t *source_ra_session,
11557 const svn_client__pathrev_t *source_loc,
11558 svn_ra_session_t *target_ra_session,
11559 const merge_target_t *target,
11560 svn_client_ctx_t *ctx,
11561 apr_pool_t *result_pool,
11562 apr_pool_t *scratch_pool)
11564 svn_client__pathrev_t *yc_ancestor;
11565 svn_client__pathrev_t *loc1;
11566 merge_source_t source;
11567 svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog;
11568 svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog;
11570 apr_hash_t *subtrees_with_mergeinfo;
11572 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11573 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11575 /* As the WC tree is "pure", use its last-updated-to revision as
11576 the default revision for the left side of our merge, since that's
11577 what the repository sub-tree is required to be up to date with
11578 (with regard to the WC). */
11579 /* ### Bogus/obsolete comment? */
11581 /* Can't reintegrate to or from the root of the repository. */
11582 if (strcmp(source_loc->url, source_loc->repos_root_url) == 0
11583 || strcmp(target->loc.url, target->loc.repos_root_url) == 0)
11584 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11585 _("Neither the reintegrate source nor target "
11586 "can be the root of the repository"));
11588 /* Find all the subtrees in TARGET_WCPATH that have explicit mergeinfo. */
11589 err = get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
11590 target->abspath, svn_depth_infinity,
11591 ctx, scratch_pool, scratch_pool);
11592 /* Issue #3896: If invalid mergeinfo in the reintegrate target
11593 prevents us from proceeding, then raise the best error possible. */
11594 if (err && err->apr_err == SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING)
11595 err = svn_error_quick_wrap(err, _("Reintegrate merge not possible"));
11598 SVN_ERR(calculate_left_hand_side(&loc1,
11599 &merged_to_source_mergeinfo_catalog,
11600 &unmerged_to_source_mergeinfo_catalog,
11602 subtrees_with_mergeinfo,
11607 scratch_pool, scratch_pool));
11609 /* Did calculate_left_hand_side() decide that there was no merge to
11610 be performed here? */
11616 *yc_ancestor_p = NULL;
11617 return SVN_NO_ERROR;
11620 source.loc1 = loc1;
11621 source.loc2 = source_loc;
11623 /* If the target was moved after the source was branched from it,
11624 it is possible that the left URL differs from the target's current
11625 URL. If so, then adjust TARGET_RA_SESSION to point to the old URL. */
11626 if (strcmp(source.loc1->url, target->loc.url))
11627 SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1->url, scratch_pool));
11629 SVN_ERR(svn_client__get_youngest_common_ancestor(
11630 &yc_ancestor, source.loc2, source.loc1, target_ra_session,
11631 ctx, scratch_pool, scratch_pool));
11634 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11635 _("'%s@%ld' must be ancestrally related to "
11637 source.loc1->url, source.loc1->rev,
11638 source.loc2->url, source.loc2->rev);
11640 /* The source side of a reintegrate merge is not 'ancestral', except in
11641 * the degenerate case where source == YCA. */
11642 source.ancestral = (loc1->rev == yc_ancestor->rev);
11644 if (source.loc1->rev > yc_ancestor->rev)
11646 /* Have we actually merged anything to the source from the
11647 target? If so, make sure we've merged a contiguous
11649 svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool);
11651 SVN_ERR(find_unsynced_ranges(source_loc, &target->loc,
11652 unmerged_to_source_mergeinfo_catalog,
11653 merged_to_source_mergeinfo_catalog,
11654 final_unmerged_catalog,
11655 target_ra_session, scratch_pool,
11658 if (apr_hash_count(final_unmerged_catalog))
11660 svn_string_t *source_mergeinfo_cat_string;
11662 SVN_ERR(svn_mergeinfo__catalog_to_formatted_string(
11663 &source_mergeinfo_cat_string,
11664 final_unmerged_catalog,
11665 " ", _(" Missing ranges: "), scratch_pool));
11666 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
11668 _("Reintegrate can only be used if "
11669 "revisions %ld through %ld were "
11670 "previously merged from %s to the "
11671 "reintegrate source, but this is "
11672 "not the case:\n%s"),
11673 yc_ancestor->rev + 1, source.loc2->rev,
11675 source_mergeinfo_cat_string->data);
11679 /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev
11680 * Right side: branch@specified-peg-revision */
11682 *source_p = merge_source_dup(&source, result_pool);
11685 *yc_ancestor_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
11686 return SVN_NO_ERROR;
11689 /* Resolve the source and target locations and open RA sessions to them, and
11690 * perform some checks appropriate for a reintegrate merge.
11692 * Set *SOURCE_RA_SESSION_P and *SOURCE_LOC_P to a new session and the
11693 * repository location of SOURCE_PATH_OR_URL at SOURCE_PEG_REVISION. Set
11694 * *TARGET_RA_SESSION_P and *TARGET_P to a new session and the repository
11695 * location of the WC at TARGET_ABSPATH.
11697 * Throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES error if the target WC node is
11698 * a locally added node or if the source and target are not in the same
11699 * repository. Throw a SVN_ERR_CLIENT_NOT_READY_TO_MERGE error if the
11700 * target WC is not at a single revision without switched subtrees and
11701 * without local mods.
11703 * Allocate all the outputs in RESULT_POOL.
11705 static svn_error_t *
11706 open_reintegrate_source_and_target(svn_ra_session_t **source_ra_session_p,
11707 svn_client__pathrev_t **source_loc_p,
11708 svn_ra_session_t **target_ra_session_p,
11709 merge_target_t **target_p,
11710 const char *source_path_or_url,
11711 const svn_opt_revision_t *source_peg_revision,
11712 const char *target_abspath,
11713 svn_client_ctx_t *ctx,
11714 apr_pool_t *result_pool,
11715 apr_pool_t *scratch_pool)
11717 svn_client__pathrev_t *source_loc;
11718 merge_target_t *target;
11720 /* Open the target WC. A reintegrate merge requires the merge target to
11721 * reflect a subtree of the repository as found at a single revision. */
11722 SVN_ERR(open_target_wc(&target, target_abspath,
11723 FALSE, FALSE, FALSE,
11724 ctx, scratch_pool, scratch_pool));
11725 if (! target->loc.url)
11726 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
11727 _("Can't reintegrate into '%s' because it is "
11728 "locally added and therefore not related to "
11729 "the merge source"),
11730 svn_dirent_local_style(target->abspath,
11733 SVN_ERR(svn_client_open_ra_session2(target_ra_session_p,
11734 target->loc.url, target->abspath,
11735 ctx, result_pool, scratch_pool));
11737 SVN_ERR(svn_client__ra_session_from_path2(
11738 source_ra_session_p, &source_loc,
11739 source_path_or_url, NULL, source_peg_revision, source_peg_revision,
11740 ctx, result_pool));
11742 /* source_loc and target->loc are required to be in the same repository,
11743 as mergeinfo doesn't come into play for cross-repository merging. */
11744 SVN_ERR(check_same_repos(source_loc,
11745 svn_dirent_local_style(source_path_or_url,
11748 svn_dirent_local_style(target->abspath,
11750 TRUE /* strict_urls */, scratch_pool));
11752 *source_loc_p = source_loc;
11753 *target_p = target;
11754 return SVN_NO_ERROR;
11757 /* The body of svn_client_merge_reintegrate(), which see for details. */
11758 static svn_error_t *
11759 merge_reintegrate_locked(conflict_report_t **conflict_report,
11760 const char *source_path_or_url,
11761 const svn_opt_revision_t *source_peg_revision,
11762 const char *target_abspath,
11763 svn_boolean_t diff_ignore_ancestry,
11764 svn_boolean_t dry_run,
11765 const apr_array_header_t *merge_options,
11766 svn_client_ctx_t *ctx,
11767 apr_pool_t *result_pool,
11768 apr_pool_t *scratch_pool)
11770 svn_ra_session_t *target_ra_session, *source_ra_session;
11771 merge_target_t *target;
11772 svn_client__pathrev_t *source_loc;
11773 merge_source_t *source;
11774 svn_client__pathrev_t *yc_ancestor;
11775 svn_boolean_t use_sleep = FALSE;
11778 SVN_ERR(open_reintegrate_source_and_target(
11779 &source_ra_session, &source_loc, &target_ra_session, &target,
11780 source_path_or_url, source_peg_revision, target_abspath,
11781 ctx, scratch_pool, scratch_pool));
11783 SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor,
11784 source_ra_session, source_loc,
11785 target_ra_session, target,
11786 ctx, scratch_pool, scratch_pool));
11790 *conflict_report = NULL;
11791 return SVN_NO_ERROR;
11794 /* Do the real merge! */
11795 /* ### TODO(reint): Make sure that one isn't the same line ancestor
11796 ### of the other (what's erroneously referred to as "ancestrally
11797 ### related" in this source file). For now, we just say the source
11798 ### isn't "ancestral" even if it is (in the degenerate case where
11799 ### source-left equals YCA). */
11800 source->ancestral = FALSE;
11801 err = merge_cousins_and_supplement_mergeinfo(conflict_report,
11806 source, yc_ancestor,
11807 TRUE /* same_repos */,
11808 svn_depth_infinity,
11809 diff_ignore_ancestry,
11810 FALSE /* force_delete */,
11811 FALSE /* record_only */,
11815 result_pool, scratch_pool);
11818 svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
11821 return SVN_NO_ERROR;
11825 svn_client_merge_reintegrate(const char *source_path_or_url,
11826 const svn_opt_revision_t *source_peg_revision,
11827 const char *target_wcpath,
11828 svn_boolean_t dry_run,
11829 const apr_array_header_t *merge_options,
11830 svn_client_ctx_t *ctx,
11833 const char *target_abspath, *lock_abspath;
11834 conflict_report_t *conflict_report;
11836 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
11837 target_wcpath, ctx, pool));
11840 SVN_WC__CALL_WITH_WRITE_LOCK(
11841 merge_reintegrate_locked(&conflict_report,
11842 source_path_or_url, source_peg_revision,
11844 FALSE /*diff_ignore_ancestry*/,
11845 dry_run, merge_options, ctx, pool, pool),
11846 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
11848 SVN_ERR(merge_reintegrate_locked(&conflict_report,
11849 source_path_or_url, source_peg_revision,
11851 FALSE /*diff_ignore_ancestry*/,
11852 dry_run, merge_options, ctx, pool, pool));
11854 SVN_ERR(make_merge_conflict_error(conflict_report, pool));
11855 return SVN_NO_ERROR;
11859 /* The body of svn_client_merge_peg5(), which see for details.
11861 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge().
11863 static svn_error_t *
11864 merge_peg_locked(conflict_report_t **conflict_report,
11865 const char *source_path_or_url,
11866 const svn_opt_revision_t *source_peg_revision,
11867 const svn_rangelist_t *ranges_to_merge,
11868 const char *target_abspath,
11870 svn_boolean_t ignore_mergeinfo,
11871 svn_boolean_t diff_ignore_ancestry,
11872 svn_boolean_t force_delete,
11873 svn_boolean_t record_only,
11874 svn_boolean_t dry_run,
11875 svn_boolean_t allow_mixed_rev,
11876 const apr_array_header_t *merge_options,
11877 svn_client_ctx_t *ctx,
11878 apr_pool_t *result_pool,
11879 apr_pool_t *scratch_pool)
11881 merge_target_t *target;
11882 svn_client__pathrev_t *source_loc;
11883 apr_array_header_t *merge_sources;
11884 svn_ra_session_t *ra_session;
11885 apr_pool_t *sesspool;
11886 svn_boolean_t use_sleep = FALSE;
11888 svn_boolean_t same_repos;
11890 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
11892 SVN_ERR(open_target_wc(&target, target_abspath,
11893 allow_mixed_rev, TRUE, TRUE,
11894 ctx, scratch_pool, scratch_pool));
11896 /* Create a short lived session pool */
11897 sesspool = svn_pool_create(scratch_pool);
11899 /* Open an RA session to our source URL, and determine its root URL. */
11900 SVN_ERR(svn_client__ra_session_from_path2(
11901 &ra_session, &source_loc,
11902 source_path_or_url, NULL, source_peg_revision, source_peg_revision,
11905 /* Normalize our merge sources. */
11906 SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url,
11908 ranges_to_merge, ra_session, ctx,
11909 scratch_pool, scratch_pool));
11911 /* Check for same_repos. */
11912 same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */);
11914 /* Do the real merge! (We say with confidence that our merge
11915 sources are both ancestral and related.) */
11916 err = do_merge(NULL, NULL, conflict_report, &use_sleep,
11917 merge_sources, target, ra_session,
11918 TRUE /*sources_related*/, same_repos, ignore_mergeinfo,
11919 diff_ignore_ancestry, force_delete, dry_run,
11920 record_only, NULL, FALSE, FALSE, depth, merge_options,
11921 ctx, result_pool, scratch_pool);
11923 /* We're done with our RA session. */
11924 svn_pool_destroy(sesspool);
11927 svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
11930 return SVN_NO_ERROR;
11933 /* Details of an automatic merge. */
11934 typedef struct automatic_merge_t
11936 svn_client__pathrev_t *yca, *base, *right, *target;
11937 svn_boolean_t is_reintegrate_like;
11938 svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees;
11939 } automatic_merge_t;
11941 static svn_error_t *
11942 client_find_automatic_merge(automatic_merge_t **merge_p,
11943 const char *source_path_or_url,
11944 const svn_opt_revision_t *source_revision,
11945 const char *target_abspath,
11946 svn_boolean_t allow_mixed_rev,
11947 svn_boolean_t allow_local_mods,
11948 svn_boolean_t allow_switched_subtrees,
11949 svn_client_ctx_t *ctx,
11950 apr_pool_t *result_pool,
11951 apr_pool_t *scratch_pool);
11953 static svn_error_t *
11954 do_automatic_merge_locked(conflict_report_t **conflict_report,
11955 const automatic_merge_t *merge,
11956 const char *target_abspath,
11958 svn_boolean_t diff_ignore_ancestry,
11959 svn_boolean_t force_delete,
11960 svn_boolean_t record_only,
11961 svn_boolean_t dry_run,
11962 const apr_array_header_t *merge_options,
11963 svn_client_ctx_t *ctx,
11964 apr_pool_t *result_pool,
11965 apr_pool_t *scratch_pool);
11968 svn_client_merge_peg5(const char *source_path_or_url,
11969 const apr_array_header_t *ranges_to_merge,
11970 const svn_opt_revision_t *source_peg_revision,
11971 const char *target_wcpath,
11973 svn_boolean_t ignore_mergeinfo,
11974 svn_boolean_t diff_ignore_ancestry,
11975 svn_boolean_t force_delete,
11976 svn_boolean_t record_only,
11977 svn_boolean_t dry_run,
11978 svn_boolean_t allow_mixed_rev,
11979 const apr_array_header_t *merge_options,
11980 svn_client_ctx_t *ctx,
11983 const char *target_abspath, *lock_abspath;
11984 conflict_report_t *conflict_report;
11986 /* No ranges to merge? No problem. */
11987 if (ranges_to_merge != NULL && ranges_to_merge->nelts == 0)
11988 return SVN_NO_ERROR;
11990 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
11991 target_wcpath, ctx, pool));
11993 /* Do an automatic merge if no revision ranges are specified. */
11994 if (ranges_to_merge == NULL)
11996 automatic_merge_t *merge;
11998 if (ignore_mergeinfo)
11999 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12000 _("Cannot merge automatically while "
12001 "ignoring mergeinfo"));
12003 /* Find the details of the merge needed. */
12004 SVN_ERR(client_find_automatic_merge(
12006 source_path_or_url, source_peg_revision,
12009 TRUE /*allow_local_mods*/,
12010 TRUE /*allow_switched_subtrees*/,
12014 SVN_WC__CALL_WITH_WRITE_LOCK(
12015 do_automatic_merge_locked(&conflict_report,
12017 target_abspath, depth,
12018 diff_ignore_ancestry,
12019 force_delete, record_only, dry_run,
12020 merge_options, ctx, pool, pool),
12021 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
12023 SVN_ERR(do_automatic_merge_locked(&conflict_report,
12025 target_abspath, depth,
12026 diff_ignore_ancestry,
12027 force_delete, record_only, dry_run,
12028 merge_options, ctx, pool, pool));
12031 SVN_WC__CALL_WITH_WRITE_LOCK(
12032 merge_peg_locked(&conflict_report,
12033 source_path_or_url, source_peg_revision,
12035 target_abspath, depth, ignore_mergeinfo,
12036 diff_ignore_ancestry,
12037 force_delete, record_only, dry_run,
12038 allow_mixed_rev, merge_options, ctx, pool, pool),
12039 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
12041 SVN_ERR(merge_peg_locked(&conflict_report,
12042 source_path_or_url, source_peg_revision,
12044 target_abspath, depth, ignore_mergeinfo,
12045 diff_ignore_ancestry,
12046 force_delete, record_only, dry_run,
12047 allow_mixed_rev, merge_options, ctx, pool, pool));
12049 SVN_ERR(make_merge_conflict_error(conflict_report, pool));
12050 return SVN_NO_ERROR;
12054 /* The location-history of a branch.
12056 * This structure holds the set of path-revisions occupied by a branch,
12057 * from an externally chosen 'tip' location back to its origin. The
12058 * 'tip' location is the youngest location that we are considering on
12060 typedef struct branch_history_t
12062 /* The tip location of the branch. That is, the youngest location that's
12063 * in the repository and that we're considering. If we're considering a
12064 * target branch right up to an uncommitted WC, then this is the WC base
12065 * (pristine) location. */
12066 svn_client__pathrev_t *tip;
12067 /* The location-segment history, as mergeinfo. */
12068 svn_mergeinfo_t history;
12069 /* Whether the location-segment history reached as far as (necessarily
12070 the root path in) revision 0 -- a fact that can't be represented as
12072 svn_boolean_t has_r0_history;
12073 } branch_history_t;
12075 /* Return the location on BRANCH_HISTORY at revision REV, or NULL if none. */
12076 static svn_client__pathrev_t *
12077 location_on_branch_at_rev(const branch_history_t *branch_history,
12079 apr_pool_t *result_pool,
12080 apr_pool_t *scratch_pool)
12082 apr_hash_index_t *hi;
12084 for (hi = apr_hash_first(scratch_pool, branch_history->history); hi;
12085 hi = apr_hash_next(hi))
12087 const char *fspath = apr_hash_this_key(hi);
12088 svn_rangelist_t *rangelist = apr_hash_this_val(hi);
12091 for (i = 0; i < rangelist->nelts; i++)
12093 svn_merge_range_t *r = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
12094 if (r->start < rev && rev <= r->end)
12096 return svn_client__pathrev_create_with_relpath(
12097 branch_history->tip->repos_root_url,
12098 branch_history->tip->repos_uuid,
12099 rev, fspath + 1, result_pool);
12107 typedef struct source_and_target_t
12109 svn_client__pathrev_t *source;
12110 svn_ra_session_t *source_ra_session;
12111 branch_history_t source_branch;
12113 merge_target_t *target;
12114 svn_ra_session_t *target_ra_session;
12115 branch_history_t target_branch;
12117 /* Repos location of the youngest common ancestor of SOURCE and TARGET. */
12118 svn_client__pathrev_t *yca;
12119 } source_and_target_t;
12121 /* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
12122 * revision range OLDEST_REV to YOUNGEST_REV (inclusive).
12124 * If the intersection is empty, the result will be a branch history object
12125 * containing an empty (not null) history.
12127 * ### The 'tip' of the result is currently unchanged.
12129 static svn_error_t *
12130 branch_history_intersect_range(branch_history_t **intersection_p,
12131 const branch_history_t *branch_history,
12132 svn_revnum_t oldest_rev,
12133 svn_revnum_t youngest_rev,
12134 apr_pool_t *result_pool,
12135 apr_pool_t *scratch_pool)
12137 branch_history_t *result = apr_palloc(result_pool, sizeof(*result));
12139 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
12140 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
12141 SVN_ERR_ASSERT(oldest_rev >= 1);
12142 /* Allow a just-empty range (oldest = youngest + 1) but not an
12143 * arbitrary reverse range (such as oldest = youngest + 2). */
12144 SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1);
12146 if (oldest_rev <= youngest_rev)
12148 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
12149 &result->history, branch_history->history,
12150 youngest_rev, oldest_rev - 1, TRUE /* include_range */,
12151 result_pool, scratch_pool));
12152 result->history = svn_mergeinfo_dup(result->history, result_pool);
12156 result->history = apr_hash_make(result_pool);
12158 result->has_r0_history = FALSE;
12160 /* ### TODO: Set RESULT->tip to the tip of the intersection. */
12161 result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool);
12163 *intersection_p = result;
12164 return SVN_NO_ERROR;
12167 /* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations
12168 * (inclusive) along BRANCH. OLDEST_P and/or YOUNGEST_P may be NULL if not
12171 static svn_error_t *
12172 branch_history_get_endpoints(svn_client__pathrev_t **oldest_p,
12173 svn_client__pathrev_t **youngest_p,
12174 const branch_history_t *branch,
12175 apr_pool_t *result_pool,
12176 apr_pool_t *scratch_pool)
12178 svn_revnum_t youngest_rev, oldest_rev;
12180 SVN_ERR(svn_mergeinfo__get_range_endpoints(
12181 &youngest_rev, &oldest_rev,
12182 branch->history, scratch_pool));
12184 *oldest_p = location_on_branch_at_rev(
12185 branch, oldest_rev + 1, result_pool, scratch_pool);
12187 *youngest_p = location_on_branch_at_rev(
12188 branch, youngest_rev, result_pool, scratch_pool);
12189 return SVN_NO_ERROR;
12192 /* Implements the svn_log_entry_receiver_t interface.
12194 Set *BATON to LOG_ENTRY->revision and return SVN_ERR_CEASE_INVOCATION. */
12195 static svn_error_t *
12196 operative_rev_receiver(void *baton,
12197 svn_log_entry_t *log_entry,
12200 svn_revnum_t *operative_rev = baton;
12202 *operative_rev = log_entry->revision;
12204 /* We've found the youngest merged or oldest eligible revision, so
12207 ...but wait, shouldn't we care if LOG_ENTRY->NON_INHERITABLE is
12208 true? Because if it is, then LOG_ENTRY->REVISION is only
12209 partially merged/elgibile! And our only caller,
12210 find_last_merged_location (via short_circuit_mergeinfo_log) is
12211 interested in *fully* merged revisions. That's all true, but if
12212 find_last_merged_location() finds the youngest merged revision it
12213 will also check for the oldest eligible revision. So in the case
12214 the youngest merged rev is non-inheritable, the *same* non-inheritable
12215 rev will be found as the oldest eligible rev -- and
12216 find_last_merged_location() handles that situation. */
12217 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
12220 /* Wrapper around svn_client__mergeinfo_log. All arguments are as per
12221 that private API. The discover_changed_paths, depth, and revprops args to
12222 svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t,
12223 and empty array respectively.
12225 If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets
12226 *REVISION to a valid revnum, then clear the error. Otherwise return
12228 static svn_error_t*
12229 short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat,
12230 svn_boolean_t finding_merged,
12231 const char *target_path_or_url,
12232 const svn_opt_revision_t *target_peg_revision,
12233 const char *source_path_or_url,
12234 const svn_opt_revision_t *source_peg_revision,
12235 const svn_opt_revision_t *source_start_revision,
12236 const svn_opt_revision_t *source_end_revision,
12237 svn_log_entry_receiver_t receiver,
12238 svn_revnum_t *revision,
12239 svn_client_ctx_t *ctx,
12240 svn_ra_session_t *ra_session,
12241 apr_pool_t *result_pool,
12242 apr_pool_t *scratch_pool)
12244 apr_array_header_t *revprops;
12246 const char *session_url;
12248 SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
12250 revprops = apr_array_make(scratch_pool, 0, sizeof(const char *));
12251 err = svn_client__mergeinfo_log(finding_merged,
12252 target_path_or_url,
12253 target_peg_revision,
12254 target_mergeinfo_cat,
12255 source_path_or_url,
12256 source_peg_revision,
12257 source_start_revision,
12258 source_end_revision,
12259 receiver, revision,
12260 TRUE, svn_depth_infinity,
12261 revprops, ctx, ra_session,
12262 result_pool, scratch_pool);
12264 err = svn_error_compose_create(
12266 svn_ra_reparent(ra_session, session_url, scratch_pool));
12270 /* We expect RECEIVER to short-circuit the (potentially expensive) log
12271 by raising an SVN_ERR_CEASE_INVOCATION -- see operative_rev_receiver.
12272 So we can ignore that error, but only as long as we actually found a
12274 if (SVN_IS_VALID_REVNUM(*revision)
12275 && err->apr_err == SVN_ERR_CEASE_INVOCATION)
12277 svn_error_clear(err);
12282 return svn_error_trace(err);
12285 return SVN_NO_ERROR;
12288 /* Set *BASE_P to the last location on SOURCE_BRANCH such that all changes
12289 * on SOURCE_BRANCH after YCA up to and including *BASE_P have already
12290 * been fully merged into TARGET.
12293 * o-------o-----------o--- SOURCE_BRANCH
12297 * o-----------o----------- TARGET branch
12299 * In terms of mergeinfo:
12301 * Source a--... o=change, -=no-op revision
12303 * YCA --> o a---o---o---o---o--- d=delete, a=add-as-a-copy
12305 * Eligible -.eee.eeeeeeeeeeeeeeeeeeee .=not a source branch location
12307 * Tgt-mi -.mmm.mm-mm-------m------- m=merged to root of TARGET or
12308 * subtree of TARGET with no
12309 * operative changes outside of that
12310 * subtree, -=not merged
12312 * Eligible -.---.--e--eeeeeee-eeeeeee
12314 * Next --------^----------------- BASE is just before here.
12319 * o-----------o-------------
12321 * If no revisions from SOURCE_BRANCH have been completely merged to TARGET,
12322 * then set *BASE_P to the YCA.
12324 static svn_error_t *
12325 find_last_merged_location(svn_client__pathrev_t **base_p,
12326 svn_client__pathrev_t *yca,
12327 const branch_history_t *source_branch,
12328 svn_client__pathrev_t *target,
12329 svn_client_ctx_t *ctx,
12330 svn_ra_session_t *ra_session,
12331 apr_pool_t *result_pool,
12332 apr_pool_t *scratch_pool)
12334 svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev,
12336 svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM;
12337 svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL;
12339 /* Using a local subpool for 'target_mergeinfo_cat' can make a big
12340 reduction in overall memory usage. */
12341 apr_pool_t *tmic_pool = svn_pool_create(scratch_pool);
12343 source_peg_rev.kind = svn_opt_revision_number;
12344 source_peg_rev.value.number = source_branch->tip->rev;
12345 source_start_rev.kind = svn_opt_revision_number;
12346 source_start_rev.value.number = yca->rev;
12347 source_end_rev.kind = svn_opt_revision_number;
12348 source_end_rev.value.number = source_branch->tip->rev;
12349 target_opt_rev.kind = svn_opt_revision_number;
12350 target_opt_rev.value.number = target->rev;
12352 /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET,
12353 if such a revision exists. */
12354 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
12355 TRUE, /* Find merged */
12356 target->url, &target_opt_rev,
12357 source_branch->tip->url,
12359 &source_end_rev, &source_start_rev,
12360 operative_rev_receiver,
12361 &youngest_merged_rev,
12363 tmic_pool, tmic_pool));
12365 if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
12367 /* No revisions have been completely merged from SOURCE_BRANCH to
12368 TARGET so the base for the next merge is the YCA. */
12373 /* One or more revisions have already been completely merged from
12374 SOURCE_BRANCH to TARGET, now find the oldest revision, older
12375 than the youngest merged revision, which is still eligible to
12376 be merged, if such exists. */
12377 branch_history_t *contiguous_source;
12378 svn_revnum_t base_rev;
12379 svn_revnum_t oldest_eligible_rev = SVN_INVALID_REVNUM;
12381 /* If the only revisions eligible are younger than the youngest merged
12382 revision we can simply assume that the youngest eligible revision
12383 is the youngest merged revision. Obviously this may not be true!
12384 The revisions between the youngest merged revision and the tip of
12385 the branch may have several inoperative revisions -- they may *all*
12386 be inoperative revisions! But for the purpose of this function
12387 (i.e. finding the youngest revision after the YCA where all revs have
12388 been merged) that doesn't matter. */
12389 source_end_rev.value.number = youngest_merged_rev;
12390 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
12391 FALSE, /* Find eligible */
12392 target->url, &target_opt_rev,
12393 source_branch->tip->url,
12395 &source_start_rev, &source_end_rev,
12396 operative_rev_receiver,
12397 &oldest_eligible_rev,
12399 tmic_pool, tmic_pool));
12401 /* If there are revisions eligible for merging, use the oldest one
12402 to calculate the base. Otherwise there are no operative revisions
12403 to merge and we can simple set the base to the youngest revision
12405 if (SVN_IS_VALID_REVNUM(oldest_eligible_rev))
12406 base_rev = oldest_eligible_rev - 1;
12408 base_rev = youngest_merged_rev;
12410 /* Find the branch location just before the oldest eligible rev.
12411 (We can't just use the base revs calculated above because the branch
12412 might have a gap there.) */
12413 SVN_ERR(branch_history_intersect_range(&contiguous_source,
12414 source_branch, yca->rev,
12416 scratch_pool, scratch_pool));
12417 SVN_ERR(branch_history_get_endpoints(NULL, base_p, contiguous_source,
12418 result_pool, scratch_pool));
12421 svn_pool_destroy(tmic_pool);
12422 return SVN_NO_ERROR;
12425 /* Find a merge base location on the target branch, like in a sync
12429 * o-------o-----------o---
12431 * -----o prev. \ \ this
12432 * YCA \ merge \ \ merge
12433 * o-----------o-----------o
12436 * Set *BASE_P to BASE, the youngest location in the history of S_T->source
12437 * (at or after the YCA) at which all revisions up to BASE are effectively
12438 * merged into S_T->target.
12440 * If no locations on the history of S_T->source are effectively merged to
12441 * S_T->target, set *BASE_P to the YCA.
12443 static svn_error_t *
12444 find_base_on_source(svn_client__pathrev_t **base_p,
12445 source_and_target_t *s_t,
12446 svn_client_ctx_t *ctx,
12447 apr_pool_t *result_pool,
12448 apr_pool_t *scratch_pool)
12450 SVN_ERR(find_last_merged_location(base_p,
12452 &s_t->source_branch,
12453 s_t->target_branch.tip,
12455 s_t->source_ra_session,
12456 result_pool, scratch_pool));
12457 return SVN_NO_ERROR;
12460 /* Find a merge base location on the target branch, like in a reintegrate
12464 * o-----------o-------o---
12466 * -----o merge / \ this
12468 * o-------o---------------o
12471 * Set *BASE_P to BASE, the youngest location in the history of S_T->target
12472 * (at or after the YCA) at which all revisions up to BASE are effectively
12473 * merged into S_T->source.
12475 * If no locations on the history of S_T->target are effectively merged to
12476 * S_T->source, set *BASE_P to the YCA.
12478 static svn_error_t *
12479 find_base_on_target(svn_client__pathrev_t **base_p,
12480 source_and_target_t *s_t,
12481 svn_client_ctx_t *ctx,
12482 apr_pool_t *result_pool,
12483 apr_pool_t *scratch_pool)
12485 SVN_ERR(find_last_merged_location(base_p,
12487 &s_t->target_branch,
12490 s_t->target_ra_session,
12491 result_pool, scratch_pool));
12493 return SVN_NO_ERROR;
12496 /* Find the last point at which the branch at S_T->source was completely
12497 * merged to the branch at S_T->target or vice-versa.
12499 * Fill in S_T->source_branch and S_T->target_branch and S_T->yca.
12500 * Set *BASE_P to the merge base. Set *IS_REINTEGRATE_LIKE to true if
12501 * an automatic merge from source to target would be a reintegration
12502 * merge: that is, if the last automatic merge was in the opposite
12503 * direction; or to false otherwise.
12505 * If there is no youngest common ancestor, throw an error.
12507 static svn_error_t *
12508 find_automatic_merge(svn_client__pathrev_t **base_p,
12509 svn_boolean_t *is_reintegrate_like,
12510 source_and_target_t *s_t,
12511 svn_client_ctx_t *ctx,
12512 apr_pool_t *result_pool,
12513 apr_pool_t *scratch_pool)
12515 svn_client__pathrev_t *base_on_source, *base_on_target;
12517 /* Get the location-history of each branch. */
12518 s_t->source_branch.tip = s_t->source;
12519 SVN_ERR(svn_client__get_history_as_mergeinfo(
12520 &s_t->source_branch.history, &s_t->source_branch.has_r0_history,
12521 s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
12522 s_t->source_ra_session, ctx, scratch_pool));
12523 s_t->target_branch.tip = &s_t->target->loc;
12524 SVN_ERR(svn_client__get_history_as_mergeinfo(
12525 &s_t->target_branch.history, &s_t->target_branch.has_r0_history,
12526 &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
12527 s_t->target_ra_session, ctx, scratch_pool));
12529 SVN_ERR(svn_client__calc_youngest_common_ancestor(
12530 &s_t->yca, s_t->source, s_t->source_branch.history,
12531 s_t->source_branch.has_r0_history,
12532 &s_t->target->loc, s_t->target_branch.history,
12533 s_t->target_branch.has_r0_history,
12534 result_pool, scratch_pool));
12537 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
12538 _("'%s@%ld' must be ancestrally related to "
12540 s_t->source->url, s_t->source->rev,
12541 s_t->target->loc.url, s_t->target->loc.rev);
12543 /* Find the latest revision of A synced to B and the latest
12544 * revision of B synced to A.
12546 * base_on_source = youngest_complete_synced_point(source, target)
12547 * base_on_target = youngest_complete_synced_point(target, source)
12549 SVN_ERR(find_base_on_source(&base_on_source, s_t,
12550 ctx, scratch_pool, scratch_pool));
12551 SVN_ERR(find_base_on_target(&base_on_target, s_t,
12552 ctx, scratch_pool, scratch_pool));
12554 /* Choose a base. */
12555 if (base_on_source->rev >= base_on_target->rev)
12557 *base_p = base_on_source;
12558 *is_reintegrate_like = FALSE;
12562 *base_p = base_on_target;
12563 *is_reintegrate_like = TRUE;
12566 return SVN_NO_ERROR;
12569 /** Find out what kind of automatic merge would be needed, when the target
12570 * is only known as a repository location rather than a WC.
12572 * Like find_automatic_merge() except that the target is
12573 * specified by @a target_path_or_url at @a target_revision, which must
12574 * refer to a repository location, instead of by a WC path argument.
12576 * Set *MERGE_P to a new structure with all fields filled in except the
12579 static svn_error_t *
12580 find_automatic_merge_no_wc(automatic_merge_t **merge_p,
12581 const char *source_path_or_url,
12582 const svn_opt_revision_t *source_revision,
12583 const char *target_path_or_url,
12584 const svn_opt_revision_t *target_revision,
12585 svn_client_ctx_t *ctx,
12586 apr_pool_t *result_pool,
12587 apr_pool_t *scratch_pool)
12589 source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t));
12590 svn_client__pathrev_t *target_loc;
12591 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
12594 SVN_ERR(svn_client__ra_session_from_path2(
12595 &s_t->source_ra_session, &s_t->source,
12596 source_path_or_url, NULL, source_revision, source_revision,
12597 ctx, result_pool));
12600 SVN_ERR(svn_client__ra_session_from_path2(
12601 &s_t->target_ra_session, &target_loc,
12602 target_path_or_url, NULL, target_revision, target_revision,
12603 ctx, result_pool));
12604 s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target));
12605 s_t->target->abspath = NULL; /* indicate the target is not a WC */
12606 s_t->target->loc = *target_loc;
12608 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t,
12609 ctx, result_pool, scratch_pool));
12611 merge->right = s_t->source;
12612 merge->target = &s_t->target->loc;
12613 merge->yca = s_t->yca;
12616 return SVN_NO_ERROR;
12619 /* Find the information needed to merge all unmerged changes from a source
12620 * branch into a target branch.
12622 * Set @a *merge_p to the information needed to merge all unmerged changes
12623 * (up to @a source_revision) from the source branch @a source_path_or_url
12624 * at @a source_revision into the target WC at @a target_abspath.
12626 * The flags @a allow_mixed_rev, @a allow_local_mods and
12627 * @a allow_switched_subtrees enable merging into a WC that is in any or all
12628 * of the states described by their names, but only if this function decides
12629 * that the merge will be in the same direction as the last automatic merge.
12630 * If, on the other hand, the last automatic merge was in the opposite
12631 * direction, then such states of the WC are not allowed regardless
12632 * of these flags. This function merely records these flags in the
12633 * @a *merge_p structure; do_automatic_merge_locked() checks the WC
12634 * state for compliance.
12636 * Allocate the @a *merge_p structure in @a result_pool.
12638 static svn_error_t *
12639 client_find_automatic_merge(automatic_merge_t **merge_p,
12640 const char *source_path_or_url,
12641 const svn_opt_revision_t *source_revision,
12642 const char *target_abspath,
12643 svn_boolean_t allow_mixed_rev,
12644 svn_boolean_t allow_local_mods,
12645 svn_boolean_t allow_switched_subtrees,
12646 svn_client_ctx_t *ctx,
12647 apr_pool_t *result_pool,
12648 apr_pool_t *scratch_pool)
12650 source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
12651 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
12653 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
12655 /* "Open" the target WC. Check the target WC for mixed-rev, local mods and
12656 * switched subtrees yet to faster exit and notify user before contacting
12657 * with server. After we find out what kind of merge is required, then if a
12658 * reintegrate-like merge is required we'll do the stricter checks, in
12659 * do_automatic_merge_locked(). */
12660 SVN_ERR(open_target_wc(&s_t->target, target_abspath,
12663 allow_switched_subtrees,
12664 ctx, result_pool, scratch_pool));
12666 if (!s_t->target->loc.url)
12667 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
12668 _("Can't perform automatic merge into '%s' "
12669 "because it is locally added and therefore "
12670 "not related to the merge source"),
12671 svn_dirent_local_style(target_abspath,
12674 /* Open RA sessions to the source and target trees. */
12675 SVN_ERR(svn_client_open_ra_session2(&s_t->target_ra_session,
12676 s_t->target->loc.url,
12677 s_t->target->abspath,
12678 ctx, result_pool, scratch_pool));
12679 SVN_ERR(svn_client__ra_session_from_path2(
12680 &s_t->source_ra_session, &s_t->source,
12681 source_path_or_url, NULL, source_revision, source_revision,
12682 ctx, result_pool));
12684 /* Check source is in same repos as target. */
12685 SVN_ERR(check_same_repos(s_t->source, source_path_or_url,
12686 &s_t->target->loc, target_abspath,
12687 TRUE /* strict_urls */, scratch_pool));
12689 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t,
12690 ctx, result_pool, scratch_pool));
12691 merge->yca = s_t->yca;
12692 merge->right = s_t->source;
12693 merge->target = &s_t->target->loc;
12694 merge->allow_mixed_rev = allow_mixed_rev;
12695 merge->allow_local_mods = allow_local_mods;
12696 merge->allow_switched_subtrees = allow_switched_subtrees;
12700 /* TODO: Close the source and target sessions here? */
12702 return SVN_NO_ERROR;
12705 /* Perform an automatic merge, given the information in MERGE which
12706 * must have come from calling client_find_automatic_merge().
12708 * Four locations are inputs: YCA, BASE, RIGHT, TARGET, as shown
12709 * depending on whether the base is on the source branch or the target
12710 * branch of this merge.
12712 * RIGHT (is_reintegrate_like)
12713 * o-----------o-------o---
12715 * -----o merge / \ this
12717 * o-------o---------------o
12722 * BASE RIGHT (! is_reintegrate_like)
12723 * o-------o-----------o---
12725 * -----o prev. \ \ this
12726 * YCA \ merge \ \ merge
12727 * o-----------o-----------o
12730 * ### TODO: The reintegrate-like code path does not yet
12731 * eliminate already-cherry-picked revisions from the source.
12733 static svn_error_t *
12734 do_automatic_merge_locked(conflict_report_t **conflict_report,
12735 const automatic_merge_t *merge,
12736 const char *target_abspath,
12738 svn_boolean_t diff_ignore_ancestry,
12739 svn_boolean_t force_delete,
12740 svn_boolean_t record_only,
12741 svn_boolean_t dry_run,
12742 const apr_array_header_t *merge_options,
12743 svn_client_ctx_t *ctx,
12744 apr_pool_t *result_pool,
12745 apr_pool_t *scratch_pool)
12747 merge_target_t *target;
12748 svn_boolean_t reintegrate_like = merge->is_reintegrate_like;
12749 svn_boolean_t use_sleep = FALSE;
12752 SVN_ERR(open_target_wc(&target, target_abspath,
12753 merge->allow_mixed_rev && ! reintegrate_like,
12754 merge->allow_local_mods && ! reintegrate_like,
12755 merge->allow_switched_subtrees && ! reintegrate_like,
12756 ctx, scratch_pool, scratch_pool));
12758 if (reintegrate_like)
12760 merge_source_t source;
12761 svn_ra_session_t *base_ra_session = NULL;
12762 svn_ra_session_t *right_ra_session = NULL;
12763 svn_ra_session_t *target_ra_session = NULL;
12766 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12767 _("The required merge is reintegrate-like, "
12768 "and the record-only option "
12769 "cannot be used with this kind of merge"));
12771 if (depth != svn_depth_unknown)
12772 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12773 _("The required merge is reintegrate-like, "
12774 "and the depth option "
12775 "cannot be used with this kind of merge"));
12778 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12779 _("The required merge is reintegrate-like, "
12780 "and the force_delete option "
12781 "cannot be used with this kind of merge"));
12783 SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url,
12784 target->abspath, ctx, scratch_pool));
12785 SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url,
12786 target->abspath, ctx, scratch_pool));
12787 SVN_ERR(ensure_ra_session_url(&target_ra_session, target->loc.url,
12788 target->abspath, ctx, scratch_pool));
12790 /* Check for and reject any abnormalities -- such as revisions that
12791 * have not yet been merged in the opposite direction -- that a
12792 * 'reintegrate' merge would have rejected. */
12794 merge_source_t *source2;
12796 SVN_ERR(find_reintegrate_merge(&source2, NULL,
12797 right_ra_session, merge->right,
12798 target_ra_session, target,
12799 ctx, scratch_pool, scratch_pool));
12802 source.loc1 = merge->base;
12803 source.loc2 = merge->right;
12804 source.ancestral = ! merge->is_reintegrate_like;
12806 err = merge_cousins_and_supplement_mergeinfo(conflict_report,
12811 &source, merge->yca,
12812 TRUE /* same_repos */,
12814 FALSE /*diff_ignore_ancestry*/,
12815 force_delete, record_only,
12819 result_pool, scratch_pool);
12821 else /* ! merge->is_reintegrate_like */
12823 /* Ignoring the base that we found, we pass the YCA instead and let
12824 do_merge() work out which subtrees need which revision ranges to
12825 be merged. This enables do_merge() to fill in revision-range
12826 gaps that are older than the base that we calculated (which is
12827 for the root path of the merge).
12829 An improvement would be to change find_automatic_merge() to
12830 find the base for each sutree, and then here use the oldest base
12831 among all subtrees. */
12832 apr_array_header_t *merge_sources;
12833 svn_ra_session_t *ra_session = NULL;
12835 /* Normalize our merge sources, do_merge() requires this. See the
12836 'MERGEINFO MERGE SOURCE NORMALIZATION' global comment. */
12837 SVN_ERR(ensure_ra_session_url(&ra_session, merge->right->url,
12838 target->abspath, ctx, scratch_pool));
12839 SVN_ERR(normalize_merge_sources_internal(
12840 &merge_sources, merge->right,
12841 svn_rangelist__initialize(merge->yca->rev, merge->right->rev, TRUE,
12843 ra_session, ctx, scratch_pool, scratch_pool));
12845 err = do_merge(NULL, NULL, conflict_report, &use_sleep,
12846 merge_sources, target, ra_session,
12847 TRUE /*related*/, TRUE /*same_repos*/,
12848 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
12849 force_delete, dry_run,
12850 record_only, NULL, FALSE, FALSE, depth, merge_options,
12851 ctx, result_pool, scratch_pool);
12855 svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
12859 return SVN_NO_ERROR;
12863 svn_client_get_merging_summary(svn_boolean_t *needs_reintegration,
12864 const char **yca_url, svn_revnum_t *yca_rev,
12865 const char **base_url, svn_revnum_t *base_rev,
12866 const char **right_url, svn_revnum_t *right_rev,
12867 const char **target_url, svn_revnum_t *target_rev,
12868 const char **repos_root_url,
12869 const char *source_path_or_url,
12870 const svn_opt_revision_t *source_revision,
12871 const char *target_path_or_url,
12872 const svn_opt_revision_t *target_revision,
12873 svn_client_ctx_t *ctx,
12874 apr_pool_t *result_pool,
12875 apr_pool_t *scratch_pool)
12877 svn_boolean_t target_is_wc;
12878 automatic_merge_t *merge;
12880 target_is_wc = (! svn_path_is_url(target_path_or_url))
12881 && (target_revision->kind == svn_opt_revision_unspecified
12882 || target_revision->kind == svn_opt_revision_working
12883 || target_revision->kind == svn_opt_revision_base);
12886 const char *target_abspath;
12888 SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_path_or_url,
12890 SVN_ERR(client_find_automatic_merge(
12892 source_path_or_url, source_revision,
12894 TRUE, TRUE, TRUE, /* allow_* */
12895 ctx, scratch_pool, scratch_pool));
12898 SVN_ERR(find_automatic_merge_no_wc(
12900 source_path_or_url, source_revision,
12901 target_path_or_url, target_revision,
12902 ctx, scratch_pool, scratch_pool));
12904 if (needs_reintegration)
12905 *needs_reintegration = merge->is_reintegrate_like;
12907 *yca_url = apr_pstrdup(result_pool, merge->yca->url);
12909 *yca_rev = merge->yca->rev;
12911 *base_url = apr_pstrdup(result_pool, merge->base->url);
12913 *base_rev = merge->base->rev;
12915 *right_url = apr_pstrdup(result_pool, merge->right->url);
12917 *right_rev = merge->right->rev;
12919 *target_url = apr_pstrdup(result_pool, merge->target->url);
12921 *target_rev = merge->target->rev;
12922 if (repos_root_url)
12923 *repos_root_url = apr_pstrdup(result_pool, merge->yca->repos_root_url);
12925 return SVN_NO_ERROR;