我正在和我的团队一起使用Git,并希望从我的差异、日志、合并等中删除空白更改。我假设做到这一点最简单的方法是Git在应用所有提交时自动删除尾随空白(和其他空白错误)。

我已经尝试将以下内容添加到~/。gitconfig文件,但是当我提交时它什么也不做。也许它是为别的东西设计的。解决方案是什么?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

我使用Ruby,以防有人对Ruby有任何具体的想法。在提交之前自动格式化代码将是下一步,但这是一个困难的问题,并不是真正造成大问题。


当前回答

我发现了一个Git预提交钩子,它删除了尾随空白。

#!/bin/sh

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
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
   # Fix them!
   sed -i 's/[[:space:]]*$//' "$FILE"
   git add "$FILE"
done
exit

其他回答

我发现了一个Git预提交钩子,它删除了尾随空白。

#!/bin/sh

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
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
   # Fix them!
   sed -i 's/[[:space:]]*$//' "$FILE"
   git add "$FILE"
done
exit

文件的for循环使用$IFS shell变量。 在给定的脚本中,包含$ ifs变量中的字符的文件名将被视为for循环中的两个不同文件。

这个脚本修复了它:sed手册中给出的多行模式修饰符似乎在我的Ubuntu盒子上默认不工作,所以我寻找了一个不同的实现,并发现了一个迭代标签,本质上它只会在文件的最后一行开始替换,如果我正确理解它。

#!/bin/sh
#

# A Git hook script to find and fix trailing white space
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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

SAVEIFS="$IFS"
# only use new-line character as separator, introduces EOL-bug?
IFS='
'
# Find files with trailing white space
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one (Mac OS X version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to Git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# Exit script with the exit-code of git's check for white space characters
exec git diff-index --check --cached $against --

如何使用sed替换换行符(\n) ?

这可能不会直接解决您的问题,但您可能希望在实际的项目空间中通过git-config设置这些,它编辑文件./。Git /config相对于~/.gitconfig文件。在所有项目成员之间保持设置一致是很好的。

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"

这些设置(核心。空格和apply.whitespace)不是用来移除尾随空格的,而是用来:

核心。空格:检测它们,并引发错误 适用。空格:并删除它们,但只在补丁期间,而不是“总是自动”

我相信git钩子预提交会做得更好(包括删除尾随空格)


注意,在任何给定的时间,你都可以选择不运行pre-commit钩子:

暂时:git提交——no-verify。 CD .git/hooks/;Chmod -x预提交

警告:默认情况下,预提交脚本(就像这个脚本)没有“移除尾随”功能,而是“警告”功能,比如:

if (/\s$/) {
    bad_line("trailing whitespace", $_);
}

然而,你可以构建一个更好的预提交钩子,特别是当你考虑到:

在Git中提交时,只向暂存区添加了一些更改,仍然会导致“原子”修订,该修订可能从未作为工作副本存在过,也可能无法工作。


例如,oldman在另一个答案中提出了一个预提交钩子,它可以检测并删除空白。 由于该钩子获取每个文件的文件名,我建议对某些类型的文件要小心:你不希望删除.md (markdown)文件中的尾随空格!


hakre在评论中建议的另一种方法是:

你可以在markdown中在行末有两个空格,而不是在\n前添加“\”作为尾随空格。

然后是内容过滤器驱动程序:

git config --global filter.space-removal-at-eol.clean 'sed -e "s/ \+$//"'
# register in .gitattributes 
*.md filter=space-removal-at-eol

使用Git属性,并使用Git配置设置过滤器

好的,这是解决这个问题的一个新方法……我的方法是不使用任何钩子,而是使用过滤器和Git属性。这允许您在开发的每台机器上设置一组过滤器,这些过滤器将在提交文件之前去除额外的尾随空白和额外的空行。

然后设置一个.gitattributes文件,说明过滤器应该应用于哪种类型的文件。过滤器有两个阶段,在将文件添加到索引时应用clean,在将文件添加到工作目录时应用smudge。

告诉Git查找全局属性文件

首先,告诉全局配置使用全局属性文件:

git config --global core.attributesfile ~/.gitattributes_global

创建全局过滤器

现在,创建过滤器:

git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true

添加sed脚本魔法

最后,将fixup-eol-eof脚本放在路径中的某个位置,并使其可执行。该脚本使用sed执行一些动态编辑(删除行尾的空格和空格,以及文件末尾无关的空行)。

fix -eol-eof应该是这样的:

#!/bin/bash
sed -e 's/[     ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1

我的要点是

告诉Git将新创建的过滤器应用于哪些文件类型

最后,创建或打开文件~/。在你最喜欢的文本编辑器中添加Gitattributes_global,并添加如下行:

pattern attr1 [attr2 [attr3 […]]]

所以如果我们想要修复空白的问题,对于我们所有的C源文件,我们将添加一行,看起来像这样:

*.c filter=fix-eol-eof

滤波器的讨论

过滤器有两个阶段。当东西被添加到索引或签入时应用的清洁阶段,以及当Git将东西放入工作目录时应用的涂抹阶段。

在这里,我们的smudge只是通过cat命令运行内容,这应该使它们保持不变,除了可能添加一个尾随换行符(如果文件末尾没有换行符的话)。

The clean command is the white space filtering which I cobbled together from notes at http://sed.sourceforge.net/sed1line.txt. It seems that it must be put into a shell script. I couldn’t figure out how to inject the sed command, including the sanitation of the extraneous extra lines at the end of the file directly into the git-config file. (You can get rid of trailing blanks, however, without the need of a separate sed script. Just set the filter.fix-eol-eof to something like sed 's/[ \t]*$//' %f where the \t is an actual tab, by pressing Tab.)

如果出现错误,require = true会引发一个错误,以避免遇到麻烦。