Skip to content

Instantly share code, notes, and snippets.

@tamphh tamphh/pre-commit
Last active Sep 9, 2018

Embed
What would you like to do?
git hook(bash script) for Rails project to avoid unwanted specific files, keywords (debugger, binding.pry,...) to be commited.
#!/bin/bash
# How to use?
# - Save this file as .git/hooks/pre-commit in your project .git folder
# - Execute:
# chmod +x .git/hooks/pre-commit
#
# If you want to skip the hook just add the --no-verify flag:
# git commit --no-verify
# Redirect output to stderr.
exec 1>&2
# Color codes
red=`tput setaf 1`
green=`tput setaf 2`
blue=`tput setaf 4`
yellow=`tput setaf 3`
reset=`tput sgr0`
# Notification
echo "${blue}"
echo "=============================="
echo "# Running pre-commit git hook."
echo "==============================${reset}"
# Debugging functions to be checked.
keywords=(debugger binding\.pry puts alert console\.log)
# Join keywords array into a single string for grep and remove the separator from the start of the string.
keywords_for_grep=$(printf "|%s" "${keywords[@]}")
keywords_for_grep=${keywords_for_grep:1}
# Directories and files to be excluded during search.
exclude_dir_and_ext='\.png$|\.gif$|\.jpg$|\.ico$|\.patch$|\.sh$|\.ttf$|\.woff$|\.eot$|\.svg$'
# Files to be prompted
files=(schema.rb)
# Flag counter
debugging_function_found=0
merge_conflict=0
warning_file_found=0
# Check for debugging functions
find_debugging_keywords() {
FILE=$1
for keyword in "${keywords[@]}" ; do
pattern="^\+(.*)?$keyword(.*)?"
result_for_file=`git diff --cached $FILE | egrep -x "$pattern"`
if [ ! -z "$result_for_file" ] ; then
if [ $debugging_function_found -eq 0 ] ; then
echo "${red}"
echo "# Debugging keywords:"
echo "------------------------${reset}"
fi
debugging_function_found=1
echo "${yellow}"
echo " Oops..." "**"$keyword"**" "found:"
git grep -n $keyword $FILE | awk '{split($0,a,":");
printf "\t-> " a[1] " on line " a[2] "\n";
}'
fi
done
}
# Check for merge conflict markers
find_conflict_markers() {
FILE=$1
pattern="(<<<<|>>>>)+.*(\n)?"
result_for_file=`egrep -in "$pattern" $FILE`
if [ ! -z "$result_for_file" ] ; then
if [ $merge_conflict -eq 0 ] ; then
echo "${red}"
echo "# Confict marker(s) found in:"
echo "-----------------------------------${reset}"
fi
merge_conflict=1
echo "${yellow}"
echo " ->" $FILE
fi
}
# Check for warning files
find_warning_files() {
FILE=$(basename "$1")
if [ $warning_file_found -eq 0 ] ; then
for f in "${files[@]}" ; do
if [ "$FILE" = "$f" ] ; then
if [ $warning_file_found -eq 0 ] ; then
warning_file_found=1
echo "${yellow}"
echo "# Warning file(s) found:"
echo "------------------------------"
echo " ->" $FILE
fi
fi
done
fi
}
# Exit with error
exit_with_error() {
echo "${red}"
echo "Git commit aborted!"
echo "${reset}"
exit 1
}
# List all files added to commit excluding the exceptions
files_changed=`git diff-index --diff-filter=ACMRT --cached --name-only HEAD -- | egrep -v $exclude_dir_and_ext`
# Find debugging function exists in file diff one by one.
if [ -n "$files_changed" ] ; then
for FILE in $files_changed ; do
find_debugging_keywords $FILE
done
fi
# Find conflict markers exists in file diff one by one.
if [ -n "$files_changed" ] ; then
for FILE in $files_changed ; do
find_conflict_markers $FILE
done
fi
errors_found=$((debugging_function_found+merge_conflict))
# Find warning files. Must execute last.
if [ $errors_found -eq 0 ] && [ -n "$files_changed" ] ; then
for FILE in $files_changed ; do
find_warning_files $FILE
done
fi
# Decision maker
if [ $errors_found -eq 0 ] ; then
if [ $warning_file_found -eq 0 ] ; then
echo "${green}"
echo "Codes committed!"
echo "${reset}"
else
exec < /dev/tty
while true; do
read -p "Warning file(s) would be committed. Are you sure? (y/n) " answer
if [[ $answer =~ ^[Yy]$ ]] ; then
echo "Accepted"
else
exit_with_error
fi
break
done
fi
else
exit_with_error
fi
@tamphh

This comment has been minimized.

Copy link
Owner Author

tamphh commented Aug 26, 2018

How to use?

  • Save this file as .git/hooks/pre-commit in your project .git folder
  • Run: chmod +x .git/hooks/pre-commit to make it executable

If you want to skip the hook just add the --no-verify flag:

  • git commit --no-verify

If you want to customize for files, keywords, just modify these contants to meet your need:

# Debugging functions to be checked.
keywords=(debugger binding\.pry puts alert console\.log)

# and

# Files to be prompted
files=(schema.rb)

Bonus: (thanks to wacko/pre-commit)

  • Save this hook under $HOME/.git-templates/hooks
  • Add to $HOME/.gitconfig:
[init]
  templatedir = $HOME/.git-templates

So it will be automatically copied into your project any time you run git init
(you can replace .git-templates with any other path)

Screen shots:

  • Debugging keys (debugger, binding.pry,...) & conflict markers checking:

screen shot 2018-08-26 at 12 34 13 pm

  • Warning files checking (as yes/no prompt):

screen shot 2018-08-26 at 12 34 31 pm

TODO

  • More user-friendly messages.
  • Better interaction with warning prompt.
  • More readable & cleaner code.
  • Details wiki.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.