19

People on my development team keep on pushing build-specific files (folder node_modules and others) onto our repositories despite these files being in a .gitignore file, presumably with git add --all -f or something related to that.

It's a huge pain and getting people to stop doing it is proving difficult.

Is there some way I can make it totally impossible to push certain files onto a repository?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Taylor Stevens
  • 436
  • 3
  • 11

2 Answers2

32

Is there some way I can make it totally impossible to push certain files onto a repository?

Yep, you can use hooks like this to prevent several files to be committed.

pre-receive hook

#!/bin/sh

# Check to see if this is the first commit in the repository or not
if git rev-parse --verify HEAD >/dev/null 2>&1
then
    # We compare our changes against the previous commit
    against=HEAD^
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Redirect output to screen.
exec 1>&2

# Check to see if we have updated the given file
if [ $(git diff-tree -r --name-only $against | grep <ANY FILE YOU WANT TO FIND OUT HERE> ) ];
then

    # Output colors
    red='\033[0;31m';
    green='\033[0;32m';
    yellow='\033[0;33m';
    default='\033[0;m';

    # personal touch :-)
    echo "${red}"
    echo "                                         "
    echo "                   |ZZzzz                "
    echo "                   |                     "
    echo "                   |                     "
    echo "      |ZZzzz      /^\            |ZZzzz  "
    echo "      |          |~~~|           |       "
    echo "      |        |-     -|        / \      "
    echo "     /^\       |[]+    |       |^^^|     "
    echo "  |^^^^^^^|    |    +[]|       |   |     "
    echo "  |    +[]|/\/\/\/\^/\/\/\/\/|^^^^^^^|   "
    echo "  |+[]+   |~~~~~~~~~~~~~~~~~~|    +[]|   "
    echo "  |       |  []   /^\   []   |+[]+   |   "
    echo "  |   +[]+|  []  || ||  []   |   +[]+|   "
    echo "  |[]+    |      || ||       |[]+    |   "
    echo "  |_______|------------------|_______|   "
    echo "                                         "
    echo "                                         "
    echo "      ${green}You have just committed code  "
    echo "      ${red}Your code ${yellow}is bad.!!!      "
    echo "      ${red} Do not ever commit again    "
    echo "                                         "
    echo "${default}"
fi;

# set the exit code to 0 or 1 based upon your needs
# 0 = good to push
# 1 = exit without pushing.
exit 0;

Note:

GitHub does not support using hooks in this way.
They have their own WebHooks

In this case you can use hooks as well but on the client side.
The same code can be placed inside pre-commit hook on the client side.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • 1
    Wouldn't this have to be installed on the server in order for this to work? And that's a bit too gaudy in my opinion... – Jeremy Rodi Feb 15 '16 at 02:26
  • 2
    The problem with client side hooks is that you can delete them (user). on the server side only git admin can change them – CodeWizard Feb 15 '16 at 02:27
  • Yes, but that also means that you have to have to access to the server itself; and if the code is being hosted by a service like Github, then they would not have access to having hooks like that. – Jeremy Rodi Feb 15 '16 at 02:28
  • 1
    You don't have pre-receive hooks on github like you normally do - any hooks you define through github will have no bearing on whether or not the commit is allowed to be pushed to the server, and what you answered would not work with whatever github allows as well. – Jeremy Rodi Feb 15 '16 at 02:30
  • I agree. github is problematic with those hooks. – CodeWizard Feb 15 '16 at 02:39
  • You will have to use pull requests in this case. – CodeWizard Feb 15 '16 at 02:41
  • 1
    It might be worth it to note that in the answer as well. – Jeremy Rodi Feb 15 '16 at 02:41
  • @JeremyRodi Awesome thanks! This is the type of solution I was looking for. We're on Github right now but I can probably get everyone to add pre-commit hooks. – Taylor Stevens Feb 15 '16 at 03:26
  • 1
    Its not @JeremyRodi who answered:-) – CodeWizard Feb 15 '16 at 03:27
  • Is `default` supposed to be named `no_color`? Or is the `${no_color}` supposed to be `${default}`? – Justin Feb 15 '16 at 07:41
  • Thank you for the comment. fixed it, both should be black – CodeWizard Feb 15 '16 at 07:56
0

It's not an easy problem to solve as Git is distributed.

Server-side filters like post commit hooks (or commit filter plugins if you are using the stash) allow the users to get themselves into a mess which is not great.

The client pre-commit hook is cleaner, because it prevents the users from polluting their repository, but this solution isn't bulletproof.

You could approach the problem from another perspective and move build artefacts and intermediate files out of you repository directory.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tymtam
  • 31,798
  • 8
  • 86
  • 126