Differences between revisions 2 and 3
Revision 2 as of 2009-05-24 21:33:02
Size: 5793
Editor: mpm
Comment:
Revision 3 as of 2009-05-24 21:56:24
Size: 5795
Comment:
Deletions are marked like this. Additions are marked like this.
Line 27: Line 27:
 * repository history corruption (hg verify reports errors.  * repository history corruption (hg verify reports errors)
Line 105: Line 105:

Dealing With Repository Corruption

1. Sources of Corruption

Mercurial runs locally with normal user privileges without a protected store. This means it's possible for regular users, their tools or their machines to damage their repository history inadvertently. There are several possible sources of corruption, including:

  • user error (damaging or deleting crucial files in .hg/)
  • hardware failure (memory corruption, disk corruption, power supply issues)
  • operationg system failure (filesystem bugs, kernel crashes, cross-platform compatibility issues)
  • tool error (third-party tools inadvertently damaging .hg/ state)
  • mercurial failure (bugs in hg causing data corruption)

Mercurial has multiple levels of defense against repository corruption including:

  • append-only history for all core operations
  • cryptographically strong hashes on all data
  • journalled transactions
  • frequent history duplication via clone/push/pull
  • lightweight integrity checking via verify

User error is easily the most common of these.

2. Classes of Corruption

There are two basics classes of corruption:

  • corrupted working directory state (mercurial becomes confused about working directory state)
  • repository history corruption (hg verify reports errors)

Only the first is really 'repository corruption', but we'll discuss on this page anyway.

3. Corrupted Working Directory State (aka dirstate)

This occurs when the file's tracking hg's notion of what you're currently working on becomes damaged. The primary file here is .hg/dirstate. This file contains pointers to the parent revision and information about all the files currently tracked in the working directory. Corruption looks something like this:

$ hg st
M foo
A bar
$ hg id
58745409d2e2+ tip
$ echo fdsjfkgsjdfhgskdfhkgshjkdfhjkgsjkhdfkhgjsdhjkfgoo > .hg/dirstate
$ hg st
abort: unknown revision '6664736a666b67736a64666867736b6466686b67'!

Recovering from dirstate corruption is usually straightforward. If you know what revision you're working on, you can run:

$ hg debugrebuildstate -r tip  # rebuild dirstate assuming we're at tip
$ hg id
58745409d2e2+ tip
$ hg st
M foo
? bar

Note that Mercurial still knows that foo is modified but has forgotten that bar was added.

If debugrebuildstate doesn't work, it's usually possible to simply clone your repository and get back to a working state:

$ cd ..
$ hg clone repo fixed-repo
updating working directory
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd fixed-repo
$ hg id
58745409d2e2+ tip

You can now copy over any changes from your damaged working directory to your repaired one.

4. Reposity Corruption

This is corruption that involves the project history, specifically the files in .hg/store. This can happen in a number of ways, most often through user error (for instance deleting all files with 'foo.c' in their name). For example:

$ hg verify
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
1213 files, 8591 changesets, 17158 total revisions

$ rm .hg/store/data/mercurial/error.py.i  # oops!
$ hg verify
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
 data/mercurial/error.py.i@7633: missing revlog!
 7633: empty or missing mercurial/error.py
 mercurial/error.py@7633: f6aad9f78a08 in manifests not found
 mercurial/error.py@7636: 4fb29207f327 in manifests not found
 mercurial/error.py@7637: 3bfff9613e8b in manifests not found
 mercurial/error.py@7640: 40ee894622ad in manifests not found
 mercurial/error.py@7641: e640820306d6 in manifests not found
 mercurial/error.py@7643: f43c616251f5 in manifests not found
 mercurial/error.py@7644: 455d738b74c7 in manifests not found
 mercurial/error.py@7646: a3128b43b03f in manifests not found
 mercurial/error.py@7947: b4a8b72bfa1c in manifests not found
 mercurial/error.py@8144: 1f996809c441 in manifests not found
 mercurial/error.py@8225: e1537136a8d0 in manifests not found
 mercurial/error.py@8226: 5f91269779c0 in manifests not found
 mercurial/error.py@8227: 6706abc98ab2 in manifests not found
1213 files, 8591 changesets, 17145 total revisions
15 integrity errors encountered!
(first damaged changeset appears to be 7633)

4.1. Basic Recovery

Here, we've damaged our repository starting at revision 7633 (see the line at the bottom). Taking advantage of the append-only property of Mercurial, we can recover everything up to this point with:

$ cd ..
$ hg clone -r 7632 damage fixed
requesting all changes
adding changesets
adding manifests
adding file changes
added 7633 changesets with 14944 changes to 1126 files
updating working directory
964 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd fixed
$ hg verify
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
1126 files, 7633 changesets, 14944 total revisions

4.2. Other Recovery Options

/!\ Make a backup before attempting repo surgery!

We can also use 'pull -r' to incrementally attempt to pull larger portions of the history into a repository that has some of the missing file revisions. It may also be possible to copy intact copies of the damaged files from a clone.

5. Advanced: Inspecting Repository Data Structures

Mercurial's internal data structures are fairly easy to understand. Details can be found at Design and in FileFormats. Mercurial includes commands for directly dumping most aspects of its internals via commands like debugindex, debugdata, debugstate.

RepositoryCorruption (last edited 2016-09-29 09:57:46 by ThomasDeSchampheleire)