Size: 10810
Comment: converted to 1.6 markup
|
Size: 371
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
#format wiki #language en #pragma section-numbers 2 Also see the corresponding chapters, [[http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html|11]] and [[http://hgbook.red-bean.com/read/advanced-uses-of-mercurial-queues.html|12]], in [[http://hgbook.red-bean.com/|the HG Book]]. = Mq Tutorial = <<TableOfContents>> == Mq for the impatient == It's one of those things that sounds a lot harder than it is. It's basically just orthogonal, mutable [[ChangeSet|changesets]]. The mutability is exactly what it sounds like you're looking for. You can keep revising a changeset until it's good enough, then transfer control to regular Mercurial. Basically, you do this: {{{ hg qinit hg qnew some-changes-i-want-to-make [edit some stuff] hg qrefresh # update the patch with the new changes [edit some more stuff] hg qrefresh # update the patch with still yet newer changes hg qfinish some-changes-i-want-to-make # Make the patch a permanent commit }}} If you use the -c option to qinit, you get revision control of the queue itself, so you can use {{{qcommit}}} to save the state of your patch queue. The patch queue aspect is actually quite nice as well. You can, for example, work on two different layers of your application (something low-level and something built on top of that) in the same queue at the same time without breaking stuff. ``qpush'' and ``qpop'' will help you move up and down while keeping your changes separate. (original version by dustin sallings, mercurial mailing list, 2007-08-11) == Why would I want to use mq? == === Save a known-good but not yet perfect version of a change === While working on a patch, when you arrive at a point that is not yet ideal but does work, use qrefresh to refresh your current patch with the current state of the project. Then, while further refining the patch, if you decide that you're moving in the wrong direction and want to get back to a known-good state, you can use hg's revert command to bring things back to the state you last saved in the current patch. === Preventing the tangled-working-copy problem === Often, while developing one change, you'll notice something else that could use improvement. It could be anything from a style issue to another bug, unrelated to the one you're working on. If you're lucky, the file where you found this other problem is as yet unmodified, so you can safely commit the fix for the new problem separately from whatever you were originally working on. More probably, though, the file is already dirty with some portion of the original change. Without mq, when this happens, you have three choices: a. Promise to yourself that you'll remember this other problem, then forget it a few minutes later. a. Write it down somewhere. a. Fix it now, and confound your next commit with both what you were originally working on and the fix for the problem you discovered. With mq, the solution is easy: 1. Momentarily stop working on the original change. 2. Add any outstanding portions of that change into your current patch. 3. Create a new patch. 4. Fix the problem you discovered. 5. Add that fix into the new patch. 6. Return to your original patch. If you're fastidious, you'll fall in love with this the first time you do it, because this process lets you keep separate changes in separate commits, never mixing them and rarely having to pull them apart. === Mutable, rearrangeable commits === Commits that are part of permanent history are immutable. You cannot change their contents or rearrange them, because that would change their hashes, which Mercurial uses to uniquely identify them. Patches in your patch queue are part of history, but they are not yet permanent, so they are mutable. You can change their contents and their commit messages, change their order, or even delete them outright, as long as you haven't made them permanent yet. == What is all this talk about a stack? == Before we begin this tutorial, there are 3 things to keep track of when using the mq extension: the {{{localRepository}}}, the {{{mqPatches}}}, and the {{{workingDirectory}}}. When the mq documentation talks about a stack, it refers to the {{{localRepository}}} as a stack on which one can push/pop patches. {{{mqPatches}}} works like a queue, where the first patch you create would be the first patch to be pushed to the {{{localRepository}}} stack. == Working with mq == === Get a repository to do work on === This can be done by either initializing a brand new Mercurial [[Repository|repository]] yourself (ie. using {{{hg init}}}) or by [[Clone|cloning]] an existing repository. For this tutorial we will use the same repository used in the Mercurial [[Tutorial]]. {{{ hg clone http://www.selenic.com/repo/hello }}} === Indicate that you want to use mq on this repository === mq provides the {{{qinit}}} command to initialize mq on a given repository. To start using mq on our recently cloned repository use:<<FootNote(Make sure you enabled mq as described in MqExtension.)>> {{{ cd hello hg qinit -c }}} You can type {{{hg help qinit}}} to see help on the specifics of the command. Here we are telling mq to not only initialize an mq queue, but also to keep itself versioned with Mercurial. This mq does by creating a new repository for use by itself under {{{hello/.hg/patches}}}. === Creating and editing a patch === Now we are ready to start hacking the {{{hello}}} code away. The first step in to create a "patch holder" which will contain the changes that we make. To do this execute: {{{ hg qnew -m "Change language of salutation" newHelloString }}} The {{{-m}}} flag allows you to pass the message to be used in the changeset. This is the same message that would be placed if you did a {{{hg commit -m}}}. Let's now edit {{{hello.c}}} and change line 14 so that you end up with a file that looks like this: {{{#!cplusplus start=12 int main(int argc, char **argv) { printf("Howdy there!\n"); return 0; } }}} At this point our changes are only recorded in the [[WorkingDirectory|working directory]]. To verify this we can execute {{{hg status}}} and see that the {{{hello.c}}} file has been marked as modified. We will record the changes into our current patch ({{{newHelloString}}}) by executing {{{hg qrefresh}}}. If we run {{{hg status}}} again, we will see that there are no pending changes in our {{{workingDirectory}}}. Let's ask mq what patches it has push on top of the repository stack by running {{{hg qapplied}}}. mq tells us that it has applied {{{newHelloString}}}, and we can verify this by running {{{hg log}}} and noticing that the repository has that patch in it's history. [Hmmm... where do we need to talk about push/pop?] === Dealing with more than one patch on our patch queue === We now realize that our {{{hello.c}}} file needs to be able to tell us who it is, and in good form, we don't want to mix our changes to the salutation with this new modification (the why of this is beyond the scope of this tutorial). So we create a new patch and make the changes: {{{ hg qnew -m "Have hello say who he is" sayName }}} ... edit {{{hello.c}}} and add line 15 below to it {{{#!cplusplus start=12 int main(int argc, char **argv) { printf("Howdy there!\n"); printf("My name is 'hello.c'!!!\n"); return 0; } }}} Lets commit our changes to the mq queue by running {{{hg qrefresh}}}. We can now see that mq has applied the last two patches to the repository by running both {{{hg qapplied}}} and {{{hg log}}}. === Versioning our patch set === This amounts to using the standard hg commands on the patch repository in {{{.hg/patches}}}. MQ provides {{{qcommit}}} as a shorthand for commit in the patch directory, but for more advanced uses (like sharing the patch queue among multiple repositories), you might find a function like the following shell alias convenient: {{{alias mq='hg -R $(hg root)/.hg/patches'}}} === Synchronizing with upstream === Time goes by and we need to synchronize with upstream. Before we do this, we need to remove our mq queue of patches from the local repository and then reapply those patches after a successful pull. So we would do: {{{ hg qpop -a hg pull -u hg qpush -a }}} For a guide on using MQ to do three-way merges of upstream changes and the patch queue, see [[MqMerge]]. == Further reading == * MqExtension : mq's main page * [[http://www.suse.de/~agruen/quilt.pdf|quilt pdf]] : more about quilt * [[http://www.red-bean.com/~bos/hgbook.pdf|The BOS book (PDF)]] [[http://hgbook.red-bean.com/hgbookch12.html|(HTML)]] : chapter 12 is an excellent overview of MQ == Other tips and tricks == === Convert a patch to a permanent changeset === You can use qfinish <revision> on an applied patch (where ''revision'' can be any symbolic name for a revision, including a patch name) to turn it into a regular Mercurial changeset. qfinish -a will convert all applied patches into changesets. qfinish replaces qdelete -r <revision>, which is deprecated since Mercurial 1.2. Previously, one of the greatest criticisms of mq was the confusing use of qdelete to make patches into permanent commits; the qfinish command exists to solve that problem. qfinish is equivalent to doing {{{hg import .hg/patches/<patchname>}}}, followed by {{{hg qdel <patchname>}}}. === Split a patch into multiple patches === Goal:: End up with OP=P1 + P2, where OP=Original Patch, P1=Patch 1, P2=Patch 2 ==== Splitting by files ==== Starting from 0.9.2, it is easy to split a patch by file: * {{{hg qpush OP}}} * {{{hg qrefresh <paths to keep>}}} to replace OP with P1, including only the paths you named. The other changes will remain as uncommitted changes in the working directory. * {{{hg qnew -f P2}}} to pick up those changes. ==== Splitting by content ==== If you need to split apart changes within individual files, you have to do it manually: * Make sure OP is applied to workingDirectory * Copy OP to a temp patch file (OPT) * Edit OPT and remove things intended to stay in P1 (OPT ends up having P2). {{{filterdiff}}} is a useful tool for this. * in workingDirectory run: * {{{patch -p1 -R < OPT}}} * {{{hg qrefresh}}} : updates mq's OP to only have P1 * {{{hg qnew -m "foo" P2}}} * {{{patch -p1 < OPT}}} * {{{hg qrefresh}}} === Re-ordering patches === This is a very safe way to do it: * Execute {{{hg qpop -a}}} to remove all patches from the stack * Reorder patches in {{{.hg/patches/series}}} file * Execute {{{hg qpush -a}}} or {{{hg qpush}}} for patches that you want to re-apply ---- |
Hi there, I am Jamison. I am genuinely fond of computers and now I have time to acquire on new issues. Choosing is how I make funds. Massachusetts is wherever we have been living for yrs but now I am taking into consideration other solutions. Go to my web page to uncover out more: http://truth777exposed.blogspot.co.nz/2011/07/more-of-global-elites-agenda-exposed.html |
Hi there, I am Jamison. I am genuinely fond of computers and now I have time to acquire on new issues. Choosing is how I make funds. Massachusetts is wherever we have been living for yrs but now I am taking into consideration other solutions. Go to my web page to uncover out more: http://truth777exposed.blogspot.co.nz/2011/07/more-of-global-elites-agenda-exposed.html