How to swap Mercurial Queues in and out of a repository - mercurial

I have a platform neutral mercurial code repo called "Simulator"
and want to apply patches that target specific platform's optimizations before a build.
According to the guide we can accomplish this by the use of patches with guards.
Windows Experimental.patch +windows
Unix Experimental.patch +unix
Mac Experimental.patch +mac
However its starting to get cumbersome because our patch queue contains 100+ patches named like windows-memory-optimization.patch +windows, unix-memory-optimization.patch +unix, windows-io-experimental-bug-fix.patch +windows, etc etc. We organized it as groups in the series file, but the file is getting huge and using qseries / qapplied is getting unmanageable
Instead we would like to have a queue for windows, unix and mac.
So that patches can be organized as:
Windows Patch Stack: memory-opt.patch, io-opt.patch, etc
Unix Patch Stack: disk.patch, graphics.patch, etc
Mac Patch Stack: io-fix.patch, io-opt.patch, experimental.patch, etc
Then swap the patch stacks for each platform in and out of the simulator repo. So that I can work on the windows patch stack and pop/push various subsystem optimization patches and work on them independently of the unix or mac patch stacks.
It does not look like I can do that, other than making 3 different repos specific to the each platform and maintaining the patch stacks that way.
Is there a way to, other than manually copying the .hg/patches directory in and out of the repo, to accomplish "swapping" patch stacks?

Interesting use of Mercurial Queues :)
I assume here that you are already versioning your mercurial queues somewhere. If you don't/for those that don't know how to do this, have a look at the relevant section from the hgbook: it's a great way to collaborate/save incrementally your work without applying the patches.
Three named branches
It should be possible to maintain three different named branches, one for each platform, in your MQ repository.
To switch platform, just switch the active branch.
(with alias mq='hg -R $(hg root)/.hg/patches')
First create a windows branch:
$ mq branch windows
marked working directory as branch windows
created, but not yet committed.
Do some stuff, add patches:
$ hg qnew windowspatch
... do some stuff
Refresh, pop and commit:
$ hg qref
$ hg qpop -a
$ mq ci -m 'new windows branch'
You now have the default branch and the new windows branch:
$ mq branches
windows 65:5fd4ef0b96c9
default 64:06c1a56a3c08 (inactive)
Now create an Unix branch.
First switch back to the base default branch:
$ mq up default
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
Create a new unix branch and add a unix-specific patch:
$ mq branch unix
marked working directory as branch unix
$ hg qnew unixpatch
... blahblah
$ hg qref
$ hg qpop -a
$ mq ci -m 'adding unix branch'
$ mq branches
unix 66:c51bb2c7b413
windows 65:5fd4ef0b96c9
default 64:06c1a56a3c08 (inactive)
Usage
Don't forget to qpop -a before operating on the mq repos...
Push all the windows patches
$ mq up windows
xx files updated, yy files merged, zz files removed, ww files unresolved
$ hg qpush -a
Three physical repos
Maintaining three separate (mercurial queue) branches can look a bit scary. If so, you can just use three different MQ repositories: one for each platform, each of them versioned in a different place.
For example :
$ cd mqs
$ hg qclone mq-windows windows
$ hg qclone mq-unix unix
$ hg qclone mq-mac mac
To work on different platforms, just switch folders (repos). The concept is similar to the first approach. But instead of having three internal branches in one MQ repo, you use three separate MQ repos.

To make an equivalent Windows alias for "mq", create a batch file in the same directory as "hg.exe" (e.g., "C:\Program Files\TortoiseHg"), name it "mq.cmd", and paste this code:
#echo off
FOR /F "tokens=1 delims=" %%A in ('hg root') do SET hgRoot=%%A
hg -R %hgRoot%/.hg/patches %1 %2 %3 %4 %5 %6 %7 %8 %9

I know this question is old, but may be someone could be interested to know there's another solution. I think this wasn't possible at the time the question got asked, but here it is more info regarding this situation: Multiple Patch Queues on MQ

Related

Mercurial merge repository as branch

I have two Mercurial repositories that are for different major revisions of the same project. The latter version is a massive change to the functionality, and especially the UI, of the project, but it will still have a lot of common code with the earlier version. (For shorthand I'll call these versions 4.6 and 5.0 and the repositories project-4.x and project-5.x going forward; that's basically what I'm dealing with.)[1]
As we thought more carefully about the structure of our repository, and thinking especially about how to handle the related code, it became apparent that we wanted to simply pull the repositories together and used named branches for the ongoing work in each (from which people can branch or bookmark and merge as necessary). To do that, we decided we basically need to pull the project-5.x repository into the project-4.x repository. From what I can see, combining the repositories should be fairly straightforward:
$ hg pull -f project-5.x # in project-4.x
$ hg merge
So far, so good. My concern is handling the branching issue.[2] These are going to come in as two completely unrelated chains (which is fine), but I'd like the branch structure to look something like this:
---4.6----- }
\ } original project-4.x
5.0----- }
/
------- } original project-5.x
The problem is, I'm not exactly sure how to do it.
Edit: See below; the answer I devised worked.
Footnotes
If you're wondering why this is only coming up now… well, the project only got version controlled as of starting 4.6. Which, yes, is a little bit crazy. And I'd never been in charge of a major version change like this before, so I decided originally to make a new repo entirely, which I of course now regret. Live and learn.
Answers I've already read on the subject (but which left me unsure how to do this exactly):
Mercurial - merging branches
How do I merge two Mercurial repos into a single one
How can I import a mercurial repo (including history) into another mercurial repo as a subdirectory, without using subrepos?
I originally thought I'd need some way to pull into just the branch, but after chewing on it some more, I concluded the best way to do this is roughly as follows:
Create the desired new branch structure (i.e. create the 4.6 and 5.0 branches).
Remove the old default branch into the 4.6 branch in the base repository.
Pull the project-5.x repository into the project-4.x repository.
Merge the default (or in the case of this repository, experimental) baseline, which is pulled in during the merge, into the 5.0 branch, closing out the experimental branch along the way.
Restrict write access to the old repository's central push/pull location; we still have it for historical reasons, but people can't accidentally push to it.
Preparation (steps 1–2)
$ cd <project-4.x directory>
$ hg branch 4.6
$ hg ci -m "New 4.0 baseline"
$ hg branch 5.0
$ hg ci -m "New 5.0 baseline"
$ hg up default
$ hg ci --close-branch -m "Close default branch going forward.
$ hg up 4.6
$ hg merge default
$ hg ci -m "branch merge default -> 4.6"
At this point, the repository is set up: it has the new baseline branches and has removed the old default branch we wanted to get rid of.
After this, I made the changes to get the repository structure looking more the way it needed to for the 5.0 branch in the project-4.x repository (since massive restructuring is part of the version change effort).
Repository merge (steps 3–4)
The next step was actually merging the repositories together and pushing the content from the old repository into the desired branch.
$ hg pull -f <path to project-5.x repository> # still in project-4.x repository
$ hg merge -m "Merge in project-5.x repository"
$ hg up experimental # experimental is the name of the "default" branch
$ hg ci --close-branch -m "Close experimental branch"
$ hg up 5.0
$ hg merge experimental
$ hg ci -m "Merge old experimental into new 5.0 baseline"
This proceeded perfectly, with no merge conflicts whatsoever (except that I needed to resolve some small differences in my .hgignore file).

Mercurial requiring manual merges unexpectedly

I've got a project running under Mercurial and am finding a lot of situations where a file needs manually merging, when I believe it should be able to merge automatically. I am wondering whether there are any options that can be given to Mercurial to help it out in these areas.
The project has an underlying platform with a couple of hundred files that can't be edited on the project. When the platform is updated, the project gets updated versions of these core files outside of Mercurial. The sequence I'm seeing repeatedly is:
On central dev system (linked to the core platform update mechanism):
Get a new version of core platform.
Commit these changes e.g. hg commit -m "New platform release"
Push to central mercurial server
On my Linux box:
Commit local changes
Pull from central mercurial server, and try to merge
Find merge conflicts on core files
The last two core files I've had to merge have no changes between the base and local versions (the access time is updated during a build, but the content is the same). The only changes are on the remote revision I'm merging with.
The only non-standard configuration I'm aware of is that the central mercurial instance is running under Rhodecode, with a commit hook setup to update a Redmine repository.
Is there anything else that can be configured in mercurial to help it figure out merges?
You can redo a merge with --debug to get more information about a merge. That is, take your repository and do
$ cd ..
$ hg clone my-project -r 123 -r 456 merge-test
where 123 and 456 is the two parents of the merge you want to examine closer. Then run
$ hg merge --debug
to see what Mercurial says. It should look like this if the file foo has only been changed in the branch you're merging in:
$ hg merge --debug
searching for copies back to rev 2
resolving manifests
overwrite: False, partial: False
ancestor: 932f5550d0ce, local: b0c286a4a76d+, remote: c491d1593652
foo: remote is newer -> g
updating: foo 1/1 files (100.00%)
getting foo
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
Here I was on revision b0c286a4a76d and merged with c491d1593652.
You can also use
$ hg status --rev "ancestor(b0c286a4a76d, c491d1593652)" --rev "c491d1593652"
M foo
$ hg status --rev "ancestor(b0c286a4a76d, c491d1593652)" --rev "b0c286a4a76d"
M bar
to double-check which files have been changed between the ancestor revision and the two changesets you're merging. Above you see that I changed foo on one branch and bar on the other.
If you see a platform file appear in both status lists, well then something went wrong in your procedures and this can explain the merge conflicts.
If this isn't enough to figure out what went wrong, then I suggest asking this question on the Mercurial mailinglist. That's a great place for discussion and bug-hunting — much better than Stack Overflow.

Mercurial - Rebase branch of old code on top of new code tip, ignoring branch's merges with old code

I was playing around with the Adium source code and discovered that they had an unreleased branch in the adium-1.4 that fixes the facebook chat integration by using XMPP, called facebook-xmpp. All good there, complied it and it works.
Problem is, if I wanted to have the same functionality in the latest Adium 1.5, whose code got split from the older version's about two years ago (with some changesets from the older version being transplanted over from time to time), I figured I'd have to somehow rebase the entire range of changesets that makes up the facebook-xmpp branch and apply it onto the tip of the newer adium-1.5 branch. I thought this might work since facebook-xmpp looks like it mostly adds new code, so it should be easily integrated with the newest development code.
However, since facebook-xmpp branch merged with adium-1.4 several times, I found that rebasing would pull in the merged changes from adium-1.4 onto adium-1.5 as well, which makes for a lot of merge conflicts.
--------------------------------------- adium-1.4
| \--- facebook-xmpp (created 1 month ago)
|
\----------------------- adium-1.5
^ sometime in 2009
Question is, is there a way to transplant onto adium-1.5 only the changesets that added to the facebook-xmpp branch, excluding the ones that merged with adium-1.4 ?
Method 1 (manual patch)
If you just want the facebook-xmpp functionality to be available in audium-1.5, you could
merge the tip of audium-1.4 into facebook-xmpp, then
create a diff between the tips of audium-1.4 and facebook-xmpp and
try to apply that patch onto the tip of adium-1.5.
That should work but the new patch is disconnected from the original development history.
--------o---o <- tip of audium-1.4
\ \ \
\ o---o <- tip of facebook-xmpp (all audium-1.4 changes merged in)
\
o-------o <- tip of audium-1.5 (apply patch here)
Basically these commands should do it:
$ hg up facebook-xmpp
$ hg merge audium-1.4
$ hg commit -m "Merge audium-1.4 into facebook-xmpp"
$ hg diff -r audium-1.4 -r facebook-xmpp > fbx.patch # facebook-only changes
$ hg up audium-1.5
$ hg import fbx.patch # good luck
Method 2 (selective merge)
Another solution, which shows more respect to the history graph, would be to directly merge facebook-xmpp into audium-1.5 while using a merge tool configuration that uses internal:local as the default merge tool (to stop your merge tool from popping up 1000 times) but that merges regularly for any facebook-xmpp related files (if your know which files are related to its functionality). Then, before committing the merge, revert all files not related to the facebook thing.
UPDATE: Here are some example instructions for this second solution. Supposed the facebook-xmpp branch created some new files named fb-<something>.c and changed the existing files foo.c and bar.c (you get these files from a diff between facebook-xmpp and its latest merge with audium-1.4). When merging facebook-xmpp into audium-1.5, use the following merge tool configuration:
$ hg up audium-1.5
$ hg --config ui.merge=internal:local \
--config merge-patterns.fb-*.c=internal:merge \
--config merge-patterns.foo.c=internal:merge \
--config merge-patterns.bar.c=internal:merge \
merge facebook-xmpp
The first merge config ensures that generally audium-1.5 changes are kept on files changed in both audium-1.4 and audium-1.5. The other config options ensure that for any files touched by the facebook-xmpp branch a regular merge is performed, potentially with conflicts which need to be resolved manually. For instance if foo.c raised conflicts, run
$ hg resolve foo.c
to resolve the conflicts with your favorite manual merge tool. Finally, you have to commit the merge while not committing any new files originating in audium-1.4. Just commit the facebook-xmpp stuff:
$ hg ci -I "fb-*.c" -I foo.c -I bar.c
$ hg up -C # get rid of remaining new files from audium-1.4

Can't branch a single file with Mercurial?

is this possible with Mercurial? and which Version Control system can do this besides Clearcase?
David is correct that you can't have a branch that exists on only a single file, but it's worth pointing out that people often have branches that alter only a single file. Since the branch metadata is stored in the changeset, and since the changeset contains only a delta (change), having a branch that alters only a single files is nearly instantanous to create, update, commit, and merge, plus it takes up almost no space on disk.
Resultingly, it's a very common way to handle per-customer configurations. Keep the tiny change for them in a branch, and merge from main, where development happened, into that branch, whenever you want to update their deployment.
How you could use MQ:
$ hg qnew -m "Changes for client0" client0
... change the file ...
$ hg qref # update the client0 patch with the changes
$ hg qpop # pop the changes off the queue stack
... develop like normal ...
... client0 asks for a build ...
$ hg qpu # apply client0's patch
$ make release
$ hg qpop
It would get a bit finicky if you've got to deal with a lot of clients… But it may be worth considering.
The other thing you could do, of course, is just commit a bunch of .diff files:
... make changes for client 0 ...
$ hg diff > client0.diff
$ hg revert --all
$ hg add client0.diff
$ hg ci -m "Adding client0 changes"
... develop ...
... client0 asks for a build ...
$ patch -p1 < client0.diff
$ make release
$ hg revert --all
No, it's not possible. A branch in Mercurial is a snapshot of the entire repository state.
You could do it with CVS, though, as CVS tracks changes on a per-file basis :)

mercurial: how to synchronize mq patches from a master repo as mq patches to a set of clone repos

I have to run a dozen of different build tests on a code base maintained in a mercurial repository. I don't want to run serially these tests on same repository because they modify a set of common files and I want to run them in parallel on different machines. Also, after all tests are run I want to have access to latest test results from those test work areas. Currently I'm cloning the master repository a dozen of times and run in each clone one different test. Before each test execution I do a pull/update/purge preparation sequence in order to start the test on latest clean state. That's good for me.
I'm also preparing new changes using mq extension that I would test on all clones as above before committing them. For testing some ready candidate mq patches I want somehow to deploy/synchronize them to be available in test clones and apply those ready for testing using some guard before running the test.
Did anybody do this synchronization before? What's the most simple way to do it? Do I need to have versioned mq patches for that?
patches can be maintained in their own repository provided you passed the "-c" switch to qinit like so
hg qinit -c
You may still be able to create a patch repo after the fact via
cd .hg/patches
hg init
hg addremove
hg commit -m "my patches"
But I haven't ever tried that personally.
then .hg/patches can be treated like any other mercurial repository. so I think you could probably roll some shell scripting. to get into the .hg dir of your cloned repos and do a
hg clone http://centralrepo.com/patch_repo ./patches
Here is the solution that I've implemented. Few notes:
all patches guarded with ready_for_testing AND those unguarded are applied for testing.
using versioned repos is better because we can make abstraction of queue repository implementation
I use mercurial 1.5.1
master repo is in master dir
clone repos are in clone-x dirs
Here are the steps (some could be optional):
once: put patches in master repository under versioning using mercurial:
a. hg -R master init --mq #no commit happen here, can be done later
b. hg -R master commit --mq --addremove --message 'initial patch queue' #make them visible to clone repos
for each clone, once after clone creation finishes: assuming no patches created yet on clones, initialize mq sub-repository:
a. hg clone master\.hg\patches clone-x\.hg\patches
b. hg -R clone-x qselect ready_for_testing
for each change ready in master (patch created/imported in mq repo): do this before launching tests for it:
a. review/update guards of mq patches: those included for testing should be unguarded or with +ready_for_testing
b. hg -R master commit --mq -A #make them visible to clone repos
for each clone, for each [test] iteration for each clone: do this preparation sequence before running the actual test:
a. hg -R clone-x qpop --all --force
b. hg -R clone-x pull
c. hg -R clone-x update --clean
d. hg -R clone-x purge --all
e. hg -R clone-x pull --mq
f. hg -R clone-x update --mq
g. hg -R clone-x qpush --all
As of Mercurial version 1.5, you can create a patch queue repository in an already existing Mercurial repo using the following command:
hg init --mq
It is OK to have queued patches when you issue that command.