当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在提交之前让git自动删除尾随空格》经验,为你挑选了10个好方法。

我正在使用我的团队的git,并希望从我的差异,日志,合并等中删除空格更改.我假设最简单的方法是让git自动删除尾随空格(以及其他空白错误)来自所有提交的应用程序.

我试图通过~/.gitconfig文件添加以下内容,但是当我提交时它没有做任何事情.也许它是为不同的东西而设计的.解决方案是什么?

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

我正在使用红宝石,以防任何人有任何红宝石特定的想法.在提交之前自动代码格式化将是下一步,但这是一个难题而不是真正导致大问题.



1> VonC..:

那些设置(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脚本(如此脚本)没有 "删除尾随"功能,但是"警告"功能如下:

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

然而,您可以构建一个更好的pre-commit钩子,尤其是当您考虑到:

在Git中提交只有一些更改添加到暂存区域仍然会导致"原子"修订版本可能永远不会作为工作副本存在,并且可能无法正常工作.


例如,oldman 在另一个答案中提出了一个检测和删除空格的pre-commit钩子.
由于该钩子获取每个文件的文件名,我建议小心某些类型的文件:你不想删除.md(降价)文件中的尾随空格!


@friederbluemle取决于markdown的类型,尾随的双空格表示`
`:https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/26#issuecomment-5825759

2> ntc2..:

您可以通过欺骗Git将您的更改视为补丁来欺骗Git为您修复空白.与"预提交挂钩"解决方案相比,这些解决方案为Git添加了空白固定命令.

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


强大的解决方案

以下Git别名取自 我的~/.gitconfig.

"健壮"我的意思是这些别名运行没有错误,做正确的事情,无论树或索引是否脏.但是,如果互动git rebase -i已在进行中,它们就无法工作; 如果你关心这个角落的情况,请看我~/.gitconfig的额外检查,git add -e最后描述的技巧应该有效.

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

修复索引但不修复树

以下fixwsGit别名修复了索引中的所有空白错误(如果有),但未触及树:

# 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:
# /sf/ask/17360801/
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 fixws之前运行git commit.

修复索引和树

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

# 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  && 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=: && git -c apply.whitespace=fix add -ue .诀窍的解释

在我git rebase --whitespace=fix从这个答案中了解到这个技巧之前,我git add到处都在使用更复杂的技巧.

如果我们手动完成:

    设置apply.whitespacefix(您只需执行此操作一次):

    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=:手段:和作为命令的手段 :是身份.



3> cmcginty..:

我发现了一个git 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
# 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 add`对我来说似乎很邪恶.如果您正在进行文件的部分暂存/提交,该怎么办?您不希望将完整文件提交到您的背后,是吗?
第二个`sed`调用(`sed -r's /:[0-9] +:.*//'`)可以用`cut -f1 -d:`代替.这应该在基于Linux和BSD的平台上都相同.
@IhorKaharlichenko:实际上,使用`cut`并不像第二个`sed`那样安全:在包含":"的文件名(极不可能)的情况下,cut会失败.您可以使用`awk'NF> 2 {NF- = 2} 1'来安全

4> AlexChaffee..:

在Mac OS(或者可能是任何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提交挂钩 - 全局设置),您可以将其放入$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 -w`和`git update-index`来(重新)将munged文件直接插入到索引中.有人非常勇敢.

5> Giacomo..:

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

只需设置一个命令即可在保存时删除尾随空格.


对不起,我在测试前赞成上述评论.百分号后面缺少"s",如果找到空格,它将移动光标,它将删除最后一个搜索模式.有关更好的替代方案,请参阅http://vim.wikia.com/wiki/Remove_unwanted_spaces.
在vim中你可以这样做:autocmd BufWritePre*.cpp,*.c,*.h:%/\s\+ $ // e
更好的是,对于emacs,通过在`.emacs`文件中添加`(add-hook'fore-save-hook'dele-trailing-whitespace)`来设置一个挂钩来删除尾随空格.[Emacs whitespace tricks](http://www.emacswiki.org/emacs/DeletingWhitespace)

6> urandom..:

我编写了这个预提交钩子,它只删除你已经改变/添加的行的空白空格,因为如果目标文件有太多的尾随空格,之前的建议往往会创建不可读的提交.

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



7> oldman..:

请尝试我的预提交挂钩,它可以自动检测尾随空格并将其删除.谢谢!

它可以工作GitBash(windows), Mac OS X and 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(-)



8> zbeekman..:
使用git属性,并使用git config设置过滤器

好吧,这是解决这个问题的新方法......我的方法是不使用任何钩子,而是使用过滤器和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脚本魔术

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

fixup-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命令运行内容,该命令应该保持不变,除了可能添加一个尾随换行符(如果文件末尾没有一个).clean命令是空格过滤,我从http://sed.sourceforge.net/sed1line.txt中的笔记拼凑而成.它似乎必须放入shell脚本,我无法弄清楚如何注入sed命令,包括将文件末尾的无关额外行的卫生直接导入git-config文件.(您CAN摆脱尾随空白,但是,而不需要单独的sed脚本,只需设置fixup-eol-eof喜欢的东西cat,其中的filter.fix-eol-eof是一个实际的选项卡,按Tab键).

如果出现问题,require = true会导致错误,以防止出现问题.

如果我关于git的语言不精确,请原谅我.我想我对这些概念有了很好的把握,但仍在学习术语.



9> sdepold..:

这是一个ubuntu + mac os x兼容版本:

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# 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

玩得开心



10> 小智..:

今天正在考虑这个问题.这就是我最终为java项目做的事情:

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

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有