Patches

One of the primary methods used for exchanging code alterations and additions in the open source development world is through the use of "patches".

A patch describes a set of changes to code (file alterations, additions, etc...). A patch is formatted as a plain text file containing these details. Patches don't only apply to source code, but to any text-file (code, configuration, documentation, anything). With regard to Portico, these files will usually be exchanged on mailing lists, or attached to issues in Jira.

All code contributions to Portico should be provides as patches (or as a group of patches - often referred to as a "patch set").

Quick Guide
If you don't want to read this whole document for the deeper explanation, here are the highlights in a condensed form (perhaps this will be useful for later reference).

Generate a patch

[tim@zapp portico]$ cd codebase [tim@zapp codebase]$ svn diff > mypatch.diff

Applying a patch

[tim@zapp codebase]$ patch -p0 < mypatch.diff

Reverting the effects of a patch

If you want to remove a particular patch from your workspace, you can just apply it in reverse as follows:

[tim@zapp codebase]$ patch -p0 -R -E < mypatch.diff

Requirements
The entire patching process prescribed here is based around Subversion. You will need a copy of it installed and accessible from the command line/prompt.

Please do not use IDE’s or the like to generate the patch files for you. The manner in which some of these tools generate patches can cause problems that make the patch difficult, or downright impossible to apply. For example, Eclipse will generate patches that use the full system path to name the files. As everyone will store their development environment in different locations, this can be quite annoying (especially when incorporating patches from windows in unix style environments that don’t have a "C" drive).

Generating a Patch
Although the information provided here uses Portico as an example, the steps are not specific to this project.

To get the example started, I've made three small changes to the latest trunk revision (none of these are real changes that are committed, they're just examples):


 * 1) Edited the README file by adding a small, self-serving comment
 * 2) Edited the  source file (which is an enum) to add a constant for the new HLA-Evolved spec
 * 3) I’ve added an shell script that doesn’t do anything useful (but will demonstrate how we include new file additions, rather than just changes to existing files)

The first step is to ensure that you are currently working with the latest revision of the trunk (unless you have a very good reason), so run an  and resolve any conflicts that may exist between your working copy and the trunk. Also, ensure that the 'codebase directory is your current working directory (as shown below).

If you want to see a general overview of how your codebase differs from that of the last update, issue the  command:

[tim@zapp codebase]$ pwd /Users/tim/tmp/portico/codebase [tim@zapp codebase]$ svn status ?     build ?     dist M     src/org/portico/shared/HLAVersion.java ?     scripts/hello-script M     resources/dist/README [tim@zapp codebase]$

You will notice above that any files that have been modified are prefixed with the M character. Those prefixed with the ? character are files or directories that have been added, but which svn does not have any record of. If we were to generate a patch right now, it would only include the two modified files. If we want the new script to be included, we have to tell Subversion about the newly added file (unlike the  and   directories which contain generated content that doesn’t belong in the patch or repository):

[tim@zapp codebase]$ svn add scripts/hello-script A        scripts/hello-script [tim@zapp codebase]$ svn status ?     build ?     dist M     src/org/portico/shared/HLAVersion.java A     scripts/hello-script M     resources/dist/README [tim@zapp codebase]$

The A character indicated that this file is to be added to the repository.

Now we are ready to generate the patch file. Patch files are formatted in what is known a "diff format". If you want to see what changes have been made to your repository since the last update in this format, you can use the  command (this is a lot like a detailed version of   in many ways):

[tim@zapp codebase]$ svn diff Index: src/org/portico/shared/HLAVersion.java

=
====================================================== --- src/org/portico/shared/HLAVersion.java   (revision 442) +++ src/org/portico/shared/HLAVersion.java   (working copy) @@ -41,5 +41,5 @@ */ public enum HLAVersion { -      HLA13, JAVA1, HLA1516; +      HLA13, JAVA1, HLA1516, HLAEVOLVED; } Index: scripts/hello-script

=
====================================================== --- scripts/hello-script       (revision 0) +++ scripts/hello-script       (revision 0) @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Hello there, this is a pretty useless script :P" +

Property changes on: scripts/hello-script ___________________________________________________________________ Name: svn:executable + *

Index: resources/dist/README

=
====================================================== --- resources/dist/README      (revision 442) +++ resources/dist/README      (working copy) @@ -45,3 +45,4 @@ --Tim Pokorny Primary Developer +Portico rocks!! [tim@zapp codebase]$

If you have made a lot of changes, this listing can become quite large and overwhelming. However, that is of little importance as the primary user of this format is the patching application, not humans (although it is formatted in a human readable representation and is often the target of many eyeballs).

To create your patch file, you will have to capture this output and redirect it to a file:

[tim@zapp codebase]$ svn diff > mypatch.patch

That's it! You now have a patch file containing your changes! This is the file that you will submit to the project. However, before you do, it is important to ensure that the patch applies cleanly. You can either revert your current workspace to its former state and apply your patch, or just checkout a second copy of Portico and test it there. Open source developers are busy people, and ensuring that your patch applies cleanly will help to ensure it is accepted.

Read on to find out how you can actually apply a patch file to your working repository.

Applying a Patch
Having learnt how to generate a patch file, let us now put ourselves in the position of the person to whom you are sending the patch. Here you will see how to apply a patch to your working copy of the codebase so that it will contain the changed outlined in the file.

I have reverted my copy of the codebase so that the changes made previous no longer exist. See the section at the end of this article for a description of how to do this.

Applying a patch is a reasonably straightforward process. First, copy the patch file into your  directory. Once you have it there, it is time to run the patch command.

In this example I am using Max OS X, which includes the patch program with its Developer Tools. The program should also be available on virtually all Linux systems by default. Windows users will need to find an appropriate program and install it (check out the gnuwin32 project).

To apply the patch in, issue the following command:

[tim@zapp codebase]$ patch -p0 < mypatch.patch patching file src/org/portico/shared/HLAVersion.java patching file scripts/hello-script patching file resources/dist/README [tim@zapp codebase]$

You can see that the three files were patched (or created) without error. The  option is important to remember (google it for more information). If you forget it, you may see something like this:

[tim@zapp codebase]$ patch < mypatch.patch can't find file to patch at input line 5 Perhaps you should have used the -p or --strip option? The text leading up to this was: -- -- File to patch:
 * Index: src/org/portico/shared/HLAVersion.java
 * --- src/org/portico/shared/HLAVersion.java  (revision 442)
 * +++ src/org/portico/shared/HLAVersion.java  (working copy)
 * +++ src/org/portico/shared/HLAVersion.java  (working copy)

Honestly, I've got no idea why the program can't find what it needs, but the problem may come up, so now you know. You can run patch in interactive mode like this and specify each of the file locations, but add the  and it will fix the problem and save you a lot of typing.

Having applied the patch, now is a good time to run an :

[tim@zapp codebase]$ svn status ?     build ?     mypatch.patch ?     dist M     src/org/portico/shared/HLAVersion.java ?     scripts/hello-script M     resources/dist/README [tim@zapp codebase]$

As you can see, the two existing files were modified and the script was added. Also notice that Subversion does not yet know about the script. It will need to be "svn added" before it can go in the repository. That is easily fixed and will obviously need to be done before any commit of the changes to the repository.

Removing a Patch

You can reverse the changes made in a patch by passing the  option to the patch command:

[tim@zapp codebase]$ patch -p0 -R -E < mypatch.patch patching file src/org/portico/shared/HLAVersion.java patching file scripts/hello-script patching file resources/dist/README [tim@zapp codebase]$ svn status ?     build ?     mypatch.patch ?     dist [tim@zapp codebase]$

The -R option tells patch to run the whole thing in reverse (add lines that were deleted, delete lines that we added). The -E option tells patch to delete any files that are empty after it has finished. If you left this option out, chances are that any files that were created as part of this patch would still exist, but would just be empty (having had all their lines removed).

Submitting a Patch
Once you have created your patch, you will need to submit it to the project. If you followed the basic steps outlined in the Contributing article, your contribution should have a dedicated issue. Using Jira, you can upload your patch and attach it to that issue (where others can download it). If you want to discuss your patch, you can do to on the developer mailing list or the forums.

There are a few little rules and items to be aware of when submitting a patch:


 * Don’t just copy the text of the patch into an email or forum post. This can cause all sorts of issues with white space that will render the patch useless. Patches should be submitted as separate files by attachment to an email, Jira issue or carrier pigeon.
 * Code submissions should conform to the project formatting and layout standards. See Code Formatting for more details.
 * Don’t use an IDE to generate your patch files!! Some applications (Eclipse) do annoying things like put the full path to a file in the location descriptions. This is fine if everyone stores their working copies of the codebase in exactly the same place, but we don't. Patch files that don't cleanly apply will be ignored.

These somewhat "draconian" mandates are necessary to ensure that everyones time is used effectively and to help make the process of incorporating user submissions simpler and faster.

Reverting your Codebase
You can use Subversion to revert your codebase (or a section therein) to the way it existed as at your last update. Just go into the codebase directory and issue the following command:

[tim@zapp codebase]$ svn revert -R ./ Reverted 'src/org/portico/shared/HLAVersion.java' Reverted 'scripts/hello-script' Reverted 'resources/dist/README' [tim@moby codebase]$ svn status ?     build ?     mypatch.patch ?     dist ?     scripts/hello-script [tim@moby codebase]$ rm scripts/hello-script [tim@moby codebase]$

Notice that the  file wasn't deleted. The revert command just removed the notation that it was to be added to the repository. In this case, it was removed manually.