Using mercurial to merge a cvs branch - mercurial

Currently my company is using cvs for version control. We have an old branch of code which has been used specifically for one client (don't ask) that we'd like to merge to the head.
Due to the delta between this branch and the head I think the merging capabilities of mercurial should make my job a bit easier. My line of reasoning is:
Create mercurial repositories of the branch and the current head.
Do a merge of the branch repo to the trunk repo.
At this stage I'm expecting mercurial to provide better merge support than cvs.
Then I would commit my changes to the trunk repository back into cvs.
Is this approach sound? Will this strategy result in a less painful merge as I think it will, or is there something I'm missing?

The reason Mercurial merges better than CVS or Subversion is because it tracks the most recent common ancestor of the two heads/branches, so you'll to make sure you're providing that information accurately or you'll probably end up with a worse merge.
If you do something like this:
hg init newrepo
cd newrepo
cvs checkout POINT_OF_DIVERGENCE
hg commit --addremove -m 'commiting point of divergence'
cvs checkout BRANCH
hg addremove --similarity 90 # let Mercurial discover any renames
hg commit -m 'committing branch head'
hg update -r 0 # jump back to point of divergence
cvs checkout HEAD
hg addremove --similarity 90 # let Mercurial discover any renames
hg commit -m 'commiting HEAD head'
hg merge
then the common ancestor for the two heads will be the point of divergence (sorry if the CVS commands are wrong, it's been a mercifully long time).
The trouble is knowing where the POINT_OF_DIVERGENCE is in the CVS repo -- CVS doesn't keep track of that at all, which is why its own merge doesn't use it.
CVS best practices always suggest that whenever you branch you create a tag that marks the point of divergence, but if you didn't do that then there's some tricky hunting ahead of you.
Without a correct most recent common ancestor the Mercurial merge won't be any better than CVS's.

Yes, that should work but there might be tiny little problems along the way (like how to get the source from CVS into Mercurial: Using hg convert or doing a manual import of a certain revision, etc).
Please create a new question if you run into a problem.

The built-in convert extension won't do well with CVS except for very simple histories. Use the fork of cvs2svn called cvs2hg
http://hg.gerg.ca/cvs2svn

Related

Remember uncommitted changes

I have some uncommitted changes C in my repo. I would like remember that changes in any way and get clean code (without that changes), make a little change and commit it. Now, I would like to recover my changes C and continue working on it. I know that I can deal with it using a lot of ways, but that ways are irritating. How to do it using mercurial?
So, to be more precise I need something like a stack:
Working on the code. Remember changes C on the stack.
hg update --clean
Make a change C2. Commit it.
Pop from stack a changeset C and work on it. But, now the repositorium contains committed change C2 and uncommitted C. It may cause that I need to merge but I expect that this merge will be invisible from the point of view repositorium.
While you certainly can work with mercurial queues, there's IMHO an easier and nicer way: change your default phase to secret and work with those commits like normal commits. Commits in phase secret are mutable and will not be exposed by push and pull commands acting on the repo.
This process has the advantage that you do not need to change your workflow - whether you work with commits you want to share (phase draft or public), or whether you still consider them work-in-progress and keep them locally only.
Additionally if you enable the evolve extension, you gain several benefits: it becomes even easier to amend commits and evolve (thus rebase) all child commits which depend on it.
The big advantage over the use of the mercurial queues is that you can make full use of the inbuild merge features - thus if the underlaying code changes, rebasing the new changesets is WAY easier and natural than using queues and hg shelve.
See the introduction to hg phases and changeset evolution which needs the evolve extension.
Enable the Mercurial Queues extension in your mercurial.ini or .hgrc file:
[extensions]
mq =
Then you can,
hg qnew save # save work in progress as a temporary commit
hg qpop # remove that commit
Make some more changes....
hg ci -m "new changes"
hg qpush # push the saved commit back.
hg qfinish -a # convert all temp commits to full commits.
You can also enable the shelve extension:
[extensions]
shelve =
Then you can:
hg shelve # "put away" current uncommitted changes.
*do other work*
hg unshelve # bring the shelved changes back
See hg help mq and hg help shelve for more info.
I've tried shelve, mq as described in other answers but to be honest I generally stick with:
hg diff > saved.patch # This assumes you've not aliased diff to a UI!!!
hg update -C
.. work
hg patch -f --no-commit saved.patch # I alias this for less typing
.. continue
Less book-keeping involved, its never gone wrong unlike shelve, and the patch itself is more easily portable. Just use common-sense and either make sure the patch applies fully, or use the --partial option and manually complete the patch.

Safe way to purge history - Mercurial

I cloned a project to my local directory and made a lot of changes. My current goal is to push my changed code to a new branch in the remote repository. And eventually this new branch will be merged back to default.
My problem is, because of some stupid effort in the past a few weeks to try to recover some missing files, I end up with a few branch names that I don't want being shown in public.
Here's what I have:
$hg branches
dev-v02 197:xxxxx
dev2 194:xxxxx
dev 183:xxxxx
qa 189:xxxxx
$hg branch
dev-v02
My question is, if I push my current branch dev-v02 to the remote repository by "hg push --new-branch", and this branch later get merged back to default, will the unwanted branches show up in history of default? And if so, is there a safe way to purge them?
I do NOT want to discard my changes. I just don't want the unwanted branches showing up in "hg branches" or "hg his" commands by whoever later clones the project from the remote repository. I searched online and found "hg strip" but I couldn't tell from the article if it would also remove the changes I've made. Thanks.
Edit: I just cloned my local repository by "hg clone -r 197 original-dir dest-dir" as suggested by both kevin and chessbot and now hg branches shows:
dev-02 192:xxxxx
qa 187:xxxxx (inactive)
I guess "qa" remains because I had pushed it to the remote as a QA branch and closed it later, and I just have to live with that. I will push from this new directory from now on. Thanks guys for your help.
Try hg push --new-branch -b dev-v02 to specify that you're pushing only that branch.
(See: https://www.mercurial-scm.org/repo/hg/help/push)
Another thing you could do: Clone the repository locally on your machine, strip out the branches you don't want, and then push that clone to the server. Then you retain your history locally without pushing it to everyone else.
It depends.
Branches are permanently associated with a commit. The branch is part of the commit, and contributes to the hash. Changing the branch of a commit in the past would alter all commit hashes from that point forward. This is quite different from Git, where a branch is little more than an ephemeral pointer to a HEAD. Such pointers are implemented in Mercurial as bookmarks.
If the unwanted branches appear on commits which are (ancestors of) commits you want to publish, there is very little you can do, short of recreating the history with all-new hashes. This could (for instance) be done with hg export and hg import, along with local cloning and (probably) a certain amount of shell scripting. More efficiently, you could use the convert extension to automate the process. Since this changes commit hashes, it will likely cause serious problems if any of the commits have already been distributed publicly.
If you have no interest in sharing the offending commits, you can simply not publish them. This can be done with selective pushing. However, since you'll always have to manually exclude those commits every time you push, it's probably safer to clone and strip (or clone selectively with the -r flag). You can then push from your partial clone with impunity. Assuming you have a sufficiently recent version of Mercurial, you can also force the commits into the secret phase, so that they will not be pushed:
hg phase -fs revisions
You don't want to use hg strip, because it permanently removes the commits from the history (see Editing History in the Mercurial wiki)
If I were you, I would close the branches instead:
hg up -C badbranch
hg commit --close-branch -m 'close badbranch, this approach never worked'
hg up -C default
(source: Pruning branches in the Mercurial wiki)
After closing a branch, hg branches doesn't show it anymore.
If you do want to see closed branches, use the -c parameter:
hg branches -c
Disadvantage:
hg his still shows closed branches.
You could use the -b parameter though, to show only the default branch:
hg his -b default

On converting from cvs to mercurial

I've got a gigantic CVS repository that I'd like to convert to a few hg repos. This question is similar, but I'm using hg convert and I've got more than one directory in cvs that should go in a given hg repo. Here's an example:
/sw
.../dir1
.../dir2
.../dir3
.../dir4
.../dir5
I want dir1, dir2, and dir4 in my hg repo, but dir3 can rot with dir5 in a separate one that nobody will ever use.
I've been converting the whole thing with hg convert --branchsort sw where sw is a sandbox checkout containing only the directories I care about. That nets me a 1.7GB hg repo with all 4 directories. The CVS repo is 2.3GB, but a sandbox is only 159MB. The hg repo has history going back to 1997, which is awesome, but some of the stuff in there is from products that have been discontinued. They don't need to be in a regular developer sandbox.
So, is there a way to cherry pick CVS directories to go into my new hg repository?
You should follow my advice on that question to which you linked. Convert everything together and then use hg -> hg converts to pick the parts you want in each repo using a filemap. Any revisions that would be empty (have only files that you're excluding in that conversation) will be omitted.
Also hg to hg converts are much faster, so you can do the slow CVS convert only once and then do the hg to hg parts again and again until you're happy with the results.
Do you have access to the CVS repository storage?
If yes, then you should be able make a complete copy of the repository, remove any files/directories that you don't want to convert, and then run hg convert with a working directory checked out from this local repository.
I say should because I haven't tried it, but since CVS stores revision history on a per-file basis, there's no reason I can think of that it shouldn't. It would not work with a SCM like Subversion, which stores multiple changes in a single revision.

Mercurial managing multiple repositories

We have a repository myproject - as the repo is nearly ready for release we are creating myproject-1_0. Version 2 dev will continue in myproject while minor tweaks and bug fixes will go in myproject-1_0. What is the best way to merge myproject-1_0 changes into myproject?
Is this the best approach:
$ cd myproject
$ hg pull ../myproject-1_0
$ hg merge
$ hg commit -m 'Merge bugfix from 1.0 branch'
$ hg push
?
What would happen if we did this merge on Feb 1st, then we made more changes in myproject-1_0? Would we follow the steps again and the hg pull ../myproject-1_0 would just pull the changesets done after the pull on Feb 1st?
In the myproject repo, is there a way to do an hg log and determine which changesets came from myproject-1_0 and which ones came from myproject?
Are there any other recommendations about this general approach?
Questions in sequence:
Is this the best approach? - yes, unless you want to use named branches and keep everything in one repository
would just pull the changesets done after the pull on Feb 1st? - yes
is there a way to do an hg log and determine which changesets came from myproject-1_0? - no
Unfortunately, unless you start mucking about with named branches, changesets that originate in the other repository looks no different from the ones in your main repository.
So this is what Mercurial is designed to do
I would suggest taking a look at http://www.hginit.com. But what you're asking if when you pull changes will it only pull the changes since the last pull, yes. You can't tell which changesets came from a different clone though, only user names are tracked in the idea that you are thinking about.
If you want to know where things are coming from this is something you can do in commit messages.

How to repeatedly merge branches in Mercurial

We're using Mercurial where I work and I want to have a setup similar to how I used SVN:
Trunk
Tags
Production
Branches
Since Mercurial supports branches natively, I know how to create a named branch, but I can't find any documentation on how to repeatedly merge 'Trunk' with 'Production'.
Quite simply, I want to have a development branch for normal work and a production branch that I routinely pull changes from the development branch into. How do I do this with Mercurial?
As the previous poster mentioned, the transplant extension can be used for cherry-picking individual changes from one branch to another. If, however, you always want to pull all the latest changes, the hg merge command will get you there.
The simplest case is when you're using clones to implement branching (since that's the use case Mercurial is designed around). Assuming you've turned on the built-in fetch extension in your .hgrc / Mercurial.ini:
cd ~/src/development
# hack hack hack
hg commit -m "Made some changes"
cd ../production
hg fetch ../development
If you're using local branches:
hg update -C development
# hack hack hack
hg commit -m "Made some changes"
hg update -C production
hg merge development
hg commit -m "Merged from development"
Something like hg transplant? That's what we use on our dev and prod branches.