== Concatenating multiple changesets into one ==
(See also: [[EditingHistory]], [[HisteditExtension]] (which provides an editor-driven UI for this), [[CollapseExtension]], [[RebaseProject]] (section ''Collapsing'')).
=== Problem ===
Suppose you want to concatenate the last k changesets of a [[Repository|repository]]
{{{#!dot
digraph {
rankdir = LR;
node [shape=box];
S -> "S+1" -> "S+2";
"S+2" -> "S+k" [style=dashed];
label="oldrepo"
}}}
into a single, combined changeset
{{{#!dot
digraph {
rankdir = LR;
node [shape=box];
S -> "S+k (combined)"
label="newrepo"
}}}
=== Revert solution (using hg only) ===
Execute the following steps:
'''~+{{{1: hg -R oldrepo update S}}}+~'''
This [[Update|updates]] the [[WorkingDirectory|working directory]] to revision S.
Specifically, this means that the contents of the working directory are
changed to that of revision S, and that S becomes the parent
of the working directory.
'''~+{{{2: hg -R oldrepo revert -r tip --all}}}+~'''
{{{#!dot
digraph {
rankdir = LR;
node [shape=box];
"working directory" -> S [label="1. update"];
S -> "S+1" -> "S+2";
"S+2" -> "S+k" [style=dashed];
"working directory" -> "S+k" [color=red label="2. revert"];
"working directory" [shape=ellipse];
label="oldrepo"
}}}
This [[Revert|reverts]] the working directory to its contents at [[Tip|tip]].
Since the parent of the working directory is still S, this means that
the combined contents of all changesets between S and S+k show up as
the modifications in the working directory.
/!\ Revert does not preserve copy and move history.
'''~+{{{3: hg -R oldrepo commit -m "Combine changesets S+1..S+k"}}}+~'''
{{{#!dot
digraph {
rankdir = LR;
node [shape=box];
"working directory" -> "S+k (combined)" [color=red label="3. commit"];
"working directory" -> S [style=invis];
S -> "S+k (combined)";
S -> "S+1" -> "S+2";
"S+2" -> "S+k" [style=dashed];
"working directory" [shape=ellipse];
label="oldrepo"
}}}
Committing these modifications creates a
new changeset "S+k (combined)", containing combined changesets S+1 to S+k.
'''~+{{{4: hg clone -r tip oldrepo newrepo}}}+~'''
{{{#!dot
digraph {
rankdir = LR;
node [shape=box];
"working directory" -> S [style=invis];
"working directory" -> "S+k (combined)" [color=red label="4. clone -r tip"]
S -> "S+k (combined)"
"working directory" [shape=ellipse label="cloned working directory"]
label="newrepo"
}}}
<
>This assumes you want to get rid of your individual changesets (which are a dangling [[Branch|branch]] in oldrepo) and just keep the combined changeset. newrepo will now just have the combined changeset.
/!\ This will strip out '''all''' other branches, not just the one dangling branch ''that you don't want.'' If you have other branches that you want to keep, specify their [[Head|head]] revisions or [[NamedBranches|branch names]] on the clone call:
{{{hg clone -r tip -r branch1 -r branch2 -r branch3 oldrepo newrepo}}}
Or you can use the {{{strip}}} command provided by the [[MqExtension|Mercurial Queues Extension]].
Note that if you're planning to use mq, there's a much more convenient way to do the above...
=== Patch solution (using hg only) ===
Make a patch containing the changesets you want to concatenate. <
>
'''~+{{{1: hg -R oldrepo export --git -r S:tip > patchfile}}}+~'''
Make a partial clone of the repository, up to and including the parent of S. This discards the patch changesets. <
>
'''~+{{{2: hg clone -r "p1(S)" oldrepo newrepo}}}+~'''
Import the patch in the cloned repository as one changeset. <
>
'''~+{{{3: hg -R newrepo import -m "Combine changesets S+1..S+k" patchfile}}}+~'''
=== Patch queue solution (using mq) ===
Integrate the changesets you want to concatenate in a patch queue (verify you don't have pending patches there using {{{hg qseries}}}). <
>
'''~+{{{1: hg qimport -r S+1:tip}}}+~'''
(note how the start of the commit range specified is the fist commit we want to squash: S+1)
Pop all the patches but the first. <
>
'''~+{{{2: hg qgoto qbase}}}+~'''
"Fold" unapplied patches, i.e. concatenate changesets. <
>
'''~+{{{3: hg qfold $(hg qunapp)}}}+~''' <
>
'''~+{{{3: for /F %i in ('hg qunapp') do hg qfold %i (Windows)}}}+~''' <
>
This has the big advantage over the previous method that the commit messages will also be concatenated (separated by the {{{* * *}}} string). You can see the message using {{{hg qhead}}} and edit it using {{{hg qrefresh -e}}}.
Reintegrate the folded patch in the repository. <
>
'''~+{{{4: hg qfinish qbase}}}+~''' <
>
{{{tip}}} is now the concatenation of former changesets {{{S:tip}}}. There's no extra branch left, therefore no additional cleanup to do.
----
CategoryTipsAndTricks