[Coco] making patches to NitrOS-9 (part II)

Tormod Volden lists.tormod at gmail.com
Fri Jan 23 15:54:54 EST 2015


(also applies to toolshed, including HDB-DOS!)

With increasing activity from more contributors to the NitrOS-9 code,
it is time for the second instalment of the "mercurial for NitrOS-9
hackers" series. The first was... er... exactly one year ago, you
should maybe read through it first:

http://five.pairlist.net/pipermail/coco/2014-January/129654.html

So you are making changes to the code and you want to share them. You
may want to show your suggested changes to others for review and
comments, or finally ask someone with commit rights to apply them to
the official repository.

* General Rules *

First of all, when working on the code, don't just make a whole lot of
different changes and then ask someone else to review and accept them,
take it or leave it. That is throwing something over the wall, or
fence. Your changes should be split up in separate patches for every
independent change. Even if one change may depend on another, they
should be split up (in a patch series) if they "logically" deal with
separate issues. This makes it much easier for others to review your
changes. It also make it easier later to track down errors which from
time to time sneak in.

Another thing is that you might want to work on your changes for a
while, testing and improving the changes. At the same time other
people are making their own changes, possibly to the same source file.
Just handing out your new file version won't cut it then, if the other
people's changes also are going to be applied. Their new file would
overwrite your changes or vice versa. Therefore it is important to
maintain and communicate your changes in patches, not in file
revisions. Patch tools or software revision systems such as mercurial
can easily combine patches that apply to the same file, as long as the
different patches don't touch exactly the same lines.

When for instance fixing a bug or changing existing code, try to
resist the temptation to fix up white-space or e.g. comments in the
surrounding code. It is much easier for someone else to review your
changes if they are limited to exactly the thing they are meant to fix
or add. White-space or other cosmetic fixes make the patch longer and
often confusing ("why was that line changed?").

The above applies to all distributed software development. So how to
do this with mercurial? There are quick and dirty ways, and then there
are the good ways, which with minimal practice will become your best
friends.

* The not so good way *

The quick and dirty way: Make your changes, one at a time as explained
above about separate changes. At any point you can run "hg diff" to
see what your changes are. When one patch is ready, do "hg commit" and
enter a comment to what your changes are doing and for what reason.
This will be a local commit, and your local tree will diverge from the
official repository. After a commit, "hg diff" will show you the
change relative to your latest commit. Once you are done with your set
of changes and want to share them, you can export your commits as text
files, actually standard patch files.

This will produce patch files from all your local commits:
hg export -r "outgoing()" -o "%n-%m.patch"

* The good way *

The better way is to use a feature of mercurial called "patch queues"
and in particular the "mq" patch system. This is implemented as an
extension in mercurial, but one that is always included. You just need
to enable it by adding this to your .hgrc file (in your home directory
or in the .hg folder in your local repository):

[extensions]
mq =

The patch queue is like a small repository of patches, which you can
roll on top of your repository tree. You can roll back to a clean
repository, for instance to sync with the official repository, then
roll out your patches again. You can modify individual patches and
reorder or delete them.

The mq commands all start with the letter "q".

Once you have done some changes, run "hg qnew my-new-fix.patch" and it
will store your changes in the patch called my-new-fix.patch . It is
customary to let the patch name start with a number to indicate the
intended order of patches, but note that a number in the patch name is
not interpreted by mq. You can rename the patch later with "hg
qrename".

If you keep on doing changes to your patch run "hg qref" to refresh
it. You can also run "hg qref -e" to add an explanation to your
changes. The comment will be used as a commit message later when your
patches are finally committed. So start your comment with a short
one-line summary, then an empty line, before you add more explanation.
See the existing log for good and bad examples: "hg log"

You can also run "hg qnew" before you make any changes, and then "hg
qref" afterwards.

"hg diff" will at any time show you the difference since the last
commit or qref.

"hg qapplied" will show your stack of patches that have been applied
to your tree.

Now comes the interesting part. You can remove the top patch from your
tree using "hg qpop". The patch is still stored in your patch
collection, but is no longer applied to your tree. Run "hg qpop -a" to
pop them all off your tree. "hg qapplied" will then list none, but "hg
qunapplied" will list all your patches.

"hg qref" will always refresh the patch on top of your tree, so to
modify a patch in the middle of your stack, just "hg qpop" until that
particular patch is on top, make your changes and then "hg qref"
again.

You can use "hg qpush" to apply patches from the queue one by one, or
"hg qpush -a" to apply all your patches.

"hg help mq" lists all the different mq commands.

This all may look complicated the first time and takes some time to
get used to, but it will enable you to work so much better together
with other developers and maintainers. It is actually quite useful if
you work alone on a project too, for instance when testing out
something temporary or something that you want to continue on later
after finishing something else that came up.

To summarize the workflow with an example:

hg qnew something-I-am-working-on.patch
(code, code, code on that)
hg qref -e

hg qnew another-thing.patch
(code, code)
hg qref -e
(rework this thing a bit)
hg qref -e

Now if you want to rework the first patch:
hg diff (to make sure there are no "unsaved" changes)
hg qpop (play back to the first patch)
(code, code, code)
hg qref -e (refresh the first patch)
hg qpush (apply second patch again)

The patches are stored in the .hg/patches folder. You can pick them
from there to send to other people etc. If another person want to
import the patch into his patch series, he can run "hg qimport
from-another-dev.patch".

* Final words *

Use "hg diff" all the time to review your changes. If your system
supports it, use "hg view" to browse through the commit history,
including your patch queue, in a graphical interface.

Remember when working with mercurial, help is only a "hg help" away.
See for instance "hg help qdelete" and "hg help qpush" about its
--move option.

Regards,
Tormod

PS. For those of you with commit rights to the sourceforge
repositories, make sure you don't inadvertently type "hg push" instead
of "hg qpush" ! For this reason I have added this to my .hgrc:
[hooks]
pre-push = echo -n 'Are you sure you want to push to remote? (y/n): ';
read reply; if test "$reply" != "y"; then echo 'Push cancelled'; exit
1; fi


More information about the Coco mailing list