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 2015/10/14 08:38:16 UTC

svn commit: r1708550 [2/2] - in /subversion/branches/move-tracking-2/subversion: include/private/ libsvn_delta/ svnmover/ tests/cmdline/ tests/cmdline/svntest/

Copied: subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_nested.c (from r1708080, subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c)
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_nested.c?p2=subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_nested.c&p1=subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c&r1=1708080&r2=1708550&rev=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_nested.c Wed Oct 14 06:38:16 2015
@@ -1,5 +1,5 @@
 /*
- * branch.c : Element-Based Branching and Move Tracking.
+ * branch_nested.c : Nested Branches
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -29,513 +29,145 @@
 #include "svn_hash.h"
 #include "svn_iter.h"
 
-#include "private/svn_element.h"
-#include "private/svn_branch.h"
-#include "private/svn_sorts_private.h"
+#include "private/svn_branch_nested.h"
+#include "private/svn_branch_repos.h"
 #include "svn_private_config.h"
 
 
-/* Is EID allocated (no matter whether an element with this id exists)? */
-#define EID_IS_ALLOCATED(branch, eid) \
-  ((eid) >= (branch)->rev_root->first_eid && (eid) < (branch)->rev_root->next_eid)
-
-#define IS_BRANCH_ROOT_EID(branch, eid) \
-  ((eid) == (branch)->root_eid)
-
-/* Is BRANCH1 the same branch as BRANCH2? Compare by full branch-ids; don't
-   require identical branch objects. */
-#define BRANCH_IS_SAME_BRANCH(branch1, branch2, scratch_pool) \
-  (strcmp(svn_branch_get_id(branch1, scratch_pool), \
-          svn_branch_get_id(branch2, scratch_pool)) == 0)
-
-/* Is BRANCH1 an immediate child of BRANCH2? Compare by full branch-ids; don't
-   require identical branch objects. */
-#define BRANCH_IS_CHILD_OF_BRANCH(branch1, branch2, scratch_pool) \
-  ((branch1)->outer_branch && \
-   BRANCH_IS_SAME_BRANCH((branch1)->outer_branch, branch2, scratch_pool))
-
-svn_branch_revision_root_t *
-svn_branch_revision_root_create(svn_branch_repos_t *repos,
-                                svn_revnum_t rev,
-                                svn_revnum_t base_rev,
-                                apr_pool_t *result_pool)
-{
-  svn_branch_revision_root_t *rev_root
-    = apr_pcalloc(result_pool, sizeof(*rev_root));
-
-  rev_root->repos = repos;
-  rev_root->rev = rev;
-  rev_root->base_rev = base_rev;
-  rev_root->root_branches = apr_array_make(result_pool, 0, sizeof(void *));
-  rev_root->branches = svn_array_make(result_pool);
-  return rev_root;
-}
-
-int
-svn_branch_txn_new_eid(svn_branch_revision_root_t *rev_root)
-{
-  int eid = (rev_root->first_eid < 0) ? rev_root->first_eid - 1 : -2;
-
-  rev_root->first_eid = eid;
-  return eid;
+void
+svn_branch_get_outer_branch_and_eid(svn_branch_state_t **outer_branch_p,
+                                    int *outer_eid_p,
+                                    const svn_branch_state_t *branch,
+                                    apr_pool_t *scratch_pool)
+{
+  const char *outer_bid;
+
+  svn_branch_id_unnest(&outer_bid, outer_eid_p, branch->bid, scratch_pool);
+  *outer_branch_p = NULL;
+  if (outer_bid)
+    {
+      *outer_branch_p
+        = svn_branch_revision_root_get_branch_by_id(branch->rev_root, outer_bid,
+                                                    scratch_pool);
+    }
 }
 
-/* Change txn-local EIDs (negative integers) in BRANCH to revision EIDs, by
- * assigning a new revision-EID (positive integer) for each one.
- */
-static svn_error_t *
-branch_finalize_eids(svn_branch_state_t *branch,
-                     int mapping_offset,
-                     apr_pool_t *scratch_pool)
+const char *
+svn_branch_get_root_rrpath(const svn_branch_state_t *branch,
+                           apr_pool_t *result_pool)
 {
-  apr_hash_index_t *hi;
+  svn_branch_state_t *outer_branch;
+  int outer_eid;
+  const char *root_rrpath;
 
-  if (branch->root_eid < -1)
+  svn_branch_get_outer_branch_and_eid(&outer_branch, &outer_eid, branch,
+                                      result_pool);
+  if (outer_branch)
     {
-      branch->root_eid = mapping_offset - branch->root_eid;
+      root_rrpath
+        = svn_branch_get_rrpath_by_eid(outer_branch, outer_eid, result_pool);
     }
-
-  if (branch->outer_eid < -1)
+  else
     {
-      branch->outer_eid = mapping_offset - branch->outer_eid;
+      root_rrpath = "";
     }
 
-  for (hi = apr_hash_first(scratch_pool, branch->e_map);
-       hi; hi = apr_hash_next(hi))
-    {
-      int old_eid = svn_int_hash_this_key(hi);
-      svn_branch_el_rev_content_t *element = apr_hash_this_val(hi);
-
-      if (old_eid < -1)
-        {
-          int new_eid = mapping_offset - old_eid;
-
-          svn_int_hash_set(branch->e_map, old_eid, NULL);
-          svn_int_hash_set(branch->e_map, new_eid, element);
-        }
-      if (element->parent_eid < -1)
-        {
-          element->parent_eid = mapping_offset - element->parent_eid;
-        }
-    }
-  return SVN_NO_ERROR;
+  SVN_ERR_ASSERT_NO_RETURN(root_rrpath);
+  return root_rrpath;
 }
 
-svn_error_t *
-svn_branch_txn_finalize_eids(svn_branch_revision_root_t *txn,
-                             apr_pool_t *scratch_pool)
+const char *
+svn_branch_get_rrpath_by_eid(const svn_branch_state_t *branch,
+                             int eid,
+                             apr_pool_t *result_pool)
 {
-  int n_txn_eids = (-1) - txn->first_eid;
-  int mapping_offset;
-  int i;
-
-  if (txn->first_eid == 0)
-    return SVN_NO_ERROR;
-
-  /* mapping from txn-local (negative) EID to committed (positive) EID is:
-       txn_local_eid == -2  =>  committed_eid := (txn.next_eid + 0)
-       txn_local_eid == -3  =>  committed_eid := (txn.next_eid + 1) ... */
-  mapping_offset = txn->next_eid - 2;
+  const char *path = svn_branch_get_path_by_eid(branch, eid, result_pool);
+  const char *rrpath = NULL;
 
-  for (i = 0; i < txn->branches->nelts; i++)
+  if (path)
     {
-      svn_branch_state_t *b = APR_ARRAY_IDX(txn->branches, i, void *);
-
-      SVN_ERR(branch_finalize_eids(b, mapping_offset, scratch_pool));
+      rrpath = svn_relpath_join(svn_branch_get_root_rrpath(branch, result_pool),
+                                path, result_pool);
     }
-
-  txn->next_eid += n_txn_eids;
-  txn->first_eid = 0;
-  return SVN_NO_ERROR;
-}
-
-svn_branch_state_t *
-svn_branch_revision_root_get_root_branch(svn_branch_revision_root_t *rev_root,
-                                         int top_branch_num)
-{
-  if (top_branch_num < 0 || top_branch_num >= rev_root->root_branches->nelts)
-    return NULL;
-  return APR_ARRAY_IDX(rev_root->root_branches, top_branch_num, void *);
-
-}
-
-const apr_array_header_t *
-svn_branch_revision_root_get_branches(svn_branch_revision_root_t *rev_root,
-                                      apr_pool_t *result_pool)
-{
-  return rev_root->branches;
+  return rrpath;
 }
 
 svn_branch_state_t *
-svn_branch_revision_root_get_branch_by_id(const svn_branch_revision_root_t *rev_root,
-                                          const char *branch_id,
-                                          apr_pool_t *scratch_pool)
+svn_branch_get_subbranch_at_eid(svn_branch_state_t *branch,
+                                int eid,
+                                apr_pool_t *scratch_pool)
 {
-  SVN_ITER_T(svn_branch_state_t) *bi;
-  svn_branch_state_t *branch = NULL;
+  svn_branch_el_rev_content_t *element = svn_branch_get_element(branch, eid);
 
-  for (SVN_ARRAY_ITER(bi, rev_root->branches, scratch_pool))
+  if (element && element->payload->is_subbranch_root)
     {
-      svn_branch_state_t *b = bi->val;
+      const char *branch_id = svn_branch_get_id(branch, scratch_pool);
+      const char *subbranch_id = svn_branch_id_nest(branch_id, eid,
+                                                    scratch_pool);
 
-      if (strcmp(svn_branch_get_id(b, scratch_pool), branch_id) == 0)
-        {
-          branch = b;
-          break;
-        }
+      return svn_branch_revision_root_get_branch_by_id(branch->rev_root,
+                                                       subbranch_id,
+                                                       scratch_pool);
     }
-  return branch;
+  return NULL;
 }
 
-static void
-branch_validate_element(const svn_branch_state_t *branch,
-                        int eid,
-                        const svn_branch_el_rev_content_t *element);
-
-/* Assert BRANCH satisfies all its invariants.
- */
-static void
-assert_branch_state_invariants(const svn_branch_state_t *branch,
-                               apr_pool_t *scratch_pool)
+apr_array_header_t *
+svn_branch_get_immediate_subbranches(svn_branch_state_t *branch,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool)
 {
+  svn_array_t *subbranches = svn_array_make(result_pool);
+  const char *branch_id = svn_branch_get_id(branch, scratch_pool);
   apr_hash_index_t *hi;
 
-  assert(branch->rev_root);
-  if (branch->outer_branch)
-    {
-      assert(EID_IS_ALLOCATED(branch, branch->outer_eid));
-    }
-  assert(branch->outer_eid != -1);
-  assert(branch->e_map);
-
-  /* Validate elements in the map */
   for (hi = apr_hash_first(scratch_pool, branch->e_map);
        hi; hi = apr_hash_next(hi))
     {
-      branch_validate_element(branch, svn_int_hash_this_key(hi),
-                              apr_hash_this_val(hi));
-    }
-}
-
-svn_branch_state_t *
-svn_branch_state_create(svn_branch_rev_bid_t *predecessor,
-                        int root_eid,
-                        svn_branch_revision_root_t *rev_root,
-                        svn_branch_state_t *outer_branch,
-                        int outer_eid,
-                        apr_pool_t *result_pool)
-{
-  svn_branch_state_t *b = apr_pcalloc(result_pool, sizeof(*b));
-
-  b->predecessor = svn_branch_rev_bid_dup(predecessor, result_pool);
-  b->root_eid = root_eid;
-  b->rev_root = rev_root;
-  b->e_map = apr_hash_make(result_pool);
-  b->outer_branch = outer_branch;
-  b->outer_eid = outer_eid;
-  assert_branch_state_invariants(b, result_pool);
-  return b;
-}
-
-svn_branch_el_rev_id_t *
-svn_branch_el_rev_id_create(svn_branch_state_t *branch,
-                            int eid,
-                            svn_revnum_t rev,
-                            apr_pool_t *result_pool)
-{
-  svn_branch_el_rev_id_t *id = apr_palloc(result_pool, sizeof(*id));
-
-  id->branch = branch;
-  id->eid = eid;
-  id->rev = rev;
-  return id;
-}
-
-svn_branch_rev_bid_eid_t *
-svn_branch_rev_bid_eid_create(svn_revnum_t rev,
-                              const char *branch_id,
-                              int eid,
-                              apr_pool_t *result_pool)
-{
-  svn_branch_rev_bid_eid_t *id = apr_palloc(result_pool, sizeof(*id));
-
-  id->bid = branch_id;
-  id->eid = eid;
-  id->rev = rev;
-  return id;
-}
-
-svn_branch_rev_bid_eid_t *
-svn_branch_rev_bid_eid_dup(const svn_branch_rev_bid_eid_t *old_id,
-                           apr_pool_t *result_pool)
-{
-  svn_branch_rev_bid_eid_t *id;
-
-  if (! old_id)
-    return NULL;
-
-  id = apr_pmemdup(result_pool, old_id, sizeof(*id));
-  id->bid = apr_pstrdup(result_pool, old_id->bid);
-  return id;
-}
-
-svn_branch_rev_bid_t *
-svn_branch_rev_bid_create(svn_revnum_t rev,
-                          const char *branch_id,
-                          apr_pool_t *result_pool)
-{
-  svn_branch_rev_bid_t *id = apr_palloc(result_pool, sizeof(*id));
-
-  id->bid = branch_id;
-  id->rev = rev;
-  return id;
-}
-
-svn_branch_rev_bid_t *
-svn_branch_rev_bid_dup(const svn_branch_rev_bid_t *old_id,
-                       apr_pool_t *result_pool)
-{
-  svn_branch_rev_bid_t *id;
-
-  if (! old_id)
-    return NULL;
-
-  id = apr_pmemdup(result_pool, old_id, sizeof(*id));
-  id->bid = apr_pstrdup(result_pool, old_id->bid);
-  return id;
-}
-
-svn_branch_el_rev_content_t *
-svn_branch_el_rev_content_create(svn_branch_eid_t parent_eid,
-                                 const char *name,
-                                 const svn_element_payload_t *payload,
-                                 apr_pool_t *result_pool)
-{
-  svn_branch_el_rev_content_t *content
-     = apr_palloc(result_pool, sizeof(*content));
-
-  content->parent_eid = parent_eid;
-  content->name = apr_pstrdup(result_pool, name);
-  content->payload = svn_element_payload_dup(payload, result_pool);
-  return content;
-}
-
-svn_branch_el_rev_content_t *
-svn_branch_el_rev_content_dup(const svn_branch_el_rev_content_t *old,
-                              apr_pool_t *result_pool)
-{
-  svn_branch_el_rev_content_t *content
-     = apr_pmemdup(result_pool, old, sizeof(*content));
-
-  content->name = apr_pstrdup(result_pool, old->name);
-  content->payload = svn_element_payload_dup(old->payload, result_pool);
-  return content;
-}
-
-svn_boolean_t
-svn_branch_el_rev_content_equal(const svn_branch_el_rev_content_t *content_left,
-                                const svn_branch_el_rev_content_t *content_right,
-                                apr_pool_t *scratch_pool)
-{
-  if (!content_left && !content_right)
-    {
-      return TRUE;
-    }
-  else if (!content_left || !content_right)
-    {
-      return FALSE;
-    }
-
-  if (content_left->parent_eid != content_right->parent_eid)
-    {
-      return FALSE;
-    }
-  if (strcmp(content_left->name, content_right->name) != 0)
-    {
-      return FALSE;
-    }
-  if (! svn_element_payload_equal(content_left->payload, content_right->payload,
-                                  scratch_pool))
-    {
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-
-/*
- * ========================================================================
- * Branch mappings
- * ========================================================================
- */
-
-svn_branch_subtree_t *
-svn_branch_subtree_create(apr_hash_t *e_map,
-                          int root_eid,
-                          apr_pool_t *result_pool)
-{
-  svn_branch_subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree));
-
-  subtree->e_map = e_map ? apr_hash_copy(result_pool, e_map)
-                         : apr_hash_make(result_pool);
-  subtree->root_eid = root_eid;
-  subtree->subbranches = apr_hash_make(result_pool);
-  return subtree;
-}
-
-svn_branch_subtree_t *
-svn_branch_subtree_get_subbranch_at_eid(svn_branch_subtree_t *subtree,
-                                        int eid,
-                                        apr_pool_t *result_pool)
-{
-  subtree = svn_int_hash_get(subtree->subbranches, eid);
-
-  return subtree;
-}
-
-/* Validate that ELEMENT is suitable for a mapping of BRANCH:EID.
- * ELEMENT->payload may be null.
- */
-static void
-branch_validate_element(const svn_branch_state_t *branch,
-                        int eid,
-                        const svn_branch_el_rev_content_t *element)
-{
-  SVN_ERR_ASSERT_NO_RETURN(element);
+      int eid = svn_int_hash_this_key(hi);
+      svn_branch_el_rev_content_t *element = apr_hash_this_val(hi);
 
-  /* Parent EID must be valid and different from this element's EID, or -1
-     iff this is the branch root element. */
-  SVN_ERR_ASSERT_NO_RETURN(
-    IS_BRANCH_ROOT_EID(branch, eid)
-    ? (element->parent_eid == -1)
-    : (element->parent_eid != eid
-       && EID_IS_ALLOCATED(branch, element->parent_eid)));
-
-  /* Element name must be given, and empty iff EID is the branch root. */
-  SVN_ERR_ASSERT_NO_RETURN(
-    element->name
-    && IS_BRANCH_ROOT_EID(branch, eid) == (*element->name == '\0'));
+      if (element->payload->is_subbranch_root)
+        {
+          const char *subbranch_id
+            = svn_branch_id_nest(branch_id, eid, scratch_pool);
+          svn_branch_state_t *subbranch
+            = svn_branch_revision_root_get_branch_by_id(branch->rev_root,
+                                                        subbranch_id,
+                                                        scratch_pool);
 
-  SVN_ERR_ASSERT_NO_RETURN(svn_element_payload_invariants(element->payload));
-  if (element->payload->is_subbranch_root)
-    {
-      /* a subbranch root element must not be the branch root element */
-      SVN_ERR_ASSERT_NO_RETURN(eid != branch->root_eid);
+          SVN_ARRAY_PUSH(subbranches) = subbranch;
+        }
     }
+  return subbranches;
 }
 
-apr_hash_t *
-svn_branch_get_elements(svn_branch_state_t *branch)
-{
-  return branch->e_map;
-}
-
-svn_branch_el_rev_content_t *
-svn_branch_get_element(const svn_branch_state_t *branch,
-                       int eid)
-{
-  svn_branch_el_rev_content_t *element;
-
-  SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid));
-
-  element = svn_int_hash_get(branch->e_map, eid);
-
-  if (element)
-    branch_validate_element(branch, eid, element);
-  return element;
-}
-
-/* In BRANCH, set element EID to ELEMENT.
- *
- * If ELEMENT is null, delete element EID. Otherwise, ELEMENT->payload may be
- * null meaning it is a subbranch-root.
- *
- * Assume ELEMENT is already allocated with sufficient lifetime.
- */
-static void
-branch_map_set(svn_branch_state_t *branch,
-               int eid,
-               svn_branch_el_rev_content_t *element)
-{
-  apr_pool_t *map_pool = apr_hash_pool_get(branch->e_map);
-
-  SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid));
-  if (element)
-    branch_validate_element(branch, eid, element);
-
-  svn_int_hash_set(branch->e_map, eid, element);
-  assert_branch_state_invariants(branch, map_pool);
-}
-
-void
-svn_branch_delete_element(svn_branch_state_t *branch,
-                          int eid)
-{
-  SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid));
-
-  branch_map_set(branch, eid, NULL);
-}
-
-void
-svn_branch_update_element(svn_branch_state_t *branch,
-                          int eid,
-                          svn_branch_eid_t new_parent_eid,
-                          const char *new_name,
-                          const svn_element_payload_t *new_payload)
-{
-  apr_pool_t *map_pool = apr_hash_pool_get(branch->e_map);
-  svn_branch_el_rev_content_t *element
-    = svn_branch_el_rev_content_create(new_parent_eid, new_name, new_payload,
-                                       map_pool);
-
-  /* EID must be a valid element id */
-  SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid));
-  /* NEW_PAYLOAD must be specified, either in full or by reference */
-  SVN_ERR_ASSERT_NO_RETURN(new_payload);
-
-  /* Insert the new version */
-  branch_map_set(branch, eid, element);
-}
-
-static void
-map_purge_orphans(apr_hash_t *e_map,
-                  int root_eid,
-                  apr_pool_t *scratch_pool);
-
 svn_branch_subtree_t *
-svn_branch_get_subtree(const svn_branch_state_t *branch,
+svn_branch_get_subtree(svn_branch_state_t *branch,
                        int eid,
                        apr_pool_t *result_pool)
 {
   svn_branch_subtree_t *new_subtree;
-  svn_branch_el_rev_content_t *subtree_root_element;
   SVN_ITER_T(svn_branch_state_t) *bi;
 
   SVN_BRANCH_SEQUENCE_POINT(branch);
 
-  new_subtree = svn_branch_subtree_create(branch->e_map, eid,
-                                          result_pool);
-  new_subtree->predecessor = svn_branch_rev_bid_dup(branch->predecessor,
-                                                    result_pool);
-
-  /* Purge orphans */
-  map_purge_orphans(new_subtree->e_map, new_subtree->root_eid, result_pool);
-
-  /* Remove 'parent' and 'name' attributes from subtree root element */
-  subtree_root_element
-    = svn_int_hash_get(new_subtree->e_map, new_subtree->root_eid);
-  svn_int_hash_set(new_subtree->e_map, new_subtree->root_eid,
-                   svn_branch_el_rev_content_create(
-                     -1, "", subtree_root_element->payload, result_pool));
+  new_subtree
+    = svn_branch_get_subtree_n(branch, eid, result_pool);
 
   /* Add subbranches */
   for (SVN_ARRAY_ITER(bi, svn_branch_get_immediate_subbranches(
                             branch, result_pool, result_pool), result_pool))
     {
       svn_branch_state_t *subbranch = bi->val;
-      const char *subbranch_relpath_in_subtree
-        = svn_branch_subtree_get_path_by_eid(new_subtree, subbranch->outer_eid,
+      const char *outer_bid;
+      int outer_eid;
+      const char *subbranch_relpath_in_subtree;
+
+      svn_branch_id_unnest(&outer_bid, &outer_eid, subbranch->bid,
+                           bi->iterpool);
+      subbranch_relpath_in_subtree
+        = svn_branch_subtree_get_path_by_eid(new_subtree, outer_eid,
                                              bi->iterpool);
 
       /* Is it pathwise at or below EID? If so, add it into the subtree. */
@@ -544,285 +176,19 @@ svn_branch_get_subtree(const svn_branch_
           svn_branch_subtree_t *this_subtree
             = svn_branch_get_subtree(subbranch, subbranch->root_eid, result_pool);
 
-          svn_int_hash_set(new_subtree->subbranches, subbranch->outer_eid,
+          svn_int_hash_set(new_subtree->subbranches, outer_eid,
                            this_subtree);
         }
     }
   return new_subtree;
 }
 
-/* Purge entries from E_MAP that don't connect, via parent directory hierarchy,
- * to ROOT_EID. In other words, remove elements that have been implicitly
- * deleted.
- *
- * ROOT_EID must be present in E_MAP.
- *
- * ### Does not detect cycles: current implementation will not purge a cycle
- *     that is disconnected from ROOT_EID. This could be a problem.
- */
-static void
-map_purge_orphans(apr_hash_t *e_map,
-                  int root_eid,
-                  apr_pool_t *scratch_pool)
-{
-  apr_hash_index_t *hi;
-  svn_boolean_t changed;
-
-  SVN_ERR_ASSERT_NO_RETURN(svn_int_hash_get(e_map, root_eid));
-
-  do
-    {
-      changed = FALSE;
-
-      for (hi = apr_hash_first(scratch_pool, e_map);
-           hi; hi = apr_hash_next(hi))
-        {
-          int this_eid = svn_int_hash_this_key(hi);
-          svn_branch_el_rev_content_t *this_element = apr_hash_this_val(hi);
-
-          if (this_eid != root_eid)
-            {
-              svn_branch_el_rev_content_t *parent_element
-                = svn_int_hash_get(e_map, this_element->parent_eid);
-
-              /* Purge if parent is deleted */
-              if (! parent_element)
-                {
-                  SVN_DBG(("purge orphan: e%d", this_eid));
-                  svn_int_hash_set(e_map, this_eid, NULL);
-                  changed = TRUE;
-                }
-              else
-                SVN_ERR_ASSERT_NO_RETURN(
-                  ! parent_element->payload->is_subbranch_root);
-            }
-        }
-    }
-  while (changed);
-}
-
-void
-svn_branch_purge_r(svn_branch_state_t *branch,
-                   apr_pool_t *scratch_pool)
-{
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  /* first, remove elements that have no parent element */
-  map_purge_orphans(branch->e_map, branch->root_eid, scratch_pool);
-
-  /* second, remove subbranches that have no subbranch-root element */
-  for (SVN_ARRAY_ITER(bi, svn_branch_get_immediate_subbranches(
-                            branch, scratch_pool, scratch_pool), scratch_pool))
-    {
-      svn_branch_state_t *b = bi->val;
-
-      if (svn_branch_get_element(branch, b->outer_eid))
-        {
-          svn_branch_purge_r(b, bi->iterpool);
-        }
-      else
-        {
-          svn_branch_delete_branch_r(b, bi->iterpool);
-        }
-    }
-}
-
-const char *
-svn_branch_get_root_rrpath(const svn_branch_state_t *branch,
-                           apr_pool_t *result_pool)
-{
-  const char *root_rrpath;
-
-  if (branch->outer_branch)
-    {
-      root_rrpath
-        = svn_branch_get_rrpath_by_eid(branch->outer_branch, branch->outer_eid,
-                                       result_pool);
-    }
-  else
-    {
-      root_rrpath = "";
-    }
-
-  SVN_ERR_ASSERT_NO_RETURN(root_rrpath);
-  return root_rrpath;
-}
-
-const char *
-svn_branch_subtree_get_path_by_eid(const svn_branch_subtree_t *subtree,
-                                   int eid,
-                                   apr_pool_t *result_pool)
-{
-  const char *path = "";
-  svn_branch_el_rev_content_t *element;
-
-  for (; eid != subtree->root_eid; eid = element->parent_eid)
-    {
-      element = svn_int_hash_get(subtree->e_map, eid);
-      if (! element)
-        return NULL;
-      path = svn_relpath_join(element->name, path, result_pool);
-    }
-  SVN_ERR_ASSERT_NO_RETURN(eid == subtree->root_eid);
-  return path;
-}
-
-const char *
-svn_branch_get_path_by_eid(const svn_branch_state_t *branch,
-                           int eid,
-                           apr_pool_t *result_pool)
-{
-  const char *path = "";
-  svn_branch_el_rev_content_t *element;
-
-  SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid));
-
-  for (; ! IS_BRANCH_ROOT_EID(branch, eid); eid = element->parent_eid)
-    {
-      element = svn_branch_get_element(branch, eid);
-      if (! element)
-        return NULL;
-      path = svn_relpath_join(element->name, path, result_pool);
-    }
-  SVN_ERR_ASSERT_NO_RETURN(IS_BRANCH_ROOT_EID(branch, eid));
-  return path;
-}
-
-const char *
-svn_branch_get_rrpath_by_eid(const svn_branch_state_t *branch,
-                             int eid,
-                             apr_pool_t *result_pool)
-{
-  const char *path = svn_branch_get_path_by_eid(branch, eid, result_pool);
-  const char *rrpath = NULL;
-
-  if (path)
-    {
-      rrpath = svn_relpath_join(svn_branch_get_root_rrpath(branch, result_pool),
-                                path, result_pool);
-    }
-  return rrpath;
-}
-
-int
-svn_branch_get_eid_by_path(const svn_branch_state_t *branch,
-                           const char *path,
-                           apr_pool_t *scratch_pool)
-{
-  apr_hash_index_t *hi;
-
-  /* ### This is a crude, linear search */
-  for (hi = apr_hash_first(scratch_pool, branch->e_map);
-       hi; hi = apr_hash_next(hi))
-    {
-      int eid = svn_int_hash_this_key(hi);
-      const char *this_path = svn_branch_get_path_by_eid(branch, eid,
-                                                         scratch_pool);
-
-      if (! this_path)
-        {
-          /* Mapping is not complete; this element is in effect not present. */
-          continue;
-        }
-      if (strcmp(path, this_path) == 0)
-        {
-          return eid;
-        }
-    }
-
-  return -1;
-}
-
-int
-svn_branch_get_eid_by_rrpath(svn_branch_state_t *branch,
-                             const char *rrpath,
-                             apr_pool_t *scratch_pool)
-{
-  const char *path = svn_relpath_skip_ancestor(svn_branch_get_root_rrpath(
-                                                 branch, scratch_pool),
-                                               rrpath);
-  int eid = -1;
-
-  if (path)
-    {
-      eid = svn_branch_get_eid_by_path(branch, path, scratch_pool);
-    }
-  return eid;
-}
-
 svn_error_t *
-svn_branch_map_add_subtree(svn_branch_state_t *to_branch,
-                           int to_eid,
-                           svn_branch_eid_t new_parent_eid,
-                           const char *new_name,
-                           svn_branch_subtree_t new_subtree,
-                           apr_pool_t *scratch_pool)
+svn_branch_instantiate_elements_r(svn_branch_state_t *to_branch,
+                                  svn_branch_subtree_t elements,
+                                  apr_pool_t *scratch_pool)
 {
-  apr_hash_index_t *hi;
-  svn_branch_el_rev_content_t *new_root_content;
-
-  if (new_subtree.subbranches && apr_hash_count(new_subtree.subbranches))
-    {
-      return svn_error_createf(SVN_ERR_BRANCHING, NULL,
-                               _("Adding or copying a subtree containing "
-                                 "subbranches is not implemented"));
-    }
-
-  /* Get a new EID for the root element, if not given. */
-  if (to_eid == -1)
-    {
-      to_eid = svn_branch_txn_new_eid(to_branch->rev_root);
-    }
-
-  /* Create the new subtree root element */
-  new_root_content = svn_int_hash_get(new_subtree.e_map, new_subtree.root_eid);
-  svn_branch_update_element(to_branch, to_eid,
-                              new_parent_eid, new_name,
-                              new_root_content->payload);
-
-  /* Process its immediate children */
-  for (hi = apr_hash_first(scratch_pool, new_subtree.e_map);
-       hi; hi = apr_hash_next(hi))
-    {
-      int this_from_eid = svn_int_hash_this_key(hi);
-      svn_branch_el_rev_content_t *from_element = apr_hash_this_val(hi);
-
-      if (from_element->parent_eid == new_subtree.root_eid)
-        {
-          svn_branch_subtree_t this_subtree;
-
-          /* Recurse. (We don't try to check whether it's a directory node,
-             as we might not have the node kind in the map.) */
-          this_subtree.e_map = new_subtree.e_map;
-          this_subtree.root_eid = this_from_eid;
-          this_subtree.subbranches = apr_hash_make(scratch_pool);
-          SVN_ERR(svn_branch_map_add_subtree(to_branch, -1 /*to_eid*/,
-                                             to_eid, from_element->name,
-                                             this_subtree, scratch_pool));
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_branch_instantiate_elements(svn_branch_state_t *to_branch,
-                                svn_branch_subtree_t elements,
-                                apr_pool_t *scratch_pool)
-{
-  apr_hash_index_t *hi;
-
-  /* Instantiate all the elements of NEW_SUBTREE */
-  for (hi = apr_hash_first(scratch_pool, elements.e_map);
-       hi; hi = apr_hash_next(hi))
-    {
-      int this_eid = svn_int_hash_this_key(hi);
-      svn_branch_el_rev_content_t *this_element = apr_hash_this_val(hi);
-
-      branch_map_set(to_branch, this_eid,
-                     svn_branch_el_rev_content_dup(
-                       this_element, apr_hash_pool_get(to_branch->e_map)));
-    }
+  SVN_ERR(svn_branch_instantiate_elements(to_branch, elements, scratch_pool));
 
   /* branch any subbranches */
   {
@@ -832,477 +198,26 @@ svn_branch_instantiate_elements(svn_bran
       {
         int this_outer_eid = svn_int_hash_this_key(bi->apr_hi);
         svn_branch_subtree_t *this_subtree = bi->val;
+        const char *new_branch_id;
         svn_branch_state_t *new_branch;
 
         /* branch this subbranch into NEW_BRANCH (recursing) */
-        new_branch = svn_branch_add_new_branch(to_branch->rev_root,
+        new_branch_id = svn_branch_id_nest(to_branch->bid, this_outer_eid,
+                                           bi->iterpool);
+        new_branch = svn_branch_add_new_branch(new_branch_id,
+                                               to_branch->rev_root,
                                                this_subtree->predecessor,
-                                               to_branch, this_outer_eid,
                                                this_subtree->root_eid,
                                                bi->iterpool);
 
-        SVN_ERR(svn_branch_instantiate_elements(new_branch, *this_subtree,
-                                                bi->iterpool));
+        SVN_ERR(svn_branch_instantiate_elements_r(new_branch, *this_subtree,
+                                                  bi->iterpool));
       }
   }
 
   return SVN_NO_ERROR;
 }
 
-apr_array_header_t *
-svn_branch_get_immediate_subbranches(const svn_branch_state_t *branch,
-                                     apr_pool_t *result_pool,
-                                     apr_pool_t *scratch_pool)
-{
-  svn_array_t *subbranches = svn_array_make(result_pool);
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  for (SVN_ARRAY_ITER(bi, branch->rev_root->branches, scratch_pool))
-    {
-      /* Is it an immediate child? */
-      if (bi->val->outer_branch == branch)
-        SVN_ARRAY_PUSH(subbranches) = bi->val;
-    }
-  return subbranches;
-}
-
-svn_branch_state_t *
-svn_branch_get_subbranch_at_eid(svn_branch_state_t *branch,
-                                int eid,
-                                apr_pool_t *scratch_pool)
-{
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  /* TODO: more efficient to search in branch->rev_root->branches */
-  for (SVN_ARRAY_ITER(bi, svn_branch_get_immediate_subbranches(
-                            branch, scratch_pool, scratch_pool), scratch_pool))
-    {
-      if (bi->val->outer_eid == eid)
-        return bi->val;
-    }
-  return NULL;
-}
-
-svn_branch_state_t *
-svn_branch_add_new_branch(svn_branch_revision_root_t *rev_root,
-                          svn_branch_rev_bid_t *predecessor,
-                          svn_branch_state_t *outer_branch,
-                          int outer_eid,
-                          int root_eid,
-                          apr_pool_t *scratch_pool)
-{
-  svn_branch_state_t *new_branch;
-
-  SVN_ERR_ASSERT_NO_RETURN(!outer_branch || outer_branch->rev_root == rev_root);
-  SVN_ERR_ASSERT_NO_RETURN(root_eid != -1);
-
-  if (! outer_branch)
-    outer_eid = rev_root->root_branches->nelts;
-
-  new_branch = svn_branch_state_create(predecessor, root_eid, rev_root,
-                                       outer_branch, outer_eid,
-                                       rev_root->branches->pool);
-
-  /* A branch must not already exist at this outer element */
-  SVN_ERR_ASSERT_NO_RETURN(!outer_branch ||
-                           svn_branch_get_subbranch_at_eid(
-                             outer_branch, outer_eid, scratch_pool) == NULL);
-
-  SVN_ARRAY_PUSH(rev_root->branches) = new_branch;
-  if (!outer_branch)
-    SVN_ARRAY_PUSH(rev_root->root_branches) = new_branch;
-
-  return new_branch;
-}
-
-/* Remove branch BRANCH from the list of branches in REV_ROOT.
- */
-static void
-svn_branch_revision_root_delete_branch(
-                                svn_branch_revision_root_t *rev_root,
-                                svn_branch_state_t *branch,
-                                apr_pool_t *scratch_pool)
-{
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  SVN_ERR_ASSERT_NO_RETURN(branch->rev_root == rev_root);
-
-  for (SVN_ARRAY_ITER(bi, rev_root->branches, scratch_pool))
-    {
-      if (bi->val == branch)
-        {
-          SVN_DBG(("deleting branch b%s e%d",
-                   svn_branch_get_id(bi->val, bi->iterpool),
-                   bi->val->root_eid));
-          svn_sort__array_delete(rev_root->branches, bi->i, 1);
-          break;
-        }
-    }
-  for (SVN_ARRAY_ITER(bi, rev_root->root_branches, scratch_pool))
-    {
-      if (bi->val == branch)
-        {
-          SVN_DBG(("deleting root-branch b%s e%d",
-                   svn_branch_get_id(bi->val, bi->iterpool),
-                   bi->val->root_eid));
-          svn_sort__array_delete(rev_root->root_branches, bi->i, 1);
-          break;
-        }
-    }
-}
-
-void
-svn_branch_delete_branch_r(svn_branch_state_t *branch,
-                           apr_pool_t *scratch_pool)
-{
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  for (SVN_ARRAY_ITER(bi, svn_branch_get_immediate_subbranches(
-                            branch, scratch_pool, scratch_pool), scratch_pool))
-    {
-      svn_branch_delete_branch_r(bi->val, bi->iterpool);
-    }
-
-  svn_branch_revision_root_delete_branch(branch->rev_root,
-                                         branch, scratch_pool);
-}
-
-
-/*
- * ========================================================================
- * Parsing and Serializing
- * ========================================================================
- */
-
-svn_string_t *
-svn_branch_get_default_r0_metadata(apr_pool_t *result_pool)
-{
-  static const char *default_repos_info
-    = "r0: eids 0 1 branches 1\n"
-      "B0 root-eid 0 num-eids 1  # at /\n"
-      "e0: normal -1 .\n";
-
-  return svn_string_create(default_repos_info, result_pool);
-}
-
-/*  */
-static svn_error_t *
-parse_branch_line(char *bid_p,
-                  int *root_eid_p,
-                  int *num_eids_p,
-                  svn_branch_rev_bid_t **predecessor,
-                  svn_stream_t *stream,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool)
-{
-  svn_stringbuf_t *line;
-  svn_boolean_t eof;
-  int n;
-  svn_revnum_t pred_rev;
-  char pred_bid[1000];
-
-  /* Read a line */
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
-  SVN_ERR_ASSERT(!eof);
-
-  n = sscanf(line->data, "%s root-eid %d num-eids %d from r%ld.%s",
-             bid_p, root_eid_p, num_eids_p, &pred_rev, pred_bid);
-  SVN_ERR_ASSERT(n == 3 || n == 5);
-
-  if (n == 5)
-    {
-      *predecessor = svn_branch_rev_bid_create(pred_rev, pred_bid, result_pool);
-    }
-  else
-    {
-      *predecessor = NULL;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*  */
-static svn_error_t *
-parse_element_line(int *eid_p,
-                   svn_boolean_t *is_subbranch_p,
-                   int *parent_eid_p,
-                   const char **name_p,
-                   svn_stream_t *stream,
-                   apr_pool_t *scratch_pool)
-{
-  svn_stringbuf_t *line;
-  svn_boolean_t eof;
-  char kind[10];
-  int n;
-  int offset;
-
-  /* Read a line */
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
-  SVN_ERR_ASSERT(!eof);
-
-  n = sscanf(line->data, "e%d: %9s %d%n",
-             eid_p,
-             kind, parent_eid_p, &offset);
-  SVN_ERR_ASSERT(n >= 3);  /* C std is unclear on whether '%n' counts */
-  SVN_ERR_ASSERT(line->data[offset] == ' ');
-  *name_p = line->data + offset + 1;
-
-  *is_subbranch_p = (strcmp(kind, "subbranch") == 0);
-
-  if (strcmp(*name_p, "(null)") == 0)
-    *name_p = NULL;
-  else if (strcmp(*name_p, ".") == 0)
-    *name_p = "";
-
-  return SVN_NO_ERROR;
-}
-
-const char *
-svn_branch_id_nest(const char *outer_bid,
-                   int outer_eid,
-                   apr_pool_t *result_pool)
-{
-  if (!outer_bid)
-    return apr_psprintf(result_pool, "B%d", outer_eid);
-
-  return apr_psprintf(result_pool, "%s.%d", outer_bid, outer_eid);
-}
-
-void
-svn_branch_id_unnest(const char **outer_bid,
-                     int *outer_eid,
-                     const char *bid,
-                     apr_pool_t *result_pool)
-{
-  char *last_dot = strrchr(bid, '.');
-
-  if (last_dot) /* BID looks like "B3.11" or "B3.11.22" etc. */
-    {
-      *outer_bid = apr_pstrndup(result_pool, bid, last_dot - bid);
-      *outer_eid = atoi(last_dot + 1);
-    }
-  else /* looks like "B0" or B22" (with no dot) */
-    {
-      *outer_bid = NULL;
-      *outer_eid = atoi(bid + 1);
-    }
-}
-
-/* Create a new branch *NEW_BRANCH, initialized
- * with info parsed from STREAM, allocated in RESULT_POOL.
- */
-static svn_error_t *
-svn_branch_state_parse(svn_branch_state_t **new_branch,
-                       svn_branch_revision_root_t *rev_root,
-                       svn_stream_t *stream,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
-{
-  char bid[1000];
-  int root_eid, num_eids;
-  svn_branch_rev_bid_t *predecessor;
-  svn_branch_state_t *branch_state;
-  svn_branch_state_t *outer_branch;
-  int outer_eid;
-  int i;
-
-  SVN_ERR(parse_branch_line(bid, &root_eid, &num_eids, &predecessor,
-                            stream, scratch_pool, scratch_pool));
-
-  /* Find the outer branch and outer EID */
-  {
-    const char *outer_bid;
-
-    svn_branch_id_unnest(&outer_bid, &outer_eid, bid, scratch_pool);
-    if (outer_bid)
-      {
-        outer_branch
-          = svn_branch_revision_root_get_branch_by_id(rev_root, outer_bid,
-                                                      scratch_pool);
-      }
-    else
-      outer_branch = NULL;
-  }
-  branch_state = svn_branch_state_create(predecessor, root_eid, rev_root,
-                                         outer_branch, outer_eid,
-                                         result_pool);
-
-  /* Read in the structure. Set the payload of each normal element to a
-     (branch-relative) reference. */
-  for (i = 0; i < num_eids; i++)
-    {
-      int eid, this_parent_eid;
-      const char *this_name;
-      svn_boolean_t is_subbranch;
-
-      SVN_ERR(parse_element_line(&eid,
-                                 &is_subbranch, &this_parent_eid, &this_name,
-                                 stream, scratch_pool));
-
-      if (this_name)
-        {
-          svn_element_payload_t *payload;
-          if (! is_subbranch)
-            {
-              payload = svn_element_payload_create_ref(rev_root->rev, bid, eid,
-                                                       result_pool);
-            }
-          else
-            {
-              payload
-                = svn_element_payload_create_subbranch(result_pool);
-            }
-          svn_branch_update_element(
-            branch_state, eid, this_parent_eid, this_name, payload);
-        }
-    }
-
-  *new_branch = branch_state;
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_branch_revision_root_parse(svn_branch_revision_root_t **rev_root_p,
-                               svn_branch_repos_t *repos,
-                               svn_stream_t *stream,
-                               apr_pool_t *result_pool,
-                               apr_pool_t *scratch_pool)
-{
-  svn_branch_revision_root_t *rev_root;
-  svn_revnum_t rev;
-  int first_eid, next_eid;
-  int num_branches;
-  svn_stringbuf_t *line;
-  svn_boolean_t eof;
-  int n;
-  int j;
-
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
-  SVN_ERR_ASSERT(! eof);
-  n = sscanf(line->data, "r%ld: eids %d %d "
-                         "branches %d",
-             &rev,
-             &first_eid, &next_eid,
-             &num_branches);
-  SVN_ERR_ASSERT(n == 4);
-
-  rev_root = svn_branch_revision_root_create(repos, rev, rev - 1,
-                                             result_pool);
-  rev_root->first_eid = first_eid;
-  rev_root->next_eid = next_eid;
-
-  /* parse the branches */
-  for (j = 0; j < num_branches; j++)
-    {
-      svn_branch_state_t *branch;
-
-      SVN_ERR(svn_branch_state_parse(&branch, rev_root, stream,
-                                     result_pool, scratch_pool));
-      SVN_ARRAY_PUSH(rev_root->branches) = branch;
-
-      /* Note the root branches */
-      if (! branch->outer_branch)
-        {
-          APR_ARRAY_PUSH(rev_root->root_branches, void *) = branch;
-        }
-    }
-
-  *rev_root_p = rev_root;
-  return SVN_NO_ERROR;
-}
-
-/* ### Duplicated in svnmover.c. */
-static int
-sort_compare_items_by_eid(const svn_sort__item_t *a,
-                          const svn_sort__item_t *b)
-{
-  int eid_a = *(const int *)a->key;
-  int eid_b = *(const int *)b->key;
-
-  return eid_a - eid_b;
-}
-
-/* Write to STREAM a parseable representation of BRANCH.
- */
-svn_error_t *
-svn_branch_state_serialize(svn_stream_t *stream,
-                           svn_branch_state_t *branch,
-                           apr_pool_t *scratch_pool)
-{
-  const char *branch_root_rrpath = svn_branch_get_root_rrpath(branch,
-                                                              scratch_pool);
-  SVN_ITER_T(svn_branch_el_rev_content_t) *hi;
-  const char *predecessor_str = "";
-
-  if (branch->predecessor)
-    {
-      assert(SVN_IS_VALID_REVNUM(branch->predecessor->rev));
-      predecessor_str = apr_psprintf(scratch_pool, " from r%ld.%s",
-                                     branch->predecessor->rev,
-                                     branch->predecessor->bid);
-    }
-
-  SVN_ERR(svn_stream_printf(stream, scratch_pool,
-                            "%s root-eid %d num-eids %d%s  # at /%s\n",
-                            svn_branch_get_id(branch, scratch_pool),
-                            branch->root_eid,
-                            apr_hash_count(branch->e_map),
-                            predecessor_str,
-                            branch_root_rrpath));
-
-  map_purge_orphans(branch->e_map, branch->root_eid, scratch_pool);
-
-  for (SVN_HASH_ITER_SORTED(hi, branch->e_map, sort_compare_items_by_eid,
-                            scratch_pool))
-    {
-      int eid = *(const int *)hi->key;
-      svn_branch_el_rev_content_t *element = svn_branch_get_element(branch, eid);
-      int parent_eid;
-      const char *name;
-
-      SVN_ERR_ASSERT(element);
-      parent_eid = element->parent_eid;
-      name = element->name[0] ? element->name : ".";
-      SVN_ERR(svn_stream_printf(stream, scratch_pool,
-                                "e%d: %s %d %s\n",
-                                eid,
-                                element ? ((! element->payload->is_subbranch_root)
-                                             ? "normal" : "subbranch")
-                                     : "none",
-                                parent_eid, name));
-    }
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_branch_revision_root_serialize(svn_stream_t *stream,
-                                   svn_branch_revision_root_t *rev_root,
-                                   apr_pool_t *scratch_pool)
-{
-  SVN_ITER_T(svn_branch_state_t) *bi;
-
-  SVN_ERR(svn_stream_printf(stream, scratch_pool,
-                            "r%ld: eids %d %d "
-                            "branches %d\n",
-                            rev_root->rev,
-                            rev_root->first_eid, rev_root->next_eid,
-                            rev_root->branches->nelts));
-
-  for (SVN_ARRAY_ITER(bi, rev_root->branches, scratch_pool))
-    {
-      svn_branch_state_t *branch = bi->val;
-
-      if (branch->predecessor && branch->predecessor->rev < 0)
-        {
-          branch->predecessor->rev = rev_root->rev;
-        }
-
-      SVN_ERR(svn_branch_state_serialize(stream, bi->val, bi->iterpool));
-    }
-  return SVN_NO_ERROR;
-}
-
-
 /*
  * ========================================================================
  */
@@ -1327,12 +242,16 @@ svn_branch_find_nested_branch_element_by
                           scratch_pool))
         {
           svn_branch_state_t *subbranch = bi->val;
+          svn_branch_state_t *outer_branch;
+          int outer_eid;
           const char *relpath_to_subbranch;
           const char *relpath_in_subbranch;
 
+          svn_branch_get_outer_branch_and_eid(&outer_branch, &outer_eid,
+                                              subbranch, scratch_pool);
+
           relpath_to_subbranch
-            = svn_branch_get_path_by_eid(root_branch, subbranch->outer_eid,
-                                         scratch_pool);
+            = svn_branch_get_path_by_eid(root_branch, outer_eid, scratch_pool);
 
           relpath_in_subbranch
             = svn_relpath_skip_ancestor(relpath_to_subbranch, relpath);
@@ -1355,23 +274,30 @@ svn_branch_find_nested_branch_element_by
     *eid_p = svn_branch_get_eid_by_path(root_branch, relpath, scratch_pool);
 }
 
-
-/*
- * ========================================================================
- */
-
-const char *
-svn_branch_get_id(svn_branch_state_t *branch,
-                  apr_pool_t *result_pool)
+svn_error_t *
+svn_branch_repos_find_el_rev_by_path_rev(svn_branch_el_rev_id_t **el_rev_p,
+                                const svn_branch_repos_t *repos,
+                                svn_revnum_t revnum,
+                                const char *branch_id,
+                                const char *relpath,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
 {
-  const char *id = "";
+  svn_branch_el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev));
+  svn_branch_state_t *branch;
 
-  while (branch->outer_branch)
-    {
-      id = apr_psprintf(result_pool, ".%d%s", branch->outer_eid, id);
-      branch = branch->outer_branch;
-    }
-  id = apr_psprintf(result_pool, "B%d%s", branch->outer_eid, id);
-  return id;
+  SVN_ERR(svn_branch_repos_get_branch_by_id(&branch,
+                                            repos, revnum, branch_id,
+                                            scratch_pool));
+  el_rev->rev = revnum;
+  svn_branch_find_nested_branch_element_by_relpath(&el_rev->branch,
+                                                   &el_rev->eid,
+                                                   branch, relpath,
+                                                   scratch_pool);
+
+  /* Any relpath must at least be within the originally given branch */
+  SVN_ERR_ASSERT_NO_RETURN(el_rev->branch);
+  *el_rev_p = el_rev;
+  return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_repos.c?rev=1708550&r1=1708549&r2=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_repos.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_delta/branch_repos.c Wed Oct 14 06:38:16 2015
@@ -71,17 +71,6 @@ svn_branch_repos_get_revision(const svn_
   return svn_array_get(repos->rev_roots, revnum);
 }
 
-struct svn_branch_state_t *
-svn_branch_repos_get_root_branch(const svn_branch_repos_t *repos,
-                                 svn_revnum_t revnum,
-                                 int top_branch_num)
-{
-  svn_branch_revision_root_t *rev_root
-    = svn_branch_repos_get_revision(repos, revnum);
-
-  return svn_branch_revision_root_get_root_branch(rev_root, top_branch_num);
-}
-
 svn_branch_revision_root_t *
 svn_branch_repos_get_base_revision_root(svn_branch_revision_root_t *rev_root)
 {
@@ -137,31 +126,4 @@ svn_branch_repos_find_el_rev_by_id(svn_b
   *el_rev_p = el_rev;
   return SVN_NO_ERROR;
 }
-
-svn_error_t *
-svn_branch_repos_find_el_rev_by_path_rev(svn_branch_el_rev_id_t **el_rev_p,
-                                const svn_branch_repos_t *repos,
-                                svn_revnum_t revnum,
-                                const char *branch_id,
-                                const char *relpath,
-                                apr_pool_t *result_pool,
-                                apr_pool_t *scratch_pool)
-{
-  svn_branch_el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev));
-  svn_branch_state_t *branch;
-
-  SVN_ERR(svn_branch_repos_get_branch_by_id(&branch,
-                                            repos, revnum, branch_id,
-                                            scratch_pool));
-  el_rev->rev = revnum;
-  svn_branch_find_nested_branch_element_by_relpath(&el_rev->branch,
-                                                   &el_rev->eid,
-                                                   branch, relpath,
-                                                   scratch_pool);
-
-  /* Any relpath must at least be within the originally given branch */
-  SVN_ERR_ASSERT_NO_RETURN(el_rev->branch);
-  *el_rev_p = el_rev;
-  return SVN_NO_ERROR;
-}
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c?rev=1708550&r1=1708549&r2=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c Wed Oct 14 06:38:16 2015
@@ -32,6 +32,7 @@
 #include "svn_pools.h"
 
 #include "private/svn_branch_repos.h"
+#include "private/svn_branch_nested.h"
 #include "private/svn_delta_private.h"
 #include "private/svn_editor3e.h"
 #include "../libsvn_delta/debug_editor.h"
@@ -952,18 +953,6 @@ apply_change(void **dir_baton,
  * (A branch root is not necessarily a directory, it could be a file.)
  */
 
-/*  */
-static int
-branch_get_top_num(const svn_branch_state_t *branch,
-                   apr_pool_t *scratch_pool)
-{
-  while (branch->outer_branch)
-    {
-      branch = branch->outer_branch;
-    }
-  return branch->outer_eid;
-}
-
 /* Get the old-repository path for the storage of the root element of BRANCH.
  *
  * Currently, this is the same as the nested-branching hierarchical path
@@ -973,7 +962,7 @@ static const char *
 branch_get_storage_root_rrpath(const svn_branch_state_t *branch,
                                apr_pool_t *result_pool)
 {
-  int top_branch_num = branch_get_top_num(branch, result_pool);
+  int top_branch_num = atoi(branch->bid + 1);
   const char *top_path = apr_psprintf(result_pool, "top%d", top_branch_num);
   const char *nested_path = svn_branch_get_root_rrpath(branch, result_pool);
 
@@ -1187,7 +1176,6 @@ editor3_open_branch(void *baton,
 {
   ev3_from_delta_baton_t *eb = baton;
   svn_branch_state_t *new_branch;
-  svn_branch_state_t *outer_branch = NULL;
 
   /* if the subbranch already exists, just return its bid */
   *new_branch_id_p
@@ -1204,14 +1192,10 @@ editor3_open_branch(void *baton,
       return SVN_NO_ERROR;
     }
 
-  if (outer_branch_id)
-    outer_branch = svn_branch_revision_root_get_branch_by_id(
-                     eb->edited_rev_root, outer_branch_id, scratch_pool);
-  new_branch = svn_branch_add_new_branch(eb->edited_rev_root,
+  new_branch = svn_branch_add_new_branch(*new_branch_id_p,
+                                         eb->edited_rev_root,
                                          predecessor,
-                                         outer_branch, outer_eid,
                                          root_eid, scratch_pool);
-  *new_branch_id_p = svn_branch_get_id(new_branch, result_pool);
   return SVN_NO_ERROR;
 }
 
@@ -1228,7 +1212,6 @@ editor3_branch(void *baton,
   ev3_from_delta_baton_t *eb = baton;
   svn_branch_rev_bid_t *predecessor;
   svn_branch_state_t *new_branch;
-  svn_branch_state_t *outer_branch = NULL;
   svn_branch_state_t *from_branch;
   svn_branch_subtree_t *from_subtree;
 
@@ -1244,20 +1227,18 @@ editor3_branch(void *baton,
                                from->rev, from->bid, from->eid);
     }
 
-  if (outer_branch_id)
-    outer_branch = svn_branch_revision_root_get_branch_by_id(
-                     eb->edited_rev_root, outer_branch_id, scratch_pool);
+  *new_branch_id_p
+    = svn_branch_id_nest(outer_branch_id, outer_eid, result_pool);
   predecessor = svn_branch_rev_bid_create(from->rev, from->bid, scratch_pool);
-  new_branch = svn_branch_add_new_branch(eb->edited_rev_root,
+  new_branch = svn_branch_add_new_branch(*new_branch_id_p,
+                                         eb->edited_rev_root,
                                          predecessor,
-                                         outer_branch, outer_eid,
                                          from->eid, scratch_pool);
 
   /* Populate the mapping from the 'from' source */
-  SVN_ERR(svn_branch_instantiate_elements(new_branch, *from_subtree,
-                                          scratch_pool));
+  SVN_ERR(svn_branch_instantiate_elements_r(new_branch, *from_subtree,
+                                            scratch_pool));
 
-  *new_branch_id_p = svn_branch_get_id(new_branch, result_pool);
   return SVN_NO_ERROR;
 }
 
@@ -1843,17 +1824,20 @@ drive_changes(ev3_from_delta_baton_t *eb
   for (i = 0; i < eb->edited_rev_root->root_branches->nelts; i++)
     {
       svn_branch_state_t *root_branch
-        = svn_branch_revision_root_get_root_branch(eb->edited_rev_root, i);
+        = APR_ARRAY_IDX(eb->edited_rev_root->root_branches, i, void *);
       apr_hash_t *paths_final;
 
       const char *top_path = branch_get_storage_root_rrpath(root_branch,
                                                             scratch_pool);
       svn_pathrev_t current;
-      svn_branch_state_t *base_root_branch
-        = svn_branch_repos_get_root_branch(eb->edited_rev_root->repos,
-                                           eb->edited_rev_root->base_rev,
-                                           root_branch->outer_eid /*top_branch_num*/);
-      svn_boolean_t branch_is_new = !base_root_branch;
+      svn_branch_state_t *base_root_branch;
+      svn_boolean_t branch_is_new;
+
+      SVN_ERR(svn_branch_repos_get_branch_by_id(&base_root_branch,
+                                                eb->edited_rev_root->repos,
+                                                eb->edited_rev_root->base_rev,
+                                                root_branch->bid, scratch_pool));
+      branch_is_new = !base_root_branch;
 
       paths_final = apr_hash_make(scratch_pool);
       convert_branch_to_paths_r(paths_final,
@@ -1913,13 +1897,35 @@ editor3_sequence_point(void *baton,
   ev3_from_delta_baton_t *eb = baton;
   int i;
 
-  for (i = 0; i < eb->edited_rev_root->root_branches->nelts; i++)
+  /* first, purge elements in each branch */
+  for (i = 0; i < eb->edited_rev_root->branches->nelts; i++)
+    {
+      svn_branch_state_t *b
+        = APR_ARRAY_IDX(eb->edited_rev_root->branches, i, void *);
+
+      svn_branch_purge(b, scratch_pool);
+    }
+
+  /* second, purge branches that are no longer nested */
+  for (i = 0; i < eb->edited_rev_root->branches->nelts; i++)
     {
       svn_branch_state_t *b
-        = svn_branch_revision_root_get_root_branch(eb->edited_rev_root, i);
+        = APR_ARRAY_IDX(eb->edited_rev_root->branches, i, void *);
+      svn_branch_state_t *outer_branch;
+      int outer_eid;
+
+      svn_branch_get_outer_branch_and_eid(&outer_branch, &outer_eid,
+                                          b, scratch_pool);
 
-      svn_branch_purge_r(b, scratch_pool);
+      if (outer_branch
+          && ! svn_branch_get_element(outer_branch, outer_eid))
+        {
+          svn_branch_revision_root_delete_branch(b->rev_root, b, scratch_pool);
+          /* Re-visit this position in the array */
+          i--;
+        }
     }
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c?rev=1708550&r1=1708549&r2=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original)
+++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Wed Oct 14 06:38:16 2015
@@ -46,6 +46,7 @@
 #include "private/svn_cmdline_private.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_branch_repos.h"
+#include "private/svn_branch_nested.h"
 #include "private/svn_editor3e.h"
 #include "private/svn_ra_private.h"
 #include "private/svn_string_private.h"
@@ -1010,10 +1011,14 @@ branch_id_str(svn_branch_state_t *branch
   else
     {
       svn_branch_el_rev_content_t *outer_el = NULL;
+      svn_branch_state_t *outer_branch;
+      int outer_eid;
 
-      if (branch->outer_branch)
-        outer_el = svn_branch_get_element(branch->outer_branch,
-                                          branch->outer_eid);
+      svn_branch_get_outer_branch_and_eid(&outer_branch, &outer_eid,
+                                          branch, scratch_pool);
+
+      if (outer_branch)
+        outer_el = svn_branch_get_element(outer_branch, outer_eid);
 
       return apr_psprintf(result_pool, "%-10s %-12s root=e%d",
                           svn_branch_get_id(branch, scratch_pool),
@@ -2515,8 +2520,8 @@ do_branch_into(svn_branch_state_t *from_
                    new_root_content);
 
   /* Populate the new branch mapping */
-  SVN_ERR(svn_branch_instantiate_elements(to_branch, *from_subtree,
-                                          scratch_pool));
+  SVN_ERR(svn_branch_instantiate_elements_r(to_branch, *from_subtree,
+                                            scratch_pool));
   notify_v("A+   %s (subtree)",
            svn_branch_get_path_by_eid(to_branch, from_eid, scratch_pool));
 
@@ -2998,17 +3003,24 @@ typedef struct arg_t
  */
 static svn_error_t *
 point_to_outer_element_instead(svn_branch_el_rev_id_t *el_rev,
-                               const char *op)
+                               const char *op,
+                               apr_pool_t *scratch_pool)
 {
   if (is_branch_root_element(el_rev->branch, el_rev->eid))
     {
-      if (! el_rev->branch->outer_branch)
+      svn_branch_state_t *outer_branch;
+      int outer_eid;
+
+      svn_branch_get_outer_branch_and_eid(&outer_branch, &outer_eid,
+                                          el_rev->branch, scratch_pool);
+
+      if (! outer_branch)
         return svn_error_createf(SVN_ERR_BRANCHING, NULL, "%s: %s", op,
                                  _("svnmover cannot delete or move a "
                                    "top-level branch"));
 
-      el_rev->eid = el_rev->branch->outer_eid;
-      el_rev->branch = el_rev->branch->outer_branch;
+      el_rev->eid = outer_eid;
+      el_rev->branch = outer_branch;
     }
 
   return SVN_NO_ERROR;
@@ -3290,7 +3302,8 @@ execute(svnmover_wc_t *wc,
           break;
 
         case ACTION_MV:
-          SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev, "mv"));
+          SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev, "mv",
+                                                 iterpool));
 
           VERIFY_REV_UNSPECIFIED("mv", 0);
           VERIFY_EID_EXISTS("mv", 0);
@@ -3333,7 +3346,8 @@ execute(svnmover_wc_t *wc,
           break;
 
         case ACTION_RM:
-          SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev, "rm"));
+          SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev, "rm",
+                                                 iterpool));
 
           VERIFY_REV_UNSPECIFIED("rm", 0);
           VERIFY_EID_EXISTS("rm", 0);
@@ -3344,7 +3358,7 @@ execute(svnmover_wc_t *wc,
 
         case ACTION_CP_RM:
           SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev,
-                                                 "copy-and-delete"));
+                                                 "copy-and-delete", iterpool));
 
           VERIFY_REV_UNSPECIFIED("copy-and-delete", 0);
           VERIFY_EID_EXISTS("copy-and-delete", 0);
@@ -3363,7 +3377,8 @@ execute(svnmover_wc_t *wc,
 
         case ACTION_BR_RM:
           SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev,
-                                                 "branch-and-delete"));
+                                                 "branch-and-delete",
+                                                 iterpool));
 
           VERIFY_REV_UNSPECIFIED("branch-and-delete", 0);
           VERIFY_EID_EXISTS("branch-and-delete", 0);
@@ -3382,7 +3397,8 @@ execute(svnmover_wc_t *wc,
 
         case ACTION_BR_INTO_RM:
           SVN_ERR(point_to_outer_element_instead(arg[0]->el_rev,
-                                                 "branch-into-and-delete"));
+                                                 "branch-into-and-delete",
+                                                 iterpool));
 
           VERIFY_REV_UNSPECIFIED("branch-into-and-delete", 0);
           VERIFY_EID_EXISTS("branch-into-and-delete", 0);

Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py?rev=1708550&r1=1708549&r2=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py (original)
+++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py Wed Oct 14 06:38:16 2015
@@ -1340,13 +1340,14 @@ def merge_swap_abc(sbox):
   sbox_build_svnmover(sbox)
 
   expected_eids = svntest.wc.State('', {
-    ''           : Item(eid=0),
-    'X'          : Item(eid=2),
-    'X/A'        : Item(eid=3),
-    'X/A/a1'     : Item(eid=4),
-    'X/A/B'      : Item(eid=5),
-    'X/A/B/C'    : Item(eid=6),
-    'X/A/B/C/c1' : Item(eid=7),
+    'B0'            : Item(eid=0),
+    'B0/X'          : Item(eid=1),
+    'B0.1'          : Item(eid=2),
+    'B0.1/A'        : Item(eid=3),
+    'B0.1/A/a1'     : Item(eid=4),
+    'B0.1/A/B'      : Item(eid=5),
+    'B0.1/A/B/C'    : Item(eid=6),
+    'B0.1/A/B/C/c1' : Item(eid=7),
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('') +
@@ -1360,20 +1361,21 @@ def merge_swap_abc(sbox):
                  'mkdir X/A/B/C/c1')
 
   expected_eids.add({
-    'Y'          : Item(eid=2),
-    'Y/A'        : Item(eid=3),
-    'Y/A/a1'     : Item(eid=4),
-    'Y/A/B'      : Item(eid=5),
-    'Y/A/B/C'    : Item(eid=6),
-    'Y/A/B/C/c1' : Item(eid=7),
+    'B0/Y'          : Item(eid=8),
+    'B0.8'          : Item(eid=2),
+    'B0.8/A'        : Item(eid=3),
+    'B0.8/A/a1'     : Item(eid=4),
+    'B0.8/A/B'      : Item(eid=5),
+    'B0.8/A/B/C'    : Item(eid=6),
+    'B0.8/A/B/C/c1' : Item(eid=7),
   })
   test_svnmover3(sbox, '', None, expected_eids,
                  'branch X Y')
 
   expected_eids.rename({
-    'X/A/B/C' : 'X/A',
-    'X/A/B'   : 'X/A/B',
-    'X/A'     : 'X/A/B/C',
+    'B0.1/A/B/C' : 'B0.1/A',
+    'B0.1/A/B'   : 'B0.1/A/B',
+    'B0.1/A'     : 'B0.1/A/B/C',
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('X') +
@@ -1387,9 +1389,9 @@ def merge_swap_abc(sbox):
                  'mv X/C X/A')
 
   expected_eids.rename({
-    'Y/A'     : 'Y/A/B/C',
-    'Y/A/B'   : 'Y/A/B',
-    'Y/A/B/C' : 'Y/A',
+    'B0.8/A'     : 'B0.8/A/B/C',
+    'B0.8/A/B'   : 'B0.8/A/B',
+    'B0.8/A/B/C' : 'B0.8/A',
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('Y') +
@@ -1404,10 +1406,11 @@ def move_to_related_branch_2(sbox):
   sbox_build_svnmover(sbox)
 
   expected_eids = svntest.wc.State('', {
-    ''      : Item(eid=0),
-    'X'     : Item(eid=2),
-    'X/A'   : Item(eid=3),
-    'X/A/B' : Item(eid=4),
+    'B0'       : Item(eid=0),
+    'B0/X'     : Item(eid=1),
+    'B0.1'     : Item(eid=2),
+    'B0.1/A'   : Item(eid=3),
+    'B0.1/A/B' : Item(eid=4),
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('') +
@@ -1418,9 +1421,10 @@ def move_to_related_branch_2(sbox):
                  'mkdir X/A/B')
 
   expected_eids.add({
-    'Y'     : Item(eid=2),
-    'Y/A'   : Item(eid=3),
-    'Y/A/B' : Item(eid=4),
+    'B0/Y'     : Item(eid=5),
+    'B0.5'     : Item(eid=2),
+    'B0.5/A'   : Item(eid=3),
+    'B0.5/A/B' : Item(eid=4),
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('') +
@@ -1429,10 +1433,10 @@ def move_to_related_branch_2(sbox):
                  'branch X Y')
 
   expected_eids.add({
-    'X/A/ax'   : Item(eid=6),
-    'X/A/B/bx' : Item(eid=7),
-    'Y/A/ay'   : Item(eid=8),
-    'Y/A/B/by' : Item(eid=9),
+    'B0.1/A/ax'   : Item(eid=6),
+    'B0.1/A/B/bx' : Item(eid=7),
+    'B0.5/A/ay'   : Item(eid=8),
+    'B0.5/A/B/by' : Item(eid=9),
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('X') +
@@ -1450,10 +1454,10 @@ def move_to_related_branch_2(sbox):
   # X and Y are related, X/A/B contains X/A/B/bx, Y/A/B contains Y/A/B/by.
   # Moving X/A/B to Y/B, i.e. from X to Y, by branch-into-and-delete,
   # results in Y/B that contains both bx and by.
-  expected_eids.rename({'X/A/B' : 'Y/B'})
-  expected_eids.remove('Y/A/B', 'Y/A/B/by')
+  expected_eids.rename({'B0.1/A/B' : 'B0.5/B'})
+  expected_eids.remove('B0.5/A/B', 'B0.5/A/B/by')
   expected_eids.add({
-    'Y/B/by' : Item(eid=9),
+    'B0.5/B/by' : Item(eid=9),
   })
   test_svnmover3(sbox, '',
                  reported_br_diff('X') +

Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/wc.py?rev=1708550&r1=1708549&r2=1708550&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/wc.py Wed Oct 14 06:38:16 2015
@@ -119,13 +119,11 @@ _re_parse_commit = re.compile('^(\w+(  \
 #rN: eids 0 15 branches 4
 _re_parse_eid_header = re.compile('^r(-1|[0-9]+): eids ([0-9]+) ([0-9]+) '
                                   'branches ([0-9]+)$')
-# B0.2 root-eid 3  # at /X
-_re_parse_eid_branch = re.compile('^B([0-9.]+) root-eid ([0-9]+) num-eids ([0-9]+)( from [^ ]*)?  # at /(.*)$')
+# B0.2 root-eid 3
+_re_parse_eid_branch = re.compile('^(B[0-9.]+) root-eid ([0-9]+) num-eids ([0-9]+)( from [^ ]*)?$')
 # e4: normal 6 C
 _re_parse_eid_ele = re.compile('^e([0-9]+): (none|normal|subbranch) '
                                '(-1|[0-9]+) (.*)$')
-# 25.34.78
-_re_parse_split_branch_eid = re.compile('^([0-9.]+)\.([0-9]+)$')
 
 class State:
   """Describes an existing or expected state of a working copy.
@@ -789,6 +787,7 @@ class State:
 
     # Need to read all elements in a branch before we can construct
     # the full path to an element.
+    # For the full path we use <branch-id>/<path-within-branch>.
 
     def eid_path(eids, eid):
       ele = eids[eid]
@@ -799,20 +798,17 @@ class State:
         return ele[1]
       return parent_path + '/' + ele[1]
 
-    def eid_full_path(eids, eid, root_path):
+    def eid_full_path(eids, eid, branch_id):
       path = eid_path(eids, eid)
-      if root_path == '':
-        return eid_path(eids, eid)
       if path == '':
-        return root_path
-      return root_path + '/' + eid_path(eids, eid)
+        return branch_id
+      return branch_id + '/' + path
 
-    def add_to_desc(eids, desc, branch_root_path):
+    def add_to_desc(eids, desc, branch_id):
       for k, v in eids.items():
-        desc[eid_full_path(eids, k, branch_root_path)] = StateItem(eid=k)
+        desc[eid_full_path(eids, k, branch_id)] = StateItem(eid=k)
 
-    branches = {}
-    branch = None
+    branch_id = None
     eids = {}
     desc = {}
     for line in lines:
@@ -828,21 +824,13 @@ class State:
 
       match = _re_parse_eid_branch.search(line)
       if match:
-        if branch:
-          branches[branch[0]] = branch
-          add_to_desc(eids, desc, branch[3])
+        if branch_id:
+          add_to_desc(eids, desc, branch_id)
           eids = {}
-        parent_branch_eid = None
-        branch_eid = match.group(1)
-        match2 = _re_parse_split_branch_eid.search(branch_eid)
-        if match2:
-          parent_branch_eid = branches[match2.group(1)]
+        branch_id = match.group(1)
         root_eid = match.group(2)
-        path = match.group(5)
-        branch = [branch_eid, parent_branch_eid, root_eid, path]
 
-    branches[branch[0]] = branch
-    add_to_desc(eids, desc, branch[3])
+    add_to_desc(eids, desc, branch_id)
 
     return cls('', desc)