Index: subversion/include/svn_client.h =================================================================== --- subversion/include/svn_client.h (revision 39658) +++ subversion/include/svn_client.h (working copy) @@ -2708,6 +2708,9 @@ * recorded in the working copy (and must be subsequently committed * back to the repository). * + * If @a mergeinfo_diff is TRUE, the merge is performed, but is limited to + * only mergeinfo property changes. + * * If @a dry_run is TRUE, the merge is carried out, and full notification * feedback is provided, but the working copy is not modified. * @@ -2717,6 +2720,30 @@ * @since New in 1.5. */ svn_error_t * +svn_client_merge4(const char *source1, + const svn_opt_revision_t *revision1, + const char *source2, + const svn_opt_revision_t *revision2, + const char *target_wcpath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t force, + svn_boolean_t record_only, + svn_boolean_t mergeinfo_diff, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + +/** + * Similar to svn_client_merge4(), but with @a mergeinfo_diff set to + * @c FALSE. + * + * @deprecated Provided for backward compatibility with the 1.6 API. + * + * @since New in 1.5. + */ +svn_error_t * svn_client_merge3(const char *source1, const svn_opt_revision_t *revision1, const char *source2, @@ -2785,10 +2812,10 @@ * pristine, unswitched working copy -- in other words, it must * reflect a single revision tree, the "target". The mergeinfo on @a * source must reflect that all of the target has been merged into it. - * Then this behaves like a merge with svn_client_merge3() from the + * Then this behaves like a merge with svn_client_merge4() from the * target's URL to the source. * - * All other options are handled identically to svn_client_merge3(). + * All other options are handled identically to svn_client_merge4(). * The depth of the merge is always @c svn_depth_infinity. * * @since New in 1.5. @@ -2815,8 +2842,31 @@ * list of provided ranges has an `unspecified' or unrecognized * `kind', return @c SVN_ERR_CLIENT_BAD_REVISION. * - * All other options are handled identically to svn_client_merge3(). + * All other options are handled identically to svn_client_merge4(). * + * @since New in 1.7. + */ +svn_error_t * +svn_client_merge_peg4(const char *source, + const apr_array_header_t *ranges_to_merge, + const svn_opt_revision_t *peg_revision, + const char *target_wcpath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t force, + svn_boolean_t record_only, + svn_boolean_t mergeinfo_diff, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + +/** + * Similar to svn_client_merge_peg4(), but with @a mergeinfo_diff set + * to @c FALSE. + * + * @deprecated Provided for backwards compatibility with the 1.6 API. + * * @since New in 1.5. */ svn_error_t * Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 39658) +++ subversion/include/svn_wc.h (working copy) @@ -2014,7 +2014,7 @@ apr_pool_t *pool); -/** A callback used in svn_client_merge3(), svn_client_update3(), and +/** A callback used in svn_client_merge4(), svn_client_update3(), and * svn_client_switch2() for resolving conflicts during the application * of a tree delta to a working copy. * Index: subversion/libsvn_client/deprecated.c =================================================================== --- subversion/libsvn_client/deprecated.c (revision 39658) +++ subversion/libsvn_client/deprecated.c (working copy) @@ -1108,6 +1108,27 @@ /*** From merge.c ***/ svn_error_t * +svn_client_merge3(const char *source1, + const svn_opt_revision_t *revision1, + const char *source2, + const svn_opt_revision_t *revision2, + const char *target_wcpath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t force, + svn_boolean_t record_only, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + return svn_client_merge4(source1, revision1, source2, revision2, + target_wcpath, depth, ignore_ancestry, force, + record_only, FALSE, dry_run, + merge_options, ctx, pool); +} + +svn_error_t * svn_client_merge2(const char *source1, const svn_opt_revision_t *revision1, const char *source2, @@ -1149,6 +1170,26 @@ svn_error_t * +svn_client_merge_peg3(const char *source, + const apr_array_header_t *ranges_to_merge, + const svn_opt_revision_t *peg_revision, + const char *target_wcpath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t force, + svn_boolean_t record_only, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + return svn_client_merge_peg4(source, ranges_to_merge, peg_revision, + target_wcpath, depth, ignore_ancestry, force, + record_only, FALSE, dry_run, + merge_options, ctx, pool); +} + +svn_error_t * svn_client_merge_peg2(const char *source, const svn_opt_revision_t *revision1, const svn_opt_revision_t *revision2, Index: subversion/libsvn_client/merge.c =================================================================== --- subversion/libsvn_client/merge.c (revision 39658) +++ subversion/libsvn_client/merge.c (working copy) @@ -227,6 +227,8 @@ svn_boolean_t force; svn_boolean_t dry_run; svn_boolean_t record_only; /* Whether to only record mergeinfo. */ + svn_boolean_t mergeinfo_diff; /* Whether to apply only mergeinfo + diffs. */ svn_boolean_t sources_ancestral; /* Whether the left-side merge source is an ancestor of the right-side, or vice-versa (history-wise). */ @@ -1095,6 +1097,27 @@ SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, subpool)); + /* If we are only applying mergeinfo changes then we need to do + additional filtering of PROPS so it contains only mergeinfo changes. */ + if (merge_b->mergeinfo_diff && props->nelts) + { + apr_array_header_t *mergeinfo_props = + apr_array_make(subpool, 1, sizeof(svn_prop_t)); + int i; + + for (i = 0; i < props->nelts; i++) + { + svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); + + if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0) + { + APR_ARRAY_PUSH(mergeinfo_props, svn_prop_t) = *prop; + break; + } + } + props = mergeinfo_props; + } + /* We only want to merge "regular" version properties: by definition, 'svn merge' shouldn't touch any data within .svn/ */ if (props->nelts) @@ -1378,6 +1401,13 @@ if (prop_state) *prop_state = svn_wc_notify_state_unchanged; + /* Easy out: We are only applying mergeinfo changes to existing paths. */ + if (merge_b->mergeinfo_diff) + { + svn_pool_destroy(subpool); + return SVN_NO_ERROR; + } + if (older) { svn_boolean_t has_local_mods; @@ -1500,6 +1530,13 @@ apr_hash_t *new_props; const char *mine_abspath; + /* Easy out: We are only applying mergeinfo changes to existing paths. */ + if (merge_b->mergeinfo_diff) + { + svn_pool_destroy(subpool); + return SVN_NO_ERROR; + } + SVN_ERR(svn_dirent_get_absolute(&mine_abspath, mine, subpool)); /* In most cases, we just leave prop_state as unknown, and let the @@ -1797,6 +1834,13 @@ svn_node_kind_t kind; const char *mine_abspath; + /* Easy out: We are only applying mergeinfo changes to existing paths. */ + if (merge_b->mergeinfo_diff) + { + svn_pool_destroy(subpool); + return SVN_NO_ERROR; + } + SVN_ERR(svn_dirent_get_absolute(&mine_abspath, mine, subpool)); if (*tree_conflicted) @@ -1927,6 +1971,13 @@ const char *parent_abspath; const char *local_abspath; + /* Easy out: We are only applying mergeinfo changes to existing paths. */ + if (merge_b->mergeinfo_diff) + { + svn_pool_destroy(subpool); + return SVN_NO_ERROR; + } + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool)); SVN_ERR(svn_dirent_get_absolute(&parent_abspath, svn_wc_adm_access_path(adm_access), @@ -2117,6 +2168,13 @@ svn_error_t *err; const char *local_abspath; + /* Easy out: We are only applying mergeinfo changes to existing paths. */ + if (merge_b->mergeinfo_diff) + { + svn_pool_destroy(subpool); + return SVN_NO_ERROR; + } + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool)); if (tree_conflicted) @@ -2442,6 +2500,14 @@ notification_receiver_baton_t *notify_b = baton; svn_boolean_t is_operative_notification = FALSE; + /* Skip notifications if this is a --mergeinfo-only merge that is adding + or deleting NOTIFY->PATH, allow only mergeinfo changes to be notified. + We will already have skipped the actual addition or deletion, but will + still get a notification callback for it.*/ + if (notify_b->merge_b->mergeinfo_diff + && notify->action != svn_wc_notify_update_update) + return; + /* Is the notification the result of a real operative merge? */ if (IS_OPERATIVE_NOTIFICATION(notify)) { @@ -7407,7 +7473,7 @@ requirements around the values of URL1, REVISION1, URL2, and REVISION2 in this case). - Handle DEPTH as documented for svn_client_merge3(). + Handle DEPTH as documented for svn_client_merge4(). NOTE: This is a wrapper around drive_merge_report_editor() which handles the complexities inherent to situations where a given @@ -7779,8 +7845,9 @@ repository as the one from which the target working copy has been checked out. - FORCE, DRY_RUN, RECORD_ONLY, IGNORE_ANCESTRY, DEPTH, MERGE_OPTIONS, - and CTX are as described in the docstring for svn_client_merge_peg3(). + FORCE, DRY_RUN, RECORD_ONLY, MERGEINFO_DIFF, IGNORE_ANCESTRY, DEPTH, + MERGE_OPTIONS, and CTX are as described in the docstring for + svn_client_merge_peg4(). REINTEGRATE_MERGE is TRUE if this is a reintegrate merge. @@ -7799,6 +7866,7 @@ svn_boolean_t force, svn_boolean_t dry_run, svn_boolean_t record_only, + svn_boolean_t mergeinfo_diff, svn_boolean_t reintegrate_merge, svn_depth_t depth, const apr_array_header_t *merge_options, @@ -7853,6 +7921,7 @@ merge_cmd_baton.force = force; merge_cmd_baton.dry_run = dry_run; merge_cmd_baton.record_only = record_only; + merge_cmd_baton.mergeinfo_diff = mergeinfo_diff; merge_cmd_baton.ignore_ancestry = ignore_ancestry; merge_cmd_baton.same_repos = same_repos; merge_cmd_baton.mergeinfo_capable = FALSE; @@ -8072,7 +8141,7 @@ APR_ARRAY_PUSH(faux_sources, merge_source_t *) = faux_source; SVN_ERR(do_merge(faux_sources, target_wcpath, entry, adm_access, FALSE, TRUE, same_repos, - ignore_ancestry, force, dry_run, FALSE, TRUE, + ignore_ancestry, force, dry_run, FALSE, FALSE, TRUE, depth, merge_options, use_sleep, ctx, pool)); } else if (! same_repos) @@ -8091,11 +8160,11 @@ { SVN_ERR(do_merge(add_sources, target_wcpath, entry, adm_access, TRUE, TRUE, same_repos, - ignore_ancestry, force, dry_run, TRUE, TRUE, + ignore_ancestry, force, dry_run, TRUE, FALSE, TRUE, depth, merge_options, use_sleep, ctx, pool)); SVN_ERR(do_merge(remove_sources, target_wcpath, entry, adm_access, TRUE, TRUE, same_repos, - ignore_ancestry, force, dry_run, TRUE, TRUE, + ignore_ancestry, force, dry_run, TRUE, FALSE, TRUE, depth, merge_options, use_sleep, ctx, pool)); } @@ -8107,7 +8176,7 @@ /*** Public APIs ***/ svn_error_t * -svn_client_merge3(const char *source1, +svn_client_merge4(const char *source1, const svn_opt_revision_t *revision1, const char *source2, const svn_opt_revision_t *revision2, @@ -8116,10 +8185,11 @@ svn_boolean_t ignore_ancestry, svn_boolean_t force, svn_boolean_t record_only, + svn_boolean_t mergeinfo_diff, svn_boolean_t dry_run, const apr_array_header_t *merge_options, svn_client_ctx_t *ctx, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { svn_wc_adm_access_t *adm_access; const svn_wc_entry_t *entry; @@ -8141,7 +8211,8 @@ const char *source_repos_uuid1, *source_repos_uuid2; const char *target_abspath; - SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, pool)); + SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, + scratch_pool)); /* Sanity check our input -- we require specified revisions. */ if ((revision1->kind == svn_opt_revision_unspecified) @@ -8151,7 +8222,7 @@ /* ### FIXME: This function really ought to do a history check on the left and right sides of the merge source, and -- if one is an - ancestor of the other -- just call svn_client_merge_peg3() with + ancestor of the other -- just call svn_client_merge_peg4() with the appropriate args. */ /* If source1 or source2 are paths, we need to get the underlying @@ -8161,35 +8232,38 @@ able to figure out some kind of revision specifications, but in that case it won't matter, because those ways of specifying a revision are meaningless for a url. */ - SVN_ERR(svn_client_url_from_path2(&URL1, source1, ctx, pool, pool)); + SVN_ERR(svn_client_url_from_path2(&URL1, source1, ctx, scratch_pool, + scratch_pool)); if (! URL1) return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, _("'%s' has no URL"), - svn_dirent_local_style(source1, pool)); + svn_dirent_local_style(source1, scratch_pool)); - SVN_ERR(svn_client_url_from_path2(&URL2, source2, ctx, pool, pool)); + SVN_ERR(svn_client_url_from_path2(&URL2, source2, ctx, scratch_pool, + scratch_pool)); if (! URL2) return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, _("'%s' has no URL"), - svn_dirent_local_style(source2, pool)); + svn_dirent_local_style(source2, scratch_pool)); /* Open an admistrative session with the working copy. */ SVN_ERR(svn_wc__adm_probe_in_context(&adm_access, ctx->wc_ctx, target_wcpath, !dry_run, -1, ctx->cancel_func, - ctx->cancel_baton, pool)); + ctx->cancel_baton, scratch_pool)); /* Fetch the target's entry. */ SVN_ERR(svn_wc__get_entry_versioned(&entry, ctx->wc_ctx, target_abspath, svn_node_unknown, FALSE, FALSE, - pool, pool)); + scratch_pool, scratch_pool)); /* Determine the working copy target's repository root URL. */ working_rev.kind = svn_opt_revision_working; SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath, - &working_rev, ctx, pool, pool)); + &working_rev, ctx, scratch_pool, + scratch_pool)); /* Open some RA sessions to our merge source sides. */ - sesspool = svn_pool_create(pool); + sesspool = svn_pool_create(scratch_pool); SVN_ERR(svn_client__open_ra_session_internal(&ra_session1, URL1, NULL, NULL, FALSE, TRUE, ctx, sesspool)); @@ -8205,8 +8279,8 @@ NULL, ra_session2, revision2, sesspool)); - SVN_ERR(svn_ra_get_uuid2(ra_session1, &source_repos_uuid1, pool)); - SVN_ERR(svn_ra_get_uuid2(ra_session2, &source_repos_uuid2, pool)); + SVN_ERR(svn_ra_get_uuid2(ra_session1, &source_repos_uuid1, scratch_pool)); + SVN_ERR(svn_ra_get_uuid2(ra_session2, &source_repos_uuid2, scratch_pool)); /* We can't do a diff between different repositories. */ if (strcmp(source_repos_uuid1, source_repos_uuid2) != 0) @@ -8223,7 +8297,7 @@ const char *wc_repos_uuid; SVN_ERR(svn_client_uuid_from_path2(&wc_repos_uuid, target_abspath, - ctx, pool, pool)); + ctx, scratch_pool, scratch_pool)); same_repos = (strcmp(wc_repos_uuid, source_repos_uuid1) == 0); } else @@ -8234,7 +8308,7 @@ SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev, URL1, rev1, URL2, rev2, - ctx, pool)); + ctx, scratch_pool)); /* Check for a youngest common ancestor. If we have one, we'll be doing merge tracking. @@ -8264,41 +8338,46 @@ related = TRUE; /* Make YC_PATH into a full URL. */ - yc_path = svn_path_url_add_component2(source_repos_root, yc_path, pool); + yc_path = svn_path_url_add_component2(source_repos_root, yc_path, + scratch_pool); /* If the common ancestor matches the right side of our merge, then we only need to reverse-merge the left side. */ if ((strcmp(yc_path, URL2) == 0) && (yc_rev == rev2)) { ancestral = TRUE; - range = apr_pcalloc(pool, sizeof(*range)); + range = apr_pcalloc(scratch_pool, sizeof(*range)); range->start.kind = svn_opt_revision_number; range->start.value.number = rev1; range->end.kind = svn_opt_revision_number; range->end.value.number = yc_rev; - ranges = apr_array_make(pool, 2, sizeof(svn_opt_revision_range_t *)); + ranges = apr_array_make(scratch_pool, 2, + sizeof(svn_opt_revision_range_t *)); APR_ARRAY_PUSH(ranges, svn_opt_revision_range_t *) = range; peg_revision.value.number = rev1; SVN_ERR(normalize_merge_sources(&merge_sources, URL1, URL1, source_repos_root, &peg_revision, - ranges, ra_session1, ctx, pool)); + ranges, ra_session1, ctx, + scratch_pool)); } /* If the common ancestor matches the left side of our merge, then we only need to merge the right side. */ else if ((strcmp(yc_path, URL1) == 0) && (yc_rev == rev1)) { ancestral = TRUE; - range = apr_pcalloc(pool, sizeof(*range)); + range = apr_pcalloc(scratch_pool, sizeof(*range)); range->start.kind = svn_opt_revision_number; range->start.value.number = yc_rev; range->end.kind = svn_opt_revision_number; range->end.value.number = rev2; - ranges = apr_array_make(pool, 2, sizeof(svn_opt_revision_range_t *)); + ranges = apr_array_make(scratch_pool, 2, + sizeof(svn_opt_revision_range_t *)); APR_ARRAY_PUSH(ranges, svn_opt_revision_range_t *) = range; peg_revision.value.number = rev2; SVN_ERR(normalize_merge_sources(&merge_sources, URL2, URL2, source_repos_root, &peg_revision, - ranges, ra_session2, ctx, pool)); + ranges, ra_session2, ctx, + scratch_pool)); } /* And otherwise, we need to do both: reverse merge the left side, and merge the right. */ @@ -8317,11 +8396,11 @@ record_only, dry_run, merge_options, &use_sleep, ctx, - pool); + scratch_pool); if (err) { if (use_sleep) - svn_io_sleep_for_timestamps(target_wcpath, pool); + svn_io_sleep_for_timestamps(target_wcpath, scratch_pool); return svn_error_return(err); } @@ -8331,14 +8410,15 @@ the merge_cousins_and_supplement_mergeinfo() routine). */ svn_pool_destroy(sesspool); - return svn_wc_adm_close2(adm_access, pool); + return svn_wc_adm_close2(adm_access, scratch_pool); } } else { /* Build a single-item merge_source_t array. */ - merge_sources = apr_array_make(pool, 1, sizeof(merge_source_t *)); - merge_source = apr_pcalloc(pool, sizeof(*merge_source)); + merge_sources = apr_array_make(scratch_pool, 1, + sizeof(merge_source_t *)); + merge_source = apr_pcalloc(scratch_pool, sizeof(*merge_source)); merge_source->url1 = URL1; merge_source->url2 = URL2; merge_source->rev1 = rev1; @@ -8352,16 +8432,16 @@ err = do_merge(merge_sources, target_wcpath, entry, adm_access, ancestral, related, same_repos, ignore_ancestry, force, dry_run, - record_only, FALSE, depth, merge_options, - &use_sleep, ctx, pool); + record_only, mergeinfo_diff, FALSE, depth, merge_options, + &use_sleep, ctx, scratch_pool); if (use_sleep) - svn_io_sleep_for_timestamps(target_wcpath, pool); + svn_io_sleep_for_timestamps(target_wcpath, scratch_pool); if (err) return svn_error_return(err); - return svn_wc_adm_close2(adm_access, pool); + return svn_wc_adm_close2(adm_access, scratch_pool); } @@ -9215,7 +9295,7 @@ svn_error_t * -svn_client_merge_peg3(const char *source, +svn_client_merge_peg4(const char *source, const apr_array_header_t *ranges_to_merge, const svn_opt_revision_t *peg_revision, const char *target_wcpath, @@ -9223,10 +9303,11 @@ svn_boolean_t ignore_ancestry, svn_boolean_t force, svn_boolean_t record_only, + svn_boolean_t mergeinfo_diff, svn_boolean_t dry_run, const apr_array_header_t *merge_options, svn_client_ctx_t *ctx, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { svn_wc_adm_access_t *adm_access; const svn_wc_entry_t *entry; @@ -9245,40 +9326,45 @@ if (ranges_to_merge->nelts == 0) return SVN_NO_ERROR; - SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, pool)); + SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, + scratch_pool)); /* Open an admistrative session with the working copy. */ SVN_ERR(svn_wc__adm_probe_in_context(&adm_access, ctx->wc_ctx, target_wcpath, (! dry_run), -1, ctx->cancel_func, - ctx->cancel_baton, pool)); + ctx->cancel_baton, scratch_pool)); /* Fetch the target's entry. */ SVN_ERR(svn_wc__get_entry_versioned(&entry, ctx->wc_ctx, target_abspath, svn_node_unknown, FALSE, FALSE, - pool, pool)); + scratch_pool, scratch_pool)); /* Make sure we're dealing with a real URL. */ - SVN_ERR(svn_client_url_from_path2(&URL, source, ctx, pool, pool)); + SVN_ERR(svn_client_url_from_path2(&URL, source, ctx, scratch_pool, + scratch_pool)); if (! URL) return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, _("'%s' has no URL"), - svn_dirent_local_style(source, pool)); + svn_dirent_local_style(source, scratch_pool)); /* Determine the working copy target's repository root URL. */ working_rev.kind = svn_opt_revision_working; SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath, - &working_rev, ctx, pool, pool)); + &working_rev, ctx, scratch_pool, + scratch_pool)); /* Open an RA session to our source URL, and determine its root URL. */ - sesspool = svn_pool_create(pool); + sesspool = svn_pool_create(scratch_pool); SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL, NULL, NULL, FALSE, TRUE, ctx, sesspool)); - SVN_ERR(svn_ra_get_repos_root2(ra_session, &source_repos_root, pool)); + SVN_ERR(svn_ra_get_repos_root2(ra_session, &source_repos_root, + scratch_pool)); /* Normalize our merge sources. */ SVN_ERR(normalize_merge_sources(&merge_sources, source, URL, source_repos_root, peg_revision, - ranges_to_merge, ra_session, ctx, pool)); + ranges_to_merge, ra_session, ctx, + scratch_pool)); /* Check for same_repos. */ if (strcmp(wc_repos_root, source_repos_root) != 0) @@ -9286,9 +9372,9 @@ const char *source_repos_uuid; const char *wc_repos_uuid; - SVN_ERR(svn_ra_get_uuid2(ra_session, &source_repos_uuid, pool)); + SVN_ERR(svn_ra_get_uuid2(ra_session, &source_repos_uuid, scratch_pool)); SVN_ERR(svn_client_uuid_from_path2(&wc_repos_uuid, target_abspath, - ctx, pool, pool)); + ctx, scratch_pool, scratch_pool)); same_repos = (strcmp(wc_repos_uuid, source_repos_uuid) == 0); } else @@ -9301,15 +9387,15 @@ sources are both ancestral and related.) */ err = do_merge(merge_sources, target_wcpath, entry, adm_access, TRUE, TRUE, same_repos, ignore_ancestry, force, dry_run, - record_only, FALSE, depth, merge_options, - &use_sleep, ctx, pool); + record_only, mergeinfo_diff, FALSE, depth, merge_options, + &use_sleep, ctx, scratch_pool); if (use_sleep) - svn_io_sleep_for_timestamps(target_wcpath, pool); + svn_io_sleep_for_timestamps(target_wcpath, scratch_pool); if (err) return svn_error_return(err); /* Shutdown the administrative session. */ - return svn_wc_adm_close2(adm_access, pool); + return svn_wc_adm_close2(adm_access, scratch_pool); } Index: subversion/svn/cl.h =================================================================== --- subversion/svn/cl.h (revision 39658) +++ subversion/svn/cl.h (working copy) @@ -194,6 +194,7 @@ const char *merge_cmd; /* the external merge command to use */ const char *editor_cmd; /* the external editor command to use */ svn_boolean_t record_only; /* whether to record mergeinfo */ + svn_boolean_t mergeinfo_diff; /* whether to apply only mergeinfo diffs */ const char *old_target; /* diff target */ const char *new_target; /* diff target */ svn_boolean_t relocate; /* rewrite urls (svn switch) */ Index: subversion/svn/main.c =================================================================== --- subversion/svn/main.c (revision 39658) +++ subversion/svn/main.c (working copy) @@ -94,6 +94,7 @@ opt_notice_ancestry, opt_old_cmd, opt_record_only, + opt_mergeinfo_diff, opt_relocate, opt_remove, opt_revprop, @@ -229,6 +230,8 @@ {"editor-cmd", opt_editor_cmd, 1, N_("use ARG as external editor")}, {"record-only", opt_record_only, 0, N_("mark revisions as merged (use with -r)")}, + {"mergeinfo-diff", opt_mergeinfo_diff, 0, + N_("applies only mergeinfo differences")}, {"old", opt_old_cmd, 1, N_("use ARG as the older target")}, {"new", opt_new_cmd, 1, N_("use ARG as the newer target")}, {"revprop", opt_revprop, 0, @@ -665,7 +668,8 @@ " The --ignore-ancestry option overrides this, forcing Subversion to\n" " regard the sources as unrelated and not to track the merge.\n"), {'r', 'c', 'N', opt_depth, 'q', opt_force, opt_dry_run, opt_merge_cmd, - opt_record_only, 'x', opt_ignore_ancestry, opt_accept, opt_reintegrate} }, + opt_record_only, opt_mergeinfo_diff, 'x', opt_ignore_ancestry, + opt_accept, opt_reintegrate} }, { "mergeinfo", svn_cl__mergeinfo, {0}, N_ ("Display merge-related information.\n" @@ -1510,6 +1514,9 @@ case opt_record_only: opt_state.record_only = TRUE; break; + case opt_mergeinfo_diff: + opt_state.mergeinfo_diff = TRUE; + break; case opt_editor_cmd: opt_state.editor_cmd = apr_pstrdup(pool, opt_arg); break; Index: subversion/svn/merge-cmd.c =================================================================== --- subversion/svn/merge-cmd.c (revision 39658) +++ subversion/svn/merge-cmd.c (working copy) @@ -310,7 +310,7 @@ options, ctx, pool); } else - err = svn_client_merge_peg3(sourcepath1, + err = svn_client_merge_peg4(sourcepath1, ranges_to_merge, &peg_revision1, targetpath, @@ -318,6 +318,7 @@ opt_state->ignore_ancestry, opt_state->force, opt_state->record_only, + opt_state->mergeinfo_diff, opt_state->dry_run, options, ctx, @@ -325,7 +326,7 @@ } else { - err = svn_client_merge3(sourcepath1, + err = svn_client_merge4(sourcepath1, &first_range_start, sourcepath2, &first_range_end, @@ -334,6 +335,7 @@ opt_state->ignore_ancestry, opt_state->force, opt_state->record_only, + opt_state->mergeinfo_diff, opt_state->dry_run, options, ctx,