Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining git hooks

Tags:

git

githooks

As many of you probably know, there can be only one hook type in git. If two update hooks need to be evaluated. The git admin is left with two unmanageable solutions:

  1. Merge the hook scripts together
  2. Manually chain them with an exec

I am looking for an elegant solution (written in BASH),something like a folder hooks/update.d or hooks/post-receive.d that will allow the loosely coupling of hook evaluations. The chaining should stop as soon as a hook fails.

I actually found an acceptable solution written in perl at this URL http://blog.bluefeet.net/2011/08/chained-git-hooks

The problem: my server runs different versions of perl and I am getting perllib version mismatches. It fails.

like image 381
Olivier Refalo Avatar asked Jan 04 '12 16:01

Olivier Refalo


People also ask

Are Git hooks synced?

Unfortunately, git doesn't automatically synchronize hooks between project contributors. I can set up git hooks for my own workflow, but I need some extra help to share them with the rest of my team. Fortunately, git hook synchronization is an easy (and in later versions of git, almost trivial) problem to solve.

Do Git hooks get cloned?

Second, you can't force developers to create commits that look a certain way—you can only encourage them to do so. Maintaining hooks for a team of developers can be a little tricky because the . git/hooks directory isn't cloned with the rest of your project, nor is it under version control.

Are Git hooks tracked?

git/hooks is the folder that hosts our customized hooks, but this is not really helpful when we need to share these scripts within the team since this folder is not tracked by git. A good approach for solving this is adding all of our custom hooks on a separate folder inside our repository.

What is the use of hooks in Git?

Git hooks are scripts that run automatically every time a particular event occurs in a Git repository. They let you customize Git's internal behavior and trigger customizable actions at key points in the development life cycle.


2 Answers

After further investigation and testing, here is a working solution:

create file .git/hooks/hook-chain as follows

#!/bin/bash # # author: orefalo  hookname=`basename $0`   FILE=`mktemp` trap 'rm -f $FILE' EXIT cat - > $FILE  for hook in $GIT_DIR/hooks/$hookname.* do     if test -x "$hook"; then #       echo $hook         cat $FILE | $hook "$@"         status=$?          if test $status -ne 0; then             echo Hook $hook failed with error code $status             exit $status         fi     fi done 

Now link any hook that requires chaining, for instance

  • ln -s hook-chain update
  • ln -s hook-chain post-receive

finally, create the chains by renaming them as hookname.action

 -rwxr-xr-x. 1 git  git  6710  functions  -rwxr-xr-x. 1 git  git   280  hook-chain  -rwxr-xr-x. 1 git  git  1524  post-mirror  lrwxrwxrwx. 1 root root   10  post-receive -> hook-chain  -rwxr-xr-x. 1 git  git  8763  post-receive.1email  -rwxr-xr-x. 1 git  git  1745  post-receive.2github  -rwxr-xr-x. 1 git  git   473  post-upload-pack  -rwxr-xr-x. 1 git  git   346  pre-receive  lrwxrwxrwx. 1 root root   10  update -> hook-chain  -rwxr-xr-x. 1 git  git  2975  update.1acl  -rwxr-xr-x. 1 git  git   328  update.2github 

for instance, in the sample above, the update hook will run update.1acl followed by update.2github.

The post-receive hook with run post-receive.1email followed by post-receive.2github

like image 135
Olivier Refalo Avatar answered Oct 03 '22 07:10

Olivier Refalo


For those who're not willing to click on every link in comments below other answer, here's a practically unmodified version of the script by @HenrikN:

#!/bin/bash  # Runs all executable hookname-* hooks and exits after, # if any of them was not successful. # # Based on # http://osdir.com/ml/git/2009-01/msg00308.html  data=$(cat) exitcodes=() hookname=$(basename $0)  # Run each hook, passing through STDIN and storing the exit code. # We don't want to bail at the first failure, as the user might # then bypass the hooks without knowing about additional issues.  for hook in $GIT_DIR/hooks/$hookname-*; do   test -x "$hook" || continue   echo "$data" | "$hook"   exitcodes+=($?) done  # If any exit code isn't 0, bail.  for i in "${exitcodes[@]}"; do   [ "$i" == 0 ] || exit $i done 
like image 41
sanmai Avatar answered Oct 03 '22 09:10

sanmai