You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2012/05/16 14:21:02 UTC
svn commit: r1339132 - /subversion/trunk/subversion/libsvn_client/merge.c
Author: julianfoad
Date: Wed May 16 12:21:01 2012
New Revision: 1339132
URL: http://svn.apache.org/viewvc?rev=1339132&view=rev
Log:
In the merge code, move the 'sources_ancestral' flag out of the big merge
baton structure and into the 'merge_source_t' structure where it more
naturally belongs, since it describes a property of that structure.
* subversion/libsvn_client/merge.c
(merge_source_t): Add an 'ancestral' field here, ...
(merge_cmd_baton_t): ... and remove the 'sources_ancestral' field here.
(HONOR_MERGEINFO, merge_source_create, merge_source_dup,
prepare_merge_props_changed, notification_receiver,
populate_remaining_ranges, single_file_merge_notify,
combine_range_with_segments, find_reintegrate_merge,
merge_peg_locked, do_symmetric_merge_locked): Adjust accordingly.
(subrange_source, do_mergeinfo_aware_dir_merge,
merge_cousins_and_supplement_mergeinfo): Adjust accordingly. Assert that
the input is an 'ancestral' source.
(do_file_merge): Adjust accordingly. Only call subrange_source() for an
'ancestral' source.
(do_merge): Don't take a 'sources_ancestral' parameter; instead, check
whether all the sources have their 'ancestral' field set.
(merge_locked): Adjust accordingly. Instead of passing
'sources_ancestral=TRUE' to subroutines, rely on getting sources with
'ancestral=TRUE' from normalize_merge_sources_internal().
(merge_reintegrate_locked): Claim that the source is not 'ancestral' when
calling merge_cousins_and_supplement_mergeinfo(), even if it really is,
in order to satisfy an existing implicit assumption and so avoid larger
changes that would be needed to remove this assumption.
Modified:
subversion/trunk/subversion/libsvn_client/merge.c
Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1339132&r1=1339131&r2=1339132&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Wed May 16 12:21:01 2012
@@ -169,6 +169,8 @@ typedef struct merge_source_t
/* "right" side URL and revision (inclusive iff youngest) */
const svn_client__pathrev_t *loc2;
+ /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */
+ svn_boolean_t ancestral;
} merge_source_t;
/* Description of the merge target root node (a WC working node) */
@@ -192,9 +194,6 @@ typedef struct merge_cmd_baton_t {
svn_boolean_t dry_run;
svn_boolean_t record_only; /* Whether to merge only mergeinfo
differences. */
- svn_boolean_t sources_ancestral; /* Whether the left-side merge source is
- an ancestor of the right-side, or
- vice-versa (history-wise). */
svn_boolean_t same_repos; /* Whether the merge source repository
is the same repository as the
target. Defaults to FALSE if DRY_RUN
@@ -297,7 +296,7 @@ typedef struct merge_cmd_baton_t {
source is in the same repository as the merge target, and ancestry is
being considered. */
#define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable \
- && (merge_b)->sources_ancestral \
+ && (merge_b)->merge_source.ancestral \
&& (merge_b)->same_repos \
&& (! (merge_b)->ignore_ancestry))
@@ -314,10 +313,11 @@ typedef struct merge_cmd_baton_t {
/*** Utilities ***/
/* Return a new merge_source_t structure, allocated in RESULT_POOL,
- * initialized with deep copies of LOC1 and LOC2. */
+ * initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */
static merge_source_t *
merge_source_create(const svn_client__pathrev_t *loc1,
const svn_client__pathrev_t *loc2,
+ svn_boolean_t ancestral,
apr_pool_t *result_pool)
{
merge_source_t *s
@@ -325,6 +325,7 @@ merge_source_create(const svn_client__pa
s->loc1 = svn_client__pathrev_dup(loc1, result_pool);
s->loc2 = svn_client__pathrev_dup(loc2, result_pool);
+ s->ancestral = ancestral;
return s;
}
@@ -337,6 +338,7 @@ merge_source_dup(const merge_source_t *s
s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool);
s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool);
+ s->ancestral = source->ancestral;
return s;
}
@@ -1192,7 +1194,7 @@ prepare_merge_props_changed(const apr_ar
merge sources are not ancestral then there is no concept of a
'forward' or 'reverse' merge and we filter unconditionally. */
if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev
- || !merge_b->sources_ancestral)
+ || !merge_b->merge_source.ancestral)
SVN_ERR(filter_self_referential_mergeinfo(&props,
local_abspath,
HONOR_MERGEINFO(merge_b),
@@ -2991,7 +2993,7 @@ notification_receiver(void *baton, const
}
/* Update the lists of merged, skipped, tree-conflicted and added paths. */
- if (notify_b->merge_b->sources_ancestral
+ if (notify_b->merge_b->merge_source.ancestral
|| notify_b->merge_b->reintegrate_merge)
{
if (notify->content_state == svn_wc_notify_state_merged
@@ -3058,7 +3060,7 @@ notification_receiver(void *baton, const
/* Notify that a merge is beginning, if we haven't already done so.
* (A single-file merge is notified separately: see single_file_merge_notify().) */
/* If our merge sources are ancestors of one another... */
- if (notify_b->merge_b->sources_ancestral)
+ if (notify_b->merge_b->merge_source.ancestral)
{
/* See if this is an operative directory merge. */
if (!(notify_b->is_single_file_merge) && is_operative_notification)
@@ -4079,6 +4081,11 @@ calculate_remaining_ranges(svn_client__m
apr_array_header_t *target_rangelist;
svn_revnum_t child_base_revision;
+ /* Since this function should only be called when honoring mergeinfo and
+ * SOURCE adheres to the requirements noted in 'MERGEINFO MERGE SOURCE
+ * NORMALIZATION', SOURCE must be 'ancestral'. */
+ SVN_ERR_ASSERT(source->ancestral);
+
/* Determine which of the requested ranges to consider merging... */
SVN_ERR(svn_ra__get_fspath_relative_to_root(ra_session, &mergeinfo_path,
primary_url, result_pool));
@@ -4455,6 +4462,15 @@ populate_remaining_ranges(apr_array_head
source->loc1, child_repos_path, iterpool);
child_source.loc2 = svn_client__pathrev_join_relpath(
source->loc2, child_repos_path, iterpool);
+ /* ### Is the child 'ancestral' over the same revision range? It's
+ * not necessarily true that a child is 'ancestral' if the parent is,
+ * nor that it's not if the parent is not. However, here we claim
+ * that it is. Before we had this 'ancestral' field that we need to
+ * set explicitly, the claim was implicit. Either way, the impact is
+ * that we might pass calculate_remaining_ranges() a source that is
+ * not in fact 'ancestral' (despite its 'ancestral' field being true),
+ * contrary to its doc-string. */
+ child_source.ancestral = source->ancestral;
/* Get the explicit/inherited mergeinfo for CHILD. If CHILD is the
merge target then also get its implicit mergeinfo. Otherwise defer
@@ -4941,7 +4957,7 @@ remove_children_with_deleted_mergeinfo(m
URL in the repository of SOURCE; they may be temporarily reparented within
this function.
- If MERGE_B->sources_ancestral is set, then SOURCE->url1@rev1 must be a
+ If SOURCE->ancestral is set, then SOURCE->url1@rev1 must be a
historical ancestor of SOURCE->url2@rev2, or vice-versa (see
`MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around
SOURCE in this case).
@@ -5352,7 +5368,7 @@ single_file_merge_notify(notification_re
if (IS_OPERATIVE_NOTIFICATION(notify) && (! *header_sent))
{
notify_merge_begin(notify_baton->merge_b->target->abspath,
- (notify_baton->merge_b->sources_ancestral ? r : NULL),
+ (notify_baton->merge_b->merge_source.ancestral ? r : NULL),
notify_baton->merge_b->same_repos,
notify_baton->merge_b->ctx, pool);
*header_sent = TRUE;
@@ -6371,9 +6387,11 @@ combine_range_with_segments(apr_array_he
MIN(segment->range_end, maxrev), segment->path, pool);
/* If this is subtractive, reverse the whole calculation. */
if (subtractive)
- merge_source = merge_source_create(loc2, loc1, pool);
+ merge_source = merge_source_create(loc2, loc1, TRUE /* ancestral */,
+ pool);
else
- merge_source = merge_source_create(loc1, loc2, pool);
+ merge_source = merge_source_create(loc1, loc2, TRUE /* ancestral */,
+ pool);
APR_ARRAY_PUSH(merge_source_ts, merge_source_t *) = merge_source;
}
@@ -6719,6 +6737,9 @@ subrange_source(const merge_source_t *so
svn_client__pathrev_t loc1 = *source->loc1;
svn_client__pathrev_t loc2 = *source->loc2;
+ /* For this function we require that the input source is 'ancestral'. */
+ SVN_ERR_ASSERT_NO_RETURN(source->ancestral);
+
loc1.rev = start_rev;
loc2.rev = end_rev;
if (! same_urls)
@@ -6732,7 +6753,7 @@ subrange_source(const merge_source_t *so
loc1.url = source->loc2->url;
}
}
- return merge_source_create(&loc1, &loc2, pool);
+ return merge_source_create(&loc1, &loc2, source->ancestral, pool);
}
/* The single-file, simplified version of do_directory_merge(), which see for
@@ -6848,7 +6869,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
range to merge, eliminate no-op ranges before going through
the effort of downloading the many copies of the file
required to do these merges (two copies per range). */
- if (merge_b->sources_ancestral && (remaining_ranges->nelts > 1))
+ if (source->ancestral && (remaining_ranges->nelts > 1))
{
const char *old_sess_url;
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url,
@@ -6866,7 +6887,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
{
svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, i,
svn_merge_range_t *);
- merge_source_t *real_source;
+ const merge_source_t *real_source;
svn_boolean_t header_sent = FALSE;
const char *tmpfile1, *tmpfile2;
apr_hash_t *props1, *props2;
@@ -6880,7 +6901,10 @@ do_file_merge(svn_mergeinfo_catalog_t re
/* While we currently don't allow it, in theory we could be
fetching two fulltexts from two different repositories here. */
- real_source = subrange_source(source, r->start, r->end, iterpool);
+ if (source->ancestral)
+ real_source = subrange_source(source, r->start, r->end, iterpool);
+ else
+ real_source = source;
SVN_ERR(single_file_merge_get_file(&tmpfile1, &props1,
merge_b->ra_session1,
real_source->loc1,
@@ -8436,7 +8460,7 @@ remove_noop_subtree_ranges(const merge_s
do_file_merge().
MERGE_B describes the merge being performed. As this function is for a
- mergeinfo-aware merge, MERGE_B->sources_ancestral should be TRUE, and
+ mergeinfo-aware merge, SOURCE->ancestral should be TRUE, and
SOURCE->url1@rev1 must be a historical ancestor of SOURCE->url2@rev2, or
vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION' for more
requirements around SOURCE).
@@ -8496,6 +8520,8 @@ do_mergeinfo_aware_dir_merge(svn_mergein
svn_client__merge_path_t *target_merge_path;
svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
+ SVN_ERR_ASSERT(source->ancestral);
+
/*** If we get here, we're dealing with related sources from the
same repository as the target -- merge tracking might be
happenin'! ***/
@@ -8851,8 +8877,8 @@ ensure_ra_session_url(svn_ra_session_t *
by the merge. Keys and values of the hash are both (const char *)
absolute paths. The contents of the hash are allocated in RESULT_POOL.
- If SOURCES_ANCESTRAL is set, then for every (const merge_source_t *)
- merge source in MERGE_SOURCES, the "left" and "right" side are
+ For every (const merge_source_t *) merge source in MERGE_SOURCES, if
+ SOURCE->ANCESTRAL is set, then the "left" and "right" side are
ancestrally related. (See 'MERGEINFO MERGE SOURCE NORMALIZATION'
for more on what that means and how it matters.)
@@ -8900,7 +8926,6 @@ do_merge(apr_hash_t **modified_subtrees,
svn_mergeinfo_catalog_t result_catalog,
const apr_array_header_t *merge_sources,
const merge_target_t *target,
- svn_boolean_t sources_ancestral,
svn_boolean_t sources_related,
svn_boolean_t same_repos,
svn_boolean_t ignore_ancestry,
@@ -8932,6 +8957,17 @@ do_merge(apr_hash_t **modified_subtrees,
(which is a merge-tracking thing). */
if (record_only)
{
+ svn_boolean_t sources_ancestral = TRUE;
+ int j;
+
+ /* Find out whether all of the sources are 'ancestral'. */
+ for (j = 0; j < merge_sources->nelts; j++)
+ if (! APR_ARRAY_IDX(merge_sources, j, merge_source_t *)->ancestral)
+ {
+ sources_ancestral = FALSE;
+ break;
+ }
+
/* We can't do a record-only merge if the sources aren't related. */
if (! sources_ancestral)
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
@@ -8977,7 +9013,6 @@ do_merge(apr_hash_t **modified_subtrees,
merge_cmd_baton.ignore_ancestry = ignore_ancestry;
merge_cmd_baton.same_repos = same_repos;
merge_cmd_baton.mergeinfo_capable = FALSE;
- merge_cmd_baton.sources_ancestral = sources_ancestral;
merge_cmd_baton.ctx = ctx;
merge_cmd_baton.target_missing_child = FALSE;
merge_cmd_baton.reintegrate_merge = reintegrate_merge;
@@ -9158,6 +9193,7 @@ merge_cousins_and_supplement_mergeinfo(c
apr_pool_t *subpool = svn_pool_create(scratch_pool);
SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
+ SVN_ERR_ASSERT(! source->ancestral);
SVN_ERR(normalize_merge_sources_internal(
&remove_sources, source->loc1,
@@ -9180,7 +9216,7 @@ merge_cousins_and_supplement_mergeinfo(c
modified_subtrees = apr_hash_make(scratch_pool);
APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source;
SVN_ERR(do_merge(&modified_subtrees, NULL, faux_sources, target,
- FALSE, TRUE, same_repos,
+ TRUE, same_repos,
ignore_ancestry, force, dry_run, FALSE, NULL, TRUE,
FALSE, depth, merge_options, use_sleep, ctx,
scratch_pool, subpool));
@@ -9194,9 +9230,7 @@ merge_cousins_and_supplement_mergeinfo(c
/* ... and now, if we're doing the mergeinfo thang, we execute a
pair of record-only merges using the real sources we've
- calculated. (We know that each tong in our fork of our merge
- source history tree has an ancestral relationship with the common
- ancestral, so we force ancestral=TRUE here.)
+ calculated.
Issue #3648: We don't actually perform these two record-only merges
on the WC at first, but rather see what each would do and store that
@@ -9214,14 +9248,14 @@ merge_cousins_and_supplement_mergeinfo(c
notify_mergeinfo_recording(target->abspath, NULL, ctx, scratch_pool);
svn_pool_clear(subpool);
SVN_ERR(do_merge(NULL, add_result_catalog, add_sources, target,
- TRUE, TRUE, same_repos,
+ TRUE, same_repos,
ignore_ancestry, force, dry_run, TRUE,
modified_subtrees, TRUE,
TRUE, depth, merge_options, use_sleep, ctx,
scratch_pool, subpool));
svn_pool_clear(subpool);
SVN_ERR(do_merge(NULL, remove_result_catalog, remove_sources, target,
- TRUE, TRUE, same_repos,
+ TRUE, same_repos,
ignore_ancestry, force, dry_run, TRUE,
modified_subtrees, TRUE,
TRUE, depth, merge_options, use_sleep, ctx,
@@ -9458,7 +9492,7 @@ merge_locked(const char *source1,
{
merge_target_t *target;
svn_client__pathrev_t *source1_loc, *source2_loc;
- svn_boolean_t related = FALSE, ancestral = FALSE;
+ svn_boolean_t related = FALSE;
svn_ra_session_t *ra_session1, *ra_session2;
apr_array_header_t *merge_sources;
svn_error_t *err;
@@ -9528,7 +9562,6 @@ merge_locked(const char *source1,
if ((strcmp(yca->url, source2_loc->url) == 0)
&& (yca->rev == source2_loc->rev))
{
- ancestral = TRUE;
SVN_ERR(normalize_merge_sources_internal(
&merge_sources, source1_loc,
svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE,
@@ -9540,7 +9573,6 @@ merge_locked(const char *source1,
else if ((strcmp(yca->url, source1_loc->url) == 0)
&& (yca->rev == source1_loc->rev))
{
- ancestral = TRUE;
SVN_ERR(normalize_merge_sources_internal(
&merge_sources, source2_loc,
svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE,
@@ -9551,7 +9583,7 @@ merge_locked(const char *source1,
side, and merge the right. */
else
{
- merge_source_t source = { source1_loc, source2_loc };
+ merge_source_t source = { source1_loc, source2_loc, FALSE };
err = merge_cousins_and_supplement_mergeinfo(target,
ra_session1,
@@ -9583,7 +9615,7 @@ merge_locked(const char *source1,
}
else
{
- merge_source_t source = { source1_loc, source2_loc };
+ merge_source_t source = { source1_loc, source2_loc, FALSE };
/* Build a single-item merge_source_t array. */
merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
@@ -9591,7 +9623,7 @@ merge_locked(const char *source1,
}
err = do_merge(NULL, NULL, merge_sources, target,
- ancestral, related, same_repos,
+ related, same_repos,
ignore_ancestry, force, dry_run,
record_only, NULL, FALSE, FALSE, depth, merge_options,
&use_sleep, ctx, scratch_pool, scratch_pool);
@@ -10587,6 +10619,10 @@ find_reintegrate_merge(merge_source_t **
&yc_ancestor, source.loc2, source.loc1,
ctx, scratch_pool, scratch_pool));
+ /* The source side of a reintegrate merge is not 'ancestral', except in
+ * the degenerate case where source == YCA. */
+ source.ancestral = (loc1->rev == yc_ancestor->rev);
+
if (! yc_ancestor)
return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
_("'%s@%ld' must be ancestrally related to "
@@ -10790,8 +10826,10 @@ merge_reintegrate_locked(const char *sou
/* Do the real merge! */
/* ### TODO(reint): Make sure that one isn't the same line ancestor
### of the other (what's erroneously referred to as "ancestrally
- ### related" in this source file). We can merge to trunk without
- ### implementing this. */
+ ### related" in this source file). For now, we just say the source
+ ### isn't "ancestral" even if it is (in the degenerate case where
+ ### source-left equals YCA). */
+ source->ancestral = FALSE;
err = merge_cousins_and_supplement_mergeinfo(target,
target_ra_session,
source_ra_session,
@@ -10894,7 +10932,7 @@ merge_peg_locked(const char *source_path
/* Do the real merge! (We say with confidence that our merge
sources are both ancestral and related.) */
err = do_merge(NULL, NULL, merge_sources, target,
- TRUE, TRUE, same_repos, ignore_ancestry, force, dry_run,
+ TRUE, same_repos, ignore_ancestry, force, dry_run,
record_only, NULL, FALSE, FALSE, depth, merge_options,
&use_sleep, ctx, scratch_pool, scratch_pool);
@@ -11507,6 +11545,7 @@ do_symmetric_merge_locked(const svn_clie
source.loc1 = merge->base;
source.loc2 = merge->right;
+ source.ancestral = (merge->mid == NULL);
SVN_DBG(("yca %s@%ld\n", merge->yca->url, merge->yca->rev));
SVN_DBG(("base %s@%ld\n", merge->base->url, merge->base->rev));
if (merge->mid)
@@ -11539,7 +11578,7 @@ do_symmetric_merge_locked(const svn_clie
APR_ARRAY_PUSH(merge_sources, const merge_source_t *) = &source;
err = do_merge(NULL, NULL, merge_sources, target,
- TRUE /*sources_ancestral*/, TRUE /*related*/,
+ TRUE /*related*/,
TRUE /*same_repos*/, ignore_ancestry, force, dry_run,
record_only, NULL, FALSE, FALSE, depth, merge_options,
&use_sleep, ctx, scratch_pool, scratch_pool);