Tuesday, September 2, 2008

Applying Patches to Git Code

My experience with group code development in bioinformatics has been limited to this point. Thus the idea of working with patches is fairly foreign. This summer, I finally got to work with them on the Pygr project. Just wanted to jot down some notes for my own reference. A simple 'man patch' command on a *nix system reveals the goodies:

SYNOPSIS
patch [options] [originalfile [patchfile]]

but usually just

patch -pnum

Knowing that a patch is simply a diff file helps. Re-remembering that source code repositories are all about diffs then helps simplify the concept. Then finally, knowing that creating and applying patches has been build into *nix systems for ever helps ease any fears of compatibility. The syntax is a bit old and *nixy but fairly straightforward.

The only option that I want to expand on is the "-pnum" part:

-pnum or --strip=num
Strip the smallest prefix containing num leading slashes from each
file name found in the patch file. A sequence of one or more adja-
cent slashes is counted as a single slash. This controls how file
names found in the patch file are treated, in case you keep your
files in a different directory than the person who sent out the
patch. For example, supposing the file name in the patch file was

/u/howard/src/blurfl/blurfl.c

setting -p0 gives the entire file name unmodified, -p1 gives

u/howard/src/blurfl/blurfl.c

without the leading slash, -p4 gives

blurfl/blurfl.c

and not specifying -p at all just gives you blurfl.c. Whatever you
end up with is looked for either in the current directory, or the
directory specified by the -d option.

If I open up the patch file I'm working with, part way in I see the text:

diff --git a/pygr/cnestedlist.pyx b/pygr/cnestedlist.pyx
index fa46280..0324c00 100644

The first line is the diff command used to create the patch file. The second line uses the keyword "index". In this case, the diff was created from a relative path position, thus no leading slash "/". When I apply the patch, I'll also use relative positioning. The "-pnum" option will help me get the proper relative position with which to apply the patch. This helps ensure that I don't have to care where the patch creator has his code installed (i.e the arbitrary /home/joesmoe/pythoncode/whatever/) but our directory structure at some point will be the same since we're working on the same code base - thus it's all relative baby.

So, if I cd to the root directory for the patch, represented by "a" or "b" in the relative paths, I can then use "-p1" to trim the "a" or "b" part and properly refer to the files I want patched:

patch -p1 < /path/to/patch/file/0001-thingy.patch

And now the patch is applied as a diff, just like a source code management tool would do. Because I was applying these changes in my local git repo, I can now see the effect:

prompt# git status
# On branch master
# Changed but not updated:
# (use "git add ..." to update what will be committed)
#
# modified: pygr/cnestedlist.pyx
# modified: tests/seqdb_test.py
#
no changes added to commit (use "git add" and/or "git commit -a")

No comments: