Mercurial (hg) equivalent of git reset (--mixed or --soft)

Solution 1:

The right way to replicate git reset --soft HEAD^ (undo the current commit but keep changes in the working copy) is:

hg strip --keep -r .

-1 will only work if the commit you want to strip is the very last commit that entered the repository. . refers to the currently checked out commit, which is the closest equivalent Mercurial has to Git's HEAD.

Note that if . has descendants, those will get stripped away too. If you'd like to keep the commit around, then once you have the commit ID, you can instead:

hg update .^
hg revert --all -r <commit id>

This will update to the commit's parent and then replace the files in the working copy with the versions at that commit.

Solution 2:

I believe the more modern and simpler way to do this now is hg uncommit. Note this leaves behind an empty commit which can be useful if you want to reuse the commit message later. If you don't, use hg uncommit --no-keep to not leave the empty commit.

hg uncommit [OPTION]... [FILE]...

uncommit part or all of a local changeset

This command undoes the effect of a local commit, returning the affected
files to their uncommitted state. This means that files modified or
deleted in the changeset will be left unchanged, and so will remain
modified in the working directory.

If no files are specified, the commit will be left empty, unless --no-keep