我正在使用我的团队的git,并希望从我的差异,日志,合并等中删除空格更改.我假设最简单的方法是让git自动删除尾随空格(以及其他空白错误)来自所有提交的应用程序.
我试图通过~/.gitconfig
文件添加以下内容,但是当我提交时它没有做任何事情.也许它是为不同的东西而设计的.解决方案是什么?
[core] whitespace = trailing-space,space-before-tab [apply] whitespace = fix
我正在使用红宝石,以防任何人有任何红宝石特定的想法.在提交之前自动代码格式化将是下一步,但这是一个难题而不是真正导致大问题.
那些设置(core.whitespace
和apply.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
(降价)文件中的尾随空格!
您可以通过欺骗Git将您的更改视为补丁来欺骗Git为您修复空白.与"预提交挂钩"解决方案相比,这些解决方案为Git添加了空白固定命令.
是的,这些都是黑客攻击.
以下Git别名取自
我的~/.gitconfig
.
"健壮"我的意思是这些别名运行没有错误,做正确的事情,无论树或索引是否脏.但是,如果互动git rebase -i
已在进行中,它们就无法工作; 如果你关心这个角落的情况,请看我~/.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: # /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-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&& 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.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=:
手段:
和作为命令的手段
:
是身份.
我发现了一个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/share)并git init
在现有的存储库中运行.
根据git help init
:
在现有存储库中运行git init是安全的.它不会覆盖已存在的东西.重新运行git init的主要原因是选择新添加的模板.
我宁愿把这个任务留给你最喜欢的编辑.
只需设置一个命令即可在保存时删除尾随空格.
我编写了这个预提交钩子,它只删除你已经改变/添加的行的空白空格,因为如果目标文件有太多的尾随空格,之前的建议往往会创建不可读的提交.
#!/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
请尝试我的预提交挂钩,它可以自动检测尾随空格并将其删除.谢谢!
它可以工作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属性.这允许你做的是,在你开发的每台机器上设置一组过滤器,这些过滤器将在提交之前剥离文件末尾的额外尾随空格和额外空白行.然后设置一个.gitattributes文件,该文件说明应该将过滤器应用于哪些类型的文件.过滤器有两个阶段,在将文件添加到索引时应用的clean,以及在将它们添加到工作目录时应用的smudge.
首先,告诉您的全局配置使用全局属性文件:
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
最后,将clean
脚本放在路径上的某个位置,并使其可执行.该脚本使用sed进行一些动态编辑(删除行末尾的空格和空格,以及文件末尾的无关空行)
fixup-eol-eof应如下所示:
#!/bin/bash sed -e 's/[ ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1
我的要点
最后,在您喜欢的编辑器中创建或打开〜/ .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的语言不精确,请原谅我.我想我对这些概念有了很好的把握,但仍在学习术语.
这是一个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
玩得开心
今天正在考虑这个问题.这就是我最终为java项目做的事情:
egrep -rl ' $' --include *.java * | xargs sed -i 's/\s\+$//g'