0

in a large multi-team envrionment, some teams have created some standard and some non-standard hooks.

git config --global init.templatedir "namedfolder" will set the hooks in "namedfolder" for all instances of git.

if there are pre-existing hooks, they get overwritten.

is there a warning that can be executed, or a way to intelligently merge the hooks? for example, if a pre-commit hook used by one team exists that warns of staleness and the hooks are updated such that pre-commit now performs some other function that could be complimentary (or not) with the staleness check, running the above command deletes the staleness check hook. suppose we want to append to the hooks. not seeing a way/flag to do so unless performed separately prior to the execution of the --global above.

  • I don't understand the claim that "if there are pre-existing hooks, they get overwritten": this just sets the template dir from which hooks get copied on `git init`. The copying only happens when you run `git init`—do you mean that running `git init` on an existing repository overwrites existing hooks with template hooks? If so, that seems like a bug: it's only supposed to *add new* hooks. – torek Nov 01 '16 at 00:24
  • my bad - the hooks are not overwritten - the new hook is ignored. faceslap test failure. – iamthehousedog Nov 01 '16 at 17:25

1 Answers1

0

Aside from my comment, the short answer is "no". One of the things I think is a small defect in Git is that each hook is just one thing:

  • the pre-commit hook is .git/hooks/pre-commit
  • the update hook is .git/hooks/update

and so on. But what if you, or your team or groups, have written several cool / useful / whatever pre-commit, prepare-commit-msg, etc., hooks and you would like to run all of them?

Git won't and can't do that. Indeed, there's no fully automatic solution that could work, because hooks might alter state, which means that running Hook A followed by Hook B would produce a different result from running Hook B followed by Hook A.

What you can do is write your hooks as useful but stand-alone scripts, then invoke each desired hook, in the desired order, from .git/hooks/name. For instance, suppose you have a "check for leftover debug junk" pre-commit hook, and a separate "spaces vs tabs" pre-commit hook. (This example is not order-dependent, since I just made it up on the fly now and couldn't think of a better example.) Your .git/hooks/pre-commit might then read:

#! /bin/sh
# run pre-commit checks
/home/shared/teamX/scripts/git-check-leftover-debug-junk || exit $?
/home/shared/teamY/scripts/git-check-spaces-vs-tabs || exit $?

(the final || exit $? is not required, it's just there so we can add more hooks later).

There is a secondary problem here, though. For some hooks, we can just add "$@" to pass arguments, and all is well. For the pre-receive and post-receive and pre-push hooks, though, important data show up on standard input. This input comes from a pipe, so when one hook reads through it, the data have been consumed and are no longer available to the remaining hooks. The workaround is to copy the input to a file, then redirect each hook to read from that file. (It's necessary to restart the reads from offset 0 each time as well, so this is not as big as bug in Git as it seems: just offering the input as a temp file, instead of a pipe, does not suffice, you still must re-seek-to-zero each time.)

In a previous $job I once wrote a "master hook" that would run "sub-hooks", using the name it was invoked by to find all the sub-hooks. The sub-hooks came from a parallel set of directories with the same name-pattern as the hooks. The master hook would copy stdin to a temp file and pass on the arguments, so that each hook could act as though it were the only hook. This allowed us to add and remove hooks at whim, controlling the order through file names: multihook/pre-receive/10.foocheck would run before multihook/pre-receive/20.barcheck even though foo sorts before bar, because 10 sorts before 20. It turns out that we didn't need that much fanciness after all, though: we never had more than three pre-receive hooks at a time and did not change them up frequently, at least while I was there.

(The code is pretty simple though. As a shell script, it's about six lines.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    This is a pretty standard 'git in a big company environment' sort of setup. See https://gist.github.com/paunin/649874a960d4eea1d5d6 based on the answer to http://stackoverflow.com/questions/8730514/chaining-git-hooks#8734391 – Mort Nov 01 '16 at 01:00