How to Prevent a file to be overwritten in a Git Repo?
Let's see how can we use Hooks in Git to add some automated checks before committing any file!
Table of contents
Hey All!
We all have worked with at least one Version Control System Softwares in our day-to-day tasks and Git is one of those and the most widely used VCS Tool in the world!
What are Hooks in Git?
According to the official site, Hooks are programs that trigger actions at certain points in gitβs execution.
How to Add a Hook?
The default directory where Git Hooks resides is .git/hooks
. (if you don't know you will find this hidden git folder at the root of your repo)
If you want, you can change this behavior and configure another directory for Hooks. Example -
$ git config core.hooksPath my-custom-hook-directory
So the idea here is that we can configure something in the pre-commit
hook and before we commit, it will check If we have modified the restricted file or not and If we have modified the file it will raise an error, and the commit will be exited/rejected.
Git Hook files are nothing but shell scripts, So Before doing any Scripting, let's see what hooks we have by default in our git repo.
So I did ls -lha .git/hooks/
on my repo's root and got the below output:
As you saw in the output of ls
command above, by default there are some sample hooks and if you want to use one, simply remove the .sample
from the name. And then you can edit the file as you want and the respective hook will be applied automatically. It is clear from the name of the files that when that particular hook will be called. Here we want to use that pre-commit
hook.
β οΈ These are Client Side hooks, so if you push your code (For example - to GitHub), the hooks won't get pushed to the remote (or can not be shared amongst other contributors), As the .git
directory never gets pushed. You can read some explanations here as well.
That was some basic info about hooks, now Coming to the title of our Blog, which is How to Prevent a file to be overwritten in a Git Repo?
So now if you have guessed already then congrats, but for others, we can configure something in the pre-commit hook which will reject any commit which includes changes of that file.
Add the hook file as I mentioned above (by creating a file called pre-commit in the .git/hooks
directory)
So now the question arises How can we check if a file changed or not?
We generally run the command git diff
to check if a file changed or not. There is an argument available for the above command --exit-code
which returns exit code 1 if the file changed, otherwise returns 0 (no error).
A more mature command looks like below:
git diff --exit-code HEAD $FileName >/dev/null 2>&1
which means it is checking the difference between HEAD (current branch or last committed state on current branch) & Current Changes (Index, Staged, or whatever you prefer to call it.)
Now what we can do is, that we can store that exit code into some variable and according to that print a message for the user before rejecting the commit.
For example, In my repo, I have created a file called secure.file
and we want to prevent any changes for this file.
So My pre-commit
file looks somewhat like below:
FileName="secure.file"
git diff --exit-code HEAD $FileName >/dev/null 2>&1
DIFF_EXIT_CODE=$(echo "$?")
echo [LOG] [DEBUG] Diff Exit code was: $DIFF_EXIT_CODE
if [ $DIFF_EXIT_CODE != 0 ]; then
RED='\033[0;31m'
NC='\033[0m' # No Color
printf "${RED}Error Ocurred! You can not change the${NC} $FileName\n"
echo "Revert the changes for $FileName file and try again"
exit 1
fi
It may look a little scary but the above code snippet is too easy to understand and interpret. We Stored the EXIT CODE, Using the If
Block and exit
command we printed the appropriate message and exited the script. Also, I have used Colourised echo output and a more customized message, just for flex ;)
So now If I try to commit any change to that file, I get the below Error:
So that was a basic example, there is no end to your creativity. Read more about all the hooks here . This way you can implement as many checks and hooks as you want, The exciting part here is that you will be the one who will be tailoring a custom UX for yourself.
As I mentioned that hooks will never get pushed to the central repo, what you can do is store the hooks in a separate directory and Push that to remote. That way, it will be shared amongst other devs and also, it will be version controlled.
Hope this article helped in some way, Let me know if there is any suggestion. Thanks!
Till We meet the next time ππ» :
Wanna buy me a Coffee β ?