Store git activity in MySQL with PHP

Git hooks are saving me so much time and providing me with interesting solutions to problems I didn’t even know I had. I can’t be the only person who this would be useful to, so give it a go.

As I said, I work on loads of sites, and keeping track of what’s been done and where is sometimes a bit of a pain. I keep a todo list, but if I get an emergency email from someone, chances are that won’t go through my todos. It will, however, be put into version control.

So this morning I had the bright idea to write a git hook that pushes relevant information to MySQL so that I can run activity reports later. All my bare git repositories are stored in a directory on our dedi, so it’s just a matter of making sure each repository has the post-receive hook in. I do this by keeping the actual hook in the same directory as all my repositories, then symlinking the hook into the appropriate place with the following little script. Obviously, this assumes that your post-receive hook is in the same place as your repositories, and that you want this hook everywhere. But that’s all true, so we’re all good. Once you’ve run the linked script, you’ll only have one hook to maintain and every time you create a new repository, you can just run the script again and everything will all be up-to-date.

Now for the hook. It’s not beautiful PHP, but little scripts like this rarely are, in my experience.

See the table create in the comment:

So basically we’re extracting the log data we need, doing some funky stuff to handle multi-line commit messages (I like to store lots of details as my subject messages tend to be a bit vague!). Other than that, if you’re familiar with PHP, the above should be pretty self-explanatory. If it’s not, hit the comments and I’ll explain things.

I’ve only been using this a little while, but it seems to work very well. If you use it and stumble across any bugs, I’d love to know about them!

Update: I’ve today realised that git log only logs the currently-selected branch, or master on a bare repo so I’ve added the –all switch to git log so I can get the logs for every branch. Most of it’s just “Merged blah” but that means it can be filtered easily and I’d rather have everything and need to filter than be missing something important.

git gtd mysql php

code

1Managing multiple working copies with git

We have a CMS at Buffalo, which we have deployed to several servers for a few of our clients. Until recently, it was only two separate servers and was relatively easy to manage with Subversion (though slightly cumbersome – svn ci -m “blah”; ssh server; cd /site; svn up; exit; ssh server2; cd /site; svn up;) but now that we’re deploying the same CMS to 8 servers, simple changes and bug fixes are becoming a pain in the ass to deploy.

I’ve been tentatively looking into git for quite some time now. I’m incredibly cautious of the bleeding edge when it comes to how I make money because I prefer to have things that I can rely on and will serve me well than keep up with the latest fads. That’s not to say that I’m not interested in all the cool new jazz, and I keep up as much as family life permits, but I don’t dive in and adopt without learning and understanding everything I need first. Sensible? Yes. I’m surprised at how many people flaunt this ethos.

That being said, git has proved itself invaluable to me in the last 4 months. The way it encourages you to work is great. I do all changes on branches then merge them into master and remove branches to keep everything clean. I also have $deploy-staging and $deploy-live (where $deploy is a working copy) so that I can manage configuration for each working copy. This probably isn’t git best practice, but I’ve found it to be incredibly convenient. I work on up to 20 different sites in any week, so being able to merge changes and conflicts for live stuff locally saves me headaches galore. No-brainer. My git workflow goes something like this:

git checkout -b hotfix-phperror
# do some work
git commit -am "Hotfix for PHP Error fixed"
git checkout master
git merge hotfix-phperror
# resolve any conflicts
git checkout staging
git merge master
# test on staging - everything OK
git checkout live
git merge master

That might seem like quite a bit of work, but it keeps everything tidy. Unfortunately, it does mean that if things fail on staging, I still have the history of it in master. I suppose it would make more sense to merge the hotfix into staging, then merge that into live, then merge everything into master and tag once it’s verified working to keep it clean, but either way, this tip will work.

I’m under the impression that git frowns upon what I’m about to recommend, but it works so well that I can hardly ignore it! One proviso for this is that all the working copies you push to have to be the same. Lucky for us, the configuration for our CMS is held by the live site (separate repository) rather than the CMS itself, so each working copy is the same.

With the above in mind, I’m going to assume the following:

• You’ve got a central, bare repository to push to
• Your live branch (identical for all working copies) is tracked from said central repository

First off, you have to make sure that your local working copy has all remotes available. Obviously your bare repository will be available because that’s how you’re doing things anyway, but we also need working copies. You can check that everything’s there by running a quick git remote. If you’re all good, then we can start pushing code around.

As I said before, git doesn’t seem to like this sort of thing. If you were to try and push to one of your working copies where the checked out branch is the one you’re pushing to, git will whine at you and preserve the changes you push so that you can stash any local differences. You can force this by changing to the directory and running git reset --hard or git stash, but that defeats the purpose of this so we need a workaround.

Luckily, git gives you all the hooks you need and more for this. We’ll be creating a post-update hook that will force-update your push. With that in mind, cd to the root of your working copy on one of your remotes and do something like:

echo "#!/bin/sh
cd ..
env -i git reset --hard" > .git/hooks/post-update;
chmod +x .git/hooks/post-update;

Now, when you push to the repository git will moan at you, but this hook will run and force all your changes. Awesome.

In the warning message git spits out, it threatens that new versions of git will auto-reject pushes to checked out branches, so a quick run of:

git config --set receive.denyCurrentBranch "ignore"

Will shut git up and have it doing what you tell it to. I suppose the reason it does this is it assumes that someone is working in that working copy and they don’t want you frivolously overwriting their code. Luckily, we know what we’re doing is safe so there’s no harm in doing this. Do remember, though, that all changes made in the working copy will be overwritten when you push using this method, so don’t work on live working copies. Don’t do that anyway, but definitely don’t do it here!

Now, you can do the following:

git remote add remote-alias ssh://root@blah/path/to/working/copy
git fetch
git push remote-alias live

In all the feedback, you’ll see something like “HEAD is now at 0d5431b HELLO!!!” (the hash and first line of your last commit message) which lets you know that things have worked.

Now you’re able to push to remotes without complaints, from the comfort of your local working copy, with a bit of scripting you can deploy your local live branch to all its remote locations with a little bit of scripting:

for remote in `git remote`; do git push $remote branchname; done;

For future reference, we’ll assume that this isn’t the only time you’ll do this, so save the following as a script in your path somewhere (I call it git-rpush):

for remote in `git remote`; do git push $remote $@; done;

Which you can call with git rpush live. Assuming that all your working copies have the config set and the hook installed, you can now push a change to all of your local repositories at once without having to remember which ones you actually need to push to, then spending half an hour SSH-ing all over the place to do it.

I don’t know about you, but that’s just saved me a crap-load of time. Hope it helps someone!

Coincidentally, if you do need this to be locally configurable, you can easily check out your branch and create a patch for configuration, then add the patch removal and application into hooks. I would do something like the following (assuming you already have your patch):

echo "#!/bin/sh
cd ..
env -i git apply -R config.patch" > .git/hooks/pre-update;
chmod +x .git/hooks/pre-update

This will remove your config so that no conflicts occur during the update. All you need is to re-apply the patch in the post-update, after you’ve done the reset. Insert the following:

git apply config.patch

Your config will be preserved. You can even keep these patches in version control, just change the name for all your remotes and update your hooks accordingly. Then enter my competition on how easy you can make your life by scripting it!

Any and all questions and improvements are welcome and appreciated.

I would like to thank the following post for hand-holding through the intricacies of what I was trying to achieve with hooks. So thanks!

git gtd script life

code

Sunday

lucky to retain all toes

sleep

king of the castle

periscope

mesmerised

still mesmerised

boredom camera iphone4 photos sunday

animals, food, people

2some credibility

No-one believes me when I say that mushrooms are evil. They look nice, sure, but they’ve got the texture of rubber and they taste like weird stuff so they’re evil.

And these ones

these mushrooms

Made Charlotte

made this girl sick

Sick.

I didn’t post a picture of the sick, though.

I got these – they’re pretty fun. You have to do this ghetto mod to your flashgun with a couple of thin strips of velcro. I like the light gold one, it’s kinda sepia-ey but only really subtle. I used it on the mushrooms to bring out that nice brown colour. The paler ones I think will be really useful, but I’m not sure about the magenta one.

magenta

charlotte food photo

food, people

days (one of those)

evile

sneak

vision based on movement

subtle

Snarg.

alcohol amelie cute iphone4 sudo train

animals, photography

le weekend

Considering I had Monday off, this week has gone so slow.

I had a couple of photos on my camera camera but I accidentally deleted them in my half-awake state. Just a couple of macros; nothing inspired.

The 4 continues to impress me. App creators are really doing wonders with the camera, and I’ve now settled on a mix of Hipstamatic and Camera+ as a complete replacement for the native camera app. Camera+ could be a little quicker to respond, but you can’t argue with the results. Well, you could, but you’d be stupid to – they’re photos; they can’t argue back.

FLY

beg

sky

Champagne and Strawberries

spots

stalk

mischief

amelie animals food iphone4 sudo

photography

aftermath

As I said, I’m not one for raucous birthdays so the aftermath is pretty tame. With that in mind, a lazy, pathetic dog, a chocolate pudding and a shitload of washing up.

I’ve switched to my 50mm for a little while. Thinking about selling the 24-70 and getting a 35mm prime – it’s like £1000 just sat in my camera bag most of the time. Seems such a waste.

shame

whore

sleep

mns chocolate pudding

washing

animals cute food sudo

animals, food, me

2he’s breaking my heart

anything sadder?

I have to leave him in his crate on his own. I haven’t felt this bad in so long, even though I know it’s for his own good.

cute puppy sudo

animals

birthdays

I don’t normally make a huge fuss of my birthday. It’s just another day, really. That is, however, an unpopular standpoint so I invariably get a bit caught up in it and end up having quite a lovely time. Yesterday (and the awesome-fun night before), despite its hiccups, was no different.

Having eaten some dodgy mayonnaise (self-diagnosis) and dealt with the dog puncturing a five-stitch hole in his armpit, we got underway and my mum came down for a visit. I never get to see my mum, so this was brilliant. The mini movie marathon was wicked, too. I love getting DVDs, and yesterday saw some gaping holes in my collection filled. Maybe I need to make a new-years resolution to not be such a grumpy bastard about my birthday and allow myself to get excited like child about it next year.

With drinking and sick dogs and birthdays and hipstamatic in mind, have some photos of the last couple of days. Flickr Uploadr really fucked me on the ordering of these in my stream. First world problems, yo.

hobbits

gangster-ish

tree

stairs

squat

converse

croissant

radiator cat

stair cat

bay

poor dog

poor dog

poor dog

poor dog

stitches

cone of shame

birthday friends iphone movies photos

me

1Losing battle, fought and lost.

hyp[ocrisy]-stamatic

incredibooth

That Hipstamatic App. Over the past couple of months, more and more of my friends have been posting photos from this app and they’ve kinda been grating on me a bit. I don’t know why this is, it’s more of a reflex than anything. I guess, being a bit of a purist with everything I try, it makes me sad to see such a beautiful artform distilled to an iPhone app and consumed by people who don’t really appreciate it. I’ve got to stop being like this – it’s great that people take photos loads now, and the voyeur in me enjoys looking at all of them really.

So, why have I now decided to try this app-I-once-hated? I’ve been lusting after something a little more organic, photographically, for a while. I really want the purely mechanical Nikon FE and the beautiful Polaroid SX70, but it’s impossible to find 35mm film that doesn’t contain the ground bones of dead animals, and that Polaroid is such an expensive habit that I don’t think I can justify it. At least not now.

The problem with the above is that the camera porn is a pretty substantial part of the battle. I mean, look at that FE. So industrial. You could beat someone to death with it, load some film and shoot away and it wouldn’t even know the horrors of its past. Without wanting to sound like I’m 90 years old, they just don’t make ‘em like that any more. And the SX70 is a gorgeous piece of kit, lovingly restored by actual Polaroid engineers – what camera/gadget nut wouldn’t swoon over it?!

The major aspect, of course, is results. Analogue photography has a certain way about it. I see a lot of people on flickr emulating the way film looks, and they do a great job, but I don’t like to change things. If a photo comes out of a camera with perfect colour representation, I don’t like changing that. If I accidentally screw the white balance or the focus is way out, I usually quite like that. It seems organic (well, as organic as a digital photograph can be). So playing with the sliders on a digital photo to make it look more film’y just doesn’t compute (awful, awful pun). Shame. With the iPhone 4 camera being the great quality it is, I’m going to start trying some of these kooky photo apps to try and fill the void of the film cameras I lust after. It probably won’t work, but I feel like I have to try it. This is the first thing in four-ish years that I feel like I’m missing out on, being vegetarian, but I just can’t bend my own rules to justify it.

So far, I’ve bought IncrediBooth, Camera+ and Hipstamatic (the latter needing an update to really bring it in line with the 4′s capabilities). What else do I need?

Before anyone points out that jelly uses ground animal bones, these little pots don’t. The only one that isn’t veggie friendly is the red one, because of the food colouring. So there

analogue film hipstamatic incredibooth iphone photography polaroid vegetarianism

photography