As described in Historical records, monotone revisions contain the sha1 hashes of their predecessors, which in turn contain the sha1 hashes of their predecessors, and so on until the beginning of history. This means that it is mathematically impossible to modify the history of a revision, without some way to defeat sha1. This is generally a good thing; having immutable history is the point of a version control system, after all, and it turns out to be very important to building a distributed version control system like monotone.
It does have one unfortunate consequence, though. It means that in the rare occasion where one needs to change a historical revision, it will change the sha1 of that revision, which will change the text of its children, which will change their sha1s, and so on; basically the entire history graph will diverge from that point (invalidating all certs in the process).
In practice there are two situations where this might be necessary:
If either of these events occur, we will provide migration commands
and explain how to use them for the situation in question; this much
is necessarily somewhat unpredictable. In the past we've used the
db rebuild
command, which extracts the ancestry graph from the
database and then recreates revisions from the manifests only — this
preserves the contents of each snapshot, but breaks tracking of file
identity across renames — and then reissues all existing certs that
you trust, signed with your key.1
While the db rebuild
command can reconstruct the ancestry graph
in your database, there are practical problems which arise when
working in a distributed work group. For example, suppose our group
consists of the fictional developers Jim and Beth, and they need to
rebuild their ancestry graph. Jim performs a rebuild, and sends Beth
an email telling her that he has done so, but the email gets caught by
Beth's spam filter, she doesn't see it, and she blithely syncs her
database with Jim's. This creates a problem: Jim and Beth have
combined the pre-rebuild and post-rebuild databases. Their databases
now contain two complete, parallel (but possibly overlapping) copies
of their project's ancestry. The “bad” old revisions that they were
trying to get rid of are still there, mixed up with the “good” new
revisions.
To prevent such messy situations, monotone keeps a table of branch epochs in each database. An epoch is just a large bit string associated with a branch. Initially each branch's epoch is zero. Most monotone commands ignore epochs; they are relevant in only two circumstances:
Thus, when a user rebuilds their ancestry graph, they select a new epoch and thus effectively disassociate with the group of colleagues they had previously been communicating with. Other members of that group can then decide whether to follow the rebuild user into a new group — by pulling the newly rebuilt ancestry — or to remain behind in the old group.
In our example, if Jim and Beth have epochs, Jim's rebuild creates a new epoch for their branch, in his database. This causes monotone to reject netsync operations between Jim and Beth; it doesn't matter if Beth loses Jim's email. When she tries to synchronize with him, she receives an error message indicating that the epoch does not match. She must then discuss the matter with Jim and settle on a new course of action — probably pulling Jim's database into a fresh database on Beth's end – before future synchronizations will succeed.
The previous section described the theory and rationale behind rebuilds and epochs. Here we discuss the practical consequences of that discussion.
If you decide you must rebuild your ancestry graph — generally by announcement of a bug from the monotone developers — the first thing to do is get everyone to sync their changes with the central server; if people have unshared changes when the database is rebuilt, they will have trouble sharing them afterwards.
Next, the project should pick a designated person to take down the netsync server, rebuild their database, and put the server back up with the rebuilt ancestry in it. Everybody else should then pull this history into a fresh database, check out again from this database, and continue working as normal.
In complicated situations, where people have private branches, or
ancestries cross organizational boundaries, matters are more complex.
The basic approach is to do a local rebuild, then after carefully
examining the new revision IDs to convince yourself that the rebuilt
graph is the same as the upstream subgraph, use the special db
epoch
commands to force your local epochs to match the upstream ones.
(You may also want to do some fiddling with certs, to avoid getting
duplicate copies of all of them; if this situation ever arises in real
life we'll figure out how exactly that should work.) Be very careful
when doing this; you're explicitly telling monotone to let you shoot
yourself in the foot, and it will let you.
Fortunately, this process should be extremely rare; with luck, it will never happen at all. But this way we're prepared.
[1] Regardless of who originally signed the certs, after the rebuild they will be signed by you. This means you should be somewhat careful when rebuilding, but it is unavoidable — if you could sign with other people's keys, that would be a rather serious security problem!