Wednesday, 14 July 2010

Guide to patching a git

Right, I do not know if any of you out there are programmers, but here is a little tip I have picked up today as it was very difficult to glean from the massive amounts of online tips. This is the problem when you venture into the world of 'advanced' programming, people fail to write simple solutions when there are so many fancy options out there.

In my field, we use Git to share and update files. If I update a file in our group that is on our git repository, I have to submit patches for review before pushing. This post is how to edit and create a patch for review. I am assuming that you already have a git repository cloned and you are editing from there on your 'master' branch. Now, I am not a great user of git, nor is this elegant or even possibly correct. This is just what I do and it seems to not break things. You have been warned...

STOP! Do not edit on your master branch. It is scary and people yell at you and the general order of things descends into chaos. Instead, execute the following (don't type the '$', that's just to show it's on a command line)

$ git branch -b editbranch

This will create and switch to a new branch called editbranch that you can play with and destroy at your freedom and leisure. Feel free to call it whatever you please, such as filebin, trashsector, development (non-exciting choice that I went with...with the sequel, development2 when I screwed up the development branch...shut up! I'm not creative when the possibility of breaking a computer is in front of me) or xwing or tiefighter (those'll be my next ones).

You can switch between branches by doing
$ git checkout master #this is your default branch
$ git checkout tiefighter #this is where you edit things

Now edit your file with your preferred text-editor of the day. I prefer a large helping of emacs with a touch of vim if I'm feeling saucy.

$ emacs filename.c

play play, compile, break, delete, play, edit, compile, break, fix, compile, delete, fix, compile, success! (You know the game of which I speak)

Now that you have a new version of a file on your git repository, it is time to do the scary scary sin of COMMITTING. All you commitment-phobes out there better suck it up and get ready to take the plunge. Type

$ git branch

to make sure you're in your development branch. Type

$ git branch

again, just to make sure... you should see a return like this:

$ git branch
tiefighter *

the asterix means that's your working branch. This is correct. If the asterix is instead next to your master branch, you are monkey-screwed up a wall of fleas. You have edited in your master branch.At this point, a point where I have been many times, I copy over my changed file to somewhere safe, reload git or copy a clean, unedited file into that directory, then switch to git using

$ git checkout tiefighter
and paste the edited copy back onto that
$ cp /home/safedirectory/changedfiles/filename.c .

It's not clean or happy, but it happens a lot and that's the best way I have found to fix it.
Now that you are sure you have made the changes in your editing branch, execute:

$ git commit -m "This is where I briefly describe the changes" filename.c

You will see lots of help files where $ git commit -a is suggested, this means you commit all your files that could be changed. I stay away from this because I like more control on the situation.

Now you want to create a patch file. This is basically a text file that clearly lays out all the insertions and deletions you made to the file. It is really handy, especially if you want a record of what you have done, or if you want someone else to look at your changes. This is created by doing

$ git format-patch origin

where origin calls back to the original committed files and compares the two. This creates a patch in your directory called "0001-This-is-where-I-briefly-describe-the-changes.patch". Now you look at the patch with something as simple as

$ more 0001-This-is-where-I-briefly-describe-the-changes.patch

Oops! You will inevitably see a mistake...maybe you'll see a changed line where it is now a comment; something you meant to delete before you committed. This happens to me far too much to be dignified. So you go back to the file:

$ emacs filename.c
edit, delete, compile, hooray!

Now if you execute the same commands from above

$ git commit -m "This is where I briefly describe the changes" filename.c
$ git format-patch origin

it will result in a second file, 0002-This-is-where-I-briefly-describe-the-changes.patch with only the minimal deletion or change. I prefer to have all my edits and changes in one single .patch file. This is how that is done. Execute:

$ git log filename.c

This will show you all the recent committed changes, including your past 2+ ones. It will look something like this:
commit #x####xxx###x#x#x##xxx###x#x#x##xxxx##
Author: His Holiness
Date: Wed Jan 14 04:27:17 2110 +0100

This is where I briefly describe the changes

commit #x####xxx####x#x##xxx###x#x###xxxx####
Author: His Holiness
Date: Wed Jan 14 04:25:17 2110 +0100

This is where I briefly describe the changes

commit #x##x#xxxx#x#x####xxx#x##x#x###xxxx####
Author: Someone smarter than me
Date: Tue Dec 25 08:30:05 1013 +0100

This is where I did AMAZING things to this file

And you want to create a patch from the last change (not yours, you Holiness) where someone smarter than you made some really amazing changes. Here is what you do so you don't have multiple patches:

$ git diff -p #x##x#xxxx#x#x####xxx#x##x#x###xxxx####[the number from commit on the smarter one] filename.c > 0001_new-patch-whatever-I-want-to-call-it.patch

There you go! There is a new patch with all your amazing (hopefully, pending review) changes that you can email to others for checking. Good luck!

Next time, in the world of Git: We look at how to do the dreaded push. Stay tuned for whenever my new patch is approved and I have to figure this all out again! (I really need to start writing stuff down)

1 comment:

  1. If someone has updated master while I've been working on a branch (call it mybranch) I find the following procedure useful:

    git checkout master # Switch back to master
    git pull --rebase # Get the awesome new changes
    git checkout mybranch # Switch back to your branch
    git merge master # Merge the new changes to master into your branch

    This makes life simpler when it comes to making patches or merging your code back into master.