The unified diff between revisions [87c82b17..] and [4c6270c7..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "commands.cc"
#  from [2f64f75b9afb4a86bac84bcc6cacaba86866be2b]
#    to [19e176916ef418e11386e0b0b76078121a201421]
#
# patch "database.cc"
#  from [430079748f8733f34aa2f781847a905d85983436]
#    to [2d2107adceb23e96ac42776c4b9e8658224581d0]
#
# patch "database.hh"
#  from [dd9695e867200e94e2d10b9e9bd74bd423c0ac10]
#    to [5d30ef040b7ce46fb8ad65578d68b1693db397d8]
#
============================================================
--- commands.cc	2f64f75b9afb4a86bac84bcc6cacaba86866be2b
+++ commands.cc	19e176916ef418e11386e0b0b76078121a201421
@@ -2126,6 +2126,11 @@ CMD(db, N_("database"),
         build_changesets_from_manifest_ancestry(app);
       else if (idx(args, 0)() == "rosterify")
         build_roster_style_revs_from_manifest_style_revs(app);
+      else if (idx(args, 0)() == "flip")
+        {
+          app.db.make_fwd_deltas("files", "file_deltas");
+          app.db.make_fwd_deltas("rosters", "roster_deltas");
+        }
       else
         throw usage(name);
     }
============================================================
--- database.cc	430079748f8733f34aa2f781847a905d85983436
+++ database.cc	2d2107adceb23e96ac42776c4b9e8658224581d0
@@ -1172,23 +1172,10 @@ database::put_version(hexenc<id> const &
                       string const & data_table,
                       string const & delta_table)
 {
+  // TODO: add an invariant or something perhaps

-  data old_data, new_data;
-  delta reverse_delta;
-
-  get_version(old_id, old_data, data_table, delta_table);
-  patch(old_data, del, new_data);
-  diff(new_data, old_data, reverse_delta);
-
   transaction_guard guard(*this);
-  if (exists(old_id, data_table))
-    {
-      // descendent of a head version replaces the head, therefore old head
-      // must be disposed of
-      drop(old_id, data_table);
-    }
-  put(new_id, new_data, data_table);
-  put_delta(old_id, new_id, reverse_delta, delta_table);
+  put_delta(new_id, old_id, del, delta_table);
   guard.commit();
 }

@@ -1476,6 +1463,91 @@ database::get_revision(revision_id const
   dat = rdat;
 }

+void
+database::make_fwd_deltas(string const & data_table, string const & delta_table)
+{
+  string query;
+  transaction_guard guard(*this);
+
+  set< hexenc<id> > del_bases, all_ids;
+  set< pair< hexenc<id>, hexenc<id> > > dels;
+
+  // id, base
+  get_ids(data_table, all_ids);
+    {
+      results res;
+      query = "SELECT id, base FROM " + delta_table;
+      fetch(res, 2, any_rows, query.c_str());
+
+      for (size_t i = 0; i < res.size(); ++i)
+        {
+          all_ids.insert(hexenc<id>(res[i][0]));
+          del_bases.insert(hexenc<id>(res[i][1]));
+          dels.insert( make_pair(res[i][0], res[i][1]) );
+        }
+    }
+
+  set< hexenc<id> > new_bases;
+
+  set_difference(all_ids.begin(), all_ids.end(), del_bases.begin(), del_bases.end(),
+                 inserter(new_bases, new_bases.begin()));
+
+  // create some empty temporary tables
+  string tmp_data_table("tmp_" + data_table);
+  string tmp_delta_table("tmp_" + delta_table);
+
+  query = "CREATE TABLE " + tmp_data_table + " AS SELECT * FROM " + data_table + " WHERE 1=0";
+  execute(query.c_str());
+  query = "CREATE TABLE " + tmp_delta_table + " AS SELECT * FROM " + delta_table + " WHERE 1=0";
+  execute(query.c_str());
+
+  ticker full("full", "g", 1);
+  for ( set< hexenc<id> >::const_iterator i = new_bases.begin(); i != new_bases.end(); i++)
+    {
+      MM(*i);
+      data dat;
+      get_version(*i, dat, data_table, delta_table);
+      put(*i, dat, tmp_data_table);
+      ++full;
+    }
+
+  ticker flips("flips", "f", 1);
+
+  for ( set< pair< hexenc<id>, hexenc<id> > >::const_iterator i = dels.begin(); i != dels.end(); i++)
+    {
+      ++flips;
+      hexenc<id> new_id = i->second;
+      hexenc<id> new_base = i->first;
+      MM(new_id);
+      MM(new_base);
+
+      data base, dat;
+      get_version(new_id, dat, data_table, delta_table);
+      get_version(new_base, base, data_table, delta_table);
+      delta del;
+      diff(base, dat, del);
+
+      put_delta(new_id, new_base, del, tmp_delta_table);
+    }
+
+  query = "DELETE FROM " + data_table;
+  execute(query.c_str());
+  query = "DELETE FROM " + delta_table;
+  execute(query.c_str());
+
+  query = "INSERT INTO " + data_table + " SELECT * FROM " + tmp_data_table;
+  execute(query.c_str());
+  query = "INSERT INTO " + delta_table + " SELECT * FROM " + tmp_delta_table;
+  execute(query.c_str());
+
+  query = "DROP TABLE " + tmp_data_table;
+  execute(query.c_str());
+  query = "DROP TABLE " + tmp_delta_table;
+  execute(query.c_str());
+
+  guard.commit();
+}
+
 void
 database::deltify_revision(revision_id const & rid)
 {
@@ -1569,7 +1641,8 @@ database::put_revision(revision_id const
               % text(new_id.inner()()));
     }

-  deltify_revision(new_id);
+  // TODO: some different version?
+  // deltify_revision(new_id);

   // Phase 4: write the roster data and commit
   put_roster(new_id, ros, mm);
============================================================
--- database.hh	dd9695e867200e94e2d10b9e9bd74bd423c0ac10
+++ database.hh	5d30ef040b7ce46fb8ad65578d68b1693db397d8
@@ -259,6 +259,8 @@ public:
   void get_revision_manifest(revision_id const & cid,
                              manifest_id & mid);

+  void make_fwd_deltas(std::string const & data_table, std::string const & delta_table);
+
   void deltify_revision(revision_id const & rid);

   void get_revision(revision_id const & id,