9

I'm considering migrating a 14 year old cvs repository (history intact) to mercurial. I think I've got all the technical conversion bits down, but I still have some questions about working effectively in mercurial.

One of the things I see a lot in individual developers' cvs sandboxes (including my own) is local uncommitted changes that aren't ready to be pushed to the mainline. My understanding is that this is a bad thing. Most of my experiments with hg suggest that uncommitted changes are a bad thing to have. The inability to merge with them is enough for that. So what I want to know is how other people who use mercurial in day to day coding deal with it. How do you deal with incomplete changes to code when it comes time to update your repository? How do you deal with local changes that you don't (yet) want to share with other developers?

4 Answers 4

5

I handle it this way:

In my local repository, I commit every change, even if I'm experimenting. If I'm okay with the experiment, and it's tested, I push it to the remote repository. If not, it stays in my local repository (or go back to an older revision).

The idea is that the remote repository only contains working, tested versions of my projects.

1
  • 3
    Do you find that your remote repository gets cluttered with "fixed bug in last commit" type commits?
    – nmichaels
    Commented Apr 15, 2011 at 14:43
4

I don't believe uncommitted changes are intrinsically a bad thing. You refer to an "inability to merge with them" - if you have an uncommitted change to some file, and you pull and update a change to that file, Mercurial will start the merge process just as if you had committed it, then asked for a merge. Did you mean something different?

So, for local changes that you don't yet want to share with other developers, you have two approaches. The first is to keep the changes in your working copy, but not push them, and the other is to put them aside, out of the working copy. Which you choose depends on whether you want to have these changes available as you work.

If you keep them in the working copy, incoming changes will work fine, so you just need to avoid creating outgoing changes, and that means avoiding committing them. If the files are new, that's easy - just don't hg add them. If they are already tracked, then you can specifically exclude them from commits with hg commit --exclude foo.txt. If you have a large number of files to exclude, or will be excluding them from many commits (eg for a permanent change to a local configuration file), look at the exclude extension.

If you are prepared to move the changes aside, you have another set of options. The simplest thing is simply to use hg diff on the files to produce a patch describing them, which you keep somewhere safe, then hg patch --no-commit to reapply that patch when you want the changes back. You can make this smoother by installing the shelve extension, the attic extension, or some other relative. You could also use the queues extension, but that's using a sledgehammer to crack a nut. You could even just commit the changes, then update back to the parent and commit other work there, leaving the changes in a stubby anonymous branch - hg commit -m 'temporary branch' && hg up $(hg log -r 'parents(.)' --template '{node}') (although it may be easier to do manually!). You would then have to take care not to push that changeset, though.

4

There are a couple of things I will add.

One is to suggest a workflow which makes judicious use of shelve, which ships as standard with TortoiseHg.

Whenever I wanted to commit part of my current working directory, I would shelve the changes I didn't want to commit, recompile (to make sure that I haven't shelved bits which now result in a broken compile) and then run my tests. Then I would commit the full, working and tested set. Finally I would run unshelve to restore my changes.

If I had rather more permanent changes, say I wanted a configuration file on my development machine to always point to localhost port 3333 rather than the production server, then I would look into using the Mercurial Queues extension, which is shipped with both Mercurial and TortoiseHg.

3

Two basic approaches are used for separating streams of development.

  • Named Branches. The idea is, you work on your own branch, the nmichaels_branch_of_awesome. That way you can commit your changes without frying other people's work. Then you merge from other people when you need their work, and when time comes for the feature, you push over to the more stable branch for integration. I favor named branches.

  • Anonymous clone. This creates a separate repository for your sandbox. Here you play around until you get what you want, then (probably) do a MQ patch for your commits and push over to where you started from. I'm not as fond of this approach, as it requires directory management, and potentially MQ work, which can be tricksy. And with some repos, they can start getting just a little large for this. That said, this seems to be preferred by the Kiln devs.

3
  • It sounds like there's someone whose job is to do the integration bits. I'm disinclined to add mq to the list of new things people are going to have to learn immediately, but I'll think about my initial aversion to the idea of named branches. It might not be well founded.
    – nmichaels
    Commented Apr 15, 2011 at 15:56
  • For your second bullet why not do a clone, work, and only push when your finished? MQ sounds way to complicated here
    – TheLQ
    Commented Apr 16, 2011 at 3:26
  • @TheLQ: That works too, but is no different from directly cloning from the base repo. MQ would squash commits down into one commit. Commented Apr 16, 2011 at 18:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.