6

Here's the situation: developer Foo created a hg repo from our svn repo. Foo's hg repo was only a shallow clone of the trunk in svn (no svn branches, tags, etc. and the history was incomplete [about 100 changesets]). Developer Bar did the same thing, but cloned the entire svn repo including the entire history, branches, tags, etc. Both Foo and Bar have done branchy development on their repositories.

There is a common SVN ancestor to both repositories, but each hg repo has a different version number for it. I would like to reparent Foo's changes from the common ancestor onto Bar's repo. Here's a diagram of what I'm looking for:

Foo's repo:

C'-D'-E-F---G
       \   /
        H-I

Bar's repo:

...A-B-C-D-J-K---L
            \   /
             M-N

C,C' and D,D' have the same content, but different version numbers & comments.

The goal:

...A-B-C-D--E-F---G
          \  \   /
           \  H-I
            \
             J-K---L
              \   /
               M-N

I've run out of ideas on how to make this happen. I tried convert --splicemap splice.map [splice.map file contained E D] (didn't do anything). Clone -f managed to get everything into one repo, but they appear to be independent trees. After clone -f, I tried rebase --source E --dest D --detach, but it just crashed :(

Ideas?

I'm aware altering the history will invalidate anyone's clone of the repositories, this is not a problem in this case. All users will be re-cloning from the result of this effort.

mattjackets
  • 101
  • 5

3 Answers3

2

SOLVED!

One thing I didn't notice initially was that my presumed common ancestor wasn't exactly the same after all. During the svn->hg conversion of Foo's repo, the $ID$ strings were expanded, but were not in the creation of Bar's repo. Step 1 below was a simple fix to create a REAL common ancestor.

The following steps allowed me to accomplish my goal:

1- Ensure that the presumed common ancestor (D and D') are actually identical. If not, create a new splice point for them (S) in Bar's repo. S should exactly match the content of D' in my example.

    ...A-B-C-D--J-K---L
              \  \   /
               S  M-N

2- Trim the history of Foo's repo to remove the duplicate history, including D', with

    hg convert --splicemap TrimSplicemap Foo FooTrimmed

TrimSplicemap contents: (where E is the full hash of E)

    E 0000000000000000000000000000000000000000

3- Use hg strip to remove the disconnected, redundant history

    cd FooTrimmed
    hg strip C'

4- Use hg convert again to splice Foo's stripped repo onto Bar's repo at commit 'S'

    cd ../Bar
    hg convert --splicemap FooBarSplicemap ../FooTrimmed .

FooBarSplicemap contents: (where E' is the NEW hash for E in the FooTrimmed, and S is the hash of S)

    E' S

That should do it! :D

mattjackets
  • 101
  • 5
1

You might be able accomplish this using Mercurial Queues.

  1. Import every changeset from repo Foo into a patch queue.
  2. Go to the Bar repo.
  3. Update Bar to the changeset that is the common ancestor.
  4. Import the patch queue into Bar.
  5. Apply the patch queue.

This would change the commit IDs of all the Foo patches, but still allow you to keep the entire history and merge their dev repos together.

Tim Henigan
  • 60,452
  • 11
  • 85
  • 78
  • 1
    THe problem with that is that merge changesets don't work well with MQ, so G and L in his example wouldn't apply with both of their parents. Transplant has the same issue. – Ry4an Brase May 06 '11 at 16:19
1

We talked about this today in IRC and my advice was to just pull both into the same repo and let it have two roots. The heads will be exactly as you want and the rest really doesn't matter.

If you just can't stomach that (you're imagining people use history/blame more than they really do) then I think your splicemap should have:

E D

in in since you're trying to get E's parent to be D (not D')

Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
  • Yep, E D is correct, I edited the diagram yesterday and didn't update the text. Thanks for pointing that out. Having two independent trees in the repo is my fall-back position, and have that solution ready if need be. I think ‘blame’ would work fine with the two trees...if that were our only need for the history then we would be in good shape. – mattjackets May 06 '11 at 14:54
  • Sounds good. Remember that you can always keep SVN around read-only too. It's been fulfilling your history requirements for years, so leaving it available probably handles them up to the point of transition just fine. Eventually people will stop consulting it but there's no cost in keeping it around for archeological work. – Ry4an Brase May 06 '11 at 16:18
  • Very true, thanks for keeping thing in perspective for me. It's easy to get wrapped up in the challenge. – mattjackets May 06 '11 at 17:20