Index: subversion/libsvn_repos/load.c =================================================================== --- subversion/libsvn_repos/load.c (revision 936046) +++ subversion/libsvn_repos/load.c (working copy) @@ -277,20 +277,98 @@ { apr_pool_t *subpool = svn_pool_create(pool); apr_hash_t *mergeinfo; + svn_mergeinfo_t outside_mergeinfo; apr_hash_t *final_mergeinfo = apr_hash_make(subpool); apr_hash_index_t *hi; SVN_ERR(svn_mergeinfo_parse(&mergeinfo, initial_val->data, subpool)); - /* Issue #3020: If the dump stream represents only part of a repository, - then mergeinfo in the stream may refer to revisions outside of the - stream. Remove any such invalid ranges before renumbering. */ - SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( - &mergeinfo, mergeinfo, - rb->pb->youngest_old_rev, rb->pb->oldest_old_rev - 1, - TRUE, /* Allow only references to revs that exist in the load stream. */ - subpool, subpool)); + if (apr_hash_count(rb->pb->rev_map) > 0) + { + /* Find any mergeinfo which predates the start of the dump load stream. */ + SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( + &outside_mergeinfo, mergeinfo, + rb->pb->youngest_old_rev, rb->pb->oldest_old_rev - 1, + FALSE, /* Allow only references to revs that exist in the load stream. */ + subpool, subpool)); + /* Issue #3020: If the dump stream represents only part of a repository, + then mergeinfo in the stream may refer to revisions outside of the + stream. Remove any such invalid ranges before renumbering. */ + SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( + &mergeinfo, mergeinfo, + rb->pb->youngest_old_rev, rb->pb->oldest_old_rev - 1, + TRUE, /* Allow only references to revs that exist in the load stream. */ + subpool, subpool)); + } + else /* No mapping, so this is the first rev loaded. */ + { + outside_mergeinfo = mergeinfo; + mergeinfo = apr_hash_make(subpool); + } + /* Check the mergeinfo that predates the load stream. If it refers + to path-revs that exist in the target repository keep it, + otherwise drop it. */ + if (apr_hash_count(outside_mergeinfo)) + { + svn_mergeinfo_t all_keeper_mergeinfo = apr_hash_make(subpool); + + for (hi = apr_hash_first(subpool, outside_mergeinfo); + hi; + hi = apr_hash_next(hi)) + { + const char *merge_source = svn__apr_hash_index_key(hi); + apr_array_header_t *rangelist = svn__apr_hash_index_val(hi); + svn_node_kind_t merge_source_kind; + struct parse_baton *pb = rb->pb; + int i; + svn_fs_root_t *root_p; + svn_merge_range_t *range; + + for (i = 0; i < rangelist->nelts; i++) + { + int y; + + range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); + + for (y = range->start + 1; y <= range->end; y++) + { + svn_error_t *err = svn_fs_revision_root(&root_p, pb->fs, + y, subpool); + if (err) + { + if (err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION) + { + svn_error_clear(err); + continue; + } + return err; + } + + SVN_ERR(svn_fs_check_path(&merge_source_kind, + rb->txn_root, + merge_source, subpool)); + if (merge_source_kind != svn_node_none) + { + apr_array_header_t *keeper_rangelist = + svn_rangelist__initialize(range->start, range->end, + range->inheritable, + subpool); + svn_mergeinfo_t keeper_mergeinfo = + apr_hash_make(subpool); + apr_hash_set(keeper_mergeinfo, merge_source, + APR_HASH_KEY_STRING, keeper_rangelist); + SVN_ERR(svn_mergeinfo_merge(all_keeper_mergeinfo, + keeper_mergeinfo, + subpool)); + } + } + } + } + if (apr_hash_count(all_keeper_mergeinfo)) + SVN_ERR(svn_mergeinfo_merge(mergeinfo, all_keeper_mergeinfo, subpool)); + } + for (hi = apr_hash_first(subpool, mergeinfo); hi; hi = apr_hash_next(hi)) { const char *merge_source; @@ -1250,32 +1328,22 @@ if (strcmp(name, SVN_PROP_MERGEINFO) == 0) { - /* If we haven't yet committed any revisions then *any* mergeinfo - will refer to the wrong revisions or revisions that don't exist. - Either way none of this mergeinfo can be valid, so remove it all. */ - if (apr_hash_count(rb->pb->rev_map) == 0) + /* Renumber mergeinfo as appropriate. */ + svn_string_t *renumbered_mergeinfo; + + SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, value, rb, + nb->pool)); + value = renumbered_mergeinfo; + if (parent_dir) { - value = NULL; + /* Prefix the merge source paths with PARENT_DIR. */ + /* ASSUMPTION: All source paths are included in the dump + stream. */ + svn_string_t *mergeinfo_val; + SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value, + parent_dir, nb->pool)); + value = mergeinfo_val; } - else - { - /* Renumber mergeinfo as appropriate. */ - svn_string_t *renumbered_mergeinfo; - - SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, value, rb, - nb->pool)); - value = renumbered_mergeinfo; - if (parent_dir) - { - /* Prefix the merge source paths with PARENT_DIR. */ - /* ASSUMPTION: All source paths are included in the dump - stream. */ - svn_string_t *mergeinfo_val; - SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value, - parent_dir, nb->pool)); - value = mergeinfo_val; - } - } } return svn_fs_change_node_prop(rb->txn_root, nb->path,