Search code examples
mercurialhg-git

What parts of the hg-git metadata state do I need to back up in order to start over?


This is currently a purely theoretical question (related to this one), but let me first give the background. Whenever you run hg gexport the initial hash will vary from invocation to invocation. This is similar to when you run git init or hg init. However, since the Mercurial and Git commits correspond to each other and build on previous hashes, there should be some way to start over from a minimal common initial state (or minimal state on the Git side, for example).

Suppose I have used hg-git in the past and now I am trying to sync again between my Mercurial and my Git states, but without (or very little of) the original .git directory from the hg gexport. What I do have, though, are the two metadata files: git-mapfile and git-tags.

There is an old Git mirror, which is sort of "behind" and the Mercurial repo which is up-to-date.

Then I configure the Mercurial repo for hg-git like so (.hg/hgrc):

[git]
intree = True

[extensions]
hgext.bookmarks=
topic=
hggit=

[paths]
default = ssh://[email protected]//project/repo
gitmirror = git+ssh://[email protected]/project/repo.git

If I now do the naive hg pull gitmirror all I will gain is a duplication of every existing commit on an unrelated branch with unrelated commit history (and the double amount of heads, compared to prior to the pull).

It clearly makes no big difference to place those two metadata files (git-mapfile and git-tags) into .hg. The biggest difference is that the pull without these files will succeed (but duplicate everything) and the pull with them will error out at the first revision because of "abort: unknown revision ..." (even makes sense).

Question: which part(s) and how much (i.e. what's the minimum!) of the Git-side data/metadata created by hg gexport do I have to keep around in order to start over syncing with hg-git? (I was unable to find this covered in the documentation.)


Solution

  • The core metadata is stored in .hg/git-mapfile, and the actual Git repository is stored in .hg/git or .git dependending on intree. The git-mapfile is the only file needed to reproduce the full state; anything else is just cache. In order to recreate a repository from scratch, do the following:

    1. Clone or initialise the Mercurial repository, somehow.
    2. Clone or initialise the embedded Git repository, e.g. using git clone --bare git+ssh://[email protected]/project/repo.git .hg/git.
    3. Copy over the metadata from the original repository, and put it into .hg/git-mapfile.
    4. Run hg git-cleanup to remove any commits from the map no longer known to Mercurial.
    5. Pull from Git.
    6. Push to Git.

    These are the steps I'd use, off the top of my head. The three last steps are the most important. In particular, you must pull from Git to populate the repository prior to pushing; otherwise, the conversion will fail.