5

I work in an enterprise environment with thousands of developers, we implemented some server side hooks to prevent large files from being pushed, as well as files with certain extensions and mime types.

The problem is that our application essentially exploded when trying to deal with our level of user activity, so I'm thinking that using client-side hooks a la edge computing would be the best way to offload this processing to the users... however, this implies:

1.- To enforce the rules we cannot rely on users downloading and installing hooks for everyone of their repositories

2.- We need to keep these hooks up to date from a central location

3.- All this should happen after users try to push, but before the changes are unpacked

Tying this to a build script, or modifying repositories would be an absolute no, since I don't want to pollute users' repositories, and ideally this should be totally transparent to users, in such a way that they don't even know the processing of these rules is being done on their side, and that it is tamper-proof (i.e. as a user I go to my local hooks directory and modify the script).

Any idea if this can be done through some obscure Git mechanism initiated on the server in a pre-receive or similar hook?, or perhaps some better solution even if the approach is totally different?

I'm tired of explaining to users that Git is not for storing binaries, especially release binaries (many of our users come from doing this horrendous practice in SVN, P4)... it affects our Git server, and starts inflating their build times... which then they blame on IT.

You guessed it, I work in IT, and yes... we have tried turning our server off and on.

enter image description here

dukeofgaming
  • 3,108
  • 4
  • 28
  • 35

1 Answers1

8

Short answer:

No. There's no built-in git feature that would allow you to invisibly install client-side hooks from the server.

Long answer:

Yes. Whilst there's no built-in way to invisibly install client-side hooks (nor should there be), if you have control over the machines your team is using (e.g. the ability to assert group policy or run administrative commands on behalf of the user) then there are ways to achieve what you're after.

Full disclosure: I work on Atlassian's Premier Support team, and pretty closely along side our Bitbucket Server developers. Having said that, this is almost entirely a git matter, not a Bitbucket one, so I'll focus on that here.

Option 1: Override core.hooksPath

(see also: https://git-scm.com/docs/githooks)

By default git looks for hooks inside your repository in $GIT_DIR/hooks/*. This is configurable on both a per-repo level and on a global level. Configuring this globally is pretty simple:

git config --global core.hooksPath /path/to/custom/hooks

This will take more or less immediate effect for all repositories, both new and existing. You need some way to run this on each team member's workstation, but most corporate environments already have methods of running scripts etc. remotely so this is really just a matter of convincing your IT admin team that it's a necessary business requirement.

Of course, to actually use your custom hooks, you either need to ensure you're using a path that's universally accessible (an auto-mounted location) or — probably safer — copy the hooks locally to their machines. Again, I am expecting you have mechanisms to do this, or can run scripts remotely to achieve the same effect.

If you want to give the core.hooksPath setting a try on your local machine, do the following:

$ mkdir ~/.globalgithooks
$ echo "printf 'hello world\n'" > ~/.globalgithooks/pre-commit
$ chmod +x ~/.globalgithooks/pre-commit
$ git config --global core.hooksPath ~/.globalgithooks

Then find some repos (new or existing) you can safely make some dummy commits to and you'll see it working.

Pros:

  • Takes effect for both current and newly created repositories

Cons:

  • Removes the ability to customise hooks on a per-repo basis

Option 2: Override the git template dir

(see also: https://git-scm.com/docs/git-init#_template_directory)

When you create a repository, git doesn't just set it up from "nothing"; it uses a pre-packaged template directory which contains (to quote the above link) 'some directory structure, suggested "exclude patterns", and sample hook files.' You can add your own custom hooks to this template directory and whenever a new repository is created, they will be copied over to that repository's local set of hooks ($GIT_DIR/hooks). Fun fact: even when you clone a repository, you're still creating a "new" one — it's simply a new repository that git then adds an upstream remote URL, fetches objects and checks out the default branch for. In other words, the template directory still gets used when cloning, so custom hooks created there will automatically be set up for any repository created by cloning.

Again, you'd need some kind of managed access to your machines to do this. However it's arguably more complicated than the first option; where with option 1 you can simply copy over your hooks anywhere you like and run a straightforward git config command, for this option to work you need to locate the correct template directory for that user's git installation. Given the myriad ways git might be installed on different operating systems and by different package managers, this means you need to determine where the directory is located. By default in Linux this is /usr/share/git-core/templates; on my homebrew install on macOS this can be found either at /usr/local/Cellar/git/$GIT_VERSION/share/git-core/templates with a symbolic link available at /usr/local/share/git-core/templates … in other words, you'd need to cobble together some kind of logic to find the right place and add your hooks there. And even then, this won't affect any existing repositories already on the machine.

An alternative approach would be to set init.templateDir in your global git configuration, obviating the need to locate the existing temp dir. This however forces you to maintain everything — if in future some fundamental part of that structure changed, you would need to maintain and update your copy.

Pros:

  • Configures hooks on a per-repo basis, meaning you can continue to use other per-repo hooks as desired

Cons:

  • Only affects new (initialized and cloned) repos; existing repos will not know about new additions to your template directory
  • Potentially brittle to configure due to the need to determine the user's git install location (or else fully maintain your own custom template directory)

For both options, you'd need to figure out how often to run these to ensure your hooks are kept up to date. You could run these on a regular interval, or simply push to all client machines whenever you make a change — it all depends on your administrative tooling

No matter how you go about this, the savvy user will always be able to get around it, but I'm guessing this is not an issue in most cases. If your developers are actively circumventing a hook that tells them not to commit something so they can do it anyway, then that ceases to be a technical issue and becomes a management one.

david
  • 997
  • 6
  • 15
daveruinseverything
  • 4,775
  • 28
  • 40