Search code examples
mercurialrevision-history

Condensing a mercurial repository - recommanded way?


Let's say I have a repository 'Main', and Max and co work on a clone each. Max has some local commits ('f'&'g') that are not yet pushed to 'Main'. This is how it looks now (pipes being pushs/pulls):

A--B1--B2--C--D1--D2--D3--E (Main)
|          |  |           |
A--B1--B2--C--D1--D2--D3--E--f--g (Max)

'B1' and 'B2' as well as 'D1', 'D2' and 'D3' are changes that only make sense together. We would like to combine 'B1' and 'B2' to a single changeset 'B' and combine 'D1', 'D2' and 'D3' to a single changeset 'D'. The new structure should look like this:

A--B--C--D--E (Main)
|     |     |
A--B--C--D--E--f--g (Max)

My (main) question is: What is the reccommended way of doing this?


Now let's make things worse: We have a branch that was merged within the change-sets that we want to collapse. It would look like this:

A--B1--B2--C--D1--D2------D4--E (Main)
|          |  \-------D3-/    |
|          |                  |
A--B1--B2--C--D1--D2------D4--E--f--g (Max)
              \-------D3-/

The new history should look like this:

A--B--C--D--E (Main)
|     |     |
A--B--C--D--E--f--g (Max)

How would you do that? Thanks in advance.


Solution

  • It depends on how much effort you want to put into this. While I don't know a solution within Mercurial itself (I only know history editing functions which can't cope with merges), Git does have the functionality you need:

    If I would really have to do such an operation, I would

    • Try to convince the management that this is not worth it
    • Try harder to convince the management that this is not worth it
    • Make a backup! The following steps involve destructive operations, so consider this as not optional. You have been warned.
    • exort the repo with hg-git into a git repository
    • export the complete (git) history into a fast-import-stream with git fastexport --no-data --all > history.fi
    • Create a Pseudohistory by editing history.fi, dropping your unwanted revisions
    • import the adjusted history into the git repo with ``git fast-import -f < history.fi`
    • check extensively if the newly created history is in fact the way you want it to have
    • clone Max into a local work repository
    • Remove successors of commmit A in the local work repository
    • pull your updated history back from git (again with hg-git) into the local work repository
    • check, if the Mercurial history matches your expectation (diffs of commits between the new and old repos, metadata (time stamps, committer names, ...)
    • Remove successors of commmit A in every repo (Main, Max and every developer clone)
    • hg push -r E Main the partial history back to Main out of the work repository
    • hg push -r g Max the complete history back to Max out of the work repository