在提交之前让git自动删除尾随的空白
我使用git与我的团队,并希望从我的差异,日志,合并等删除空格的变化。我假设最简单的方法来做到这一点是让git自动删除尾随空白(和其他空白错误)从所有提交应用。
我曾尝试通过~/.gitconfig
文件添加以下内容,但在提交时它不会执行任何操作。 也许它是为不同的东西devise的。 有什么解决scheme?
[core] whitespace = trailing-space,space-before-tab [apply] whitespace = fix
我使用ruby,以防有人有任何ruby的具体想法。 提交之前的自动代码格式化将是下一步,但这是一个难题,并没有真正造成大问题。
这些设置( core.whitespace
和apply.whitespace
)不能删除尾随的空白,而是:
-
core.whitespace
:检测它们,并引发错误 -
apply.whitespace
:并剥离它们,但只在补丁期间,而不是“始终自动”
我相信git hook pre-commit
会做得更好(包括删除尾随的空白)
请注意,在任何给定的时间,您可以select不运行pre-commit
挂钩:
- 暂时:
git commit --no-verify .
- 永久:
cd .git/hooks/ ; chmod -x pre-commit
cd .git/hooks/ ; chmod -x pre-commit
警告:默认情况下, pre-commit
脚本(如这个 ) 没有 “删除尾随”function,而是“警告”function,如:
if (/\s$/) { bad_line("trailing whitespace", $_); }
然而,你可以build立一个更好的pre-commit
钩子 ,特别是当你考虑到:
在Git中只join了一些修改,但是仍然会导致一个“primefaces”的修改,这个修改可能永远不会作为工作副本存在,并且可能无法工作 。
例如, oldman 在另一个答案中提出了一个检测和删除空格的pre-commit
钩子 。
由于该钩子获取每个文件的文件名,我build议小心某些types的文件:你不想删除.md
(markdown)文件中的尾随空格!
你可以欺骗Git去修正你的空白,通过欺骗Git把你的修改作为补丁来处理。 与“预先提交钩子”解决scheme相比,这些解决scheme将添加空格的命令添加到Git中。
是的,这些都是黑客。
强大的解决scheme
下面的Git别名是从我的~/.gitconfig
。
通过“健壮”我的意思是这些别名运行没有错误,做正确的事情,无论树或索引是否脏。 但是,如果交互式git rebase -i
已经在进行,则它们不起作用。 看看我的~/.gitconfig
的额外检查,如果你关心这个angular落的情况下,最后描述的git add -e
技巧应该工作。
如果你想直接在shell中运行它们,而不创build一个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://stackoverflow.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
简单但不稳健的解决scheme
这些版本更容易复制和粘贴,但如果他们的条件不满足,他们不会做正确的事情。
修复以当前目录为根的子树(但如果不是空的,则重置索引)
使用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 .
说明export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
招
在我学习git rebase --whitespace=fix
这个答案的技巧之前,我使用的是比较复杂的git add
trick。
如果我们手动完成:
-
设置
apply.whitespace
来fix
(你只需要做一次):git config apply.whitespace fix
这告诉Git 修补补丁中的空白。
-
说服Git把你的改变作为一个补丁 :
git add -up .
点击+ input以select每个文件的所有更改。 你会得到一个Git修正你的空白错误的警告。
(git -c color.ui=auto diff
在这一点上显示你的非索引改变正是空白错误)。 -
从您的工作副本中删除空白错误:
git checkout .
-
带回您的更改(如果您还没有准备好提交):
git reset
GIT_EDITOR=:
表示使用:
作为编辑器,作为命令:
是身份。
我发现了一个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
在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 /共享),并在现有的回购站内运行git init
。
根据git help init
:
在现有的仓库中运行git init是安全的。 它不会覆盖已经存在的东西。 重新运行git init的主要原因是挑选新添加的模板。
我宁愿把这个任务交给你最喜欢的编辑器。
只需设置一个命令来保存时删除尾随空格。
我写了这个预先提交的钩子,它只删除已经更改/添加的行中的尾随空白,因为如果目标文件有太多的尾随空白,以前的build议往往会创build不可读的提交。
#!/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
这里是一个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
玩的开心
请尝试我的预先提交挂钩 ,它可以自动检测尾随空白, 并将其删除 。 谢谢!
它可以在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(-)
使用git属性,并使用git config过滤设置
好的,这是解决这个问题的新方法…我的方法是不使用任何钩子,而是使用filter和git属性。 你可以这样做,在你开发的每台机器上设置一组filter,在提交文件之前,会在文件末尾去掉多余的空白和额外的空白行。 然后设置一个.gitattributes文件,说明filter应该应用于哪些types的文件。 这些filter有两个阶段,在向索引添加文件时使用clean,在将其添加到工作目录时应用了smudge。
告诉你的git去寻找一个全局属性文件
首先,告诉你的全局configuration使用全局属性文件:
git config --global core.attributesfile ~/.gitattributes_global
创build全局filter
现在,创buildfilter:
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
脚本放在你的path上,并使其可执行。 该脚本使用sed来进行一些即时编辑(删除行尾的空格和空格以及文件尾部的多余的空行)
fixup-eol-eof应该是这样的:
#!/bin/bash sed -e 's/[ ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1
我的这个主旨
告诉git哪些文件types应用你新创build的filter
最后,在您最喜欢的编辑器中创build或打开〜/ .gitattributes_global,并添加如下行:
pattern attr1 [attr2 [attr3 […]]]
所以,如果我们想解决空白问题,对于我们所有的c源文件,我们会添加一个如下所示的行:
*.c filter=fix-eol-eof
讨论filter
这个filter有两个阶段,当添加到索引或签入时应用的清理阶段,以及当git将东西放入工作目录时的涂抹阶段。 在这里,我们的涂抹只是通过cat
命令运行内容,应该保持不变,除了可能添加一个尾随的换行符,如果没有一个在文件的末尾。 干净的命令是我在http://sed.sourceforge.net/sed1line.txt从笔记拼凑在一起的空白过滤。; 看来它必须放在一个shell脚本中,我不知道如何注入sed命令,包括在文件末尾多余的额外行的清理直接到git-config文件中。 (你可以删除尾随空白,但是,不需要单独的sed脚本,只需将filter.fix-eol-eof
为像sed 's/[ \t]*$//' %f
\t
是一个实际的选项卡,通过按Tab。)
如果出现错误,require = true会导致错误,从而避免麻烦。
如果我的git语言不准确,请原谅我。 我认为我对这些概念有相当好的把握,但是仍然在学习术语。
今天正在想这个。 这就是我最终为java项目所做的一切:
egrep -rl ' $' --include *.java * | xargs sed -i 's/\s\+$//g'
文件的for循环使用$ IFS shellvariables。 在给定的脚本中,带有一个字符的文件名也会在$ IFSvariables中被看作for循环中的两个不同的文件。 这个脚本解决了这个问题:多行模式修改器作为给定的sed手册似乎不工作默认情况下在我的Ubuntu的盒子,所以我寻求一个不同的实现,发现这与迭代标签,本质上它只会开始替代如果我正确地理解了文件的最后一行。
#!/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 SAVEIFS="$IFS" # only use new-line character as seperator, introduces EOL-bug? IFS=' ' # Find files with trailing whitespace 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( MacOSx-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 whitespace-characters exec git diff-index --check --cached $against --
sed-subsition模式: 如何使用sedreplace换行符(\ n)? 。
对于崇高的文本用户。
在设置 – 用户configuration中正确设置以下内容。
"trim_trailing_white_space_on_save": true
稍迟,但由于这可能会帮助那里的人,在这里。
在VIM中打开文件。 要使用空格replace制表符,请在vim命令行中input以下内容
:%s#\t# #gc
摆脱其他尾随的空白
:%s#\s##gc
这几乎为我做了。 如果你有很多文件需要编辑,那就太单调乏味了。 但是我发现它比预先提交钩子和使用多个编辑器更容易。
要删除文件尾部的尾部空格,请使用ed
:
test -s file && printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file
这不会在提交之前自动删除空格,但是很容易实现。 我把下面的perl脚本放在一个名为git-wsf(git whitespace fix)的文件中,放在$ PATH的目录中,这样我就可以:
git wsf | SH
它只会从git报告为diff的文件行删除所有的空白。
#! /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"; }
这可能不会直接解决你的问题,但是你可能想要通过git-config在你的实际项目空间中设置,它们编辑./.git/config而不是〜/ .gitconfig。 很高兴保持所有项目成员之间的设置一致。
git config core.whitespace "trailing-space,space-before-tab" git config apply.whitespace "trailing-space,space-before-tab"