Differences between revisions 12 and 13
Revision 12 as of 2010-10-15 06:28:16
Size: 7129
Editor: abuehl
Comment: conform with WikiStyleGuide
Revision 13 as of 2010-10-15 21:57:05
Size: 7129
Editor: abuehl
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Dealing with repository and dirstate corruption = = Dealing with Repository and Dirstate Corruption =

Dealing with Repository and Dirstate 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)

User error is easily the most common of these. 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

2. Classes of corruption

There are two basics classes of corruption:

Note that only damage to history should properly be referred to as 'repository corruption', but we'll discuss both on this page anyway.

3. Dirstate corruption

This occurs when the files 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. Recovery using convert extension

Alternatively, you can try to use the convert extension to force a rebuild of the repository. Be forewarned that this will result in new hashes for all revisions and will require all users to re-clone from the recovered repository.

First step is to enable the convert extension, assuming the repository is in the directory named REPO:

$ vim REPO/.hg/hgrc
...
[extensions]
hgext.convert=
...

While it is possible to convert in-place, a wise safety precaution is to convert to an empty directory:

$ mkdir REPOFIX

Use the convert extension to recover the repository:

$ hg convert --config convert.hg.ignoreerrors=True REPO REPOFIX
scanning source...
sorting...
converting...
[Various messages, most of which will be the commit messages]
ignoring: data/.DS_Store.i@26a47e9188c: no match found
[More commit messages]
.hgtags@78ff9079978f, line 1: tag '1.0b1' refers to unknown node
updating tags

The output from your command will vary greatly, but the important part is that the corrupted files have been ignored and the rest of the files are in the new repository.

4.3. 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 (see DebuggingFeatures).

6. See also


CategoryHowTo

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