views:

368

answers:

5

Like many people, I have several SVN repositories that contains several projects. I've decided to convert one of these repositories to Mercurial for several reasons.

I've successfully converted the repository using instructions located here. The new hg repo includes everything; all history and the correct tags. The conversion worked great.

Now, I need to "diverge" the two projects but I want to maintain the history on both sides. I'm wondering if there is a way to do this appropriately to prevent things like accidentally importing the changesets in to the others repository down the road.

To be clear, I don't care that each repository will have the same history for the current change set back (in fact, I want this). I just want to somehow indicate that they are "different" repositories from now on...

Update: Can someone elaborate on the --force? At what point will that flag be necessary. At http://www.selenic.com/mercurial/hg.1.html, under "pull", I see that the -f, --force options are to "run even when remote repository is unrelated" but what makes a repository unrelated? To me, since I cloned from the original repository they are (or could be) related....

Update: What I'm trying to prevent is allowing one repo to be pulled in to the other repo after some time has passed. (Which is now the case.) I wrote a script that produce the problem. And accomplishes exactly what I don't want to happen (It's a windows batch file):

@echo off

REM - First, create two distinct repos. 
REM - Add some files to each.

MD test1
MD test2

cd test1
hg init

REM - Do several writes and commits to give content to the repo.

echo This is some text for test1  > test1.txt
echo This iss some more text; blah blah; >> test1.txt

echo Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sapien velit, hendrerit sit amet ultrices nec, malesuada a mauris. Mauris eget nisi sit amet diam sodales tristique nec at turpis. Nam viverra pulvinar est, quis accumsan nunc fringilla ut. Nullam eu massa sapien, ac molestie magna. Curabitur nec pharetra nibh. Pellentesque velit dui, placerat vel porta eget, malesuada vitae dolor. In a lectus vel sapien imperdiet fringilla quis eu odio. Donec pellentesque ante nec est iaculis a aliquam nibh varius. Vivamus sit amet dolor non lorem ullamcorper ultricies quis in risus. Mauris eget orci leo. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut lorem lacus. In hac habitasse platea dictumst. Mauris pellentesque purus non elit molestie vehicula.  >> test1.txt
echo This is another text file for test1 > test2.txt

hg addremove
hg commit -m"First commit on test1"


echo Nunc mollis, neque vel tempus iaculis, eros erat egestas metus, vitae condimentum tortor tortor id sem. Integer ac ante quis nisl condimentum iaculis. Vestibulum et quam vel lectus porta ultricies. Donec ultricies dignissim sollicitudin. Morbi sit amet est urna, a bibendum felis. In aliquet, tortor nec consequat ultricies, sapien diam eleifend nulla, in ullamcorper eros sapien ac magna. Phasellus sit amet congue quam. Nulla gravida justo aliquam libero tristique non tempor nunc mollis. Suspendisse venenatis tincidunt massa, a tempus odio blandit non. Suspendisse egestas orci lorem. Curabitur bibendum nibh quis elit tempus id suscipit nisl viverra. Pellentesque placerat nisl at felis porta laoreet. >> test1.txt
hg commit -m"second commit on test1"

echo Nunc placerat cursus scelerisque. Sed ac magna lacus, quis facilisis elit. Praesent mattis purus in urna congue auctor. Fusce pellentesque scelerisque dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus vulputate nunc quis ante laoreet posuere. Curabitur ante turpis, blandit vitae dapibus vitae, convallis at tortor. Sed augue leo, fermentum id consequat et, accumsan in neque. In pellentesque luctus nisi, ac sagittis nisl condimentum tincidunt. Cras nec dui vitae purus adipiscing consectetur id at mi. Vestibulum quis est vitae purus dictum mollis. Phasellus ultrices rhoncus eleifend. Sed sit amet euismod orci. Curabitur id turpis tortor, nec mollis neque. Praesent egestas augue vitae sem fringilla at molestie lacus venenatis.  >> test1.txt

hg commit -m"thrid commit on test1"

echo Suspendisse nec porta velit. Donec aliquet mi vel felis tempor vehicula vitae interdum quam. Phasellus tempor orci at ligula adipiscing sagittis. Quisque faucibus accumsan dui vel facilisis. Pellentesque laoreet quam vel nisl mattis ac venenatis sapien suscipit. Nam eget dictum risus. Proin quam magna, volutpat quis congue vitae, dapibus et mi. Etiam tempus purus ut massa sodales sed cursus odio ultrices. Ut vel dictum urna. Fusce blandit dignissim nibh a tempus. Nullam libero arcu, feugiat vel sollicitudin vitae, lacinia pulvinar enim. Nulla hendrerit faucibus tortor, sit amet convallis velit vehicula ut. Cras leo sem, fermentum eu adipiscing non, bibendum et lacus. Nulla volutpat tortor non libero feugiat fermentum id quis sem. Vivamus lobortis nibh quis diam semper feugiat. Phasellus ac lobortis purus. Vivamus at mi sem. Quisque accumsan consequat placerat.  >> test1.txt

hg commit -m"fourth commit on test1"

cd ..

cd test2
hg init

echo Nala is a cat >> myCats.txt
hg addremove
hg commit -m"first commit on test2"

echo Simba is a cat >> myCats.txt
hg commit -m"2nd commit on test2"

echo Nanoon is a cat >> myCats.txt
hg commit -m"3rd commit on test2"

cd ..

REM ------------------------------------------------------------------------------------------------------------------------------------------------------

hg clone --pull test1 test-combined

cd test-combined
hg pull ../test2

echo -
echo You should have gotten a "abort: repository is unrelated" error. 
echo this is from attempting to pull test2 in to the test-combined. Can't without --force flag.

echo This is another file for combined repo > combinedRepo.txt
echo This should be unique to test-combined >> combinedRepo.txt
hg addremove
hg commit -m"1st Change to combined repo"

echo Fusce lectus arcu, cursus et dictum et, ultrices ut magna. Cras ultrices leo ac arcu commodo auctor. Pellentesque commodo sem et elit euismod posuere. Nam cursus, nisl ut placerat tincidunt, diam ante congue felis, id facilisis sem eros nec augue. Phasellus vel interdum est. Nunc at tellus non dui aliquam placerat nec placerat augue. Vestibulum justo sem, laoreet et blandit eu, mollis a nibh. Cras convallis, turpis quis vulputate euismod, risus neque convallis dui, posuere eleifend dolor quam ut dui. Integer pharetra porttitor lorem, vitae commodo mi semper non. Duis ipsum nisi, vulputate vel cursus ut, consectetur eu tellus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce lobortis quam molestie leo scelerisque blandit. Ut massa neque, dapibus rutrum porta et, molestie vitae augue. Mauris eu erat a turpis suscipit viverra. Praesent vitae ante non dui volutpat ullamcorper eu in nisl.  >> combinedRepo.txt
hg commit -m"2nd Change to combined repo"

cd .hg

rem - Replace the hgrc file where we blank out the default file.
echo [paths] > hgrc
echo default = >> hgrc

cd ..
cd ..
REM - We are not back in the starting folder...
REM ------------------------------------------------------------------------------------------------------------------------------------------------------

cd test1
echo A third file to make yet another commit in the repo. > myThirdFile.txt
hg addremove
hg commit -m"a third file to make this (test1) different than test-combined"
cd ..

REM - Retry the pull - Same source but diverged repos.
cd test-combined
hg pull ../test1

ECHO -
ECHO The pull just executed (in test-combined) succeeded but we want to prevent this.
ECHO Here is the log for test-combined

hg log

cd ..
@echo on

To run this, create an empty directory and save the text in the code block in to a .cmd file. Open a command window and navigate to the file and execute the .cmd.

You'll see the following above the log text:

added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge)

The log text shows that the two repos were, indeed, combined. In my ideal solution, this would have resulted in an error or a request for the --force flag.

Update (9/10/2009): The hg convert didn't work for what I needed.

+3  A: 

Clone the repository, then simply remove the original remote repo path from the new clone (so that it's impossible to push changes back to the old repo) and you should have a new completely independent repository.

Amber
Your talking about the hgrc file in the .hg folder, yes? I have done this. I felt this was a first step. Thank you. Anything further?
Frank V
You should be good to go.
Amber
As soon as the repos are diverging the only way to push to the other is to use --force. So you won't do that accidentally.
tonfa
@tonfa: See question update please.
Frank V
By default, `hg push` will refuse to run if doing so would create a new branch at the remote repository (i.e. if local commits are not a direct continuation of existing history as it exists at the remote repo). Thus if the last commit before splitting your repo into two was A, then as soon as someone makes commit B to the first repo and someone else makes a different commit C to the second repo, `hg push` will refuse to push between the two since B doesn't exist in the second and C doesn't exist in the first. Using `hg push --force` would tell hg to go ahead and do it anyways.
Amber
However, if you remove the reference path to the remote repository completely (as I mentioned), then `hg push` won't even know about the other repo and thus won't push to it period, even if you tried to force it to.
Amber
@Dav: What about pull? Sometimes I'll execute a command like `hg pull ./OtherRepo/`. I'm not sure that is the exact syntax but the basic idea is to go back one directory and grab the changes from another repo. Will I still need `--force` in this instances?
Frank V
If the directory is one that was already being tracked in the repo before the split, then you can probably pull without `--force` (unless you removed the remote repo info).
Amber
@Dav: I think we are back to square 1. The pull is what I want to error out (along with push and all that). I posted a script that reproduced my dilemma (for Vista). Could you take a look at that? It is possible that what I want to do is not possible.
Frank V
Because you're manually specifying a repository path, it doesn't matter that you remove the remote path from the .hgrc - the path there is only used if you don't specify an absolute path. `hg pull` won't complain about pulling into testcombined because it's still related (as far as directory trees go) to test1. `hg pull` *doesn't* mind about adding heads because it assumes you know what you're pulling - it's only `hg push` that will complain about adding heads because you may not know what you're doing to someone else's remote repo.
Amber
+1  A: 

Use hg convert again with its filemap option to filter your files.

diverge>hg init repo
diverge>cd repo
diverge\repo>echo some text > file1.txt
diverge\repo>hg ci -A -m "added first file"
adding file1.txt

diverge\repo>echo more text > file2.txt
diverge\repo>echo 123 >> file1.txt
diverge\repo>hg ci -A -m "some changes and new file"
adding file2.txt

diverge\repo>hg log
1[tip]   0f37e61d075b   2009-09-11 10:35 +0200   wierob83
  some changes and new file

0   b04d9d12fb1d   2009-09-11 10:34 +0200   wierob83
  added first file


diverge\repo>cd ..
diverge>echo include file1.txt > files-in-repo-one.txt
diverge>echo exclude file1.txt > files-in-repo-two.txt
diverge>hg convert --filemap files-in-repo-one.txt repo new-repo-one
initializing destination new-repo-one repository
scanning source...
sorting...
converting...
1 added first file
0 some changes and new file

diverge>hg convert --filemap files-in-repo-two.txt repo new-repo-two
initializing destination new-repo-two repository
scanning source...
sorting...
converting...
1 added first file
0 some changes and new file

diverge>cd new-repo-two
diverge\new-repo-two>hg out ..\repo
comparing with ..\repo
searching for changes
abort: repository is unrelated

diverge\new-repo-two>hg push ..\repo
pushing to ..\repo
searching for changes
abort: repository is unrelated  <-- can't push because its an independent repo

So it should have worked, but:

diverge\new-repo-two>cd ..\new-repo-one
diverge\new-repo-one>hg out ..\repo
comparing with ..\repo
searching for changes
1[tip]   62119640bde6   2009-09-11 10:35 +0200   wierob83
  some changes and new file

the second repo seems to be still related (which I didn't know before ;).

I'm not sure if this is the intended behavior or a bug.

Update:

You can pull from the original repository if one of the created sup-repositories is still related. This happens when the splitting process does not split changsets at the beginning of the branch because these changsets do not contain files that should end in different subrepos. Hence, there is no need to create a new changset.

wierob
I tried this. It included only the history for the relevant files (ok...) but I can still pull from one of the other hg-converted repos without the force flag. So this didn't seem to work...
Frank V
A: 

To answer the part of your question concerning related repositories: two Mercurial repositories are related if they share a common root.

More precisely, two repositories A and B are related if they share one or more changesets. Let's say A and B share a changeset X. By "changeset X" I mean a changeset with hash X -- the hash value is the identity of a changeset. The hash value is computed recursively from the hash values of the parent changesets, the date, the committer, and the change itself. This implies that both A and B must share the parent changeset of X. Continuing like this, we see that A and B must share a common root changeset, which is an ancestor of changeset X.

This gives us the common definition of being related: they must share a common root. You will normally only have one root changeset and you can look at it like this:

hg log --rev 0

For your case, my guess is that convert has created the same root changeset in both conversions. You should check with hg log in both clones to verify that they indeed are related. That should also tell you something about why they are related.

If your filemaps really do include different subtrees in the two conversions, then I cannot see how the repositories can be related. So perhaps you have an overlap in your include/exclude rules so that the first changeset is equal in both conversions?

Martin Geisler
I understand your post. I'm going to test it this evening. Thank you. I'll follow up with new information.
Frank V
A: 

Diverging a repository is easy enough; just clone/push/pull as you see fit. Mercurial will regard the diverged repositories as related. There's no way in standard mercurial to stop a pull from a related repository from succeeding; "hg pull" assumes you know what you're doing.

If a whole bunch of unwanted changesets from diverged repositories do get pulled, you can clear out the changesets you don't want by:

  1. Rename the repository
  2. Clone the renamed repository back to the original name, using -r to
    select the head you do want.
  3. (Optional) push the heads you've got in the confused repository to the diverged repositories as appropriate so you don't lose anything.
  4. Delete the renamed repository.

Depending on your environment you may be able to setup something with people, file permissions and/or web services to guarantee what you want.

Dickon Reed
A: 

While there might be a different solution to my given problem, I ended up writing a script that created a fresh repo and brought things in to it.

Since the script was external to Mercurial, Mercurial assigned new changesets ID (which ultimately gave me a new root) and essentially diverged the repo. My script did what (I suppose) hg convert does but it did it in such a way that the resulting repositories were considered different. If I had re-merged them (for the sake of argument) they would have not represented their source. Each changeset would have ran parallel up until I executed the merge command on this hypothetical re-merging.

Frank V