How do I put a bunch of uncommitted changes aside while working on something else

Solution 1:

You have a handful options:

  1. Shelve the items. This saves the changes and removes them from the working directory so the branch can continue. It doesn't create a change-set.

    hg shelve --all --name "UnfinishedChanges"
    
    hg unshelve --name "UnfinishedChanges"
    

    Update/Edit: Newer versions of mercurial may need to use

    hg shelve -n "UnfinishedChanges"
    hg unshelve "UnfinishedChanges"
    

    You can still use --name as an alternative to -n, but mercurial doesn't seem to like --name anymore. Additionally, the --all is no longer required and mercurial will in fact freak out over it.

  2. Patch queue the items using mq. This isn't too dissimilar to shelve in some respects, but behaves differently. The end result is the same, changes are removed and can be optionally re-applied later. When pushed, the patches are logical change-sets, when popped they are saved elsewhere and are not part of change-set history.

    hg qnew "UnfinishedWork"
    hg qrefresh
    hg qpop
    
    hg qpush "UnfinishedWork"
    
  3. Commit them locally, update to the previous change-set and continue working and make use of anonymous branches (or multiple heads). If you then want the changes, you can merge heads. If you don't want the changes, you can strip the change-set.

    hg commit -m"Commiting unfinished work in-line."
    hg update -r<previous revision>
    
    hg strip -r<revision of temporary commit>
    
  4. Commit them to a named branch. The workflow then becomes the same as option 3 - merge or strip when you are ready.

    hg branch "NewBranch"
    hg commit -m"Commiting unfinished work to temporary named branch."
    hg update <previous branch name>
    

Personally I use option 3 or 4 as I don't mind stripping change-sets or checking-in partial code (so long as that doesn't eventually get pushed). This can be used in conjunction with the new Phase stuff to hide your local change-sets from other users if need-be.

I also use the rebase command to move change-sets around to avoid merges where a merge wouldn't add anything to the history of the code. Merges I tend to save for activity between important branches (such as release branches), or activity from a longer-lived feature branch. There is also the histedit command I use for compressing change-sets where the "chattiness" of them reduces the value.

Patch queues are also a common mechanism for doing this, but they have stack semantics. You push and pop patches, but a patch that is "underneath" another patch in the stack requires that the one on top of it be pushed also.

Warning, as with all these options, if the files have more changes since the temporary changes that you've shelved / queued / branched, there will be merge resolution required when un-shelving / pushing / merging.

Solution 2:

Personally, I don't like any of the answers posted so far:

  1. I don't like clone branching because I like each project to have only one directory. Working on different directories at the same time completly messes the history of recent files of my editors. I always end up changing the wrong file. So I don't do that anymore.
  2. I use shelve for quick fixes (just to move my uncommited changes to another branch, if I realize I'm at the wrong one). You are talking about days, no way I'd shelve something for days.
  3. I think mq is too complicated for such an ordinary sittuation

I think the best way is to simply commit your changes, than you go back to the changeset before you start these changes and work from there. There are some minor issues, let me illustrate:

Let's say you have the changeset A. Than you start your changes. At this point you want set it aside for a while. First of all, commit your work:

hg ci -m "Working on new stuff"

If you want, you can add a bookmark to make it easier to come back later. I always create bookmarks to my anonymous branches.

hg bookmark new-stuff

Go back to the changeset before these modifications

hg update A

From here, you work and generate the changeset C. Now you have 2 heads (B and C), you'll be warned when you try to push. You can push only one branch by specifying the head of that branch:

hg push -r C

Or you can change the phase of the new-stuff branch to secret. Secret changesets won't be pushed.

hg phase -r new-stuff --secret --force