patcher(1) a patch maintenance tool

DESCRIPTION

Later we will have a walkthrought, but let me first explain the basic operation modes of patcher:

Editing files

When you call patcher with a filename, patch will make a backup of this file (if the file exists). Now you can create or change the file. Later you can ask patcher to create a unified diff with all your changes.

Creating unified diffs

Just call ``patcher -r'' and you will get a unified diff of all your additions, modification and deletions. The diff will be stored in .patches/<patchname>.patch. It is in a form that allows direct application via patch(1) or, of course, via ``patcher -i''.

Whenever you do ``patcher -r'' your .patches/<patchname>.patch file get's refreshed.

Back out a patch

To revoke your changes and go to the previous version, just enter ``patcher -b''. Patcher will make sure that you don't loose your changes by asking you to create a diff if something has changed since the last refresh. You may use -f (or --force) patcher to go back anyway.

You can back out more than one patch by either specifying a number a patch name after -b.

Re-Apply a patch

With ``patcher -n <patchname> -a'' one can apply an already existing managed patch. A managed patch is a patch that already is stored in the .patches directory and is mentioned in the .patches/series file. Patcher tests if the patch would apply without problem and applies it. If the patch would be rejected, you can use -f (or --force) to apply the patch anyway.

You can apply more than one patch by either specifying a number a patch name after -a.

Importing external patches

Sometimes you have an external patch. That's the opposite of a managed patch, the patch is not stored in the .patches directory. By importing it, it will become a managed patch.

Import the patch simply with -i <filename>. You can use -p <num> to specify the directory level, similar to the -p<num> option of patch(1). But please keep in mind that we need a space between -p and the number.

Normally only clean patches will be imported. To import a patch that creates rejects use -f (or --force). You'll see a list of files where the patch did not apply cleanly, fix the problems manually.

Later you can use ``patcher -r'' to create a clean patch.

INTERNALS

All work occurs with a single directory tree. All commands are invoked within the root of that tree (TODO: this can and should change). Patcher manages a ``stack'' of patches.

Each patch is a changeset against the base tree plus the preceding patches.

All patches are listed, in order, in the file ``.patches/series''. Patcher adds patches into this file, but never deletes entries. You can edit this file with a text editor, but please do only so if the patch you delete is currently not applied.

Any currently applied patches is listed in the file ``.patches/applied''. The patcher manage this file, there is no need for you to ever edit this file manually.

Each patch affects a number of files in the tree. These files are listed in a file list named ``.patches/*.files''. Patcher manages them. When you back out a patch, this file will deleted. Or, in other words, this file exists only for applied patches. It's only used by ``patcher -r''.

Patches are placed into ``.patches/*.patch'' files. They are always unified diffs with -p1 as patchlevel. You can copy then anywhere, the patch(1) utility will read them without problems.

Optionally you can put descriptions for the patches in files named ``.patches/*.txt''.

So for a particular patch ``my-first-patch'' the following will exist:

-
An entry ``my-first-patch.patch'' in ``.patches/series''.
-
An entry ``my-first-patch'' in ``.patches/applied'' (if it's currently applied)
-
A file ``.patches/my-first-patch.files'' which contains the names of the files which my-first-patch modifies, adds or removes
-
A file ``.patches/my-first-patch.patch'', which is the context diff, basically the main output of patcher.
-
Optionally a file ``.patches/my-first-patch.txt'' which contains the patch's changelog, description or whatever you put in there.

WALKTHROUGHT

Let's start.

Go into /usr/src/linux (or wherever).

Now let's start with changing some source files:

        patcher -n my-patch kernel/sched.c

OK, patcher copied kernel/sched.c to kernel/sched.c~my-patch for you, the program has also done some magic in the .patches directory, which won't be of interest to us now.

        Now edit kernel/sched.c a bit.

Now we're ready to document the patch:

        Create .patches/my-patch.txt

Now generate a patch:

        patcher -r

This will generate ``.patches/my-patch.patch''. Take a look at this file.

Now we remove our change to sched.c by going backwards:

        patcher -b

Look at where we're now:

        patcher -s

Now let's add another file to my-patch. First we re-apply the patch:

        patcher -a

Now edit a second file:

        patcher kernel/printk.c

Note that here we gave patcher a single argument, without command line options. This always tells patcher to add another file to the current patch.

        Edit kernel/printk.c

Refresh my-patch:

        patcher -r

Now start a second patch:

        patcher -n my-second-patch kernel/sched.c

Here we have a filename in the command line for patcher, so we edit a file. But now we specified a patch name with -n. This told patcher to create a new patch. Now patcher manages two patches, ``my-patch'' and ``my-second-patch''.

        Edit kernel/sched.c, to make some changes for my-second-patch

Generate my-second-patch:

        patcher -r

Take a look in ``.patches/my-second-patch.patch''.

Also note that ``my-second-patch.patch'' has been added to the series file. Whenever you manually begin a patch, it will automatically be put into the series file.

In this way, the whole thing is stackable. If you have four patches applied, say ``patch-1'', ``patch-2'', ``patch-3'' and ``patch-4'', and if patch-2 and patch-4 both touch kernel/sched.c then you will have:

kernel/sched.c~patch-2
Original copy, before patch-2
kernel/sched.c~patch-4
Copy before patch-4. Contains changes from patch-2
kernel/sched.c
Current working copy. Contains changes from patch-4.

This means that your diff headers contain ``~patch-name'' in them, which is convenient documentation.

To end our tour, we remove both patches:

        patcher -b
        patcher -b

That's pretty much it, really.