#
# patch "ChangeLog"
# from [ff8c5b74caec143b53b946742bcf9738c2c840c2]
# to [b94614caa19ed2c1aae1cfcddd0fc2507556acdf]
#
# patch "rcs_import.cc"
# from [8373f2d2ce0e3ea6e5ac087666ebca573c49d2e6]
# to [5939848d4ed3b95d701024c3b99cebfa648b89fb]
#
# patch "tests/t_cvsimport_deleted_invar.at"
# from [3c166c4e55776d45437b807b165fed231d7dcaca]
# to [32da8b246eea20fe065e860c6b2428ffce7230ed]
#
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,9 @@
+2005-05-15 graydon hoare
+
+ * rcs_import.cc: rewrite most of the branch logic to
+ address issues raised in bugs 13032 and 13063.
+ * tests/t_cvsimport_deleted_invar.at: un-XFAIL.
+
2005-05-14 Timothy Brownawell
* contrib/monoprof.sh: Clean up variable definitions some.
@@ -4286,7 +4292,7 @@
* AUTHORS: Mention Wojciech and Neil.
* revision.cc (calculate_ancestors_from_graph): Make non-recursive.
-2005-01-17 Wojciech MiÅkowski
+2005-01-17 Wojciech MiÃ
Âkowski
* std_hooks.lua: Teach about meld.
--- rcs_import.cc
+++ rcs_import.cc
@@ -186,21 +186,10 @@
cvs_state
{
set in_edges;
- map< cvs_key, shared_ptr > substates;
};
-struct
-branch_point
-{
- branch_point() {}
- branch_point(cvs_key const & k,
- shared_ptr const & s,
- size_t l)
- : key(k), state(s), rev_comp_len(l) {}
- cvs_key key;
- shared_ptr state;
- size_t rev_comp_len;
-};
+typedef map >
+cvs_branch;
struct
cvs_history
@@ -220,11 +209,23 @@
cvs_key & key,
shared_ptr & state);
- typedef stack< shared_ptr > state_stack;
- map branchpoints;
+ // assume admin has foo:X.Y.0.N in it, then
+ // this multimap contains entries of the form
+ // X.Y -> foo
+ multimap branchpoints;
+
+ // and this map contains entries of the form
+ // X.Y.N.1 -> foo
+ map branch_first_entries;
- state_stack stk;
+ // branch name -> branch
+ map > branches;
+
+ // stack of branches we're injecting states into
+ stack< shared_ptr > stk;
+ stack< cvs_branchname > bstk;
+
file_path curr_file;
string base_branch;
@@ -235,18 +236,17 @@
cvs_history();
void set_filename(string const & file,
file_id const & ident);
- void push_branch(rcs_file const & r,
- string const & branchpoint_version,
- string const & first_branch_version);
+
+ void index_branchpoint_symbols(rcs_file const & r);
+
+ void push_branch(string const & branch_name, bool private_branch);
+
void note_file_edge(rcs_file const & r,
string const & prev_rcs_version_num,
string const & next_rcs_version_num,
file_id const & prev_version,
file_id const & next_version);
- void find_branchpoint(rcs_file const & r,
- string const & branchpoint_version,
- string const & first_branch_version,
- shared_ptr & bp_state);
+
void pop_branch();
};
@@ -476,7 +476,6 @@
rcs_put_raw_file_edge(next_id, curr_id, del, db);
}
-
static void
process_branch(string const & begin_version,
vector< piece > const & begin_lines,
@@ -510,7 +509,7 @@
insert_into_db(curr_data, curr_id,
*next_lines, next_data, next_id, db);
- cvs.note_file_edge (r, curr_version, next_version,
+ cvs.note_file_edge (r, curr_version, next_version,
file_id(curr_id), file_id(next_id));
}
else
@@ -533,29 +532,117 @@
}
}
- // recursively follow any branches rooted here
+
+ /*
+
+ please read this exhaustingly long comment and understand it
+ before mucking with the branch inference logic.
+
+ we are processing a file version. a branch might begin here. if
+ the current version is X.Y, then there is a branch B starting
+ here iff there is a symbol in the admin section called X.Y.0.Z,
+ where Z is the branch number (or if there is a private branch
+ called X.Y.Z, which is either an import branch or some private
+ RCS cruft).
+
+ the version X.Y is then considered the branchpoint of B in the
+ current file. this does *not* mean that the CVS key -- an
+ abstraction representing whole-tree operations -- of X.Y is the
+ branchpoint across the CVS archive we're processing.
+
+ in fact, CVS does not record the occurrence of a branching
+ action (tag -b). we have no idea who executed that command and
+ when. what we know instead is the commit X.Y immediately
+ preceeding the branch -- CVS consideres this the branchpoint --
+ in this file's reduced view of history. we also know the first
+ commit X.Y.Z.1 inside the branch (which might not exist).
+
+ our old strategy was to consider all branches nested in a
+ hierarchy, which was a super-tree of all the branch trees in all
+ the CVS files in a repository. this involved considering X.Y as
+ the parent version of branch X.Y.Z, an selecting "the"
+ branchpoint connecting the two as the least CVS key X.Y.Z.1
+ committed inside the branch B.
+
+ this was a mistake, for two significant reasons.
+
+ first, some files do not *have* any commit inside the branch B,
+ only a branchpoint X.Y.0.Z. this branchpoint is actually the
+ last commit *before* the user branched, and could be a very old
+ commit, long before the branch was formed, so it is useless in
+ determining the branch structure.
+
+ second, some files do not have a branch B, or worse, have
+ branched into B from an "ancestor" branch A, where a different
+ file branches into B from a different ancestor branch C. in
+ other words, while there *is* a tree structure within the X.Y.Z
+ branches of each file, there is *no* shared tree structure
+ between the branch names across a repository. in one file A can
+ be an ancestor of B, in another file B can be an ancestor of A.
+
+ thus, we give up on establishing a hierarchy between branches
+ altogether. all branches exist in a flat namespace, and all are
+ direct descendents of the empty revision at the root of
+ history. each branchpoint symbol mentionned in the
+ administrative section of a file is considered the root of a new
+ lineage.
+
+ */
+
+ typedef multimap::const_iterator ity;
+ pair range = cvs.branchpoints.equal_range(curr_version);
+ if (range.first != cvs.branchpoints.end()
+ && range.first->first == curr_version)
+ {
+ // here we are making a slightly odd note that the file
+ // springs into existence on the branch, with an edge from
+ // the null id to the branchpoint. we do this because we are
+ // transplanting the RCS file branchpoint (which is
+ // hierarchical) onto a tree-wide branch root (which is
+ // non-hierarchical, starting from the null revision).
+
+ for (ity branch = range.first; branch != range.second; ++branch)
+ {
+ L(F("noting branchpoint for %s = %s\n") % branch->first % curr_version);
+ cvs.push_branch(branch->second, false);
+ cvs.note_file_edge (r, curr_version, curr_version,
+ file_id(), file_id(curr_id));
+ cvs.pop_branch();
+ }
+ }
+
+ // recursively follow any branch commits coming from the branchpoint
boost::shared_ptr curr_delta = r.deltas.find(curr_version)->second;
for(vector::const_iterator i = curr_delta->branches.begin();
- i != curr_delta->branches.end(); ++i)
- {
- L(F("following RCS branch %s\n") % (*i));
- vector< piece > branch_lines;
- construct_version(*curr_lines, *i, branch_lines, r);
-
- data branch_data;
- hexenc branch_id;
- insert_into_db(curr_data, curr_id,
- branch_lines, branch_data, branch_id, db);
- cvs.push_branch (r, curr_version, *i);
+ i != curr_delta->branches.end(); ++i)
+ {
+ string branch;
+ bool priv = false;
+ map::const_iterator be = cvs.branch_first_entries.find(*i);
- cvs.note_file_edge (r, curr_version, *i,
- file_id(curr_id), file_id(branch_id));
+ if (be != cvs.branch_first_entries.end())
+ branch = be->second;
+ else
+ priv = true;
+
+ L(F("following RCS branch %s = '%s'\n") % (*i) % branch);
+ vector< piece > branch_lines;
+ construct_version(*curr_lines, *i, branch_lines, r);
+
+ data branch_data;
+ hexenc branch_id;
+ insert_into_db(curr_data, curr_id,
+ branch_lines, branch_data, branch_id, db);
+
+ cvs.push_branch (branch, priv);
+ cvs.note_file_edge (r, curr_version, *i,
+ file_id(curr_id), file_id(branch_id));
+ process_branch(*i, branch_lines, branch_data, branch_id, r, db, cvs);
+ cvs.pop_branch();
+
+ L(F("finished RCS branch %s = '%s'\n") % (*i) % branch);
+ }
- process_branch(*i, branch_lines, branch_data, branch_id, r, db, cvs);
- cvs.pop_branch();
- L(F("finished RCS branch %s\n") % (*i));
- }
-
if (!r.deltas.find(curr_version)->second->next.empty())
{ // advance
curr_data = next_data;
@@ -588,6 +675,7 @@
file_id fid = id;
cvs.set_filename (filename, fid);
+ cvs.index_branchpoint_symbols (r);
if (! db.file_version_exists (fid))
{
@@ -675,70 +763,26 @@
}
static void
-version_to_components(string const & version,
- vector & components)
+split_version(string const & v, vector & vs)
{
- typedef boost::tokenizer > tokenizer;
+ vs.clear();
boost::char_separator sep(".");
- tokenizer tokens(version, sep);
-
- components.clear();
- copy(tokens.begin(), tokens.end(), back_inserter(components));
+ typedef boost::tokenizer > tokenizer;
+ tokenizer tokens(v, sep);
+ copy(tokens.begin(), tokens.end(), back_inserter(vs));
}
-static string
-find_branch_for_version(multimap const & symbols,
- string const & version,
- string const & base)
+static void
+join_version(vector const & vs, string & v)
{
- typedef multimap::const_iterator ity;
-
- L(F("looking up branch name for %s\n") % version);
-
- vector components;
- version_to_components(version, components);
-
- if (components.size() < 4)
+ v.clear();
+ for (vector::const_iterator i = vs.begin();
+ i != vs.end(); ++i)
{
- L(F("version %s has too few components, using branch %s\n")
- % version % base);
- return base;
+ if (i != vs.begin())
+ v += ".";
+ v += *i;
}
-
- string branch_version;
- components[components.size() - 1] = components[components.size() - 2];
- components[components.size() - 2] = "0";
- for (size_t i = 0; i < components.size(); ++i)
- {
- if (i != 0)
- branch_version += ".";
- branch_version += components[i];
- }
-
- pair range = symbols.equal_range(branch_version);
- if (range.first == symbols.end())
- {
- L(F("no branch %s found, using base '%s'\n")
- % branch_version % base);
- return base;
- }
- else
- {
- string res = base;
- res += ".";
- res += range.first->second;
- int num_results = 0;
- while (range.first != range.second)
- { range.first++; num_results++; }
-
- if (num_results > 1)
- W(F("multiple entries (%d) for branch %s found, using: '%s'\n")
- % num_results % branch_version % res);
- else
- L(F("unique entry for branch %s found: '%s'\n")
- % branch_version % res);
- return res;
- }
}
cvs_key::cvs_key(rcs_file const & r, string const & version,
@@ -777,10 +821,7 @@
id = nextid++;
}
- string branch_name = find_branch_for_version(r.admin.symbols,
- version,
- cvs.base_branch);
- branch = cvs.branch_interner.intern(branch_name);
+ branch = cvs.bstk.top();
changelog = cvs.changelog_interner.intern(deltatext->second->log);
author = cvs.author_interner.intern(delta->second->author);
}
@@ -790,7 +831,6 @@
n_versions("versions", "v", 1),
n_tree_branches("branches", "b", 1)
{
- stk.push(shared_ptr(new cvs_state()));
}
void
@@ -811,6 +851,42 @@
curr_file = file_path(ss);
}
+void cvs_history::index_branchpoint_symbols(rcs_file const & r)
+{
+ branchpoints.clear();
+ branch_first_entries.clear();
+
+ for (std::multimap::const_iterator i =
+ r.admin.symbols.begin(); i != r.admin.symbols.end(); ++i)
+ {
+ std::string const & num = i->first;
+ std::string const & sym = i->second;
+
+ vector components;
+ split_version(num, components);
+
+ if (components.size() > 2 &&
+ components[components.size() - 2] == string("0"))
+ {
+ string first_entry_version;
+ components[components.size() - 2] = components[components.size() - 1];
+ components[components.size() - 1] = string("1");
+ join_version(components, first_entry_version);
+
+ L(F("first version in branch %s would be %s\n")
+ % sym % first_entry_version);
+ branch_first_entries.insert(make_pair(first_entry_version, sym));
+
+ string branchpoint_version;
+ components.erase(components.end() - 2, components.end());
+ join_version(components, branchpoint_version);
+
+ L(F("file branchpoint for %s at %s\n") % sym % branchpoint_version);
+ branchpoints.insert(make_pair(branchpoint_version, sym));
+ }
+ }
+}
+
bool
cvs_history::find_key_and_state(rcs_file const & r,
string const & version,
@@ -818,7 +894,7 @@
shared_ptr & state)
{
I(stk.size() > 0);
- map< cvs_key, shared_ptr > & substates = stk.top()->substates;
+ shared_ptr branch = stk.top();
cvs_key nk(r, version, *this);
nk.add_file(curr_file, version);
@@ -839,8 +915,8 @@
if (static_cast(k_old.time - constants::cvs_window / 2) < k_old.time)
k_old.time -= constants::cvs_window / 2;
- i_new = substates.lower_bound(k_new);
- i_old = substates.upper_bound(k_old);
+ i_new = branch->lower_bound(k_new);
+ i_old = branch->upper_bound(k_old);
for (i = i_new; i != i_old; ++i)
{
@@ -849,99 +925,38 @@
key = i->first;
state = i->second;
key.add_file(curr_file, version);
- substates.erase(i->first);
- substates.insert(make_pair(key, state));
return true;
}
}
key = nk;
state = shared_ptr(new cvs_state());
- substates.insert(make_pair(key, state));
+ branch->insert(make_pair(key, state));
return false;
}
-void
-cvs_history::find_branchpoint(rcs_file const & r,
- string const & branchpoint_version,
- string const & first_branch_version,
- shared_ptr & bp_state)
-{
- cvs_key k;
- I(find_key_and_state(r, branchpoint_version, k, bp_state));
+void
+cvs_history::push_branch(string const & branch_name, bool private_branch)
+{
+ shared_ptr branch;
- string branch_name = find_branch_for_version(r.admin.symbols,
- first_branch_version,
- base_branch);
+ I(stk.size() > 0);
- unsigned long branch = branch_interner.intern(branch_name);
-
- map::const_iterator i
- = branchpoints.find(branch);
-
- vector new_components;
- version_to_components(branchpoint_version, new_components);
- size_t newlen = new_components.size();
-
-
- if (i == branchpoints.end())
+ map >::const_iterator b = branches.find(branch_name);
+ if (b == branches.end())
{
- ++n_tree_branches;
- L(F("beginning branch %s at %s : %s\n")
- % branch_name % curr_file % branchpoint_version);
- branchpoints.insert(make_pair(branch,
- branch_point(k, bp_state, newlen)));
+ branch = shared_ptr(new cvs_branch());
+ if (!private_branch)
+ branches.insert(make_pair(branch_name, branch));
}
else
- {
- // if this version comes off the main trunk, but the previous branchpoint
- // version comes off a branch (such as an import 1.1.1.1), then we want
- // to take the one closest to the trunk.
- // TODO perhaps we need to reconsider branching in general for cvs_import,
- // this is pretty much just a workaround for 1.1<->1.1.1.1 equivalence
+ branch = b->second;
- // take the earlier of the new key and the existing branchpoint
- if ((k.time < i->second.key.time && newlen <= i->second.rev_comp_len)
- || newlen < i->second.rev_comp_len)
- {
- L(F("moving branch %s back to %s : %s\n")
- % branch_name % curr_file % branchpoint_version);
- shared_ptr old = i->second.state;
- set moved;
- for (map< cvs_key, shared_ptr >::const_iterator j =
- old->substates.begin(); j != old->substates.end(); ++j)
- {
- if (j->first.branch == branch)
- {
- bp_state->substates.insert(*j);
- moved.insert(j->first);
- }
- }
- for (set::const_iterator j = moved.begin(); j != moved.end();
- ++j)
- {
- old->substates.erase(*j);
- }
- branchpoints[branch] = branch_point(k, bp_state, newlen);
- }
- else
- {
- L(F("using existing branchpoint for %s at %s : %s\n")
- % branch_name % curr_file % branchpoint_version);
- bp_state = i->second.state;
- }
- }
-}
+ stk.push(branch);
-void
-cvs_history::push_branch(rcs_file const & r,
- string const & branchpoint_version,
- string const & first_branch_version)
-{
- shared_ptr bp_state;
- I(stk.size() > 0);
- find_branchpoint(r, branchpoint_version,
- first_branch_version, bp_state);
- stk.push(bp_state);
+ if (private_branch)
+ bstk.push(bstk.top());
+ else
+ bstk.push(branch_interner.intern(base_branch + "." + branch_name));
}
void
@@ -957,7 +972,9 @@
I(stk.size() > 0);
I(! curr_file().empty());
-
+
+ L(F("noting file edge %s -> %s\n") % prev_rcs_version_num % next_rcs_version_num);
+
// we can't use operator[] since it is non-const
std::map >::const_iterator
prev_delta = r.deltas.find(prev_rcs_version_num),
@@ -1004,8 +1021,8 @@
cvs_history::pop_branch()
{
I(stk.size() > 1);
- I(stk.top()->substates.size() > 0);
stk.pop();
+ bstk.pop();
}
@@ -1041,21 +1058,17 @@
manifest_id const & child_mid,
app_state & app,
cvs_history & cvs,
- unsigned long depth,
bool head_manifest_p)
{
- if (depth == 0)
- L(F("storing trunk manifest %s (base %s)\n") % parent_mid % child_mid);
- else
- L(F("storing branch manifest %s (base %s)\n") % child_mid % parent_mid);
+ L(F("storing manifest %s (base %s)\n") % parent_mid % child_mid);
- if (depth == 0 && head_manifest_p)
+ if (head_manifest_p)
{
- L(F("storing trunk head %s\n") % child_mid);
- // the trunk branch has one very important manifest: the head.
- // this is the "newest" of all manifests within the import, and
- // we store it in its entirety.
+ L(F("storing head %s\n") % child_mid);
+ // a branch has one very important manifest: the head. this is
+ // the "newest" of all manifests within the branch (including
+ // the trunk), and we store it in its entirety.
if (! app.db.manifest_version_exists(child_mid))
{
manifest_data mdat;
@@ -1070,81 +1083,44 @@
return;
}
- unsigned long p, c, older, newer;
- p = cvs.manifest_version_interner.intern(parent_mid.inner()());
- c = cvs.manifest_version_interner.intern(child_mid.inner()());
- older = (depth == 0) ? p : c;
- newer = (depth == 0) ? c : p;
+ unsigned long older, newer;
+
+ older = cvs.manifest_version_interner.intern(parent_mid.inner()());
+ newer = cvs.manifest_version_interner.intern(child_mid.inner()());
+
if (cvs.manifest_cycle_detector.edge_makes_cycle(older,newer))
{
- if (depth == 0)
- {
- L(F("skipping cyclical trunk manifest delta %s -> %s\n")
- % parent_mid % child_mid);
- // if this is on the trunk, we are potentially breaking the chain
- // one would use to get to p. we need to make sure p exists.
- if (!app.db.manifest_version_exists(parent_mid))
- {
- L(F("writing full manifest %s\n") % parent_mid);
- manifest_data mdat;
- write_manifest_map(parent, mdat);
- app.db.put_manifest(parent_mid, mdat);
- }
- }
- else
- {
- L(F("skipping cyclical branch manifest delta %s -> %s\n")
- % child_mid % parent_mid);
- // if this is on a branch, we are potentially breaking the chain one
- // would use to get to c. we need to make sure c exists.
- if (!app.db.manifest_version_exists(child_mid))
- {
- L(F("writing full manifest %s\n") % child_mid);
- manifest_data mdat;
- write_manifest_map(child, mdat);
- app.db.put_manifest(child_mid, mdat);
- }
- }
+
+ L(F("skipping cyclical manifest delta %s -> %s\n")
+ % parent_mid % child_mid);
+ // we are potentially breaking the chain one would use to get to
+ // p. we need to make sure p exists.
+ if (!app.db.manifest_version_exists(parent_mid))
+ {
+ L(F("writing full manifest %s\n") % parent_mid);
+ manifest_data mdat;
+ write_manifest_map(parent, mdat);
+ app.db.put_manifest(parent_mid, mdat);
+ }
return;
}
cvs.manifest_cycle_detector.put_edge(older,newer);
- if (depth == 0)
- {
- L(F("storing trunk manifest delta %s -> %s\n")
- % child_mid % parent_mid);
+
+ L(F("storing manifest delta %s -> %s\n")
+ % child_mid % parent_mid);
+
+ // the ancestry-based 'child' is a 'new' version as far as the
+ // storage system is concerned; that is to say that the
+ // ancestry-based 'parent' is a temporally older tree version, which
+ // can be constructed from the 'newer' child. so the delta should
+ // run from child (new) -> parent (old).
- // in this case, the ancestry-based 'child' is on a trunk, so it is
- // a 'new' version as far as the storage system is concerned; that
- // is to say that the ancestry-based 'parent' is a temporally older
- // tree version, which can be constructed from the 'newer' child. so
- // the delta should run from child (new) -> parent (old).
-
- delta del;
- diff(child, parent, del);
- rcs_put_raw_manifest_edge(parent_mid.inner(),
- child_mid.inner(),
- del, app.db);
- }
- else
- {
- L(F("storing branch manifest delta %s -> %s\n")
- % parent_mid % child_mid);
-
- // in this case, the ancestry-based 'child' is on a branch, so it is
- // an 'old' version as far as the storage system is concerned; that
- // is to say it is constructed by first building a 'new' version (the
- // ancestry-based 'parent') and then following a delta to the
- // child. remember that the storage system assumes that all deltas go
- // from temporally new -> temporally old. so the delta should go from
- // parent (new) -> child (old)
-
- delta del;
- diff(parent, child, del);
- rcs_put_raw_manifest_edge(child_mid.inner(),
- parent_mid.inner(),
- del, app.db);
- }
+ delta del;
+ diff(child, parent, del);
+ rcs_put_raw_manifest_edge(parent_mid.inner(),
+ child_mid.inner(),
+ del, app.db);
}
@@ -1217,89 +1193,23 @@
% state->in_edges.size());
}
-
static void
-import_states_recursive(ticker & n_edges,
- ticker & n_branches,
- shared_ptr state,
- cvs_branchname branch_filter,
- revision_id parent_rid,
- manifest_id parent_mid,
- manifest_map parent_map,
- cvs_history & cvs,
- app_state & app,
- vector< pair > & revisions,
- unsigned long depth);
-
-static void
-import_states_by_branch(ticker & n_edges,
- ticker & n_branches,
- shared_ptr state,
- revision_id const & parent_rid,
- manifest_id const & parent_mid,
- manifest_map const & parent_map,
- cvs_history & cvs,
- app_state & app,
- vector< pair > & revisions,
- unsigned long depth)
+import_branch_states(ticker & n_edges,
+ cvs_branch & branch,
+ cvs_history & cvs,
+ app_state & app,
+ vector< pair > & revisions)
{
- set branches;
-
- // collect all the branches
- for (map< cvs_key, shared_ptr >::reverse_iterator i = state->substates.rbegin();
- i != state->substates.rend(); ++i)
- branches.insert(i->first.branch);
-
- // walk each sub-branch in order
- for (set::const_iterator branch = branches.begin();
- branch != branches.end(); ++branch)
- {
- import_states_recursive(n_edges, n_branches, state, *branch,
- parent_rid, parent_mid, parent_map,
- cvs, app, revisions, depth);
- }
-}
-
-static void
-import_states_recursive(ticker & n_edges,
- ticker & n_branches,
- shared_ptr state,
- cvs_branchname branch_filter,
- revision_id parent_rid,
- manifest_id parent_mid,
- manifest_map parent_map,
- cvs_history & cvs,
- app_state & app,
- vector< pair > & revisions,
- unsigned long depth)
-{
- if (state->substates.size() > 0)
- ++n_branches;
-
- manifest_id child_mid;
- revision_id child_rid;
- manifest_map child_map = parent_map;
+ manifest_map parent_map, child_map;
+ manifest_id parent_mid, child_mid;
+ revision_id parent_rid, child_rid;
- string branchname = cvs.branch_interner.lookup(branch_filter);
- ui.set_tick_trailer("building branch " + branchname);
+ // we look through the branch temporally *backwards* from oldest to
+ // newest
- // these are all sub-branches, so we look through them temporally
- // *backwards* from oldest to newest
- map< cvs_key, shared_ptr >::reverse_iterator newest_branch_state;
- for (map< cvs_key, shared_ptr >::reverse_iterator i = state->substates.rbegin();
- i != state->substates.rend(); ++i)
+ for (cvs_branch::reverse_iterator i = branch.rbegin();
+ i != branch.rend(); ++i)
{
- if (i->first.branch != branch_filter)
- continue;
- newest_branch_state = i;
- }
-
- for (map< cvs_key, shared_ptr >::reverse_iterator i = state->substates.rbegin();
- i != state->substates.rend(); ++i)
- {
- if (i->first.branch != branch_filter)
- continue;
-
revision_set rev;
boost::shared_ptr cs(new change_set());
build_change_set(i->second, parent_map, cvs, *cs);
@@ -1315,13 +1225,8 @@
store_manifest_edge(parent_map, child_map,
parent_mid, child_mid,
- app, cvs, depth, i == newest_branch_state);
+ app, cvs, i->first == branch.begin()->first);
- if (i->second->substates.size() > 0)
- import_states_by_branch(n_edges, n_branches, i->second,
- child_rid, child_mid, child_map,
- cvs, app, revisions, depth+1);
-
// now apply same change set to parent_map, making parent_map == child_map
apply_change_set(*cs, parent_map);
parent_mid = child_mid;
@@ -1351,6 +1256,10 @@
N(app.branch_name() != "", F("need base --branch argument for importing"));
cvs.base_branch = app.branch_name();
+ // push the trunk
+ cvs.stk.push(shared_ptr(new cvs_branch()));
+ cvs.bstk.push(cvs.branch_interner.intern(cvs.base_branch));
+
{
transaction_guard guard(app.db);
cvs_tree_walker walker(cvs, app.db);
@@ -1368,7 +1277,6 @@
P(F("phase 1 (version import) complete\n"));
I(cvs.stk.size() == 1);
- shared_ptr state = cvs.stk.top();
vector< pair > revisions;
{
@@ -1378,10 +1286,19 @@
manifest_map root_manifest;
manifest_id root_mid;
revision_id root_rid;
+
- import_states_by_branch(n_edges, n_branches, state,
- root_rid, root_mid,
- root_manifest, cvs, app, revisions, 0);
+ ui.set_tick_trailer("building trunk");
+ import_branch_states(n_edges, *cvs.stk.top(), cvs, app, revisions);
+
+ for(map >::const_iterator branch = cvs.branches.begin();
+ branch != cvs.branches.end(); ++branch)
+ {
+ ui.set_tick_trailer("building branch " + branch->first);
+ ++n_branches;
+ import_branch_states(n_edges, *(branch->second), cvs, app, revisions);
+ }
+
P(F("phase 2 (ancestry reconstruction) complete\n"));
guard.commit();
}
--- tests/t_cvsimport_deleted_invar.at
+++ tests/t_cvsimport_deleted_invar.at
@@ -1,8 +1,7 @@
# -*- Autoconf -*-
AT_SETUP([cvs import, deleted file invariant])
AT_KEYWORDS(cvs)
-AT_XFAIL_IF(true)
NEED_UNGZB64
MONOTONE_SETUP