Last active
November 7, 2022 15:45
-
-
Save feosuna1/14877 to your computer and use it in GitHub Desktop.
Git hook for cleaning white spaces
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
#==============================================================================# | |
# Remove whitespace errors from text files. | |
# | |
# If a whitespace error is found, it notifies the user and fixes the errors. | |
# This script will only run if the `git config` variable `apply.whitespace` is | |
# set to fix. You can use `git config` to make this change, use the `--global` | |
# to apply these changes globally to all your git repos: | |
# ``` | |
# $ git config apply.whitespace fix | |
# ``` | |
# | |
# You can configure this script to be a part of your pre-commit hooks. You can | |
# create an executable pre-commit file that references `git-clean-whitespace`: | |
# ``` | |
# #!/usr/bin git-clean-whitespace | |
# ``` | |
# | |
# Or you can create a symbolic link: | |
# ``` | |
# ln -s ~/bin/git-clean-whitespace .git/hooks/pre-commit | |
# ``` | |
# | |
# Alternatively, you can add this to your git template directory so that | |
# the script is automagically included with each git repo instance. | |
#==============================================================================# | |
set -e | |
function _error() { | |
>&2 echo "_error: $@" | |
} | |
function assert_git() { | |
local git=`which git` | |
if [[ -z "$git" ]]; then | |
_error 'unable to find the `git`' | |
exit 1 | |
fi | |
} | |
function assert_in_git_repository() { | |
# Check to see if we are working within a git repository -- it's kind of hard to fix a whitespace in git if we are not | |
# in a git repo. | |
if [[ $? -ne 0 ]]; then | |
_error 'you must invoke from a working git repository.' | |
exit 2 | |
fi | |
} | |
function exit_quietly_if_in_middle_of_merge() { | |
local merge_head=`git rev-parse -q --verify MERGE_HEAD` | |
if [[ -n "$merge_head" ]]; then | |
exit 0 | |
fi | |
} | |
function exit_quietly_if_whitespace_not_configured_to_fix() { | |
local apply_whitespace="$@" | |
if [[ -z "$apply_whitespace" || "$apply_whitespace" == 'nowarn' ]]; then | |
exit 0 | |
fi | |
} | |
function get_files_with_whitespace_errors() { | |
git diff --cached --check "$@" | sed '/^\+/d ; s/:.*//' | uniq | |
} | |
function _fix_whitespace_errors_for_file() { | |
# Get the diff of what is currently staged | |
local file="$@" | |
local diff=`git diff --cached -- "$file"` | |
# Unstage the diff so when we reapply it will fix the whitespaces for us | |
echo "$diff" | git apply --cached -R - > /dev/null 2>&1 | |
# Add the diff back on, this time using the 'apply' command and it will fix the whitespace errors | |
echo "$diff" | git apply --cached --whitespace=fix - > /dev/null 2>&1 | |
} | |
function fix_whitespaces_errors() { | |
# Figure out which files have whitespace errors and strip them | |
local files_with_whitespace_errors=`get_files_with_whitespace_errors` | |
if [[ -z "$files_with_whitespace_errors" ]]; then | |
return | |
fi | |
local git_toplevel_dir=`git rev-parse --show-toplevel` | |
while IFS= read -r file; do | |
local file="$git_toplevel_dir/$file" | |
echo "warning: removing whitespaces for $file" | |
_fix_whitespace_errors_for_file "$file" | |
if [[ -n `get_files_with_whitespace_errors -- $file` ]]; then | |
# For some reason, EOF newline errors don't get fixed on the first pass, | |
# but they get fixed on the second one. | |
_fix_whitespace_errors_for_file "$file" | |
fi | |
done <<< "$files_with_whitespace_errors" | |
} | |
assert_git | |
assert_in_git_repository | |
exit_quietly_if_in_middle_of_merge | |
apply_whitespace=`git config apply.whitespace` | |
exit_quietly_if_whitespace_not_configured_to_fix $apply_whitespace | |
if [[ "$apply_whitespace" != 'fix' ]]; then | |
exec get_files_with_whitespace_errors | |
else | |
fix_whitespaces_errors | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment