问题
I'm on Mac Mojave. I have created a file at ~/.git-templates/hooks/pre-commit , which I wanted to remove white space from the end of lines in files I'm committing. I would like this to happen globally, across all of my projects.
# A git hook script to find and fix trailing whitespace in your commits. Bypass
# it with the --no-verify option to git-commit.
# detect platform
platform="win"
uname_result=`uname`
if [[ "$uname_result" == "Linux" ]]; then
platform="linux"
elif [[ "$uname_result" == "Darwin" ]]; then
platform="mac"
fi
# change IFS to ignore filename's space in |for|
IFS="
"
# remove trailing whitespace in modified lines
for line in `git diff --check --cached | sed '/^[+-]/d'` ; do
# get file name
if [[ "$platform" == "mac" ]]; then
file="`echo $line | sed -E 's/:[0-9]+: .*//'`"
line_number="`echo $line | sed -E 's/.*:([0-9]+).*/\1/'`"
else
file="`echo $line | sed -r 's/:[0-9]+: .*//'`"
line_number="`echo $line | sed -r 's/.*:([0-9]+).*/\1/'`"
fi
# since $file in working directory isn't always equal to $file in index,
# we backup it; thereby we can add our whitespace fixes without accidently
# adding unstaged changes
backup_file="${file}.working_directory_backup"
cat "$file" > "$backup_file"
git checkout -- "$file" # discard unstaged changes in working directory
# remove trailing whitespace in $file (modified lines only)
if [[ "$platform" == "win" ]]; then
# in windows, `sed -i` adds ready-only attribute to $file (I don't kown why), so we use temp file instead
sed "${line_number}s/[[:space:]]*$//" "$file" > "${file}.bak"
mv -f "${file}.bak" "$file"
elif [[ "$platform" == "mac" ]]; then
sed -i "" "${line_number}s/[[:space:]]*$//" "$file"
else
sed -i "${line_number}s/[[:space:]]*$//" "$file"
fi
git add "$file" # to index, so our whitespace changes will be committed
# restore unstaged changes in $file from its working directory backup, fixing
# whitespace that we fixed above
sed "${line_number}s/[[:space:]]*$//" "$backup_file" > "$file"
rm "$backup_file"
[[ "$platform" == "mac" ]] || e_option="-e" # mac does not understand -e
echo $e_option "Removed trailing whitespace in \033[31m$file\033[0m:$line_number"
done
echo
# credits:
# https://github.com/philz/snippets/blob/master/pre-commit-remove-trailing-whitespace.sh
# https://github.com/imoldman/config/blob/master/pre-commit.git.sh
# If there still are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --
# Now we can commit
exit
So the problem is that it is not trimming the white space at the end of lines. When I open my file after doing a commit, I still see the white space. So my quesiton is how do I fix this? Did I put the hook at the wrong location or is there something else I need to be doing in my file?
回答1:
First, make sure the hook is in a folder referenced by a global hook path (available since Git 2.9)
git config --global core.hooksPath /path/to/my/centralized/hooks
Then, check the pre-commit
hook is executable, and actually runs: Add at least one echo at the start, to validate its execution on a commit.
回答2:
Regarding your script : on your last instrcution before exiting, you probably wanted to call git diff
rather than git diff-index
, didn't you ?
Regarding the action "removing trailing whitespaces from my files before committing" :
most editors allow to run this action on file save, and it is probably the simplest way to have your trailing spaces removed from files you edited yourself
using git specific triggers : a more adapted way would be to use a clean filter in git attributes (see the Keyword Expansion section of the git book) :
This would apply the changes when you "git add" each file, rather than when you commit :
# choose a name for your filter (e.g : 'trimspace'), and write
# the two 'clean' and 'smudge' action :
$ git config filter.trimspace.clean 'sed -e "s/[[:space:]]*$//g"'
$ git config filter.trimspace.smudge cat
# edit the `.gitattributes` file at the root of your repo,
# and target all the files you may want to trim :
$ cat .gitattributes
*.txt filter=trimspace
*.c filter=trimspace
*.py filter=trimspace
...
# from now on : running `git add` will auto trim targeted files when
# they are added to the index
回答3:
The variable $against
seems to be causing issue here. The $against
variable is not initialized here which seems to be the cause for the failure.
As you mentioned that your code dies at that line. If I remove the line exec git diff-index --check --cached $against --
, your code executes fine (no error situation).
Coming to that particular line: That line is used to print out any of the lines if whitespace still remains in them. But, I found that code is partially written.
The full code needs to be:
#!/bin/sh
#
# This hook script verifies that there are no whitespace errors in the files to be committed
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Redirect output to stderr.
exec 1>&2
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --
The code can be found at this site.
You need to perform a comparison in the last line but $against
is undefined. This code will define it properly either to HEAD or some dummy tree object if HEAD is not present.
After adding this code, it works properly in my system (Ubuntu 16.04LTS, Git version 2.7.4)
Try adding the full code and let me know if it works for you.
Thanks
回答4:
$against
is undefined. Add the following from the official pre-commit.sample:
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
来源:https://stackoverflow.com/questions/59147108/why-isnt-my-git-pre-commit-hook-trimming-white-space-from-the-end-of-lines