Friday October 31, 2008 NetBeans, like OpenJDK and OpenSolaris, uses the Mercurial distributed version control system. I'm a big fan of of distributed version control. However, one thing that drives me nuts is this error message:
% hg merge abort: outstanding uncommitted changesThis isn't just going to be a rant - I've finally found a solution which is working extremely well for me. I've suggested it to some other developers who have also reported that it works well for them, so I thought I would share it with you.
The reason I run into this all the time is my preferred style of work:
@todo tasks for myself, or leave editorial comments in various source files. I might also work on a couple of larger tasks simultaneously. Yes, I know the preferred Mercurial idiom for this is to have multiple clones, one for each task - but that isn't my preferred way of doing it. Each NetBeans clone is huge and takes a while to both clone and build - and I would have to switch my IDE editing context between these large source trees all the time.
% hg push pushing to https://tor:***@hg.netbeans.org/main/ searching for changes abort: push creates new remote heads! (did you forget to merge? use push -f to force)This tells me that somebody has checked in something since my last pull. That happens a lot with a project like NetBeans where there are checkins every few minutes.
% hg pull && hg update pulling from http://hg.netbeans.org/main/ searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) abort: crosses branches (use 'hg merge' or 'hg update -C')
% hg merge abort: outstanding uncommitted changes!@#@%*#%$%&*$ ! Now, if I have dozens of changes, what do I do? When I first started using Mercurial, I would either try to finish my other changes and check them in and then try the merge again, or if I really wasn't ready to do that, I would copy the contents of my modified files to another location, hg revert the changes, and try again.
It's really very simple: Use two clones. Do all your work in clone "main", and all your merging and pushing from clone "sync".
Let's say the main repository is "master", and your two clones are "main" and "sync":
To get set up, either clone the master repository twice, or, you can clone your main locally, but be sure to update
the "parent" reference in your sync clone such that it points to the master instead of your working clone
(I do that by copying main/.hg/hgrc to sync/.hg/hgrc.)
Here's the new workflow:
sync clone, and pull your new changesets from your working clone:
% cd ../sync
% hg pull ../main && hg update
At this point, it's best to try a build/test as well, to make sure changeset is complete. If you're working
on many things in parallel, it's possible that your changeset is depending on a change in a file you haven't
checked in yet.
% hg fetch
(Or if don't have the fetch extension installed, do it manually - hg pull && hg merge && hg ci -m "Merge").
sync clone
and try again! Your modified files, and your new changesets, are still sitting completely unaffected in the main
clone. Just clone sync again and try more carefully :)
% hg push
main repository:
% hg pull ../sync && hg update
This will give you all the tip changes into your working clone, but without the risk of causing multiple heads that you
have to merge. You've already merged your local changesets over in the sync clone, and therefore there is no
conflict between your local changesets and the new changesets in the tip!
Work inFinally, I want to call attention to item #4. Doing it this way means that it's trivial to try again if something wrong happens during the merge. I've had a couple of merges where I've really mucked things up. Unfortunately, this was in my tree that contained the changesets that I cared about. In the end I had to go and manually copy out the files I wanted to check in and try again. With the above approach, if something goes wrong, just nuke the sync clone and try again.main, push and merge insync, and pull back intomain.
This is the reason I'm suggesting this approach to anyone using Mercurial, not just people who want to work with edited files.
Especially when you're new to distributed version control systems or Mercurial, it's great to be able to go back if you make
a mistake. Just make sure you know what you're doing before you submit that final hg push command to push everything
back to the master repository!
Yes, this works, although I use hg fetch instead of hg pull/hg merge.
But I use Mercurial Queues rather than a "push clone". When I get the "outstanding uncommitted changes" error, I do the following:
hg qinit -f mypatchname.diff
hq qpop
hg fetch
hg push
hg qpush
Very nice.
Note that when you want to commit your local changes that were put on the patch queue, you have to do the following, a minor annoyance...
hg qpop
hg import .hg/patches/mypatch.diff
Posted by David Van Couvering on October 31, 2008 at 01:20 PM PDT #
Hi David,
thanks. I'm aware of Mercurial Queues, but the main reason I really recommend having an alternate clone to people new to Mercurial is the ability to throw it all away when something goes wrong during a merge. I also like the ability to be able to build/test individual changesets in isolation before pushing them.
Posted by Torbjorn Norbye on October 31, 2008 at 02:05 PM PDT #
Your description and level of detail for how to use Mercurial is exactly what I've been looking for. I'm new to Mercurial and am suggesting it for company wide use where I work. Thanks Tor.
Posted by Greg Strockbine on November 03, 2008 at 08:22 AM PST #
I agree with David and I prefer using MQ for working on several things at once in one repo (code for each bug/enhancement is stored in a separate patch). It's much faster, but also requires some discipline and awareness of which patch is currently on the top of the stack.
Once a patch is ready to be permanently moved to the main repo, hg import + hg push will do the job.
There are times when working on a separate clone makes more sense, mainly when working on major changes for a longer period of time.
Posted by Igor Minar on November 10, 2008 at 02:08 PM PST #
Hi Tor,
------------------
hg merge
abort: outstanding uncommitted changes
------------------
I had similar issues (when I had to tweak GSF modules in the clone of /main-golden to add friend dependencies on my module). I fixed it like this- I edit the .hg/hgrc file and changed the "default-push" value back to the one pointing to /main-golden.
Will this work all the time?
Then, as I had configured Hudson yesterday to automate builds for /main-golden locally. I ran the build myself and it worked. Also, build succeeded after nearly 100 minutes!
Posted by Varun on November 11, 2008 at 03:26 AM PST #