Why isn't my git pre-commit hook trimming white space from the end of lines?

南笙酒味 提交于 2019-12-21 12:12:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!