让 Git 在提交前自动删除尾随空格

Posted

技术标签:

【中文标题】让 Git 在提交前自动删除尾随空格【英文标题】:Make Git automatically remove trailing white space before committing 【发布时间】:2010-10-10 04:00:15 【问题描述】:

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

我尝试将以下内容添加到~/.gitconfig 文件中,但是当我提交时它没有做任何事情。也许它是为不同的东西而设计的。解决办法是什么?

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

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

【问题讨论】:

如果 core.whitespace 指令不能解决您的问题,您还可以更改预提交挂钩 (.git/hooks/pre-commit) 来为您查找并修复它们。有关详细说明,请参阅this 帖子。 我对类似的空白错误和部分解决方案感到沮丧,并编写了一个灵活且功能相当完整的实用程序,可以修复简单地报告困扰版本控制系统的空白错误: Whitespace Total Fixer on Github(如果这太自我宣传了,请见谅) 这似乎是一个独立的工具,可以持续监控文件夹中更改的文件并修改它们会更容易。 【参考方案1】:

这些设置(core.whitespaceapply.whitespace)不是为了删除尾随空格,而是为了:

core.whitespace:检测它们并引发错误 apply.whitespace:并剥离它们,但仅在补丁期间,而不是“总是自动”

我相信 git hook pre-commit 会做得更好(包括删除尾随空格)


请注意,在任何给定时间,您都可以选择不运行 pre-commit 挂钩:

暂时:git commit --no-verify . 永久:cd .git/hooks/ ; chmod -x pre-commit

警告:默认情况下,pre-commit 脚本(如 this one)不是“删除尾随”功能,而是“警告”功能,例如:

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

但是您可以build a better pre-commit hook,尤其是当您考虑到这一点时:

在 Git 中只添加一些更改到暂存区域的提交仍然会导致“原子”修订,可能从未作为工作副本存在并且可能无法正常工作


例如,oldman 建议 in another answer 一个 pre-commit hook 检测并删除空格。 由于该挂钩获取每个文件的文件名,因此我建议对某些类型的文件要小心:您不想删除 .md (markdown) 文件中的尾随空格!


hakre 在the comments 中建议的另一种方法:

您可以在 Markdown 的行尾添加两个空格,而不是将其作为尾随空格,方法是在 \n 之前添加“\”。

然后是内容过滤驱动:

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

【讨论】:

事实证明 git 可以通过 apply.whitespace 说服 git 修复工作副本中的空白,方法是诱骗 git 将您的工作副本更改视为一个补丁。见my answer below。 > "您不想删除 .md (markdown) 文件中的尾随空格" - 为什么?降价文件中尾随空格的目的是什么?我注意到一些.editorconfig 文件对此有特定的规则。 @friederbluemle 取决于降价的类型,尾随双空格表示<br>:github.com/FriendsOfphp/PHP-CS-Fixer/issues/… git 2.5.0 中提交时,使用git configcore.whitespace 设置为trailing-space 不会引发错误。 你可以在 Markdown 中的行尾有两个空格,而不是通过在 \n 之前添加“\”将其作为尾随空格。 Mind 认为并非所有声称可以处理 Markdown 的工具都支持所有 Markdown,所以 YMMV。【参考方案2】:

相同结果的 Python 脚本。

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)                                          

【讨论】:

【参考方案3】:

这不会在提交前自动删除空格,但它很容易实现。我将以下 Perl 脚本放在 $PATH 目录中名为 git-wsf(Git white space fix)的文件中,这样我可以:

git wsf | sh

它会从 Git 报告为差异的文件行中删除所有空格。

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) 
    if (/trailing whitespace./) 
        my ($file,$line) = split(/:/);
        push @$stuff$file,$line;
    


while (my ($file, $line) = each %stuff) 
    printf "ex %s <<EOT\n", $file;
    for (@$line) 
        printf '%ds/ *$//'."\n", $_;
    
    print "wq\nEOT\n";

【讨论】:

【参考方案4】:

使用 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 进行一些即时编辑(删除行尾的空格和空白,以及文件末尾的无关空白行)

fixup-eol-eof 应该如下所示:

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

My gist of this

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

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

pattern attr1 [attr2 [attr3 […]]]

因此,如果我们想解决空白问题,对于我们所有的 C 源文件,我们将添加如下所示的一行:

*.c filter=fix-eol-eof

过滤器的讨论

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

在这里,我们的涂抹只是通过cat 命令运行内容,这应该使它们保持不变,但如果文件末尾没有换行符,则可能会添加尾随换行符。

clean 命令是我从http://sed.sourceforge.net/sed1line.txt 的笔记中拼凑起来的空白过滤。看来它必须放入一个shell脚本。我不知道如何将 sed 命令注入到 git-config 文件中,包括将文件末尾多余的额外行清理干净。 (您可以摆脱尾随空格,但是,不需要单独的 sed 脚本。只需将 filter.fix-eol-eof 设置为 sed 's/[ \t]*$//' %f 之类的 \t 是一个实际的选项卡,通过按 Tab。)

require = true 会在出现问题时引发错误,以免您遇到麻烦。

【讨论】:

有趣的方法。 +1 感谢@VonC!我还想借此机会指出,git 属性可以在 .git 文件夹中的每个存储库中配置,而不是全局配置,这可能更有意义。【参考方案5】:

要以可移植的方式删除文件中行尾的尾随空格,请使用ed

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file

【讨论】:

【参考方案6】:

在 Vim 中打开文件。要用空格替换制表符,请在 Vim 命令行中输入以下内容:

:%s#\t#    #gc

去除其他尾随空格

:%s#\s##gc

这对我来说几乎是这样做的。如果您有很多文件要编辑,这很乏味。但我发现它比预提交挂钩和使用多个文本编辑器更容易。

【讨论】:

如果它变得乏味 - 并且如果你有你要编辑的内容的备份 - 那么我通常只使用 sed 将制表符更改为空格:sed -i 's|\t| |g' filenames(替换位置中的空格) .请注意,您可以使用 find 来获取文件名。如果您还没有想到如何获得该备份,我通常只是提交所有内容,然后通过软重置回到我所在的位置“撤消”提交;有时我将所有内容添加到树中但不提交,有时我使用存储/应用(不是弹出!)。如果我感到焦虑,我会在干预之前将我的整棵树同步到一个安全的位置......【参考方案7】:

对于Sublime Text 用户。

在您的 Setting-User 配置中正确设置以下内容。

"trim_trailing_white_space_on_save": true

【讨论】:

这是一种按文件类型设置的方法吗?我有*.md(降价)文件,它们依赖于“”(尾随双空格)来标记一个简单的&lt;br /&gt;,并且该设置似乎适用于所有文件,包括那些我不想删除尾随空格。 @VonC 这里有关于如何应用配置的层次结构更多细节,***.com/questions/16983328/…希望它有所帮助 这与 git 无关【参考方案8】:

请尝试my pre-commit hooks。它可以自动检测尾随空白并将其删除

它可以在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(-)

【讨论】:

有趣。 +1。我在my own answer 中引用了你的钩子 @VonC 感谢您的肯定!对于'.md',我只找到git commit -no-verify,有什么建议吗? 我宁愿让钩子能够检测到.md 文件而不删除空格,而不是要求最终用户在git commit 上添加--no-verify 选项。 如果提交以+- 开头的文件/目录则失败【参考方案9】:

我编写了这个 pre-commit 钩子,它只从您更改/添加的行中删除尾随空格,因为如果目标文件有太多尾随空格,则前面的建议往往会创建不可读的提交。

#!/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

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m^\+')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done

【讨论】:

有趣。 +1。请参阅 my other answer 计算空树。 好主意,这正是我想要的。但是,使用时要小心!对于我在 OSX 和 git 版本 2.3.5 上的我来说,它吹走了我上演的任何添加但未提交的更改。不过,我仍然会对解决此问题的可行解决方案感兴趣。【参考方案10】:

我今天正在考虑这个问题。这就是我最终为 Java 项目所做的一切:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'

【讨论】:

【参考方案11】:

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

1 sed 替换模式:How can I replace a newline (\n) using sed?

【讨论】:

脚注似乎没有被引用。目的是什么?【参考方案12】:

这是一个兼容 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

【讨论】:

看起来你和我的唯一区别是你在重写文件之前检查 sed 是否会实际替换某些东西......我不确定这是否重要,因为 git 不会提交不实际上并没有改变任何东西。我想它稍微安全一点,但也稍微慢一点,而且我更喜欢不要在一行上重复两次正则表达式的清晰度。 De gustibus non disputandum est! 没有区别,版本首先使用 ubuntu 语法,然后(如果失败)使用 osx 语法。 我编辑了 sdepold 的帖子,它现在应该也可以在文件名中允许空格了。【参考方案13】:

在 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它。

或者为了全局使用(通过Applying a git post-commit hook to all current and future repos),您可以将其放入$GIT_PREFIX/git-core/templates/hooks(其中GIT_PREFIX 是/usr 或/usr/local 或/usr/share 或/opt/local/share)并运行git init在您现有的存储库中。

根据git help init

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

【讨论】:

这个钩子不是在修改工作文件,用修改后的工作文件覆盖索引吗?如果你用 'git add -p' 来构建你的索引,这个提交钩子会把它吹走。 是的,你可能是对的。有人可能不得不重写此脚本以使用 git hash-object -wgit update-index 将 munged 文件直接(重新)插入到索引中。一个非常勇敢的人。【参考方案14】:

我找到了一个 Git pre-commit hook that removes trailing white space。

#!/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

【讨论】:

第二个 sed 调用 (sed -r 's/:[0-9]+:.*//') 可以替换为 cut -f1 -d:。这在基于 Linux 和 BSD 的平台上应该是一样的。 @IhorKaharlichenko:实际上,使用cut 不如第二个sed 安全:在包含“:”的文件名(极不可能)的情况下,剪切将失败。为了安全起见,您可以使用awk 'NF&gt;2NF-=21' 顺便说一句,如果您在 Windows (msysgit) 上并使用 core.autocrlf=true,您可能希望在 sed 之后的 for 循环中添加 dos2unix -D "$FILE"。否则,它将通过仅发出 sed 将所有 CRLF 更改为 LF。 在提交钩子中执行git add 对我来说似乎很邪恶。如果您正在对文件进行部分暂存/提交怎么办?你不希望整个文件在你背后提交,是吗?【参考方案15】:

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

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

【讨论】:

afaik,.git 中的设置与其他任何人共享;它们特定于您的本地存储库【参考方案16】:

您可以欺骗 Git 为您修复空白,方法是欺骗 Git 将您的更改视为一个补丁。与“预提交挂钩”解决方案相比,这些解决方案向 Git 添加了空白修复命令。

是的,这些都是黑客攻击。


稳健的解决方案

以下 Git 别名取自 my ~/.gitconfig.

“健壮”是指这些别名运行时不会出错, 正确的事情,无论树或索引是否脏。但是,如果交互式 git rebase -i 已经在进行中,它们将不起作用;如果您关心这种极端情况,请参阅my ~/.gitconfig 进行额外检查,最后描述的git add -e 技巧应该可以工作。

如果你想直接在 shell 中运行它们,而不需要创建 Git 别名,只需复制并粘贴双引号之间的所有内容 (假设你的 shell 类似于 Bash)。

修复索引而不是树

以下fixws Git 别名修复了索引中的所有空白错误, 如果有,但不要碰树:

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://***.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

这个想法是在 git commit 之前运行 git fixws 如果你有 索引中的空白错误。

修复索引和树

以下fixws-global-tree-and-index Git 别名修复了所有空格 索引和树中的错误(如果有):

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

要修复未版本化文件中的空白,请执行

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

简单但不可靠的解决方案

这些版本更容易复制和粘贴,但它们不具备 如果不满足他们的附带条件,那就对了。

修复以当前目录为根的子树(如果不为空则重置索引)

使用git add -e 使用身份编辑器:“编辑”补丁:

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

修复并保留索引(但如果树脏或索引为空则失败)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

修复树和索引(但如果它不为空则重置索引)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

export GIT_EDITOR=: &amp;&amp; git -c apply.whitespace=fix add -ue . 技巧的解释

在我从this answer 了解git rebase --whitespace=fix 技巧之前,我一直在使用更复杂的git add 技巧。

如果我们手动操作:

    apply.whitespace 设置为fix(您只需执行一次):

    git config apply.whitespace fix
    

    这告诉 Git 修复补丁中的空白。

    说服 Git 将您的更改视为补丁

    git add -up .
    

    点击 a+enter 以选择每个文件的所有更改。您将收到有关 Git 修复空白错误的警告。 (此时git -c color.ui=auto diff 表明您的非索引更改正是空白错误)。

    从工作副本中删除空白错误:

    git checkout .
    

    带回您的更改(如果您还没有准备好提交):

    git reset
    

GIT_EDITOR=: 表示将: 用作编辑器,并用作命令 : 是身份。

【讨论】:

我刚刚在 Windows 中进行了测试:这在 DOS 命令提示符下工作得很好:set VISUAL= &amp;&amp; git add -ue . &amp;&amp; git checkout . 注意与git add 一起使用的'.':即because of git1.8.3 @VonC 不会永久取消设置 VISUAL,例如导致后续使用git commit 使用错误的编辑器?我将VISUAL= 部分包装在我上面的unix 版本的子shell 中以避免这种情况,但我不知道DOS 是否有子shell。 感谢伟大的黑客!仅供参考,如果您设置了core.editor,则导出VISUAL 无效,因为配置设置优先于man git-var。要覆盖它,您需要改为导出 GIT_EDITOR=: 另外,我调整了我的fixws 版本,如果你已经在一个交互式rebase 中,它会快速失败,否则它会在git rebase --whitespace=fix 行中死掉,让你处于一个奇怪的状态。我从 this question 借来的,只是在 if 之前添加了一个额外的案例:fixws = !"\ if test -d $(git rev-parse --git-dir)/rebase-merge ; then \ echo 'In rebase - cannot fixws' ; \ elif (! git diff-files --quiet .) &amp;&amp; \ (! git diff-index --quiet --cached HEAD) ; then \ ... 仅供参考:我将其改编为pre-commit hook【参考方案17】:

我宁愿把这个任务留给你最喜欢的编辑。

只需设置一个命令以在保存时删除尾随空格。

【讨论】:

在 vim 中你可以这样做:autocmd BufWritePre .cpp,.c,*.h :%/\s\+$//e 对不起,我在测试之前赞成上述评论。百分号后缺少一个“s”,如果找到空格,它将移动光标,并删除最后一个搜索模式。请参阅vim.wikia.com/wiki/Remove_unwanted_spaces 了解更好的选择。 在 emacs 中是 M-x delete-trailing-whitespace。 更好的是,对于 emacs,通过将 (add-hook 'before-save-hook 'delete-trailing-whitespace) 添加到您的 .emacs 文件来设置一个挂钩以在保存之前删除尾随空格。 Emacs whitespace tricks 这是迄今为止最安全、最可靠的解决方案。我已经浪费了好几个小时来修复由看似无辜的预提交钩子引起的意外问题。

以上是关于让 Git 在提交前自动删除尾随空格的主要内容,如果未能解决你的问题,请参考以下文章

在 IntelliJ IDEA 12 中保存时删除尾随空格

如何在 Android Studio 中自动删除尾随空格?

如何在 Visual Studio 2008 中自动删除尾随空格?

如何在 Matlab 中保存时自动删除尾随空格?

如何使用正则表达式删除尾随空格?

如何使用正则表达式删除尾随空格?