Is there any way to squash commits with uncommitted changes? - mercurial

I want to squash two commits.
I'm executing the following command:
hg rebase --dest .~2 --base . --collapse
Which gives me:
abort: uncommitted changes
Yes, I have uncommitted changes and I want to keep them.
Is there any way to force this?

You can shelve the uncommitted changes and then do the rebase. Once you are done, unshelve the changes.
hg shelve
hg rebase ...
hg unshelve
I highly recommend backing up your repository first, just to be on the safe side.

Related

Mercurial - `hg graft` with custom destination?

Is there a way to graft a commit onto somewhere other than the current revision?
The documentation makes it sound like there isn't:
hg graft [OPTION]... [-r REV]... REV...
copy commits from a different location
And I don't see any parameters that can be passed to hg graft to do so. I'm surprised though that hg rebase allows this with the -d flag, but hg graft doesn't. Just like how sometimes I want to rebase a branch to somewhere other than the current revision, sometimes I want to graft a branch to somewhere other than the current revision.
You can use the rebase extension to achieve this. Do hg rebase -r <rev> -d <dest> --keep to rebase the onto while keeping the old rev.
Fundamentally the answer is "no", but you can still get the desired effect.
The help text for graft says "copy changes from other branches onto the current branch
" which implies that if you first update to the destination changeset, you can get the result you want.
Presumably you want to use graft to make an actual copy, vs rebase which would "move" the changeset. So this will get that result although it requires several steps.
To summarize:
hg up <destination revision>
hg graft <source revision>
hg up tip

Undoing a revert in mercurial (not a duplicate query)

I have a mercurial repo with no uncommitted changes. I was on revision 846, and decided my last 2 commits were junk and wanted to carry on as if from revision 844. So I was going to type:
hg revert -r 844 --all
Unfortunately I mistyped, and wrote:
hg revert -r 44 --all
So my whole repository has changed dramatically, including directory structure. I don't see any .orig files, so I don't think the answer in:
How to undo a revert in mercurial
helps me.
hg log still has all of my commits up to revision 846 - do you think I can revert back to revision 846?
Advice very welcome
hg revert just sets your working copy to the revision that you specify so if you didn't do a commit after the revert then your repository has not changed. To fix it you can just do hg update -C and then delete all the .orig files.
After that you can do the correct revert statement to remove the last two revisions.
If you did do the commit then the command that you wanted to do (hg revert -r 844 --all) would still get you to the point that you want by undoing the revert commit as well as the two commits that you originally intended to undo.

Mercurial: Switch working directory to branch without losing changes?

Let's say that I have a named branch 'B1' which I'm doing feature development on.
I am at a good stopping point before a demo though not done with the feature so I:
hg up default
hg merge B1
hg ci -m "merged in feature drop"
hg push
Now I continue working for a half an hour or so and go to commit only to realize that I forgot to update back to B1 and that my current working directory is on default - uhoh. In theory I should be able to just mark my working directory parent as the tip of B1 - is there an easy way to do this?
I could of course commit, update back to B1, and merge my changes back, but then there's an unstable changeset in default and this happens often enough to me that I would like a real solution.
Two ways. First, the obvious way:
hg diff > foo
hg up -C b1
hg import --no-commit foo
rm foo
Second, the magical way:
hg up -r 'ancestor(., b1)' # take working dir back to the fork point
hg up b1 # take it forward to the branch head
This way involves merges. Depending on how much your branches have diverged, this may be painless. Or it may be complicated, and you may make a mess of your changes that you haven't saved anywhere. Which is why even magicians like myself prefer to do it the first way.
I would use the shelve extension. I think it’s distributed along with TortoiseHg, you can also use it from the UI:
hg shelve --all
hg up B1
hg unshelve
Rebase extension allow you to change parent for any commit for wrongly commited changeset.
If you want just change branch for future commit - MQ (as mentioned) or Shelve
Typically for this sort of dynamic approach, I favor mercurial queues.
In your situation, what I would do would be to create a patch on default with the changes, pop the patch off, switch over to B1, and apply the patch.
It goes something like:
hg qnew OOPSPATCH
hg qrefresh
hg qpop
hg up B1
hg qpush
<hack hack>
hg qrefresh
hg qfinish
All you need is simple hg up -m B1
From hg up --help:
options:
…
-m --merge merge uncommitted changes
…

taking uncommitted changes on the wrong branch to the right branch

I am using Mercurial.
I have some uncommitted changes but I am on the wrong branch, how do I update to the right branch and take the changes with me?
For uncommited changes you can use the Shelve extension:
hg shelve --all
hg up correct_branch_name
hg unshelve
I asked on irc
mpm said
hg diff > mychanges; hg up -C somewhere; hg import --no-commit mychanges
which I had considered but is what I was trying to avoid.
d70 said
i think you can easily do it by "hg update"ing to a changeset that is a
parent of the branch you're trying to switch to, and then "hg update"ing to the
tip of that branch
so I did that.
hg up -r <shared root rev>
hg up branchIwant
I asked about "why" and was told "you are not allowed to update across branches" which didn't make sense to me at first. Then I realized that because I went through the shared root rev, it isn't across branches.
I usually use
hg qnew
hg qpop
hg up -c <target-rev>
hg qpush
hg qfinish qtip
But I also use jrwren’s approach of going through an ancestor quite regularly.

Transplanting into one changeset

I'm trying to move changes from a couple of changesets into one changeset on the other branch. There are other changes in between that I want to skip, so I don't want to simply merge everything.
hg transplant moves the changes correctly, but now I'd like to flatten them into a single commit. How can I do that?
You can fold them by
Backup the repository, a failure during the process can destroy data
transplant the desired changes to the target branch
transform them there into a mercurial queue (hg qimport -r first-to-fold-rev:)
fold them into one patch (hg qpop until the first patch is applied, then hg qfold <<patch name>> the following patches into this one)
Edit the commit message (When there are NO OUTSTANDING CHANGES hg qrefresh -e)
apply the single patch to your repository (hg qfinish -a).
When there are further unfolded patches:
hg qpush until the head patch
hg qfinish -a
Review the new repo state (hg glog/hg incoming)
hg rebase has an '--collapse` option. I think this is what you are looking for.