10

If I've been churning away at the code for a while, and forgotten to create a patch series as I go, how do I create the patch series retrospectively? So far the only thing that comes to mind is:

# Prepare and test the first batch of changes.
$ hg qrecord -m 'first batch' 1.patch
$ hg qnew -m 'stash downstream changes' stash-1.patch
$ hg qdelete -k temp-1.patch
$ make hello
cc     hello.c   -o hello
hello.c: In function ‘main’:
hello.c:4: error: syntax error at end of input
make: *** [hello] Error 1
$ echo '}' >> hello.c
$ make hello
cc     hello.c   -o hello
$ hg qrefresh

# Recover the stashed changes.
$ patch -p1 < .hg/patches/last.patch

# And around we go again!
$ hg qrecord -m 'second batch' 2.patch
$ hg qnew -m 'stash downstream changes' stash-2.patch
$ hg qdelete -k stash-2.patch
$ make hello
...

This very cumbersome approach is also hazardous. I might forget the -k on qdelete, at which point I'll go bash my forehead against a brick wall for several minutes, or I might include too much or too little during the qrecord operation.

Is there a better way?

(What I'd really like is to be able to hg qpop to just before a patch I want to split, and use a currently non-existent command, hg qunrecord, to interactively suck changes out of the patch into my working directory. Once I'm happy with the changes, hg qnew -f could squeeze a new patch in front of the old one.)

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • Is this question about splitting into different patches by file? Ie. changes for a given file are not split up across multiple patches. Because if so, one can do better than the approach you described above. This is an old question, but still a relevant one. – Faheem Mitha Aug 19 '13 at 09:07
  • @FaheemMitha: I switched to git quite a while ago, so it's not particularly relevant to me. But for the record, I most certainly do want to differentiate changes within files, especially top-level project files which often contain multiple unrelated file additions/deletions. In fact, this is almost the norm rather than the exception. – Marcelo Cantos Aug 20 '13 at 03:18

5 Answers5

6

The MQTutorial explains how to split patches. So you could create a patch from you current work and split it into several patches.

ctuffli
  • 3,559
  • 4
  • 31
  • 43
wierob
  • 4,299
  • 1
  • 26
  • 27
  • Thanks. That's not an ideal solution, but it's much better than what I've been doing so far. – Marcelo Cantos Feb 01 '10 at 12:51
  • 3
    What I usually do is to use two repositories and a nice visual diff tool like Beyond Compare. Using the names in the tutorial, I start with repo A with OP applied, and I clone A to B. Then in A I `qpop -a`, diff A and B, cherry-pick the changes for P1 to copy from B to A, `qnew -f P1`, then copy the rest, `qnew -f P2`. – Geoffrey Zheng Sep 16 '10 at 02:33
3

TortoiseHg has very useful feature "Hunk Selection" in Commit dialog for kind of this work:
http://tortoisehg.bitbucket.io/manual/2.0/commit.html#change-selection

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
kuy
  • 944
  • 5
  • 12
  • Most of my work isn't in Windows, but I use it occasionally, so thank you for the tip. Unfortunately, as with @RyanWilcox's suggestion, this seems to help with the first step in my process, rather than simplifying the process overall. – Marcelo Cantos Jan 27 '10 at 01:33
  • 2
    FYI: If need, you can run TortoiseHg on Linux and Mac OS :) http://bitbucket.org/tortoisehg/stable/wiki/install – kuy Jan 27 '10 at 22:09
  • I had no idea! That's great to know. – Marcelo Cantos Feb 01 '10 at 12:52
  • After upgrading to the latest TortoiseHg release and enabling the mq and shelf extensions, I found I could select individual hunks in the Shelve tool. With non-finalized patches in the patch queue, that makes it fairly easy to move hunks in either direction between the working directory and the selected, unapplied patch. Changes in the working directory can then be applied to whichever patch is at the top of the queue. – Zarepheth Nov 04 '14 at 16:01
2

I think the crecord extension will let you do this. It gives you an interactive curses based interface where you can choose exactly what's in a commit.

RyanWilcox
  • 13,890
  • 1
  • 36
  • 60
  • Based on a cursory reading, crecord seems to be a curses-based equivalent to the record extension. Thank you for pointing this extension out, as it looks quite handy. However, it doesn't appear to reduce the number of steps I have to perform; it just makes the first step more pleasant. – Marcelo Cantos Jan 27 '10 at 01:28
  • 1
    @MarceloCantos, qcrecord does reduce the steps. Whereas qrecord almost always tells me "cannot edit patch for whole file", qcrecord merrily lets me exclude arbitrary hunks & lines in my patches. – CJ Gaconnet Jul 25 '13 at 03:14
1

Enable built-in extensions:

[extensions]
mq=
record=
shelve=

Then move MQ into working tree and split changes and remove original patch:

$ hg qpop my.patch
$ patch -p1 <.hg/patches/my.patch

$ hg qnew -i my1.patch
 ....
$ hg qnew -i my2.patch
 ....
$ hg qnew myN.patch   # last without interactive stuff

$ hg qdelete --keep my.patch

Between my$i.patch and my$((i+1)).patch you can use hg shelve/hg unshelve to test if project built and pass tests on top of my$i.patch without later changes!

If you find that something missing on this stage use hg qref on shelved changes or hg qref -i on unshelved changes!

See also Mercurial: move MQ patch to shelve?

Community
  • 1
  • 1
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
0

First, install crecord because it is just a way way nicer way of splitting changes up.

$ hg qcrecord part1
$ hg qnew part2 # ok, slightly a lie at this point
$ hg qpop
$ echo "}" >> hello.c
$ hg qrefresh
$ hg qpush
$ hg qcrefresh # Keep just what you want in part2
$ ...

The only thing special to crecord here is the qcrefresh command. If you're not a curses fan, you can still do all of the same stuff here, just replace qcrefresh with hg qrefresh -X 're:.'. Or hg qrefresh -I aauuuuuggghhh if you'd prefer. (It's your "uncommit" using -X or -I.)

sfink
  • 1,726
  • 1
  • 17
  • 22