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

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

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

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


当前回答

文件的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) ?

其他回答

同样的结果。

import subprocess                                                                 
                                                                              
def get_trailing_lines():                                                         
                                                                              
    result = subprocess.run([                                                     
                            'git',                                            
                            'diff',                                           
                            '--check'                                         
                        ], capture_output=True)                               
                                                                              
    return result.stdout.decode().split('\n')                                     
                                                                              
                                                                              
def modify_line(file_path, l_num):                                                
                                                                              
    f_lines = open(file_path).readlines()                                         
    f_lines[l_num] = f_lines[l_num].rstrip()+'\n'\                                
                     if '\n' in f_lines[l_num] else f_lines[l_num].rstrip()    
                                                                              
    with open(file_path, "w") as w_fp:                                            
        w_fp.writelines(f_lines)                                                  
                                                                              
                                                                              
if __name__ == '__main__':                                                        
                                                                              
    l = get_trailing_lines()                                                      
    for m, d in zip(l[::2], l[1::2]):                                             
        f_path, l_no, *_ = m.split(":")                                           
        modify_line(f_path, int(l_no)-1)                                          

在macOS(或者可能是任何BSD)上,sed命令参数必须略有不同。试试这个:

#!/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 -E 's/:[0-9]+:.*//' | uniq` ; do
    # Fix them!
    sed -i '' -E 's/[[:space:]]*$//' "$FILE"
    git add "$FILE"
done

将该文件保存为.git/hooks/pre-commit——或者寻找已经存在的文件,并将底部块粘贴到其中的某个地方。还有chmod (a+x)

或者为了全局使用(通过将git post-commit钩子应用到所有当前和未来的回购中),你可以把它放在$GIT_PREFIX/git-core/templates/hooks中(其中GIT_PREFIX是/usr或/usr/local或/usr/share或/opt/local/share),并在你现有的回购中运行git init。

根据git帮助init:

在现有的存储库中运行git init是安全的。它不会覆盖已经存在的东西。重新运行git init的主要原因是获取新添加的模板。

崇高的文本用户。

在“设置-用户”配置中正确设置以下内容。

"trim_trailing_white_space_on_save": true

请试试我的预提交钩子。它可以自动检测尾随空白并删除它。

它可以在Git Bash (Windows), Mac OS X和Linux下工作!


快照:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)

下面是Ubuntu和Mac OS X兼容的版本:

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

# Now we can commit
exit