Creating patches
This page explains how to create patches with CVS or diff. Other programs can make patch files, including IDEs like Eclipse or XCode, editors like TextMate, or the tools included in Unix or Linux systems.
Related resources:
- Overview of patching
- Submitting patches to the issue tracker
- Applying patches to your own code
- Video patching tutorial
CVS example
This assumes you have an up-to-date, clean CVS checkout of the Drupal files. (More help: set up CVS, check out Drupal core and check out contributed code.)
- Change your copy of the files and save them.
- Change into the proper "root" directory. For Drupal core:
cd /Applications/MAMP/htdocs/head. For contributed modules/themes:cd /Applications/MAMP/htdocs/6x/sites/all/modules/cck - Create a patch of your changes:
cvs diff -up > example.patch - Review your patch in a text editor.
- Post it to an issue on Drupal.org.
diff example
- Make sure you have the latest copy of the file(s) by downloading the latest tarball.
- Create a working copy of the file you are editing in the same directory as the original (e.g. example.module copied to exampleNew.module).
- Edit the working (exampleNew.module) copy, and save it.
- When you are ready to roll your patch, go to the command line and change (
cd) to the proper "root" directory. - Enter this command:
diff -up path/to/file/example.module path/to/file/exampleNew.module > mypatchname.patch. This creates a new patch file in the current directory that you can now attach to a reply in a Drupal project's issue thread.
CVS diff vs. diff
cvs diff compares locally-edited files to the CVS repository version. diff compares two local files (the original and edited version). diff can be used if you don't use the CVS. Both commands use the same options and produce equally effective patches.
Check your directory!
Make sure others can use your patch:
- Drupal core patches: Run the
diffcommand in the root Drupal directory where you're making a patch (the same directory that contains the index.php, cron.php, etc. files). Core patches should always be made from Drupal root. - Contributed module/theme patches: Run the
diffcommand in the module or theme's root directory. (Example:/sites/all/modules/foobar).
With these guidlines, others can use your patch even if they don't have your same directory structure.
Patch readability
Readable patches are more likely to be accepted. Use the -u option for unified formatting and -p to show the function closest to the difference in the code. This makes it easier to see what changed.
Keeping things organized
To help reviewers understand the scope of changes, separate each change type into its own patch. For example, bug fixes, performance enhancements, code style fixes, and whitespace fixes all should be in different patches. Likewise all white space and code style cleanup should be in a separate patch.
Line endings and directory separators
Note for Windows users: Use Unix line endings (LF) and directory separators (/). Many text editors can convert line endings, or you can pipe diff output through dos2unix.
The diff command
In your command line, simply type in the following:
cvs diff -up original.php > filename.patch
- or -
diff -up original.php new.php > filename.patch
In this example, > writes diff's outpt in a file named filename.patch. If you omit> filename.patch, diff's output goes to your screen.
Give the patch file a descriptive name, such as modulename_code_cleanup.patch.
You can save the patch file to another place, like your desktop or a patch folder, by prefixing the filename with a path. For example: cvs diff -up original.php > path/to/desktop/filename.patch.
Switches for the diff command
When you've modified multiple files in the source tree, use diff's ability to compare directories. Add the -R (uppercase) switch to cvs diff and the -r (lowercase) switch to plain diff to instruct the respective program to recurse (sub)directories. To compare files from the root directory, cd to the root directory and use a dot (full stop) in place of the directory name:
cvs diff -uRp directory > filename.patch
or
diff -urp original_directory new_directory > filename.patch
Adding/Deleting Files Using the Diff Command
Note: the fakeadd utility can save you from fiddling with CVS internals.
Having one patch represent all code changes, including adding and deleting files is vital. The problem is that "cvs diff" won't let you diff files that haven't been added (cvs add) or deleted (cvs rm) from the repository. To do that you would normally need to get read/write permissions for the repository. Unless you are the maintainer of the module you won't have that, but there are a few solutions.
note: You use the -N switch to account for new or deleted files.
cvsdo
For linux users, a script called cvsdo is available to use that will basically do the long steps below for you:
cvsdo add file.module
it is part of the overall useful cvsutils package. for Ubuntu/Debian users:
sudo apt-get install cvsutils
Fedora users:
sudo yum install cvsutils
fakeadd
a shell script that again, does the work below for you.
http://tinyurl.com/fakeadd
by-hand method
see below about changing CVS/Entries to add and remove files manually.
Once you've added/removed the file from CVS by one of these methods, you can now use:
cvs diff -upN directory > filename.patch
or
diff -upN original_directory new_directory > filename.patch
Changing CVS/Entries to add and remove files manually
If you're using -N to account for a new file, you'll also need to edit the CVS/Entries file for that directory and manually add a line for the new file. For example, if you have created a new file called newfile.inc in the modules/system directory, you will need to add a line at the end of the modules/system/CVS/Entries file like this:
Editing modules/system/CVS/Entries:
/admin.css/1.12/Tue Jan 16 23:15:28 2007//
/defaults.css/1.2/Fri Aug 25 09:01:12 2006//
/system.css/1.22/Wed Feb 7 03:46:21 2007//
/system.info/1.3/Tue Nov 21 20:55:35 2006//
/system.install/1.79/Fri Feb 16 16:39:46 2007//
/system.js/1.1/Thu Feb 22 16:33:29 2007//
/system.module/1.451/Thu Feb 22 16:33:29 2007//
/newfile.inc/0/New file//
If you are working from a tagged version the line will have the tag at the end. Use the other entries in the file to guide you:
/newfile.inc/0/New file//TDRUPAL-5
In this example, the "New file" string is arbitrary, but the 0 must be specified as the file's revision to show that it is new. Once this new line has been added cvs diff -Nup will properly include the new file in the diff.
Note: Do not add binary files (like PNG files) to a patch file. They will cause the testing system to fail with an “Invalid PHP syntax” error. If your patch requires additional binary files, simply post them as separate attachments to the issue and specify which directory they should go in.
If you are using -N to account for a deleted file, you will also need to edit the CVS/Entries file for that directory and manually change the line for the removed file. For example, if you want to remove system.module in the modules/system directory, you will need to modify the corresponding of the modules/system/CVS/Entries file like this:
/admin.css/1.12/Tue Jan 16 23:15:28 2007//
/defaults.css/1.2/Fri Aug 25 09:01:12 2006//
/system.css/1.22/Wed Feb 7 03:46:21 2007//
/system.info/1.3/Tue Nov 21 20:55:35 2006//
/system.install/1.79/Fri Feb 16 16:39:46 2007//
/system.js/1.1/Thu Feb 22 16:33:29 2007//
/system.module/-1.451/Thu Feb 22 16:33:29 2007//
That's it! all you need to do is add a - to the version, so 1.451 becomes -1.451. (This works for files only—not directories).
Adding directories
It is also possible to use cvs patches to add a directory. For example, to add an add-on module to an existing module.
- Within a directory that cvs knows about, add a new file to cvs shown above. With contributed modules, this would be in the root directory of that module.
- Create the patch file by modifying CVS/Entries and using the -N switch shown above.
- Edit the patch file adding the directory path that the files should reside in.
- Example shown below, the first part shows the first few lines of the patch file created in the module root, after editing, I manually add 'contrib/exhibit_apachesolr' in front of any reference to the new file.
- After running the patch file, on a cvs checked out module, it creates both the file exhibit_apachesolr.info inside the created directory exhibit_apachesolr (that resides under contrib).
Index: exhibit_apachesolr.info
==============================================================
RCS file: exhibit_apachesolr.info
diff -N exhibit_apachesolr.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ exhibit_apachesolr.info 8 Nov 2008 16:18:41 -0000Index: contrib/exhibit_apachesolr/exhibit_apachesolr.info
==============================================================
RCS file: contrib/exhibit_apachesolr/exhibit_apachesolr.info
diff -N contrib/exhibit_apachesolr/exhibit_apachesolr.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ contrib/exhibit_apachesolr/exhibit_apachesolr.info 8 Nov 2008 16:18:41 -0000An example using cvs diff
- Make sure you have the latest CVS version of the file(s) before you begin making your changes: change (
cd) to the Drupal root directory and run the update command:cvs update -dP. - Make your changes to the file(s).
- When you are ready to roll your patch, change back to the Drupal root directory.
- Do a
cvs diff -up path/to/file/example.module > mypatchname.patch. This creates a new patch file in the Drupal root that you can now upload to an issue.
Reverting to Drupal head
To revert your install to the committed version of Drupal, and get rid of all differences, run the command: cvs up -dPC. Be careful with this command, because it will wipe out any changes that you are working on.

More discussion on line endings and directory separators
Thanks to some gentle coaching from Khalid Baheyeldin, an experienced drupal contributor, I came to discover an additional "diff" parameter called "--strip-trailing-cr" that could be useful to anyone creating patches on Linux (or any Unix) servers. Below I discuss when it is important to consider using this parameter and a typical use case.
Windows text files include a carriage-return ASCII character [CR, "\r", Hex 0D, or decimal 13, for example] that is not present in Unix text files. This difference in text file formats can defeat the purpose of using the "diff" command.
In my case, I created a new version of an existing module with just a few lines of code changed on my Windows PC using dreamweaver for PHP coding. I uploaded the new module to my Unix drupal site. The patch I then created wasn't the difference of the two modules but instead it was a union of both files. By union, I mean the patch included every line from the original module - not just the PHP lines I changed or added. The bloated patch was created, of course, because every line of text coming from my Windows file ended with an additional "\r" carriage-return ASCII character - not present in the original Unix version of the file.
Here are the steps I used to create a patch that solved the Windows to Unix mixed environment for me:
diff -up --strip-trailing-cr modules/amodule/amodule.module modules/amodule/amoduleNew.module > myNewamodule.patchAn alternative, as presented above in the main text, would have been to convert my Windows [aka Dos] module into Linux [aka Unix] format before creating the patch with these commands in a telnet window to my Linux server:
dos2unix modules/amodule/amoduleNew.modulediff -up modules/amodule/amodule.module modules/amodule/amoduleNew.module > myNewamodule.patch
Both methods above, produced exactly the same patch.
Best regards,
Ron Fredericks
Automatically adding files onto CVS/Entries
Adding multiple files manually into CVS/Entries files can be tedious and error prone.
Here's a small Unix shell script snippet (scrippet?) that can help you automate this task. This works for cases where no branch/tags are used. Add it yourself in the proper place if you like.
#!/bin/shADDED=`cvs -nq up|grep ^\? |awk '{print $2}'`
for file in $ADDED; do
echo '/'`basename $file`'/0/New file//' >> `dirname $file`/CVS/Entries
done
Adding new files to patches
As an alternative to manually adding new files to the CVS/Entries file, I can recommend the cvsutils script collection.
There's a perl script called cvsdo that allows you to do
cvsdo add foobar.phpto add a file locally (without accessing the remote repository). Then, you can create a patch with the -N switch (as described above) to include the newly added files. Very convenient.
See http://www.red-bean.com/cvsutils/ for details and download.
SVN cmd line with external diff
If you hold your drupal projects into SVN repositories, as I do, a handy way of creating a patch using the guidelines in this page and the diff external program would be:
# svn diff --diff-cmd diff -x -up modified.php > filename.patchor if you want to ignore whitespaces:
# svn diff --diff-cmd diff -x -wup modified.php > filename.patchIf the files are within a
If the files are within a new directory,
* follow procedure for adding new files above, in a directory that cvs knows about.
* edit the patch file adding the directory path required.
Index: exhibit_apachesolr.info==============================================================
RCS file: exhibit_apachesolr.info
diff -N exhibit_apachesolr.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ exhibit_apachesolr.info 8 Nov 2008 16:18:41 -0000
Index: contrib/exhibit_apachesolr/exhibit_apachesolr.info==============================================================
RCS file: contrib/exhibit_apachesolr/exhibit_apachesolr.info
diff -N contrib/exhibit_apachesolr/exhibit_apachesolr.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ contrib/exhibit_apachesolr/exhibit_apachesolr.info 8 Nov 2008 16:18:41 -0000
fakeadd
see also an automated way to cvs diff with a new file with fakeadd: http://wimleers.com/blog/cvs-diff-new-files-fakeadd
WinMerge is good
I found that WinMerge (http://winmerge.org/) is a good program for windows users to create patches.
Here's a simple guide on how to use it to create unified patch.
1. Download an install WinMerge.
2. Open WinMerget by going to Start->All Programms->WinMerge
3. Click on Tools->Generate Patch
4. Select the two different files you wish to compare.
5. Select the patch file path
6. In "Format", select "Unified"
7. Hit "Ok"
Hope it helps.
Attitude is mind's paintbrush, it can color any situation.
WinMerge is great.
Shouldn't this go into the documentation?
And, wouldn't it be a good idea to split the long article into sub-pages for CVS, diff and WinMerge?
EDIT: I notice the subpages already exist.
See my other comment down here, http://drupal.org/patch/create#comment-1930250
WinMerge is great, but...
WinMerge is great, but remember you still need to edit out the extraneous parts of directory trees by hand (unless there's an option to do this within WinMerge?)
creating a patch from a git mirror
Git mirrors of the Drupal codebase are available - details at http://drupal.org/node/355154
By Default git adds a prefix to the filenames (a and b for source and destination versions)
This causes the file information to look like
--- a/includes/database/sqlite/install.inc
+++ b/includes/database/sqlite/install.inc
to get rid of this use
git-diff --no-prefixand the file info should be like
--- includes/database/sqlite/install.inc
+++ includes/database/sqlite/install.inc
You can test if the patch applies cleanly by cd'ing to a clean Drupal root and running
patch -p0 < path_to/my.patchSean Burlington
www.practicalweb.co.uk
London
Doing it with SVN
I got really frusterated with the "copy files from subdirs to main dirs and then fix the diff" method, so I just did it with svn.
Just co drupal, then add it to an SVN repo.
svnadmin create /home/svn/drupalcd drupal-from-cvs
svn import file:///home/svn/drupal
checkout the SVN repo to a new directory
svn co file:///home/svn/drupal drupal-from-svncd drupal-from-svn
make your code changes there (and run your site from there if you want). Of course, you can use "svn add"
Cut the patch
svn diff > 11111_11_something.diffThen, probably want to revert the svn repo
svn revert -RNow, just use your svn co as a proxy. When you update drupal core, you can update from cvs and then check-in to your svn repo. All patches can then use svn add.
Subscribing so I can track
Subscribing so I can track changes (per #424596: How to track pages I am working on or have edited).
Change to root directory?
Is it really necessary to change to the Drupal root directory? If I am just changing one file in a contributed module, what's the harm of creating a patch from the affected directory?
It makes patching easier
When all patches can be applied with the same command, you don't need to read the patch file itself to find out how to apply it. That's easier for anyone who applies a lot of patches. (And as a bonus, automation is a lot easier.)
If you create a patch from the affected directory, please make sure that the filenames in the patch are relative to the project root. (For Drupal core, that's the Drupal root. For a contributed module, it's the module root.)
--
Rob Hunter
ThoughtWorks Australia
Split this article
The main article has a lot of parts that you will skip if you are only interested in one patching method. Even worse, for some parts it is unclear which patching method they refer to.
I think it would be a good idea to split this article.
I started a child page for Creating patches with CVS- I supposed the "Adding/Deleting Files Using the Diff Command" section refers to the CVS method?
Split this article - too fast?
Hu.. maybe I've been too fast here?
It seems there is a reason for having diff and cvs diff instructions in the same page.
But still, the article is way too heavy.
So, new solution:
- Have a dedicated child page for "Creating patches with diff / CVS diff"
- The main article (this one) will have a summary of different methods, and the guidelines for creating quality patches.
Please, some feedback would be helpful!
How do you work on multiple different patches at the same time?
If you have multiple issues, how can I work on them at the same time and make separate patch for each?
-HdDigitalworks.com-