Can I squash commits in Mercurial?
Yes, you can do this using mercurial without any extensions by Concatenating Changesets.
Alternately if you want to use an extension you could use:
- The Collapse Extension
- The Rebase Extension or
- The Histedit Extension
If you are reading this answer, you can forget every other option mentioned in this answer and use the
fold
command from the evolve extension.
evolve
is an extension of mercurial which helps us in having safe mutable history, it's still experimental though. You can use it by cloning it from its repo and adding it in your .hgrc like this.
[extensions]
evolve = ~/evolve/hgext/evolve.py
Assuming that you cloned evolve repo in your home directory. Now you are good to go. You can also look for help by hg help fold
.
Fold Command
You tell fold
to squash/fold a linear chain of commits which is not broken. What fold does is, it creates a new changeset which contains changes from all the changesets and mark all those commits as obsolete. You can have a more deep view into this at docs.
Now suppose you have the following history.
a -> b -> c -> d -> e -> f -> g
You want to squash e
, f
and g
. You can do
hg up g
hg fold -r e
The result will be
a -> b -> c -> d -> h
where h
is the changeset which contains changes from all the three commits e
, f
and g
.
You can also fold changesets from the middle of the history, i.e. not necessarily you have to pick a chain which includes the tip. Suppose you want to fold b
, c
and d
. You can do
hg up d
hg fold -r b
hg evolve --all
This will result in
a -> i -> j
where i
is the folded changeset of b
, c
, d
and j
is the same changeset as h
.
Evolve user guide is a must read.
The Rebase extension worked like a charm. To squash 2 commits:
$ hg rebase --dest .~2 --base . --collapse
Dot is a shortcut for current revision.
It's even easier when you have a few commits on a branch and want to collapse them all into one:
$ hg rebase --dest {destination branch (e.g. master)} --base . --collapse
How this works:
(from http://mercurial-scm.org/wiki/RebaseExtension#Collapsing)
My favourite is hg strip <commit_hash> --keep
command. And then I commit all changes in one commit.
It is the fastest and most comfortable way for me, because I like to do many small commits during my daily work ;)
Note 1: strip
needs a built-in extension mq
to be enabled.
Note 2: My favourite Git/ Mercurial client (SmartGit/Hg) appends by default --keep
parameter during strip
. And what is even more convenient: it provides option called join commits
:]