The commit emails need to be modified to fix:
1) There is no reply-to set to dev@ and the author of the commit.
2) None of the commit emails should be formed as an attachments regardless of
size, it makes replying to a commit and making comments inline hard.
Blair
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=518274
attached mail follows:
For efficiency reasons, the system has converted the large body of this message into an attachment.
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=495&dsMessageId=420433
To unsubscribe from this discussion, e-mail: [svn-unsubscribe_at_subversion.tigris.org].
attached mail follows:
Author: pburba
Date: Tue Dec 2 07:07:21 2008
New Revision: 34521
Log:
On the 1.5.x-reintegrate-improvements branch, merge r34306 from trunk.
* subversion/include/private/svn_mergeinfo_private.h
Fix minor conflict because svn_mergeinfo__catalog_dup is now declared here.
* subversion/libsvn_client/merge.c
Fix a slew of minor text conflicts and replace SVN_ERR_ASSERT() with
assert() as the former is not present on 1.5.x
* subversion/libsvn_subr/mergeinfo.c
* subversion/tests/cmdline/merge_tests.py
Clean merge.
* src-branch-1.5.x-reintegrate-improvements
* CHANGES
* COMMITTERS
* notes/tree-conflicts/scratch-pad.txt
* subversion/bindings/swig
* www/images/subversion-diagram.png
* www/images/subversion_logo-200x173.png
* www/images/subversion_logo-384x332.png
* www/images/subversion_logo_hor-468x64.png
Mergeinfo changes only.
Modified:
branches/1.5.x-reintegrate-improvements/ (props changed)
branches/1.5.x-reintegrate-improvements/CHANGES (props changed)
branches/1.5.x-reintegrate-improvements/COMMITTERS (props changed)
branches/1.5.x-reintegrate-improvements/notes/tree-conflicts/scratch-pad.txt (props changed)
branches/1.5.x-reintegrate-improvements/subversion/bindings/swig/ (props changed)
branches/1.5.x-reintegrate-improvements/subversion/include/private/svn_mergeinfo_private.h
branches/1.5.x-reintegrate-improvements/subversion/libsvn_client/merge.c (contents, props changed)
branches/1.5.x-reintegrate-improvements/subversion/libsvn_subr/mergeinfo.c
branches/1.5.x-reintegrate-improvements/subversion/tests/cmdline/merge_tests.py
branches/1.5.x-reintegrate-improvements/www/images/subversion-diagram.png (props changed)
branches/1.5.x-reintegrate-improvements/www/images/subversion_logo-200x173.png (props changed)
branches/1.5.x-reintegrate-improvements/www/images/subversion_logo-384x332.png (props changed)
branches/1.5.x-reintegrate-improvements/www/images/subversion_logo_hor-468x64.png (props changed)
Merged:
/trunk:r34306
Modified: branches/1.5.x-reintegrate-improvements/subversion/include/private/svn_mergeinfo_private.h
URL: http://svn.collab.net/viewvc/svn/branches/1.5.x-reintegrate-improvements/subversion/include/private/svn_mergeinfo_private.h?pathrev=34521&r1=34520&r2=34521
==============================================================================
--- branches/1.5.x-reintegrate-improvements/subversion/include/private/svn_mergeinfo_private.h Tue Dec 2 06:46:43 2008 (r34520)
+++ branches/1.5.x-reintegrate-improvements/subversion/include/private/svn_mergeinfo_private.h Tue Dec 2 07:07:21 2008 (r34521)
@@ -99,6 +99,40 @@ svn_mergeinfo__to_formatted_string(svn_s
const char *prefix,
apr_pool_t *pool);
+/* Set *YOUNGEST_REV and *OLDEST_REV to the youngest and oldest revisions
+ found in the rangelists within MERGEINFO. If MERGEINFO is NULL or empty
+ set *YOUNGEST_REV and *OLDEST_REV to SVN_INVALID_REVNUM. */
+svn_error_t *
+svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
+ svn_revnum_t *oldest_rev,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *pool);
+
+/* Set *FILTERED_MERGEINFO to a deep copy of MERGEINFO, allocated in POOL, less
+ any rangelists that fall outside of the range OLDEST_REV:YOUGEST_REV
+ (inclusive). If all the rangelists mapped to a given path are filtered
+ then filter that path as well. If all paths are filtered or MERGEINFO is
+ empty or NULL then *FILTERED_MERGEINFO is set to an empty hash. */
+svn_error_t *
+svn_mergeinfo__filter_mergefino_by_ranges(svn_mergeinfo_t *filtered_mergeinfo,
+ svn_mergeinfo_t mergeinfo,
+ svn_revnum_t youngest_rev,
+ svn_revnum_t oldest_rev,
+ apr_pool_t *pool);
+
+/* Filter each mergeinfo in CATALOG as per
+ svn_mergeinfo__filter_mergefino_by_ranges and put a deep copy of the
+ result in *FILTERED_CATALOG. If any mergeinfo is filtered to an empty
+ hash then filter that path/mergeinfo as well. If all mergeinfo is filtered
+ or CATALOG is NULL then set *FILTERED_CATALOG to an empty hash. */
+svn_error_t*
+svn_mergeinfo__filter_catalog_by_ranges(
+ svn_mergeinfo_catalog_t *filtered_catalog,
+ svn_mergeinfo_catalog_t catalog,
+ svn_revnum_t youngest_rev,
+ svn_revnum_t oldest_rev,
+ apr_pool_t *pool);
+
/* Return a deep copy of MERGEINFO_CATALOG, allocated in POOL. */
svn_mergeinfo_catalog_t
svn_mergeinfo__catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
Modified: branches/1.5.x-reintegrate-improvements/subversion/libsvn_client/merge.c
URL: http://svn.collab.net/viewvc/svn/branches/1.5.x-reintegrate-improvements/subversion/libsvn_client/merge.c?pathrev=34521&r1=34520&r2=34521
==============================================================================
--- branches/1.5.x-reintegrate-improvements/subversion/libsvn_client/merge.c Tue Dec 2 06:46:43 2008 (r34520)
+++ branches/1.5.x-reintegrate-improvements/subversion/libsvn_client/merge.c Tue Dec 2 07:07:21 2008 (r34521)
@@ -6392,70 +6392,83 @@ ensure_wc_reflects_repository_subtree(co
return SVN_NO_ERROR;
}
-/* Given a "mergeinfo" hash HISTORY_AS_MERGEINFO representing revision
- ranges from a merge target that are not represented in the merge
+/* Given a mergeinfo catalog UNMERGED_HISTORY representing the history
+ (as mergeinfo) from a merge target that is not represented in the merge
source, check (using RA_SESSION, which is pointed at the repository
- root) that all of the ranges in the hash are "phantoms": that is,
- their corresponding path did not change in any of their revisions.
+ root) that all of the ranges in the catalog's mergeinfos are "phantoms":
+ that is, their corresponding path did not change in any of their revisions.
Raises SVN_ERR_CLIENT_NOT_READY_TO_MERGE if any are not phantoms.
Temporary allocations in POOL.
*/
static svn_error_t *
ensure_all_missing_ranges_are_phantoms(svn_ra_session_t *ra_session,
- svn_mergeinfo_t history_as_mergeinfo,
+ svn_mergeinfo_catalog_t unmerged_history,
apr_pool_t *pool)
{
- apr_hash_index_t *hi;
+ apr_hash_index_t *hi1, *hi2;
apr_pool_t *iterpool = svn_pool_create(pool);
- for (hi = apr_hash_first(pool, history_as_mergeinfo); hi;
- hi = apr_hash_next(hi))
+ for (hi1 = apr_hash_first(pool, unmerged_history); hi1;
+ hi1 = apr_hash_next(hi1))
{
const void *key;
void *value;
- const char *path;
- apr_array_header_t *rangelist;
- int i;
-
- apr_hash_this(hi, &key, NULL, &value);
- path = key;
- rangelist = value;
-
- /* mergeinfo hashes contain paths that start with slashes;
- ra APIs take paths without slashes. */
- assert(*path);
- path++;
+ const char *catalog_path;
+ svn_mergeinfo_t history_as_mergeinfo;
+
+ apr_hash_this(hi1, &key, NULL, &value);
+ catalog_path = key;
+ history_as_mergeinfo = value;
- for (i = 0; i < rangelist->nelts; i++)
+ for (hi2 = apr_hash_first(pool, history_as_mergeinfo); hi2;
+ hi2 = apr_hash_next(hi2))
{
- svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i,
- svn_merge_range_t *);
- svn_dirent_t *dirent;
-
- /* This function should not receive any "rollback"
- ranges. */
- assert(range->start < range->end);
-
- svn_pool_clear(iterpool);
+ const char *path;
+ apr_array_header_t *rangelist;
+ int i;
- SVN_ERR(svn_ra_stat(ra_session,
- path,
- range->end,
- &dirent,
- iterpool));
+ apr_hash_this(hi2, &key, NULL, &value);
+ path = key;
+ rangelist = value;
+
+ /* mergeinfo hashes contain paths that start with slashes;
+ ra APIs take paths without slashes. */
+ assert(*path);
+ path++;
- if (svn_merge_range_contains_rev(range, dirent->created_rev))
+ for (i = 0; i < rangelist->nelts; i++)
{
- const char *full_url;
+ svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i,
+ svn_merge_range_t *);
+ svn_dirent_t *dirent;
+
+ /* This function should not receive any "rollback"
+ ranges. */
+ assert(range->start < range->end);
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_ra_stat(ra_session,
+ path,
+ range->end,
+ &dirent,
+ iterpool));
- svn_pool_destroy(iterpool);
+ if (svn_merge_range_contains_rev(range, dirent->created_rev))
+ {
+ const char *full_url;
+
+ svn_pool_destroy(iterpool);
- SVN_ERR(svn_ra_get_session_url(ra_session, &full_url, pool));
- full_url = svn_path_url_add_component(full_url, path, pool);
- return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("At least one revision (r%ld) "
- "not yet merged from '%s'"),
- dirent->created_rev, full_url);
+ SVN_ERR(svn_ra_get_session_url(ra_session, &full_url,
+ pool));
+ full_url = svn_path_url_add_component(full_url, path, pool);
+ return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
+ NULL,
+ _("At least one revision (r%ld) "
+ "not yet merged from '%s'"),
+ dirent->created_rev, full_url);
+ }
}
}
}
@@ -6465,9 +6478,9 @@ ensure_all_missing_ranges_are_phantoms(s
}
-/* Helper for calculate_left_hand_side() which filters the mergeinfo catalog
- on a reintegrate source down to only that which came from the reintegrate
- target.
+/* Helper for calculate_left_hand_side() which produces a mergeinfo catalog
+ describing what parts of of the reintegrate target have not previously been
+ merged to the reintegrate source.
SOURCE_CATALOG is the collection of explicit mergeinfo on
SOURCE_REPOS_REL_PATH_at_SORUCE_REV and all its children, i.e. the mergeinfo
@@ -6491,26 +6504,49 @@ ensure_all_missing_ranges_are_phantoms(s
RA_SESSION is a session opened to the repository root.
- Return a new catalog in *FILTERED_CATALOG_P equal to SOURCE_CATALOG, but
- containing only mergeinfo which came from TARGET_REPOS_REL_PATH_at_TARGET_REV's
- natural history. *FILTERED_CATALOG_P is (deeply) allocated in POOL. */
+ For each path/segment in TARGET_SEGMENTS_HASH check that the history that
+ segment represents is contained in either the explicit mergeinfo for the
+ corresponding path in SOURCE_CATALOG, the corresponding path's inherited
+ mergeinfo (if no explicit mergeinfo for the path is found in
+ SOURCE_CATALOG), or the corresponding path's natural history. Populate
+ *UNMERGED_TO_SOURCE_CATALOG with the corresponding source paths mapped to
+ the mergeinfo from the target's natural history which is *not* found. Also
+ include any mergeinfo from SOURCE_CATALOG which explicitly describes the
+ target's history but for which *no* path/segment was found in
+ TARGET_SEGMENTS_HASH.
+
+ If no part of TARGET_SEGMENTS_HASH is found in SOURCE_CATALOG set
+ *NEVER_SYNCHED to TRUE and set *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM.
+ Otherwise set *NEVER_SYNCHED to FALSE, *YOUNGEST_MERGED_REV to the youngest
+ revision previously merged from the target to the source, and filter
+ *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than
+ *YOUNGEST_MERGED_REV.
+
+ *UNMERGED_TO_SOURCE_CATALOG is (deeply) allocated in POOL. */
static svn_error_t *
-remove_irrelevant_ranges(svn_mergeinfo_catalog_t *filtered_source_catalog_p,
- svn_mergeinfo_catalog_t source_catalog,
- apr_hash_t *target_segments_hash,
- const char *source_repos_rel_path,
- const char *target_repos_rel_path,
- svn_revnum_t target_rev,
- svn_revnum_t source_rev,
- svn_ra_session_t *ra_session,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
+ svn_boolean_t *never_synched,
+ svn_revnum_t *youngest_merged_rev,
+ svn_mergeinfo_catalog_t source_catalog,
+ apr_hash_t *target_segments_hash,
+ const char *source_repos_rel_path,
+ const char *target_repos_rel_path,
+ svn_revnum_t target_rev,
+ svn_revnum_t source_rev,
+ svn_ra_session_t *ra_session,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
{
apr_hash_index_t *hi;
svn_mergeinfo_catalog_t new_catalog = apr_hash_make(pool);
- svn_mergeinfo_t history_as_mergeinfo;
+ svn_mergeinfo_t target_history_as_mergeinfo, source_history_as_mergeinfo;
+ svn_mergeinfo_t common_mergeinfo;
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool = svn_pool_create(subpool);
+ svn_revnum_t old_rev, young_rev;
+
+ *never_synched = TRUE;
+ *youngest_merged_rev = SVN_INVALID_REVNUM;
/* Examine the natural history of each path in the reintegrate target
with explicit mergeinfo. */
@@ -6524,32 +6560,57 @@ remove_irrelevant_ranges(svn_mergeinfo_c
apr_array_header_t *segments;
svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
- svn_pool_clear(iterpool);
+ svn_pool_clear(iterpool);
apr_hash_this(hi, &key, NULL, &val);
path = key;
segments = val;
- source_path = path + strlen(target_repos_rel_path);
+ source_path = path + strlen(target_repos_rel_path);
if (source_path[0] == '/') /* Remove leading '/' for svn_path_join. */
source_path++;
source_path = svn_path_join(source_repos_rel_path, source_path,
iterpool);
- SVN_ERR(svn_client__mergeinfo_from_segments(&history_as_mergeinfo,
+ /* Convert this target path's natural history into mergeinfo. */
+ SVN_ERR(svn_client__mergeinfo_from_segments(&target_history_as_mergeinfo,
segments,
iterpool));
- /* If we find mergeinfo for source_path remove that from
- SOURCE_CATALOG. When this iteration over TARGET_SEGMENTS_HASH is
- complete all that should be left in SOURCE_CATALOG are subtrees that
- have explicit mergeinfo on the reintegrate source where there is no
- corresponding explicit mergeinfo on the reintegrate target. */
+ /* Look for any explicit mergeinfo on the source path corresponding to
+ the target path. If we find any remove that from SOURCE_CATALOG.
+ When this iteration over TARGET_SEGMENTS_HASH is complete all that
+ should be left in SOURCE_CATALOG are subtrees that have explicit
+ mergeinfo on the reintegrate source where there is no corresponding
+ explicit mergeinfo on the reintegrate target. */
source_mergeinfo = apr_hash_get(source_catalog, source_path,
APR_HASH_KEY_STRING);
if (source_mergeinfo)
{
+ svn_mergeinfo_t explicit_source_target_history_intersection;
+
apr_hash_set(source_catalog, source_path, APR_HASH_KEY_STRING,
NULL);
+ /* If there is an intersection between the *explicit* mergeinfo on
+ this source path and the corresponding target's history then we
+ know that at least one merge was done from the target to the
+ source. */
+ SVN_ERR(svn_mergeinfo_intersect(
+ &explicit_source_target_history_intersection,
+ source_mergeinfo, target_history_as_mergeinfo,
+ iterpool));
+ if (apr_hash_count(explicit_source_target_history_intersection))
+ {
+ *never_synched = FALSE;
+ /* Keep track of the youngest revision merged from the
+ target to the source. */
+ SVN_ERR(svn_mergeinfo__get_range_endpoints(
+ &young_rev, &old_rev,
+ explicit_source_target_history_intersection,
+ iterpool));
+ if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
+ || (young_rev > *youngest_merged_rev))
+ *youngest_merged_rev = young_rev;
+ }
}
else
{
@@ -6583,31 +6644,38 @@ remove_irrelevant_ranges(svn_mergeinfo_c
source_mergeinfo = apr_hash_make(iterpool);
}
+ /* Get the source path's natural history and convert it to mergeinfo.
+ Then merge that natural history into source path's explicit
+ or inherited mergeinfo. */
+ SVN_ERR(svn_client__repos_location_segments(&segments,
+ ra_session,
+ source_path,
+ source_rev, source_rev,
+ SVN_INVALID_REVNUM,
+ ctx, iterpool));
+ SVN_ERR(svn_client__mergeinfo_from_segments(&source_history_as_mergeinfo,
+ segments, iterpool));
+ SVN_ERR(svn_mergeinfo_merge(source_mergeinfo,
+ source_history_as_mergeinfo, iterpool));
+
+ /* Now source_mergeinfo represents everything we know about
+ source_path's history. Now we need to know what part, if any, of the
+ corresponding target's history is *not* part of source_path's total
+ history; because it is neither shared history nor was it ever merged
+ from the target to the source. */
+ SVN_ERR(svn_mergeinfo_intersect(&common_mergeinfo,
+ source_mergeinfo,
+ target_history_as_mergeinfo,
+ iterpool));
+
/* Use subpool rather than iterpool because filtered_mergeinfo is
going into new_catalog below and needs to last to the end of
this function. */
- SVN_ERR(svn_mergeinfo_intersect(&filtered_mergeinfo,
- source_mergeinfo,
- history_as_mergeinfo,
- subpool));
+ SVN_ERR(svn_mergeinfo_remove(&filtered_mergeinfo,
+ common_mergeinfo,
+ target_history_as_mergeinfo,
+ subpool));
- /* Don't put an empty hash in the catalog for the root of the source.
- An empty hash represents empty mergeinfo as opposed to *no*
- mergeinfo. We need to do this for the root of the source because
- if calculate_left_hand_side() sees *any* mergeinfo left on the source
- it will interpret this as coming from the target, when in fact
- nothing has been merged from the target to the source. This
- ultimately causes calculate_left_hand_side() to follow the wrong code
- path and abort. We only do this for the root of the source however,
- subtrees with mergeinfo cannot lose all mergeinfo as that would mean
- they are inheriting from the root, which isn't the case. See here
- for more details:
- http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=136908
- */
- if (apr_hash_count(filtered_mergeinfo)
- || (strcmp(source_repos_rel_path, source_path) != 0
- && (apr_hash_count(source_mergeinfo) == 0)))
- {
/* As with svn_mergeinfo_intersect above, we need to use subpool
rather than iterpool. */
apr_hash_set(new_catalog,
@@ -6615,7 +6683,6 @@ remove_irrelevant_ranges(svn_mergeinfo_c
APR_HASH_KEY_STRING,
filtered_mergeinfo);
}
- }
/* Are there any subtrees with explicit mergeinfo still left in the merge
source where there was no explicit mergeinfo for the corresponding path
@@ -6641,7 +6708,7 @@ remove_irrelevant_ranges(svn_mergeinfo_c
source_path = key;
source_mergeinfo = val;
- target_path = source_path + strlen(source_repos_rel_path);
+ target_path = source_path + strlen(source_repos_rel_path);
if (target_path[0] == '/') /* Remove leading '/' for svn_path_join */
target_path++;
target_path = svn_path_join(target_repos_rel_path, target_path,
@@ -6658,8 +6725,8 @@ remove_irrelevant_ranges(svn_mergeinfo_c
if (err->apr_err == SVN_ERR_FS_NOT_FOUND
|| err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
{
- /* This path with explicit mergeinfo in the source doesn't exist
- on the target. */
+ /* This path with explicit mergeinfo in the source doesn't
+ exist on the target. */
svn_error_clear(err);
err = NULL;
}
@@ -6670,16 +6737,58 @@ remove_irrelevant_ranges(svn_mergeinfo_c
}
else
{
- SVN_ERR(svn_client__mergeinfo_from_segments(&history_as_mergeinfo,
- segments,
+ svn_mergeinfo_t explicit_source_target_history_intersection;
+
+ SVN_ERR(svn_client__mergeinfo_from_segments(
+ &target_history_as_mergeinfo, segments, iterpool));
+
+ /* If there is an intersection between the *explicit* mergeinfo
+ on this source path and the corresponding target's history
+ then we know that at least one merge was done from the target
+ to the source. */
+ SVN_ERR(svn_mergeinfo_intersect(
+ &explicit_source_target_history_intersection,
+ source_mergeinfo, target_history_as_mergeinfo,
iterpool));
+ if (apr_hash_count(explicit_source_target_history_intersection))
+ {
+ *never_synched = FALSE;
+ /* Keep track of the youngest revision merged from the
+ target to the source. */
+ SVN_ERR(svn_mergeinfo__get_range_endpoints(
+ &young_rev, &old_rev,
+ explicit_source_target_history_intersection, iterpool));
+ if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
+ || (young_rev > *youngest_merged_rev))
+ *youngest_merged_rev = young_rev;
+ }
+
+ /* Get the source path's natural history and convert it to
+ mergeinfo. Then merge that natural history into source
+ path's explicit or inherited mergeinfo. */
+ SVN_ERR(svn_client__repos_location_segments(&segments,
+ ra_session,
+ source_path,
+ target_rev,
+ target_rev,
+ SVN_INVALID_REVNUM,
+ ctx, iterpool));
+ SVN_ERR(svn_client__mergeinfo_from_segments(
+ &source_history_as_mergeinfo, segments, iterpool));
+ SVN_ERR(svn_mergeinfo_merge(source_mergeinfo,
+ source_history_as_mergeinfo,
+ iterpool));
+ SVN_ERR(svn_mergeinfo_intersect(&common_mergeinfo,
+ source_mergeinfo,
+ target_history_as_mergeinfo,
+ iterpool));
/* Use subpool rather than iterpool because filtered_mergeinfo
is going into new_catalog below and needs to last to the
end of this function. */
- SVN_ERR(svn_mergeinfo_intersect(&filtered_mergeinfo,
- source_mergeinfo,
- history_as_mergeinfo,
- subpool));
+ SVN_ERR(svn_mergeinfo_remove(&filtered_mergeinfo,
+ common_mergeinfo,
+ target_history_as_mergeinfo,
+ subpool));
if (apr_hash_count(filtered_mergeinfo))
apr_hash_set(new_catalog,
apr_pstrdup(subpool, source_path),
@@ -6689,8 +6798,19 @@ remove_irrelevant_ranges(svn_mergeinfo_c
}
}
+ /* Limit new_catalog to the youngest revisions previously merged from
+ the target to the source. */
+ if (SVN_IS_VALID_REVNUM(youngest_merged_rev))
+ {
+ SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog,
+ new_catalog,
+ *youngest_merged_rev,
+ 0, /* No oldest bound. */
+ subpool));
+ }
+
/* Make a shiny new copy before blowing away all the temporary pools. */
- *filtered_source_catalog_p = svn_mergeinfo__catalog_dup(new_catalog, pool);
+ *unmerged_to_source_catalog = svn_mergeinfo__catalog_dup(new_catalog, pool);
/* iterpool was allocated out of subpool so this destroys both. */
svn_pool_destroy(subpool);
@@ -6714,14 +6834,17 @@ remove_irrelevant_ranges(svn_mergeinfo_c
TARGET_REPOS_REL_PATH is at. SOURCE_REV is the peg revision of the
reintegrate source.
- RA_SESSION is a session opened to the repository root.
+ Populate *UNMERGED_TO_SOURCE_CATALOG with the mergeinfo describing what
+ parts of TARGET_REPOS_REL_PATH_at_TARGET_REV have not been merged to
+ SOURCE_REPOS_REL_PATH_at_SOURCE_REV, up to the youngest revision ever merged
+ from the target to the source if such exists, see doc string for
+ find_unmerged_mergeinfo().
- Check that mergeinfo in SUBTREES_WITH_MERGEINFO
- */
+ RA_SESSION is a session opened to the repository root. */
static svn_error_t *
calculate_left_hand_side(const char **url_left,
svn_revnum_t *rev_left,
- svn_mergeinfo_t *source_mergeinfo_p,
+ svn_mergeinfo_t *unmerged_to_source_catalog,
const char *target_repos_rel_path,
apr_hash_t *subtrees_with_mergeinfo,
svn_revnum_t target_rev,
@@ -6735,15 +6858,18 @@ calculate_left_hand_side(const char **ur
apr_array_header_t *segments; /* array of (svn_location_segment_t *) */
svn_boolean_t have_mergeinfo_for_source = FALSE,
have_mergeinfo_for_descendants = FALSE;
- svn_mergeinfo_catalog_t mergeinfo_catalog, filtered_mergeinfo_catalog;
+ svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog;
apr_array_header_t *source_repos_rel_path_as_array
= apr_array_make(pool, 1, sizeof(const char *));
apr_pool_t *subpool = svn_pool_create(pool);
apr_hash_index_t *hi;
/* hash of paths mapped to arrays of svn_location_segment_t *. */
apr_hash_t *segments_hash = apr_hash_make(pool);
+ svn_boolean_t never_synced;
+ svn_revnum_t youngest_merged_rev;
- /* Get the history (segments) for the target and any of it's subtrees. */
+ /* Get the history (segments) for the target and any of its subtrees
+ with explicit mergeinfo. */
for (hi = apr_hash_first(pool, subtrees_with_mergeinfo);
hi;
hi = apr_hash_next(hi))
@@ -6765,7 +6891,8 @@ calculate_left_hand_side(const char **ur
APR_HASH_KEY_STRING, segments);
}
- /* Get the mergeinfo from the source, including its descendants. */
+ /* Get the mergeinfo from the source, including its descendants
+ with differing explicit mergeinfo. */
APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *)
= source_repos_rel_path;
SVN_ERR(svn_ra_get_mergeinfo(ra_session, &mergeinfo_catalog,
@@ -6775,45 +6902,30 @@ calculate_left_hand_side(const char **ur
if (!mergeinfo_catalog)
mergeinfo_catalog = apr_hash_make(subpool);
- /* Filter the source's mergeinfo catalog so that all mergeinfo
- comes from the target's history. */
- SVN_ERR(remove_irrelevant_ranges(&filtered_mergeinfo_catalog,
- mergeinfo_catalog,
- segments_hash,
- source_repos_rel_path,
- target_repos_rel_path,
- target_rev,
- source_rev,
- ra_session,
- ctx,
- subpool));
+ /* Filter the source's mergeinfo catalog so that we are left with
+ mergeinfo that describes what has *not* previously been merged from
+ TARGET_REPOS_REL_PATH_at_TARGET_REV to SOURCE_REPOS_REL_PATH_at_SOURCE_REV. */
+ SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
+ &never_synced,
+ &youngest_merged_rev,
+ mergeinfo_catalog,
+ segments_hash,
+ source_repos_rel_path,
+ target_repos_rel_path,
+ target_rev,
+ source_rev,
+ ra_session,
+ ctx,
+ subpool));
- /* We can tolerate subtrees with mergeinfo on the source if the
- mergeinfo on each subtree that came from the target elides
- to SOURCE_REPOS_REL_PATH. */
- SVN_ERR(svn_client__elide_mergeinfo_catalog(filtered_mergeinfo_catalog,
+ /* Simplify unmerged_catalog through elision then make a copy in POOL. */
+ SVN_ERR(svn_client__elide_mergeinfo_catalog(unmerged_catalog,
subpool));
+ *unmerged_to_source_catalog = svn_mergeinfo__catalog_dup(unmerged_catalog,
+ pool);
- /* See which case we fall into: */
- /* TODO(reint): make sure we look things up with keys that start
- with slash. This may not be as simple as it sounds, since
- source_repos_rel_path is also used as the component argument to
- (e.g.) svn_path_join(), which expects the component to *not*
- start with a slash (or at least, it will behave in a way we
- probably don't want if the component *does* start with slash).
- */
- if (apr_hash_get(filtered_mergeinfo_catalog, source_repos_rel_path,
- APR_HASH_KEY_STRING))
- have_mergeinfo_for_source = TRUE;
- if (apr_hash_count(filtered_mergeinfo_catalog) > 1 ||
- (! have_mergeinfo_for_source
- && apr_hash_count(filtered_mergeinfo_catalog) == 1))
- have_mergeinfo_for_descendants = TRUE;
-
- if (! have_mergeinfo_for_source && ! have_mergeinfo_for_descendants)
+ if (never_synced)
{
- /* TODO(reint): Make sure we're not fetching location segments
- over and over. */
/* We never merged to the source. Just return the branch point. */
const char *yc_ancestor_path,
*source_url = svn_path_join(source_repos_root, source_repos_rel_path,
@@ -6832,77 +6944,29 @@ calculate_left_hand_side(const char **ur
"'%s@%ld'"), source_url, source_rev,
target_url, target_rev);
*url_left = svn_path_join(source_repos_root, yc_ancestor_path, pool);
- *source_mergeinfo_p = apr_hash_make(pool);
-
- svn_pool_destroy(subpool);
- return SVN_NO_ERROR;
- }
- else if (! have_mergeinfo_for_descendants)
- {
- /* Easy case: return the last path/rev in the mergeinfo. */
- svn_mergeinfo_t source_mergeinfo = apr_hash_get(filtered_mergeinfo_catalog,
- source_repos_rel_path,
- APR_HASH_KEY_STRING);
- apr_pool_t *iterpool = svn_pool_create(subpool);
- int i;
-
- /* Get the segments for the reintegrate target. */
- segments = apr_hash_get(segments_hash, target_repos_rel_path,
- APR_HASH_KEY_STRING);
- for (i = segments->nelts - 1; i >= 0; i--)
- {
- svn_location_segment_t *segment
- = APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
- apr_array_header_t *rangelist;
-
- svn_pool_clear(iterpool);
-
- /* Ignore gaps in history. */
- if (!segment->path)
- continue;
-
- rangelist = apr_hash_get(source_mergeinfo,
- apr_pstrcat(iterpool, "/", segment->path,
- NULL),
- APR_HASH_KEY_STRING);
- if (rangelist != NULL && rangelist->nelts > 0)
- {
- svn_merge_range_t *last_range
- = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
- svn_merge_range_t *);
- *rev_left = last_range->end;
- *url_left = svn_path_url_add_component(source_repos_root,
- segment->path, pool);
- *source_mergeinfo_p = svn_mergeinfo_dup(source_mergeinfo, pool);
- svn_pool_destroy(iterpool);
- svn_pool_destroy(subpool);
- return SVN_NO_ERROR;
- }
- }
- /* We only got here because we had mergeinfo for the source; if
- there were no segments, then our logic was wrong. */
- abort();
}
else
{
- const char *full_url;
- svn_string_t *filtered_mergeinfo_catalog_string;
-
- SVN_ERR(svn_ra_get_session_url(ra_session, &full_url, pool));
- full_url = svn_path_url_add_component(full_url, source_repos_rel_path,
- pool);
-
- SVN_ERR(svn_mergeinfo__catalog_to_formatted_string(
- &filtered_mergeinfo_catalog_string, filtered_mergeinfo_catalog,
- " ", " ", pool));
- return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("Reintegrate can only be used if the "
- "revisions previously merged from the "
- "reintegrate target to '%s' are the same, "
- "but there are differences:\n%s"),
- full_url,
- filtered_mergeinfo_catalog_string->data);
+ /* We've previously merged some or all of the target, up to
+ youngest_merged_rev, from the target to the source. Set *URL_LEFT
+ and *REV_LEFT to cover the youngest part of this range. */
+ svn_opt_revision_t peg_revision;
+ const char *youngest_url;
+
+ peg_revision.kind = svn_opt_revision_number;
+ peg_revision.value.number = youngest_merged_rev;
+
+ *rev_left = youngest_merged_rev;
+ SVN_ERR(svn_client__derive_location(
+ &youngest_url, NULL,
+ svn_path_url_add_component(source_repos_root,
+ target_repos_rel_path,
+ subpool),
+ &peg_revision, ra_session, NULL, ctx, subpool));
+ *url_left = apr_pstrdup(pool, youngest_url);
}
+
+ svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
@@ -6990,7 +7054,8 @@ svn_client_merge_reintegrate(const char
svn_revnum_t yc_ancestor_rev;
const char *url1, *url2;
svn_revnum_t rev1, rev2;
- svn_mergeinfo_t source_mergeinfo;
+ svn_mergeinfo_t unmerged_to_source_mergeinfo_catalog;
+ svn_error_t *err;
static const svn_wc_entry_callbacks2_t walk_callbacks =
{ get_subtree_mergeinfo_walk_cb, get_mergeinfo_error_handler };
struct get_subtree_mergeinfo_walk_baton wb;
@@ -7060,7 +7125,8 @@ svn_client_merge_reintegrate(const char
ra_session, peg_revision,
source_repos_rel_path, pool));
- SVN_ERR(calculate_left_hand_side(&url1, &rev1, &source_mergeinfo,
+ SVN_ERR(calculate_left_hand_side(&url1, &rev1,
+ &unmerged_to_source_mergeinfo_catalog,
target_repos_rel_path,
wb.subtrees_with_mergeinfo,
rev1,
@@ -7087,26 +7153,36 @@ svn_client_merge_reintegrate(const char
/* Have we actually merged anything to the source from the
target? If so, make sure we've merged a contiguous
prefix. */
- svn_opt_revision_t opt_rev1;
- svn_mergeinfo_t target_mergeinfo, deleted_mergeinfo, added_mergeinfo;
-
- opt_rev1.kind = svn_opt_revision_number;
- opt_rev1.value.number = rev1;
- SVN_ERR(svn_client__get_history_as_mergeinfo(&target_mergeinfo,
- entry->url,
- &opt_rev1,
- rev1,
- yc_ancestor_rev + 1,
- NULL, adm_access, ctx,
- pool));
-
- /* ### TODO(reint): Consider CONSIDER_INHERITANCE parameter... */
- SVN_ERR(svn_mergeinfo_diff(&deleted_mergeinfo, &added_mergeinfo,
- target_mergeinfo, source_mergeinfo, FALSE,
- pool));
+ err = ensure_all_missing_ranges_are_phantoms(
+ ra_session, unmerged_to_source_mergeinfo_catalog, pool);
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_CLIENT_NOT_READY_TO_MERGE)
+ {
+ svn_string_t *source_mergeinfo_cat_string;
- SVN_ERR(ensure_all_missing_ranges_are_phantoms(ra_session,
- deleted_mergeinfo, pool));
+ svn_error_clear(err);
+ err = NULL;
+ SVN_ERR(svn_mergeinfo__catalog_to_formatted_string(
+ &source_mergeinfo_cat_string,
+ unmerged_to_source_mergeinfo_catalog,
+ " ", " Missing ranges: ", pool));
+ return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
+ NULL,
+ _("Reintegrate can only be used if "
+ "revisions %i through %i were "
+ "previously merged from %s to the "
+ "reintegrate source, but this is "
+ "not the case:\n%s"),
+ yc_ancestor_rev + 1, rev2,
+ entry->url,
+ source_mergeinfo_cat_string->data);
+ }
+ else
+ {
+ return err;
+ }
+ }
}
/* Left side: trunk_at_youngest-trunk-rev-merged-to-branch-at-specified-peg-rev
Modified: branches/1.5.x-reintegrate-improvements/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.collab.net/viewvc/svn/branches/1.5.x-reintegrate-improvements/subversion/libsvn_subr/mergeinfo.c?pathrev=34521&r1=34520&r2=34521
==============================================================================
--- branches/1.5.x-reintegrate-improvements/subversion/libsvn_subr/mergeinfo.c Tue Dec 2 06:46:43 2008 (r34520)
+++ branches/1.5.x-reintegrate-improvements/subversion/libsvn_subr/mergeinfo.c Tue Dec 2 07:07:21 2008 (r34521)
@@ -1620,3 +1620,129 @@ svn_mergeinfo__to_formatted_string(svn_s
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
+ svn_revnum_t *oldest_rev,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *pool)
+{
+ *youngest_rev = *oldest_rev = SVN_INVALID_REVNUM;
+ if (mergeinfo)
+ {
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *value;
+ const char *path;
+ apr_array_header_t *rangelist;
+
+ apr_hash_this(hi, &key, NULL, &value);
+ path = key;
+ rangelist = value;
+
+ if (rangelist->nelts)
+ {
+ svn_merge_range_t *range = APR_ARRAY_IDX(rangelist,
+ rangelist->nelts - 1,
+ svn_merge_range_t *);
+ if (!SVN_IS_VALID_REVNUM(*youngest_rev)
+ || (range->end > *youngest_rev))
+ *youngest_rev = range->end;
+
+ range = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
+ if (!SVN_IS_VALID_REVNUM(*oldest_rev)
+ || (range->start < *oldest_rev))
+ *oldest_rev = range->start;
+ }
+ }
+ }
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_mergeinfo__filter_catalog_by_ranges(svn_mergeinfo_catalog_t *filtered_cat,
+ svn_mergeinfo_catalog_t catalog,
+ svn_revnum_t youngest_rev,
+ svn_revnum_t oldest_rev,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+
+ *filtered_cat = apr_hash_make(pool);
+ for (hi = apr_hash_first(pool, catalog);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *val;
+ const char *path;
+
+ svn_mergeinfo_t mergeinfo, filtered_mergeinfo;
+ apr_hash_this(hi, &key, NULL, &val);
+ path = key;
+ mergeinfo = val;
+ SVN_ERR(svn_mergeinfo__filter_mergefino_by_ranges(&filtered_mergeinfo,
+ mergeinfo,
+ youngest_rev,
+ oldest_rev,
+ pool));
+ if (apr_hash_count(filtered_mergeinfo))
+ apr_hash_set(*filtered_cat,
+ apr_pstrdup(pool, path),
+ APR_HASH_KEY_STRING,
+ filtered_mergeinfo);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_mergeinfo__filter_mergefino_by_ranges(svn_mergeinfo_t *filtered_mergeinfo,
+ svn_mergeinfo_t mergeinfo,
+ svn_revnum_t youngest_rev,
+ svn_revnum_t oldest_rev,
+ apr_pool_t *pool)
+{
+ *filtered_mergeinfo = apr_hash_make(pool);
+
+ if (mergeinfo)
+ {
+ apr_hash_index_t *hi;
+ svn_merge_range_t *range = apr_palloc(pool, sizeof(*range));
+ apr_array_header_t *filter_rangelist =
+ apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
+
+ range->start = oldest_rev;
+ range->end = youngest_rev;
+ range->inheritable = TRUE;
+ APR_ARRAY_PUSH(filter_rangelist, svn_merge_range_t *) = range;
+
+ for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *value;
+ const char *path;
+ apr_array_header_t *rangelist;
+
+ apr_hash_this(hi, &key, NULL, &value);
+ path = key;
+ rangelist = value;
+
+ if (rangelist->nelts)
+ {
+ apr_array_header_t *new_rangelist;
+
+ svn_rangelist_intersect(&new_rangelist, rangelist,
+ filter_rangelist, FALSE, pool);
+ if (new_rangelist->nelts)
+ apr_hash_set(*filtered_mergeinfo,
+ apr_pstrdup(pool, path),
+ APR_HASH_KEY_STRING,
+ new_rangelist);
+ }
+ }
+ }
+ return SVN_NO_ERROR;
+}
Modified: branches/1.5.x-reintegrate-improvements/subversion/tests/cmdline/merge_tests.py
URL: http://svn.collab.net/viewvc/svn/branches/1.5.x-reintegrate-improvements/subversion/tests/cmdline/merge_tests.py?pathrev=34521&r1=34520&r2=34521
==============================================================================
--- branches/1.5.x-reintegrate-improvements/subversion/tests/cmdline/merge_tests.py Tue Dec 2 06:46:43 2008 (r34520)
+++ branches/1.5.x-reintegrate-improvements/subversion/tests/cmdline/merge_tests.py Tue Dec 2 07:07:21 2008 (r34521)
@@ -10042,7 +10042,7 @@ def reintegrate_branch_never_merged_to(s
wc_dir = sbox.wc_dir
expected_disk, expected_status = set_up_branch(sbox)
- # Make a change on the branch, to A/mu. Commit in r7.
+ # Make a change on the branch, to A_COPY/mu. Commit in r7.
svntest.main.file_write(os.path.join(wc_dir, "A_COPY", "mu"),
"Changed on the branch.")
expected_output = wc.State(wc_dir, {'A_COPY/mu' : Item(verb='Sending')})
@@ -13918,14 +13918,12 @@ def reintegrate_with_subtree_mergeinfo(s
svntest.verify.verify_outputs("Reintegrate failed but not "
"in the way expected",
err, None,
- "(svn: Reintegrate can only be used if the "
- "revisions previously merged from the "
- "reintegrate target to '.*A_COPY' are the "
- "same, but there are differences:\n)"
- "|( A_COPY\n)"
- "|( /A:2-12\n)"
+ "(svn: Reintegrate can only be used if "
+ "revisions 2 through 15 were previously "
+ "merged from .*/A to the reintegrate source, "
+ "but this is not the case:\n)"
"|( A_COPY/D\n)"
- "|( /A/D:2-7,9-12\n)"
+ "|( Missing ranges: /A/D:8\n)"
"|(\n)"
"|(.*apr_err.*)", # In case of debug build
None,
@@ -13938,14 +13936,15 @@ def reintegrate_with_subtree_mergeinfo(s
# subtree has explicit mergeinfo. Commit this rename as rev N.
#
# B) Synch merge the rename in A) to our 'branch' in rev N+1. The
- # renamed subtree now has explicit mergeinfo.
+ # renamed subtree now has the same explicit mergeinfo on both
+ # the branch and trunk.
#
# C) Make some more changes on the renamed subtree in 'trunk' and
# commit in rev N+2.
#
# D) Synch merge the changes in C) from 'trunk' to 'branch' and commit in
- # rev N+3. The renamed subtree on 'branch' now has explicit mergeinfo
- # from 'trunk' for rev.
+ # rev N+3. The renamed subtree on 'branch' now has additional explicit
+ # mergeinfo decribing the synch merge from trunk_at_N+1 to trunk_at_N+2.
#
# E) Reintegrate 'branch' to 'trunk'. This fails as it appears not all
# of 'trunk' was previously merged to 'branch'
@@ -14031,26 +14030,14 @@ def reintegrate_with_subtree_mergeinfo(s
svntest.actions.run_and_verify_commit(wc_dir, expected_output,
expected_status, None, wc_dir)
- # Reintegrate A_COPY to A, this should work, but is currently failing
- # with an error like this:
- #
- # svn: Reintegrate can only be used if the revisions previously merged
- # from the reintegrate target to 'URL/merge_tests-126/A_COPY' are the
- # same, but there are differences:
- # A_COPY
- # /A:2-18
- # A_COPY/D/gamma_moved
- # /A/D/gamma_moved:17-18
- #
- # Reintegrate currently acts as if A_COPY/D/gamma_moved_at_2-16 hasn't been
- # merged, but A_COPY/D/gamma_moved's natural history,
+ # Reintegrate A_COPY to A, this should work A_COPY/D/gamma_moved's natural
+ # history,
#
# /A/D/gamma:1-15
# /A/D/gamma_moved:16
# /A_COPY/D/gamma_moved:17-19
#
- # already shows that it is fully synched up with trunk. This test is marked
- # as XFail until this is fixed.
+ # shows that it is fully synched up with trunk.
svntest.actions.run_and_verify_svn(None, ["At revision 19.\n"], [], 'up',
wc_dir)
expected_output = wc.State(A_path, {
@@ -14304,8 +14291,8 @@ test_list = [ None,
server_has_mergeinfo),
SkipUnless(no_self_referential_filtering_on_added_path,
server_has_mergeinfo),
- XFail(SkipUnless(reintegrate_with_subtree_mergeinfo,
- server_has_mergeinfo)),
+ SkipUnless(reintegrate_with_subtree_mergeinfo,
+ server_has_mergeinfo),
]
if __name__ == '__main__':
Received on 2008-12-02 17:00:21 CET