threads / discuss / 16424

What about allowing multiple hooks?

Subject: What about allowing multiple hooks?

## tl;dr

10 messages between Nov 21, 2008 and Jan 22, 2009.

replies: 9people: 7as markdown or json

Marc Weber· Nov 21, 2008, 13:38 UTC · lore
Use case:

I've been reading parts of the topGit code. And it does make for it to add its own checks. However having to change the existing scripts insterting a call to the tg hooks isn't the best way. Why? one is using #/bin/sh the next is using #/bin/ruby maybe..

So what about allowing (or even enforcing) ths directory layout?

.git/hooks/pre-commit/hook1.sh .git/hooks/pre-commit/hook2.sh .git/hooks/pre-commit/topGitcheck.sh

instead of .git/hooks/pre-commit # <- the one and only pre-commit hook

so that all can be run in squence?

This way you can keep the original git sample files and update them while adding you very own checks more easily.

But maybe this isn't the best choice either and the way to go is
.git/hooks/list-of-hook-directories # eg containing ".git/hooks/samples\n.git/hooks/topgit" ?

.git/hooks/sample/<all the sample hook files> .git/hooks/topgit/pro-commit

?

Then you can actually link in your own personal check script directories easily *and* you can add them to the repository eg by using comitted-repo-hooks instead of .git/hooks ? This way you could provide different hook directories for different platforms and all you have to do is enabling them by adding the path to .git/list-of-hook-directories ?

I guess the second approach of defining kind of overlays is better because it doesn't interfer with the existiing scheme? Maybe it should be implemented as git config option instead of a file containing the list of directories?

The hook direcotry list apporach is better because you've more control about order of execution..

Thoughts?
Marc Weber
martin f krafft· Nov 21, 2008, 13:55 UTC · re: Marc Weber · lore

Re: What about allowing multiple hooks?

also sprach Marc Weber <marco-oweber@gmx.de> [2008.11.21.1438 +0100]:
Show 8 quoted lines
> So what about allowing (or even enforcing) ths directory layout?
> 
> .git/hooks/pre-commit/hook1.sh
> .git/hooks/pre-commit/hook2.sh
> .git/hooks/pre-commit/topGitcheck.sh
> 
> instead of
> .git/hooks/pre-commit # <- the one and only pre-commit hook

If you do this, I strongly suggest .git/hooks/pre-commit.d, and to use .git/hooks/pre-commit to invoke it, which adds to transparency. Debian does this all over the place. You need to ignore backup files and/or only execute *.hook files, to be able to have other files in there. Or the +x flag, as it is used now.

> The hook direcotry list apporach is better because you've more
> control about order of execution..
It's also way more transparent and natural.
-- 
martin | http://madduck.net/ | http://two.sentenc.es/
 
"america may be unique in being a country which has leapt
 from barbarism to decadence without touching civilization."
                                                        -- john o'hara
 
spamtraps: madduck.bogus@madduck.net
Rogan Dawes· Nov 21, 2008, 14:56 UTC · re: Marc Weber · lore

Re: What about allowing multiple hooks?

Marc Weber wrote:
Show 12 quoted lines
> Use case:
> 
> I've been reading parts of the topGit code. And it does make for it to
> add its own checks. However having to change the existing scripts
> insterting a call to the tg hooks isn't the best way.
> Why? one is using #/bin/sh the next is using #/bin/ruby maybe..
> 
> So what about allowing (or even enforcing) ths directory layout?
> 
> .git/hooks/pre-commit/hook1.sh
> .git/hooks/pre-commit/hook2.sh
> .git/hooks/pre-commit/topGitcheck.sh
I second Martin's suggestion, that you implement:

.git/hooks/pre-commit .git/hooks/pre-commit.d/hook1.sh

where hooks/pre-commit is e.g. a shell script much like the init scripts that iterate over the executables in the corresponding .d/ directory, and execute them one at a time. Basing your script on initscripts will likely save you some time, since they have already considered things like script ordering, backups, etc.

I'm also inclined to think that this is likely to be a local customisation, because you need to decide what makes sense in your context, aborting if a script exits with a non-zero result, or continuing to see if the next script manages to exit with a zero result.

e.g. in the pre-commit case, it *probably* makes sense to allow any script to abort the commit, but your site-specific requirements might be that all hooks must fail to abort the commit.

Regards,
Rogan
Alexander Potashev· Jan 3, 2009, 23:32 UTC · re: Marc Weber · lore

Re: What about allowing multiple hooks?

On 14:38 Fri 21 Nov     , Marc Weber wrote:
Show 17 quoted lines
> Use case:
> 
> I've been reading parts of the topGit code. And it does make for it to
> add its own checks. However having to change the existing scripts
> insterting a call to the tg hooks isn't the best way.
> Why? one is using #/bin/sh the next is using #/bin/ruby maybe..
> 
> So what about allowing (or even enforcing) ths directory layout?
> 
> .git/hooks/pre-commit/hook1.sh
> .git/hooks/pre-commit/hook2.sh
> .git/hooks/pre-commit/topGitcheck.sh
> 
> instead of
> .git/hooks/pre-commit # <- the one and only pre-commit hook
> 
> so that all can be run in squence?

If we have a single hook, git just runs a script. But multiple scripts can be run in different orders. We can assume that git should run them in lexicographical order, but sometimes it's not the best order can be used.

However, prefixes can be used to force a particular lexicographical
order:
	.git/hooks/pre-commit/01-hook2.sh
	.git/hooks/pre-commit/02-topGitcheck.sh
	.git/hooks/pre-commit/03-hook1.sh
Is there a better way to choose the scripts order?
Show 32 quoted lines
> 
> This way you can keep the original git sample files and update them
> while adding you very own checks more easily.
> 
> But maybe this isn't the best choice either and the way to go is
> 
> .git/hooks/list-of-hook-directories # eg containing ".git/hooks/samples\n.git/hooks/topgit" ?
> 
> .git/hooks/sample/<all the sample hook files>
> .git/hooks/topgit/pro-commit
> 
> ?
> 
> Then you can actually link in your own personal check script directories
> easily *and* you can add them to the repository eg by using
> comitted-repo-hooks instead of .git/hooks
> ?
> This way you could provide different hook directories for different
> platforms and all you have to do is enabling them by adding the path to
> .git/list-of-hook-directories ?
> 
> I guess the second approach of defining kind of overlays is better
> because it doesn't interfer with the existiing scheme?
> Maybe it should be implemented as git config option instead of a file
> containing the list of directories?
> 
> The hook direcotry list apporach is better because you've more control
> about order of execution..
> 
> Thoughts?
> 
> Marc Weber
Junio C Hamano· Jan 4, 2009, 10:01 UTC · re: Alexander Potashev · lore

Re: What about allowing multiple hooks?

Alexander Potashev <aspotashev@gmail.com> writes:
>> Thoughts?

I deliberately omitted support for multiple scripts in core git Porcelains to avoid this exact issue. It is a huge can of worms and it is dubious if you can have a coherent and generic enough semantics.

In the meantime, you can have a single .git/hooks/pre-commit script that defines your own convention. Maybe it uses .git/hooks/pre-commit.d/ directory, full of scripts, and implements the semantics you want, including:

 (1) the execution order and the naming convention of the scripts (e.g.
     they all live in pre-commit.d/ directory, and executed in ASCII byte
     value order of their names);
 (2) how their exit status combine together.  For example, maybe a failure
     from one of the scripts prevents none of the later scripts to even
     run and make the whole hook return a failure; maybe a failure will be
     remembered, but the other scripts may still want to be run to learn
     about the fact that the commit was attempted, and the whole hook
     returns a failure if any of them fail.
     In a hook that is run primarily for its side effects and not for
     validation, it may even be desireble if the whole hook returns a
     failure only when all of them fail, iow, for such a hook the status
     is not ANDed but ORed together.

Once you have such a framework and get help from others to widely try it in the field, it may prove generic enough to include it as the sample hook script to be installed everywhere.

Anders Waldenborg· Jan 21, 2009, 20:35 UTC · re: Junio C Hamano · lore

Re: What about allowing multiple hooks?

Junio C Hamano wrote:
Show 12 quoted lines
> I deliberately omitted support for multiple scripts in core git Porcelains
> to avoid this exact issue.  It is a huge can of worms and it is dubious if
> you can have a coherent and generic enough semantics.
> 
> In the meantime, you can have a single .git/hooks/pre-commit script that
> defines your own convention.  Maybe it uses .git/hooks/pre-commit.d/
> directory, full of scripts, and implements the semantics you want,
> including:
> 
>  (1) the execution order and the naming convention of the scripts (e.g.
>      they all live in pre-commit.d/ directory, and executed in ASCII byte
>      value order of their names);
 >
 >  (2) how their exit status combine together.

I need multiple hooks, so I've done some thinking about this, so I thought it may be a good idea to share this here.

I currently use configvalues to specify which hooks to run. For example this is how my post-receive looks:

data=$(cat)
git config --get-all hooks.post-receive.hook | while read hook; do
         $hook <<__EOF__
"$data"
__EOF__
done

Now none of my hooks wants to prevent update, so I don't care about return status. But it could easily be extended, for example by having some indicator per hook that can have the values (are these enough?):

  ignore - pretent that no failure was returned no matter what
  sufficient - if this hook suceeds end result is always sucess
  required - if this hook fails we fail, no more hooks are run
That could be done with the simple configvalue thing as follows:
git config -add hooks.post-receive.hook \
    "sufficient allow-repo-owner-to-do-anything.sh"
git config -add hooks.post-receive.hook \
    "required finegrained-access-control.sh"
git config -add hooks.post-receive.hook \
    "required allow-repo-owner-to-do-anything.sh"
git config -add hooks.post-receive.hook \
    "ignore send-mail.sh"
git config -add hooks.post-receive.hook \
    "ignore send-irc-notification.py"

One problem is that to change order one has to resort to manually editing config. So maybe something richer could be used:

[hooks "allow-repo-owner-to-do-anything"]
  cmd = /usr/share/git-hooks/allow-repo-owner-to-do-anything.sh
  enabled = 1
  type = post-receive
  mode = sufficient
  priority = 10
[hooks "mail"]
  cmd = /usr/share/git-hooks/allow-repo-owner-to-do-anything.sh
  enabled = 1
  type = post-receive
  mode = ignore
  priority = 1000
(this would even allow running hooks at same priority simultaneously)

Also then the hook's own config variables fits nicely in same section. (note that then each [hooks "x"] will be an instance that could use the same script, but different configvars)

  anders
Johannes Schindelin· Jan 21, 2009, 21:10 UTC · re: Anders Waldenborg · lore

Re: What about allowing multiple hooks?

Hi,
On Wed, 21 Jan 2009, Anders Waldenborg wrote:
Show 12 quoted lines
> I need multiple hooks, so I've done some thinking about this, so I 
> thought it may be a good idea to share this here.
> 
> I currently use configvalues to specify which hooks to run. For example 
> this is how my post-receive looks:
> 
> data=$(cat)
> git config --get-all hooks.post-receive.hook | while read hook; do
>         $hook <<__EOF__
> "$data"
> __EOF__
> done
I wonder why you don't do the obvious thing:
	data=$(cat)
	for hook in .git/hooks/update.d/*
	do
		test -x "$hook" || continue
		echo "$data" | "$hook" | exit
	done

and then name the hooks in your .git/hooks/update.d/ with leading zero-padded numbers so that you guarantee a certain order.

You can even share special hooks between repositories by symlinking, as is done in /etc/init.d/rc?.d.

Hth, Dscho

P.S.: If you want to save even more interactive work, you can name the hooks .git/hooks/update.[0-9]*.

Anders Waldenborg· Jan 21, 2009, 21:30 UTC · re: Johannes Schindelin · lore

Re: What about allowing multiple hooks?

Johannes Schindelin wrote:
Show 11 quoted lines
>> I currently use configvalues to specify which hooks to run. For example 
>> this is how my post-receive looks:
>>
>> data=$(cat)
>> git config --get-all hooks.post-receive.hook | while read hook; do
>>         $hook <<__EOF__
>> "$data"
>> __EOF__
>> done
> 
> I wonder why you don't do the obvious thing:
Because I wanted to be able to do things like this:
git config -add hooks.post-receive.hook \
  "sh hooks/buildbot 192.168.99.9:9989"
git config -add hooks.post-receive.hook \
  "sh hooks/buildbot 192.168.99.9:9988"

So, the thing I initially wanted to solve was "multiple instances" of the same hook.

Then when I found this thread I saw that the richer meta information needed to implement multiple hooks with sane semantics could be done with the config values.

  anders
Johannes Schindelin· Jan 21, 2009, 21:50 UTC · re: Anders Waldenborg · lore

Re: What about allowing multiple hooks?

Hi,
On Wed, 21 Jan 2009, Anders Waldenborg wrote:
Show 18 quoted lines
> Johannes Schindelin wrote:
> > > I currently use configvalues to specify which hooks to run. For example
> > > this is how my post-receive looks:
> > >
> > > data=$(cat)
> > > git config --get-all hooks.post-receive.hook | while read hook; do
> > >         $hook <<__EOF__
> > > "$data"
> > > __EOF__
> > > done
> > 
> > I wonder why you don't do the obvious thing:
> 
> 
> Because I wanted to be able to do things like this:
> 
> git config -add hooks.post-receive.hook \
>  "sh hooks/buildbot 192.168.99.9:9989"
You are missing a "-".
> So, the thing I initially wanted to solve was "multiple instances" of 
> the same hook.
And why not use a shell function for that?
-- snip --
buildbot () {
	echo "Who is so evil and puts a bot into a post-receive hook?" >&2
	echo "This function would connect to $* if it were building a bot."
}

buildbot www.google.com buildbot www.kernel.org -- snap --

> Then when I found this thread I saw that the richer meta information 
> needed to implement multiple hooks with sane semantics could be done 
> with the config values.

I think this is technically called an "XY" problem. You ask for a specific technical solution, while your real problem would be better solved by other means.

Ciao, Dscho

Anders Waldenborg· Jan 22, 2009, 09:57 UTC · re: Johannes Schindelin · lore

Re: What about allowing multiple hooks?

Johannes Schindelin wrote:
Show 14 quoted lines
>> So, the thing I initially wanted to solve was "multiple instances" of 
>> the same hook.
> 
> And why not use a shell function for that?
> 
> -- snip --
> buildbot () {
> 	echo "Who is so evil and puts a bot into a post-receive hook?" >&2
> 	echo "This function would connect to $* if it were building a bot."
> }
> 
> buildbot www.google.com
> buildbot www.kernel.org
> -- snap --
That is basically what I started with except that it looked like this:

-- 8< -- #!/bin/sh /opt/git-triggers/buildbot-sendchange.py 192.168.9.99:9989 /opt/git-triggers/buildbot-sendchange.py 192.168.9.99:9988 /opt/git-triggers/send-mail /opt/git-triggers/irc-notification -- 8< --

At that point it thought "hey this looks like a configuration file, shouldn't a repository's config live in $GIT_DIR/config?".

We will continue use this config based approach on our site[*] until git has something better. For us it wins over shellscript-as-configuration for two reasons: 1) git config is easier to script 2) it allows us to define site wide triggers in /etc/gitconfig

[*] (our site is medium sized I guess, ~100 repos when all are converted to git)

  anders

← back to recent threads