On Fri, Dec 16, 2011 at 3:05 PM, <julianfoad_at_apache.org> wrote:
> Author: julianfoad
> Date: Fri Dec 16 21:05:07 2011
> New Revision: 1215273
>
> URL: http://svn.apache.org/viewvc?rev=1215273&view=rev
> Log:
> Reject attempts to merge between unrelated branches, or where the source and
> target are different objects within their respective branches. These checks
> are applied in 'svn merge', only on 'reintegrate' and simple 'sync' merges
> where no revision range is specified. They are also applied in the
> 'svn mergeinfo' command.
We should probably make sure this change ends up in the 1.8 docs, as
it potentially removes merging scenarios which folks may be using.
-Hyrum
>
> * subversion/include/private/svn_client_private.h,
> subversion/libsvn_client/ra.c
> (svn_client__youngest_common_ancestor): New function.
>
> * subversion/libsvn_client/client.h
> (svn_client__get_youngest_common_ancestor): Cross-reference to
> svn_client__youngest_common_ancestor().
>
> * subversion/svn/cl.h,
> subversion/svn/util.c
> (svn_cl__check_related_source_and_target, path_for_display): New functions.
>
> * subversion/svn/merge-cmd.c
> (svn_cl__merge): Check relatedness of source and target for 'reintegrate'
> and simple 'sync' merges.
>
> * subversion/svn/mergeinfo-cmd.c
> (svn_cl__mergeinfo): Check relatedness of source and target.
>
> Modified:
> subversion/trunk/subversion/include/private/svn_client_private.h
> subversion/trunk/subversion/libsvn_client/client.h
> subversion/trunk/subversion/libsvn_client/ra.c
> subversion/trunk/subversion/svn/cl.h
> subversion/trunk/subversion/svn/merge-cmd.c
> subversion/trunk/subversion/svn/mergeinfo-cmd.c
> subversion/trunk/subversion/svn/util.c
>
> Modified: subversion/trunk/subversion/include/private/svn_client_private.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/include/private/svn_client_private.h (original)
> +++ subversion/trunk/subversion/include/private/svn_client_private.h Fri Dec 16 21:05:07 2011
> @@ -59,6 +59,29 @@ svn_client__create_status(svn_client_sta
> apr_pool_t *result_pool,
> apr_pool_t *scratch_pool);
>
> +/* Set *ANCESTOR_URL and *ANCESTOR_REVISION to the URL and revision,
> + * respectively, of the youngest common ancestor of the two locations
> + * PATH_OR_URL1_at_REV1 and PATH_OR_URL2_at_REV2. Set *ANCESTOR_RELPATH to
> + * NULL and *ANCESTOR_REVISION to SVN_INVALID_REVNUM if they have no
> + * common ancestor. This function assumes that PATH_OR_URL1_at_REV1 and
> + * PATH_OR_URL2_at_REV2 both refer to the same repository.
> + *
> + * Use the authentication baton cached in CTX to authenticate against
> + * the repository.
> + *
> + * See also svn_client__get_youngest_common_ancestor().
> + */
> +svn_error_t *
> +svn_client__youngest_common_ancestor(const char **ancestor_url,
> + svn_revnum_t *ancestor_rev,
> + const char *path_or_url1,
> + const svn_opt_revision_t *revision1,
> + const char *path_or_url2,
> + const svn_opt_revision_t *revision2,
> + svn_client_ctx_t *ctx,
> + apr_pool_t *result_pool,
> + apr_pool_t *scratch_pool);
> +
> #ifdef __cplusplus
> }
> #endif /* __cplusplus */
>
> Modified: subversion/trunk/subversion/libsvn_client/client.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_client/client.h (original)
> +++ subversion/trunk/subversion/libsvn_client/client.h Fri Dec 16 21:05:07 2011
> @@ -199,6 +199,8 @@ svn_client__repos_location_segments(apr_
>
> Use the authentication baton cached in CTX to authenticate against
> the repository. Use POOL for all allocations.
> +
> + See also svn_client__youngest_common_ancestor().
> */
> svn_error_t *
> svn_client__get_youngest_common_ancestor(const char **ancestor_relpath,
>
> Modified: subversion/trunk/subversion/libsvn_client/ra.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/ra.c?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_client/ra.c (original)
> +++ subversion/trunk/subversion/libsvn_client/ra.c Fri Dec 16 21:05:07 2011
> @@ -897,3 +897,36 @@ svn_client__get_youngest_common_ancestor
> *ancestor_revision = yc_revision;
> return SVN_NO_ERROR;
> }
> +
> +svn_error_t *
> +svn_client__youngest_common_ancestor(const char **ancestor_url,
> + svn_revnum_t *ancestor_rev,
> + const char *path_or_url1,
> + const svn_opt_revision_t *revision1,
> + const char *path_or_url2,
> + const svn_opt_revision_t *revision2,
> + svn_client_ctx_t *ctx,
> + apr_pool_t *result_pool,
> + apr_pool_t *scratch_pool)
> +{
> + apr_pool_t *sesspool = svn_pool_create(scratch_pool);
> + svn_ra_session_t *session;
> + const char *url1, *url2;
> + svn_revnum_t rev1, rev2;
> +
> + /* Resolve the two locations */
> + SVN_ERR(svn_client__ra_session_from_path(&session, &rev1, &url1,
> + path_or_url1, NULL,
> + revision1, revision1,
> + ctx, sesspool));
> + SVN_ERR(resolve_rev_and_url(&rev2, &url2, session,
> + path_or_url2, revision2, revision2,
> + ctx, scratch_pool));
> +
> + SVN_ERR(svn_client__get_youngest_common_ancestor(
> + NULL, ancestor_url, ancestor_rev,
> + url1, rev1, url2, rev2, ctx, result_pool));
> +
> + svn_pool_destroy(sesspool);
> + return SVN_NO_ERROR;
> +}
>
> Modified: subversion/trunk/subversion/svn/cl.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/svn/cl.h (original)
> +++ subversion/trunk/subversion/svn/cl.h Fri Dec 16 21:05:07 2011
> @@ -822,6 +822,23 @@ svn_cl__local_style_skip_ancestor(const
> const char *path,
> apr_pool_t *pool);
>
> +/* Check that PATH_OR_URL1_at_REVISION1 is related to PATH_OR_URL2_at_REVISION2.
> + * Raise an error if not.
> + *
> + * ### Ideally we would also check that they are on different lines of
> + * history. That is easy in common cases, but to give a correct answer in
> + * general we need to know the operative revision(s) as well. For example,
> + * when one location is the branch point from which the other branch was
> + * copied.
> + */
> +svn_error_t *
> +svn_cl__check_related_source_and_target(const char *path_or_url1,
> + const svn_opt_revision_t *revision1,
> + const char *path_or_url2,
> + const svn_opt_revision_t *revision2,
> + svn_client_ctx_t *ctx,
> + apr_pool_t *pool);
> +
> #ifdef __cplusplus
> }
> #endif /* __cplusplus */
>
> Modified: subversion/trunk/subversion/svn/merge-cmd.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/merge-cmd.c?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/svn/merge-cmd.c (original)
> +++ subversion/trunk/subversion/svn/merge-cmd.c Fri Dec 16 21:05:07 2011
> @@ -112,6 +112,7 @@ svn_cl__merge(apr_getopt_t *os,
> svn_opt_revision_t first_range_start, first_range_end, peg_revision1,
> peg_revision2;
> apr_array_header_t *options, *ranges_to_merge = opt_state->revision_ranges;
> + svn_opt_revision_t unspecified = { svn_opt_revision_unspecified, { 0 } };
>
> /* Merge doesn't support specifying a revision or revision range
> when using --reintegrate. */
> @@ -347,6 +348,11 @@ svn_cl__merge(apr_getopt_t *os,
>
> if (opt_state->reintegrate)
> {
> + SVN_ERR_W(svn_cl__check_related_source_and_target(
> + sourcepath1, &peg_revision1, targetpath, &unspecified,
> + ctx, pool),
> + _("Source and target must be different but related branches"));
> +
> err = merge_reintegrate(sourcepath1, &peg_revision1, targetpath,
> opt_state->dry_run, options, ctx, pool);
> }
> @@ -364,6 +370,12 @@ svn_cl__merge(apr_getopt_t *os,
> range->start.value.number = 1;
> range->end = peg_revision1;
> APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) = range;
> +
> + /* This must be a 'sync' merge so check branch relationship. */
> + SVN_ERR_W(svn_cl__check_related_source_and_target(
> + sourcepath1, &peg_revision1, targetpath, &unspecified,
> + ctx, pool),
> + _("Source and target must be different but related branches"));
> }
>
> err = svn_client_merge_peg4(sourcepath1,
>
> Modified: subversion/trunk/subversion/svn/mergeinfo-cmd.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/mergeinfo-cmd.c?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/svn/mergeinfo-cmd.c (original)
> +++ subversion/trunk/subversion/svn/mergeinfo-cmd.c Fri Dec 16 21:05:07 2011
> @@ -114,6 +114,11 @@ svn_cl__mergeinfo(apr_getopt_t *os,
> tgt_peg_revision.kind = svn_opt_revision_base;
> }
>
> + SVN_ERR_W(svn_cl__check_related_source_and_target(source, &src_peg_revision,
> + target, &tgt_peg_revision,
> + ctx, pool),
> + _("Source and target must be different but related branches"));
> +
> /* Do the real work, depending on the requested data flavor. */
> if (opt_state->show_revs == svn_cl__show_revs_merged)
> {
>
> Modified: subversion/trunk/subversion/svn/util.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/util.c?rev=1215273&r1=1215272&r2=1215273&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/svn/util.c (original)
> +++ subversion/trunk/subversion/svn/util.c Fri Dec 16 21:05:07 2011
> @@ -1423,3 +1423,43 @@ svn_cl__local_style_skip_ancestor(const
>
> return svn_dirent_local_style(relpath ? relpath : path, pool);
> }
> +
> +/* Return a string of the form "PATH_OR_URL_at_REVISION". */
> +static const char *
> +path_for_display(const char *path_or_url,
> + const svn_opt_revision_t *revision,
> + apr_pool_t *pool)
> +{
> + const char *rev_str = svn_opt__revision_to_string(revision, pool);
> +
> + if (! svn_path_is_url(path_or_url))
> + path_or_url = svn_dirent_local_style(path_or_url, pool);
> + return apr_psprintf(pool, "%s@%s", path_or_url, rev_str);
> +}
> +
> +svn_error_t *
> +svn_cl__check_related_source_and_target(const char *path_or_url1,
> + const svn_opt_revision_t *revision1,
> + const char *path_or_url2,
> + const svn_opt_revision_t *revision2,
> + svn_client_ctx_t *ctx,
> + apr_pool_t *pool)
> +{
> + const char *ancestor_url;
> + svn_revnum_t ancestor_rev;
> +
> + SVN_ERR(svn_client__youngest_common_ancestor(
> + &ancestor_url, &ancestor_rev,
> + path_or_url1, revision1, path_or_url2, revision2,
> + ctx, pool, pool));
> +
> + if (ancestor_url == NULL)
> + {
> + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
> + _("Source and target have no common ancestor: "
> + "'%s' and '%s'"),
> + path_for_display(path_or_url1, revision1, pool),
> + path_for_display(path_or_url2, revision2, pool));
> + }
> + return SVN_NO_ERROR;
> +}
>
>
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Received on 2011-12-16 22:44:46 CET