How can I qfold the currently applied patches? - mercurial

I have two Mercurial patches applied with MQ. I would like to fold them into one, but qfold requires the patches to be un-applied. Why? And how can I fold them without explicitly popping?

The patch to be folded needs to be un-applied, in order to be folded onto an applied (current) patch.
hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...
fold the named patches into the current patch
Patches must not yet be applied. Each patch will be successively applied
to the current patch in the order given. If all the patches apply
successfully, the current patch will be refreshed with the new cumulative
patch, and the folded patches will be deleted.
With only 2 patches, you only need to un-apply the last patch to fold it on the qbase patch.

Related

Is it possible to undo an accidental "hg unshelve"?

Now my there's an extra few hundred lines of code in my project, scattered over half a dozen classes, and I'm not looking forward to tracking them down one by one.
No, but this is an avoidable problem
Instead of doing hg shelve, do hg commit --secret. This will create a "real" commit in the repository, which can be rebased or stripped (hg strip) when you no longer need it. It can also be folded into another changeset using hg histedit or hg fold (the latter requires the Evolve extension, which is experimental at the time of writing, while the former is interactive and may be hard to script).
The --secret flag ensures the changeset will not be accidentally pushed until you manually run hg phase -d REV on the changeset.
Yes, with a few steps. The help for unshelve specifies "If a shelved change is applied successfully, the bundle that contains the shelved changes is moved to a backup location (.hg/shelve-backup)." So hg update --clean will return you to the pre-unshelve state, unless you added changes in the mean-time, in which case you need to figure out how to recover the world prior to the unwanted patches. Then you can re-apply the patches stored in the backup individually if you wish to essentially re-do the unshelve under whatever conditions you prefer. In any event, the back-up contains the data you thought was missing.

How to submit a sequence of changesets into Review Board (Mercurial)?

I want to submit a sequence of changesets as one changeset (patch) into Review Board. How to do that?
The technical term for combining multiple patches into one is "folding". If you want to truly fold a series of commits into one (changing history), then the HistEdit extension provides a way as do Mercurial Queues.
If you're just interested in generating a patch, then you have a few options. You can use hg export (but this will not fold the patches together, but rather dumps a series of patches to console) or you can use hg diff to generate a diff. More precisely,
hg diff -r start:end > summary.patch
will generate a single diff for all the changes in the range start to end. You can replace end with tip to get all changes starting with start. This should even work if there are merge changesets in between. (hg export produces odd output if there are merge changesets in there.)
I would suggest that since you need to submit a sequence of changes in as a single item for review you should diff your final result with either the point that you started making changes or with the latest version of the code - creating a patch. Then attach the patch, details of the version that you diffed with, etc., to the Request for Review form.

Mercurial patch queue collapse

I am using the patch queue to achieve something like what this person asked here:
Why can't I rebase on to an ancestor of source changesets if on a different branch?
However, what I would like to do, is that when I have all the patches in the queue, rather than apply them one by one, I would like to collapse them into one changeset. Is this possible, by either a switch I didn't find, or by when pushing the patch from the queue, not committing, just having a local change.
Thanks
It sounds like you want to try hg qfold <PATCH>.... See the EditingHistory wiki or hg help qfold for further info.
There is no --all option for the qfold command, so you must specify each patch file manually or write a script / one-liner if you want to make this a batch process. See this related SO question:
Mercurial qfold ALL patches?

Mercurial commit only tip

In my setup I have a central Hg repo to which I'm pushing my local changes. Say in my local clone I have a series of local commits and then I want to push the changes to the central repo. How can I push only the final state without including all of the "small" local commits that I made?
I want this because sometimes I dont want to pollute the central repo's history with all of the small local commits that I made.
Why would you want to do that? Committing small changes makes it easy to revert something. If you collect everything in one big commit, reverting a small change might not be as easy.
I agree with bjorn (and I'm upvoting his answer), what you're doing isn't a great idea -- meaningful history is a good thing. If you can't be talked out of it then what you're trying to do isn't just push the last changeset but a new changeset that is a combination of all those changesets. The easiest way to do that is to use the collapse extension, though mq or even export/import can do it. The key there is that in collapsing multiple changesets into one you're rewriting history and you're going to remove your existing changesets and replace them with that new combined changeset. Doing so violates the immutability of history that makes Mercurial so trust worthy.
How to do this without any extensions is explained in the mercurial wiki page ConcatenatingChangesets.
That page also links to a few alternative approaches with hg extensions, like the CollapseExtension.
It is possible to rewrite your history using the mq extension. Suppose the revisions you want to collapse are revs, 5,6,7 with 7 being the tip. You would accomplish this via:
# Import the revs you want to collapse into mq
# mq will create patches for each revision from 5:tip, with the name
# <local rev number>.diff
hg qimport -r5:tip
# Goto the first commit
hg qgoto 5.diff
# Fold in the other commits successively. Aside from shell magic, there is
# no command line way to specify multiple patches at once.
hg qfold 6.diff
hg qfold 7.diff
# Commit the new mq patch as a changeset of its own
hg qfinish 5.diff
Now, your repository contains only a rev 5 with the contents of what was previously revisions 5, 6, and 7.

Mercurial cherry picking changes for commit

Say, I made many changes to my code and only need to commit a few of those changes. Is there a way to do it in mercurial? I know that darcs has a feature like this one.
I know hg transplant can do this between branches, but I need something like this for committing code in the present branch and not when adding change sets from some other branch.
If you are using TortoiseHg 1.x for Windows, this feature is implemented beautifully right out of the box (no extensions required).
Run the TortoiseHg Commit Tool.
Choose a file for which you only
want to commit a subset of its
changes.
Click on the Hunk
Selection tab in the preview pane.
Double-click or use the spacebar to
toggle which change hunks should be
included in the commit.
For TortoiseHg 2.x, the Hunk Selection tab is now gone. In its place, is the Shelve tool. It has a few more features than the old hunk selection. Those new features come at the cost of some added complexity.
Note that there is no need to explicitly enable the Mercurial Shelve extension when using this feature. According to Steve Borho (lead TortoiseHg developer) in response to a different TortoiseHg question: "We have a local copy of the shelve extension and call into it directly."
For TortoiseHg 2.7+, this functionality has been improved and re-introduced. It is now built directly into the Commit tool:
Notice in the file list on the left that the top file is checked to indicate it will be included, the second file is unchecked because it will not be included, and the third file, Sample.txt, is filled (the Null checkbox indicator) because only select changes from that file will be included in the commit.
The change to Sample.txt that will be included is checked in the lower-right change selection portion of the image. The change that will be excluded is unchecked and the diff view is grayed out. Also notice that the icon for the shelve tool is still readily available.
MQ as Chad mentioned are one way. There's also more lightweight solutions:
Record extension which works roughly the same way as darcs record. It's distributed with mercurial.
Shelve extension which allows you to "shelve" certain changes, allowing you to commit only a subset of your changes (the ones that are not shelved)
I feel like I'm missing something because nobody has suggested this already.
The normal "hg commit" command can be used to selectively choose what to commit (you don't have to commit all pending changes in the local working directory).
If you have a set of changes like so:
M ext-web/docroot/WEB-INF/liferay-display.xml
M ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
M ext-web/docroot/WEB-INF/portlet-ext.xml
You can commit just two of those changes with...
hg commit -m "partial commit of working dir changes" ext-web/docroot/WEB-INF/liferay-display.xml ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
Not super convenient from the command line because you have to hand-type the files to selectively commit (vs a GUI check-box process like tortoise) but it's about as straightforward as it gets and requires no extensions. And file-globbing can probably help reduce typing (as it would above, both committed files uniquely share "liferay" in their pathnames.
The Mercurial Queues tutorial is terrible for this use case. All the examples I have seen assume you have yet to make a commit and you are refreshing a single patch. Most of the time this is not the case, and you have 2 or 3 commits that you want to squash together or change in some other way.
Lets say you have this sort of history:
---O---O---A---B---C
The first example is to squash commits A, B, and C. First init mq:
$ hg qinit
Now we need to "import" the commits A, B and C into the patch queue. Lets assume they are the last 3 commits. We can use the "-N" revision syntax to import them like so:
$ hg qimport -r -3:-1
That means import as patches from 3 patches back up to the last commit. You can check the status of these patches with hg qseries. It should show something like this:
$ hg qseries
101.diff
102.diff
103.diff
Where the numbers 101, 102 and 103 correspond to the local revision numbers of the commits A, B and C. Now these patches are applied, which means the changes that they describe are already in the working copy. You can get rid of the changes the working copy and remove them from the history of commits, saving them in patch form only, by using hg qpop. You can either say hg qpop; hg qpop to pop changes C and B off the stack, or specify a patch to "pop to". In this case, it would be something like this:
$ hg qpop 101.diff
now at: 101.diff
You now have the patches for commits B and C in the patch queue, but they are not applied (their changes have been "lost" - they only exist in the patch queue area). Now you can fold these patches into the last one, i.e. we create a new commit that is the equivalent of the sum of the changes A+B+C.
$ hg qfold -e 102.diff 103.diff
This will show your editor so you can change the commit message. By default the message will be the concatenation of the commit messages for the changes A, B and C, separated by asterisks. The nice thing here is that hg qfold will tab-complete the patches if you are using bash and have the hg-completion script sourced. This leaves the history like this, where A+B+C is a single commit that is the combination of the 3 patches that interest us:
---O---O---A+B+C
Another use case is if we have the same sort of history as before, but we want to drop patch B and merge A+C. This is pretty similar to above actually. When you get to the qfold step, you would simply fold in the last commit rather than the last 2 commits:
$ hg qfold -e 103.diff
This leaves the change for B in the patch queue, but it is not applied to the working copy and its commit is not in the history. You can see this by running:
$ hg qunapplied
102.diff
The history now looks like this, where A+C is a single commit that combines changes A and C:
---O---O---A+C
A final use case might be that you need to apply only commit C. You'd do this by running the qimport as above, and you would pop off all patches you didn't want:
$ hg qpop -a
The -a flag means pop off all patches. Now you can apply just the one you do want:
$ hg qpush 103.diff
This leaves you with this history:
---O---O---C
Once you are done with all this, you need to finish off the queue fiddling. This can be done with:
$ hg qfinish -a
So there we are. You can now run hg push and only commit exactly what you want, or hg email a coherent patch to the mailing list.
Some time has passed. Seems the best option now is hg commit --interactive
You can use the record extension, which is distributed with Mercurial.
You need to enable it in your ~/.hgrc file first, by adding it to the [extensions] section:
[extensions]
record=
Then, just type hg record instead of hg commit, and you will be able to select which changes to which files you want to commit.
You can also use the crecord extension which provides a nicer interface to review and select the changes. (It is not distributed with Mercurial, though, and I've seen it occasionally mess up a commit so it's not completely bug-free.)
I believe Mercurial Queues fills this role for Mercurial. There's a pretty good tutorial linked there.
Try qct (Qt Commit Tool). It has a "select changes" feature that starts up a 3-way merge tool for you to undo individual changes. After you commit, those changes you "undid" come back.
I use commit-patch. It's a script that lets you edit the diff before committing. It's really nice with Emacs's diff-mode and vc-mode.
In the past I used crecord, but it has bugs related to unicode (actually the record extension has the bugs, which crecord depends on).
First you must forget everything you ever knew about GUI's and return to the commandline. Next from the commandline do this:
hg stat > filelist.txt
This pipes all your modified files into a text file called filelist.txt
Next edit your filelist to include only the files you wish to commit.
Finally commit using the fileset sytnax:
hg commit "set: 'listfile:test.txt'"