0

How can I prevent a file (.json) to be commited with a git hook ?

I have a .json which is on the server yet. So I can not use an gitignore. But now I do not want to allow anyone to change this file (commit it) because it would break something. I want to use a local hook.

How can I even get the special file in the commit ?

Could you please give me an instruction how to achieve this ?

Thank your for your help.

Coder949
  • 987
  • 1
  • 8
  • 29
  • You want to prevent the autogenerated file or code file to be commited? – danglingpointer Oct 17 '17 at 13:17
  • No sorry it is a bit complicated to explain. I want that the hook checks if a special file will be commited and abort the commit it if the file is in the commit. – Coder949 Oct 17 '17 at 13:20
  • 2
    yes its possible to do. You can write pre-commit hook rule, which will be triggered during commit and remove the file if it exist and then it will commit. – danglingpointer Oct 17 '17 at 13:21
  • do you have an example for me ? That would be very nice. – Coder949 Oct 17 '17 at 13:23
  • if you written some code then I can say what's wrong with that. However this link can give you some insight: https://jakemccrary.com/blog/2015/05/31/use-git-pre-commit-hooks-to-stop-unwanted-commits/. this is about unwanted commits but you can get some inspiration from that. – danglingpointer Oct 17 '17 at 13:27
  • okay thank you ! I did not now how to do it all so I will now begin to write the code. – Coder949 Oct 17 '17 at 13:27

1 Answers1

2

A pre-commit sample:

#!/bin/bash

ipath="foo/bar.json"
git diff --cached --name-only | if grep -qE "^$ipath$";then
    git reset HEAD -- "$ipath"
    echo "Warning: $ipath is removed from the index. It's not allowed to be committed."
fi

git diff --cached --name-only lists all the changed files that are going to be committed. If foo/bar.json is found in the list, then git reset HEAD -- foo/bar.json removes it from the index so that it's not committed but left in the working tree.

It works fine for you. However you can't ensure it does for others. For example, other contributors may delete it from their local repositories. What you need is a pre-receive hook in the central repository, the one on the server side. It rejects any push if the incoming commits touch foo/bar.json.

A pre-receive sample:

#!/bin/bash

ipath="foo/bar.json"
zero="0000000000000000000000000000000000000000"

while read old new name;do
    if [ "$zero" == "$old" ];then
        #creating new ref, do something here
        continue
    fi

    if [ "$zero" == "$new" ];then
        #deleting a ref, do something here
        continue
    fi

    #updating a ref, check if the incoming commits touch `foo/bar.json`
    git diff $old..$new --name-only | if grep -qE "^$ipath$";then
        c=$(git log $old..$new --pretty=%H -- $ipath)
        echo "Error: $ipath is changed in:"
        echo $c
        echo "Error: $ipath is not allowed to be committed and pushed."
        exit 1
    fi
done

The contributors receive the error message after git push. They must amend their commits and remove the changes of foo/bar.json before another try. In pre-receive, you need to deal with deleting a ref and creating a ref if necessary.

ElpieKay
  • 27,194
  • 6
  • 32
  • 53
  • Thank you! The problem is that the server side does not support it. So I have to do it locally. But the first part will do it for me locally right ? – Coder949 Oct 17 '17 at 17:20