With Mercurial, how can I "compress" a series of changesets into one before pushing?

26,198

Solution 1

How about the Collapse Extension?

Solution 2

The histedit extension is exactly what you are looking for.

hg histedit -o

or

hg histedit --outgoing

will bring up a list of the outgoing changesets. From the list you can

  • Fold 2 or more changesets creating one single changeset
  • Drop changesets removing them from the history
  • Reorder changesets however you like.

histedit will prompt you for the new commit message of the folded changesets which it defaults to the two messages with "\n***\n" separating them.

You can also get similar results using the mq extension, but it is a lot more difficult.

You can also use the collapse extension to just do folding, but it doesn't provide as nice a UI and doesn't provide a way to edit the resulting commit message. Editing the resulting commit message also allows for cleaning up the final message, which is something I always end up utilizing.

Solution 3

Yes, you can do it with patches: Let's assume your work is in changesets 100 through 110, inclusive

  1. Create a patch:

    % hg export -o mypatch 100:110 --git

  2. Update to 99:

    % hg update 99

  3. Apply the patch with --no-commit (otherwise you'll get all your changesets back):

    % hg import --no-commit mypatch

  4. Commit all changes at once:

    % hg commit

  5. You now have two heads (110 and 111) which should be equivalent in terms of files they produce in your working directory -- maybe diff them for sanity before stripping the old ones out:

    % hg strip 100

OK, now that I have spelled it all out, it does seem lengthy, but having done it a bunch of times myself, I don't find it to be too much of a chore...

Solution 4

My preferred method of using mq for this folding is using TortoiseHg as described here. However, it can easily be done from the command line like so:

hg qimport -r <first>:<last> 
    -- where <first> and <last> are the first and last changesets 
    -- in the range of revisions you want to collapse

hg qpop <first>.diff
    -- remove all except for the first patch from the queue
    -- note: mq names patches <#>.diff when it imports them, so we're using that here

hg qfold <next>.diff
    -- where <next> is <first>+1, then <first>+2, until you've reached <last>

hg qfinish -a
    -- apply the folded changeset back into the repository

(There may be a better way to do the qfold step, but I'm not aware of it, as I usually use TortoiseHg for that operation.)

It seems a little complicated at first, but once you've started using mq, it's pretty straightforward and natural -- plus you can do all kinds of other things with mq that can be pretty handy!

Solution 5

hg collapse and hg histedit are the best ways. Or, rather, would be the best ways, if they worked reliably... I got histedit to crash with a stack dump within three minutes. Collapse is not that much better.

Thought I might share two other BKMs:

  1. hg rebase --collapse

    This extension is distributed with Mercurial. I haven't had problems with it yet. You may have to play some games to work around hg rebase limitations -- basically, it doesn't like rebasing to an ancestor on the same branch, named or default, although it does allow it if rebasing between (named) branches.

  2. Move the repository (foo/.hg) to the working directory (bar) and its files. Not the other way around.

Some people have talked about creating two clone trees, and copying files between them. Or patching between them. Instead, its easier to move the .hg directories.

hg clone project work
... lots of edits
... hg pull, merge, resolve
hg clone project, clean
mv work/.hg .hg.work
mv clean/.hg work/.hg
cd work
... if necessary, pull, nerge, reconcile - but that would only happen because of a race
hg push

This works as long as the true repositories, the .hg trees, are independent of the working directory and its files.

If they are not independent...

Share:
26,198
Stephan B.
Author by

Stephan B.

Updated on August 05, 2022

Comments

  • Stephan B.
    Stephan B. almost 2 years

    Let's say I have a local and a remote Mercurial repository. Now, I start working on a feature. I work on it, and when I think it's done, I commit the changeset. Testing it a bit more, I find that I could further improve this feature by tweaking something in the code. I make the change and commit. 20 minutes later, I find there's a bug in this new feature, so I fix it and commit that too.

    I now have 3 changesets that I would really like to push to the remote repository as one changeset with message "Implementing feature X", for instance.

    How can I do this without much hassle? I believe I could do it with patches, but it seems like a lot of work.

  • Stephan B.
    Stephan B. almost 15 years
    That looks more than a bit complicated, but thanks for the link. Honestly I'm hoping for some magical extension that will do just what I want, like fetch and transplant did with pulling and cherry-picking changsets.
  • sylvanaar
    sylvanaar over 14 years
    thanks, thats exactly what i needed. It'd be nice if you could do it from within TortoiseHg - but the command line is simple enough.
  • Stefan Rusek
    Stefan Rusek over 14 years
    though it does provide a much easier to use and understand UI, which is more than enough of a reason to use it, but it also provides a mechanism to edit the merged changeset message, which is another thing that I always want to do when I merge changesets.
  • Chris Kelly
    Chris Kelly about 12 years
    Great answer, but there is a prerequisite: the MQ extension must be enabled.
  • Kharlos Dominguez
    Kharlos Dominguez about 10 years
    To include changes in binary files as well, make sure to use the --git option: for example: "hg export -o mypatch 100:110 --git" For more information, please see: stackoverflow.com/a/12537738/367663 I have taken the liberty to amend the answer.
  • G. Demecki
    G. Demecki about 10 years
    Seems overcomplicated, why not hg strip --keep and then commits everything in a one commit?
  • a.peganz
    a.peganz over 8 years
    Greetings from the future! I just googled for the same functionality and apparently nowadays hg supports this out of the box with hg rebase --collapse. Check out the hg wiki on the rebase command. Since this question is the 3rd overall search result and the first on stackoverflow I thought that info might be useful.
  • user2864740
    user2864740 over 8 years
    @G.Demecki Because it's a potentially very lossy operation..? Although MQ is overkill (and even oft not recommended), except when desiring such a workflow.
  • user2864740
    user2864740 over 8 years
    In 2015, histedit is a very good option for this task. I still don't trust it as I do a git rebase -i, but it doesn't crash.. at least newer versions will leave you on a temp branch if something goes horribly wrong so the only time that the changesets will be stripped is after the new branch is committed.
  • user2864740
    user2864740 over 8 years
    And the problem of only understanding the UI is one really doesn't understand.. Anyway, for the past while histedit allows changing 'mess'ages, as well as changing messages when 'fold'ing. The histedit is perfect; if anything, the collapse extension is underuseful.
  • G. Demecki
    G. Demecki over 8 years
    @Strawberry doesn't provide an answer?? It think it perfectly answers the author question. Can you elaborate your point?
  • G. Demecki
    G. Demecki over 8 years
    @user2864740 You may be right, cause I'm not a Mercurial expert. But by default, hg strip will place a backup in the .hg/strip-backup/ directory. I guess it's not that safe as git reflog but still provides some kind of rescue.
  • Strawberry
    Strawberry over 8 years
    It's ancient history, so I'll retract the remark - but the Approved answer seems like a more authoritative reference.
  • G. Demecki
    G. Demecki over 8 years
    @Strawberry Indeed it's ancient thread. But the accepted answer is outdated, because Mercurial no longer needs a separate 3rd party extension to this job.
  • user2864740
    user2864740 over 8 years
    @G.Demecki Yeah (my previous comment was incorrect!), newer Hg even says that it is doing so - was this [message] added by the Evolve extension or is it now default? Also, I just found out with the new Evolution extensions the other 'history rewrite' changes are also written as strip backups. Not nearly as clean to navigate to as a 'headless' branch .. but just as safe.
  • Brad Oestreicher
    Brad Oestreicher over 8 years
    Greeting from even further in the future!! The rebase extension appears to be solely targeted at moving changesets from one branch to another. Yes, there is a --collapse option, but still appears to be only applicable when moving a set of changesets across branches. See <mercurial-scm.org/wiki/…>
  • StayOnTarget
    StayOnTarget almost 8 years
    You can use hg rebase with --collapse within a single branch.