18

This is a pretty esoteric question, so just to make clear here from the start: I am not talking about converting from svn to git, git to mercurial, or mercurial to git. I am talking about a complex situation that has arisen from taking advantage of "cross-system" plugins that allow Mercurial to interoperate, to some extent, with git and SVN.

For some time I have used the hg-subversion plugin to Mercurial to "track" an upstream SVN repository on code.google.com. Thanks to this plugin, Mercurial considers the repository to be "related" and is able to pull in just changes that have occurred since I last pulled from the repo. This allows me to maintain my own, private Mercurial repository that includes private changesets, branches, tags, etc., but which periodically syncs up and merges with the changes that have been occurring on the upstream SVN repo.

The upstream repo has moved, cleanly, from SVN to git. When I say cleanly, I mean they have taken with them the entire commit tree, or at least the part affecting the default/master branch that I care about.

I am now in a situation where I have a Mercurial repository that is up-to-date merged with the very last checkin on the now-defunct SVN repository, and I want to start pulling in changes from the new upstream git repository, starting at the change that occurred just after the svn repository was moved to github.

I can use the wonderful hg-git plugin to pull changes from this repository, but as the current repository has no notion of being "related" to the git upstream repo, it will pull ALL changes, including all the changes whose mirror-image changesets are already present in my repository.

So what I'm looking for is advice for how I can get my Mercurial repository to consider itself, via hg-git, related to the upstream git repository, and also consider all the appropriate commits from the git repository as "already pulled" for purposes of maintaining changeset parity.

I see that internally hg-git appears to use a file .hg/git-mapfile which I presume maps changesets between the upstream git and the local Mercurial repository. This is probably a clue.

What's the easiest way to get my local Mercurial repository into such a state where it essentially behaves as though it started as a clone of the upstream git repository, but maintains all of my own unrelated changesets that have been added over time?

(Note: I would prefer not to "start over" with a fresh clone, and then applying my private changes, because I want to maintain the historical integrity of this repository for my own build/debugging purposes).

danielpunkass
  • 17,527
  • 4
  • 24
  • 38
  • 2
    How willing are you to make a new repository, if I can walk you through keeping your changes with full history? If that's okay, the magic answer will be a brief tutorial on hg-git (make sure you're using durin42's branch, by the way) and `hg convert`'s rarely used `splicemap`. – Benjamin Pollack Sep 21 '11 at 23:04
  • What would I be giving up with a new repository? Just the specific UUID tags for each changeset? This would probably be OK assuming I preserve the tag names for them. I actually did get somewhat involved with hg convert's splicemap when I went from svn to hg. – danielpunkass Sep 22 '11 at 01:41
  • Yeah, that's all you'd be giving up. – Benjamin Pollack Sep 22 '11 at 14:27
  • Cool. I wonder if the general approach for how you would do this could be written up succinctly as an answer to this question, or does it feel like it needs to be interactive and depend heavily on the specifics of the repositories? I bet others would benefit if it's possible to clarify the approach! – danielpunkass Sep 23 '11 at 00:49
  • @BenjaminPollack 's suggestion was the first (only) thing I could think of that met the requirement of not having all the extra changesets in the repo. – StayOnTarget Dec 13 '18 at 19:18

3 Answers3

5

I have done something similar with git before. In the git->git case I was able to do a git-merge --strategy=ours which basically made my current repository believe that everything that was being merged in was a no-op.

What you need to do that is a branch that represents everything upstream that you know is already merged into your tree and then do a no-op style of merge into your tree then start pulling in changes with "real" merges.

From this site:

https://www.mercurial-scm.org/wiki/TipsAndTricks#Keep_.22My.22_or_.22Their.22_files_when_doing_a_merge

I see that a command like the following may be able to help you merge in the upstream repository and ignore everything upstream:

$ hg --config ui.merge=internal:local merge #keep my files

That should allow you to re-sync your downstream with upstream.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
  • Great clue, Ben. Thanks! Quick Google suggests that there are some other strategies for this, too. I think your suggestion sums up an interesting constraint: "I only care about my history from this point back, but want to track their history from this point forward." – danielpunkass Sep 21 '11 at 14:32
  • I guess this might reflect my lack of a complete understanding of DVCS operation, but how would I do that "keep my files" merge without actually pulling the changesets into the repository? In Mercurial at least, it seems I have to pull changesets in before a merge can happen, and one of the goals here is to avoid having all those redundant changesets in my repository. – danielpunkass Sep 21 '11 at 14:56
  • I don't see an immediate solution to the duplicate changesets issue. – Ben Goodwyn Sep 21 '11 at 15:08
2

I would clone the new upstream repository with Hg-git, then try to use the Convert extension to splice all the changes in the old local repository into the new one. In fact, I'd probably clone the local Hg-git repository into a native Mercurial repository and use a two-step pull from the upstream Git repository.

james woodyatt
  • 2,170
  • 17
  • 17
  • This would meet the OP's requirement exactly, and would probably produce the cleanest end result. It would look like the tracking HG repo had ALWAYS been following the parent git repository. – StayOnTarget Dec 13 '18 at 19:20
1

If no existing solution exists, I suppose one could write a script that patches and commits your changes to a new repository that is based on the git-clone instead. You "just" need to correlate the svn versions between hg-git-fromsvn and hg-svn, and replicate the update/patch/commit/merge sequence you've done on a new repo.

A fun project, to whomever does it. :)

Macke
  • 24,812
  • 7
  • 82
  • 118
  • This would definitely produce the "purest" result, hiding any evidence of there being some "graft" point. We'll see, if Ben's suggestion makes it easy enough to just "take all the changesets and run" then I probably won't fret too much about purity :) – danielpunkass Sep 21 '11 at 14:47