30

I have recently needed to write git hooks, for all commits to reference a particular ticket.

I was hoping for a place to start learning. All the stuff in the pro git book is written in Ruby. Since Ruby is not my strong suit, can anybody share tutorials about git hooks written in other languages? (I'd particularly prefer Python or Bash scripts.)

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
Mahdi Yusuf
  • 19,931
  • 26
  • 72
  • 101
  • 3
    Worded properly, this can be a good general question, so I've reworded this to be more general and less language specific (while still respecting the questioner's expertise in python and bash.) If someone wants to help clean it up more, so that it's general enough to be linked into the unofficial GIT FAQ http://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide, that would be much appreciated. – Ken Bloom Jul 22 '10 at 18:12

3 Answers3

25

Here is an example of using Python for a hook. In general the hooks are language agnostic. You use the script to do some work or to exit with a 0/other return code to alter the flow of a git process.

Peter Loron
  • 1,156
  • 10
  • 15
9

The examples that come with git are written in shell script; there are some basic ones in .git/hooks of each repo and more advanced ones installed to /usr/share/doc/git-core/contrib/hooks.

There's also more info on the various hooks available via $ man githooks.

intuited
  • 23,174
  • 7
  • 66
  • 88
5

I found out that it's easy to write git hook on python. It's an example of post-receive hook on python. Provided example deploys master and develop branches in different folders (changes in master will be pushed to production website and changes in develop branch will be pushed to qa site)

#!/usr/bin/env python                                                                    
# -*- coding: UTF-8 -*-                                                                  
#post-receive                                                                            

import sys                                                                               
import subprocess                                                                        

# 1. Read STDIN (Format: "from_commit to_commit branch_name")                            
(old, new, branch) = sys.stdin.read().split()                                            

# 2. Only deploy if master branch was pushed                                             
if branch == 'refs/heads/master':                                                        
    subprocess.call('date >> ~/prod-deployment.log', shell=True)                         
    subprocess.call('GIT_WORK_TREE=/home/ft/app.prod git checkout master -f', shell=True)
    subprocess.call('cd ../../app.prod;bower update', shell=True)                        

#3. Only deploy if develop branch was pushed                                             
if branch == 'refs/heads/develop':                                                       
    subprocess.call('date >> ~/dev-deployment.log', shell=True)                          
    subprocess.call('GIT_WORK_TREE=/home/ft/app.dev git checkout develop -f', shell=True)
    subprocess.call('cd ../../app.dev;bower update', shell=True)                         
Roman Podlinov
  • 23,806
  • 7
  • 41
  • 60
  • The variable you named `branch` is actually the remote reference (so I like to use `remote_ref`). This means the conditions for #2 and #3 aren't really checking what they claim to be checking. For example, with the command `git push origin develop:master` the 2nd condition thinks you're pushing the master branch but you're not -- it's pushing *to* master, but not pushing *from* master. The conditions in the example assume that you only push local master to remote master and similarly for other named branches. – Dennis Dec 17 '14 at 16:44
  • Also note that `old` is the local reference and `new` is the local commit's SHA-1. Here is the full line that's supplied via STDIN to the hook: ` ` – Dennis Dec 17 '14 at 16:50
  • @Dennis sorry I do not understand your comment. git push origin develop:master you push local.develop to origin.master. Ok but you push into master doesn't mater from master or from other brunch. I'm trying to understand I didn't get point of your question or you didn't get idea of the solution – Roman Podlinov Feb 26 '15 at 11:50
  • @Dennis The idea is you have production & qa sites on the server. The master branch is binded to production site and develop branch is binded to qa site – Roman Podlinov Feb 26 '15 at 11:56
  • Maybe I misunderstood? There's some ambiguity with the naming of your `branch` variable. Is that referring to the local branch or the remote branch? My comments assumed that you were referring to the local branch. If that's the case, there are issues with the solution as I pointed out. – Dennis Feb 26 '15 at 23:09
  • 1
    @Dennis Now I got your point. Actually it's a remote branch for developer (but a local branch for the server to which you push/deploy your code) – Roman Podlinov Mar 02 '15 at 12:49