Hi All,
I have been working on a project where by I needed to come up with one solution that would help stop team members checking in connection strings that could contain production server names. please note this is by no means a solution that solves such a problem out right as there are workarounds to avoid this solution but it certainly helps as a first barrier to such a problem.
to help solve such a problem I decided to use git hooks and for my example outlined below I used the “Pre-Commit” hook. I am going to assume that you are familiar with Git but allow me to explain git hooks.
what are git hooks.
Git hooks are scripts that run automatically at certain points in the Git workflow, such as committing, merging, or pushing code. They can be used to enforce coding standards, perform automated testing, or deploy code to a live environment. Git hooks are stored in the .git/hooks directory of a repository, and are triggered by specific events in the Git workflow. They are written in any scriptable language, such as Bash, Python, or JavaScript, and are executed by the command line interface. Git hooks can be useful for automating repetitive tasks and ensuring that code is always in a releasable state.
My Solution
within my git repo root, I created a folder called “git-config” followed by a filename called “ExcludedWords.txt”, I then created a folder called “hooks” within the same directory followed by a filename called “pre-commit”.
the “ExcludedWords.txt” contains a list of server names that I would like to check to ensure they are not being checked into the repo, the contents of this file is shown below as an example:
SERVERPRD3
SERVERSTG2
Pre-Commit script
now the fun part, the pre-commit script, the contents is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!C:/Program\ Files/Git/usr/bin/sh.exe cat ./git-config/ExcludedWords.txt| sed 's/\r$//' |while read line || [[ -n $line ]]; do matches=$(git diff-index --patch HEAD ":(exclude)./git-config/hooks/pre-commit" ":(exclude)./git-config/ExcludedWords.txt" | grep '^+' | grep -Piw "$line") if [ ! -z "$matches" ] then cat <<\EOT Error: Words from the blocked list were present in the diff, THe blocked word was: EOT echo $line echo $matches exit 1 fi done |
lets break down this file:
Below is the shebang for windows and is pointing to my version of git.
1 |
#!C:/Program\ Files/Git/usr/bin/sh.exe |
I am then using cat to pipe the output for the “ExcludedWords.txt” into sed to remove non unix carriage returns (windows adds this ^M to the end of the line) I then pipe this out to a while loop.
1 |
cat ./git-config/ExcludedWords.txt| sed 's/\r$//' |while read line || [[ -n $line ]]; |
the below command I am using the “git diff-index ” exclude certain files to not compare against, I am then using Grep to filter and perform pattern matching. Once done I am then storing that in the “matches” variable and if there is a match to output the word and the line that match occurred in, I then exit the git commit process.
1 2 3 4 5 6 7 8 9 |
matches=$(git diff-index --patch HEAD ":(exclude)./git-config/hooks/pre-commit" ":(exclude)./git-config/ExcludedWords.txt" | grep '^+' | grep -Piw "$line") if [ ! -z "$matches" ] then cat <<\EOT Error: Words from the blocked list were present in the diff, The blocked word was: EOT echo $line echo $matches exit 1 fi |
Final setup
in order for this to work, your other developers when they pull down the repo, will need to run the following command from the repo in question:
1 |
git config core.hooksPath ./git-config/hooks |
this tells git that from now on for this repo, use the following folder for all git hooks.
Caveats
as mentioned at the beginning of this tutorial there are some pit falls:
- Devs can override the git hooks folder – resulting in the above no longer working.
- code already checked in will not be picked up unless the files in question are modified after the above is implemented.