git 使git在提交前自动删除尾随空格
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/591923/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Make git automatically remove trailing whitespace before committing
提问by mloughran
I'm using git with my team and would like to remove whitespace changes from my diffs, logs, merges, etc. I'm assuming that the easiest way to do this would be for git to automatically remove trailing whitespace (and other whitespace errors) from all commits as they are applied.
我正在与我的团队一起使用 git,并希望从我的差异、日志、合并等中删除空格更改。我假设最简单的方法是让 git 自动删除尾随空格(和其他空格错误) ) 来自所有提交,因为它们被应用。
I have tried to add the following to by ~/.gitconfig
file but it doesn't do anything when I commit. Maybe it's designed for something different. What's the solution?
我试图将以下内容添加到~/.gitconfig
文件中,但是当我提交时它没有做任何事情。也许它是为不同的东西而设计的。解决办法是什么?
[core]
whitespace = trailing-space,space-before-tab
[apply]
whitespace = fix
I'm using ruby in case anyone has any ruby specific ideas. Automatic code formatting before committing would be the next step, but that's a hard problem and not really causing a big problem.
我正在使用 ruby,以防有人有任何 ruby 特定的想法。在提交之前自动格式化代码将是下一步,但这是一个难题,并不会真正造成大问题。
回答by VonC
Those settings (core.whitespace
and apply.whitespace
) are not there to remove trailing whitespace but to:
这些设置(core.whitespace
和apply.whitespace
)不是为了删除尾随空格而是为了:
core.whitespace
: detect them, and raise errorsapply.whitespace
: and strip them, but only during patch, not "always automatically"
core.whitespace
: 检测它们,并引发错误apply.whitespace
:并剥离它们,但仅在补丁期间,而不是“始终自动”
I believe the git hook pre-commit
would do a better job for that (includes removing trailing whitespace)
我相信这git hook pre-commit
会做得更好(包括删除尾随空格)
Note that at any given time you can choose to not run the pre-commit
hook:
请注意,在任何给定时间您都可以选择不运行pre-commit
钩子:
- temporarily:
git commit --no-verify .
- permanently:
cd .git/hooks/ ; chmod -x pre-commit
- 暂时地:
git commit --no-verify .
- 永久:
cd .git/hooks/ ; chmod -x pre-commit
Warning: by default, a pre-commit
script (like this one), has nota "remove trailing" feature", but a "warning" feature like:
警告:默认情况下,pre-commit
脚本(像这样)没有“删除尾随”功能,而是“警告”功能,例如:
if (/\s$/) {
bad_line("trailing whitespace", $_);
}
You could however build a better pre-commit
hook, especially when you consider that:
但是,您可以构建一个更好的pre-commit
hook,尤其是当您考虑到这一点时:
Committing in Git with only some changes added to the staging area still results in an “atomic” revision that may never have existed as a working copy and may not work.
在 Git 中提交仅添加到暂存区的一些更改仍然会导致“原子”修订,该修订可能永远不会作为工作副本存在并且可能无法工作。
For instance, oldmanproposes in another answera pre-commit
hookwhich detects and remove whitespace.
Since that hook get the file name of each file, I would recommend to be careful for certain type of files: you don't want to remove trailing whitespace in .md
(markdown) files!
例如,oldman在另一个答案中提出了一个检测和删除空格的pre-commit
钩子。
由于该钩子获取每个文件的文件名,我建议对某些类型的文件要小心:您不想删除.md
(降价)文件中的尾随空格!
回答by ntc2
You can trick Git into fixing the whitespace for you, by tricking Git into treating your changes as a patch. In contrast to the "pre-commit hook" solutions, these solutions add whitespace-fixing commands to Git.
您可以通过欺骗 Git 将您的更改视为补丁来欺骗 Git 为您修复空白。与“预提交钩子”解决方案相比,这些解决方案向 Git 添加了空白修复命令。
Yes, these are hacks.
是的,这些都是黑客。
Robust solutions
强大的解决方案
The following Git aliases are taken from
my ~/.gitconfig
.
以下 Git 别名取自
我的~/.gitconfig
.
By "robust" I mean that these aliases run without error, doing
the right thing, regardless of whether the tree or index are dirty. However, they don't work if an interactive git rebase -i
is already in progress; see my ~/.gitconfig
for additional checks if you care about this corner case, where the git add -e
trick described at the end should work.
“健壮”是指这些别名运行没有错误,做正确的事情,无论树或索引是否脏。但是,如果交互git rebase -i
已经在进行中,它们就不起作用;如果您关心这种极端情况,请参阅我~/.gitconfig
的其他检查,git add -e
最后描述的技巧应该起作用。
If you want to run them directly in the shell, without creating a Git alias, just copy and paste everything between the double quotes (assuming your shell is Bash like).
如果您想直接在 shell 中运行它们,而不创建 Git 别名,只需复制并粘贴双引号之间的所有内容(假设您的 shell 类似于 Bash)。
Fix the index but not the tree
修复索引而不是树
The following fixws
Git alias fixes all whitespace errors in the index,
if any, but doesn't touch the tree:
以下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"
The idea is to run git fixws
before git commit
if you have
whitespace errors in the index.
这个想法是在索引中有空格错误git fixws
之前运行git commit
。
Fix the index and the tree
修复索引和树
The following fixws-global-tree-and-index
Git alias fixes all whitespace
errors in the index and the tree, if any:
以下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"
To also fix whitespace in unversioned files, do
还要修复未版本化文件中的空格,请执行
git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index
Simple but not robust solutions
简单但不可靠的解决方案
These versions are easier to copy and paste, but they don't do the right thing if their side conditions are not met.
这些版本更容易复制和粘贴,但如果不满足其附带条件,它们就不会做正确的事情。
Fix the sub-tree rooted at the current directory (but resets the index if it's not empty)
修复以当前目录为根的子树(但如果它不为空则重置索引)
Using git add -e
to "edit" the patches with the identity editor :
:
使用git add -e
身份编辑器“编辑”补丁:
:
(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset
Fix and preserve the index (but fails if the tree is dirty or the index is empty)
修复并保留索引(但如果树脏或索引为空则失败)
git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~
Fix the tree and the index (but resets the index if it's not empty)
修复树和索引(但如果索引不为空则重置索引)
git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~
Explanation of the export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
trick
该说明export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
伎俩
Before I learned about the git rebase --whitespace=fix
trick from this answerI was using the more complicated git add
trick everywhere.
在我git rebase --whitespace=fix
从这个答案中了解到这个技巧之前,我git add
到处都在使用更复杂的技巧。
If we did it manually:
如果我们手动完成:
Set
apply.whitespace
tofix
(you only have to do this once):git config apply.whitespace fix
This tells Git to fix whitespace in patches.
Convince Git to treat your changes as a patch:
git add -up .
Hit a+enterto select all changes for each file. You'll get a warning about Git fixing your whitespace errors.
(git -c color.ui=auto diff
at this point reveals that your non-indexed changes are exactly the whitespace errors).Remove the whitespace errors from your working copy:
git checkout .
Bring back your changes (if you aren't ready to commit them):
git reset
设置
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
The GIT_EDITOR=:
means to use :
as the editor, and as a command
:
is the identity.
该GIT_EDITOR=:
装置使用:
作为编辑器,并作为命令
:
是标识。
回答by cmcginty
I found a git pre-commit hook that removes trailing whitespace.
我发现了一个 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
回答by AlexChaffee
On Mac OS (or, likely, any BSD), the sed command parameters have to be slightly different. Try this:
在 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
Save this file as .git/hooks/pre-commit
-- or look for the one that's already there, and paste the bottom chunk somewhere inside it. And remember to chmod a+x
it too.
将此文件另存为.git/hooks/pre-commit
-- 或查找已经存在的文件,然后将底部块粘贴到其中的某处。并记住chmod a+x
它。
Or for global use (via Git commit hooks - global settings) you can put it in $GIT_PREFIX/git-core/templates/hooks
(where GIT_PREFIX is /usr or /usr/local or /usr/share or /opt/local/share) and run git init
inside your existing repos.
或者为了全局使用(通过Git 提交钩子 - 全局设置),您可以将它放入$GIT_PREFIX/git-core/templates/hooks
(其中 GIT_PREFIX 是 /usr 或 /usr/local 或 /usr/share 或 /opt/local/share)并git init
在您现有的存储库中运行。
According to git help init
:
根据git help init
:
Running git init in an existing repository is safe. It will not overwrite things that are already there. The primary reason for rerunning git init is to pick up newly added templates.
在现有存储库中运行 git init 是安全的。它不会覆盖已经存在的东西。重新运行 git init 的主要原因是选择新添加的模板。
回答by Giacomo
I'd rather leave this task to your favorite editor.
我宁愿把这个任务留给你最喜欢的编辑器。
Just set a command to remove trailing spaces when saving.
只需设置一个命令即可在保存时删除尾随空格。
回答by zbeekman
Using git attributes, and filters setup with git config
使用 git 属性,并使用 git config 设置过滤器
OK, this is a new tack on solving this problem… My approach is to not use any hooks, but rather use filters and git attributes. What this allows you to do, is setup, on each machine you develop on, a set of filters that will strip extra trailing white space and extra blank lines at the end of files before committing them. Then setup a .gitattributes file that says which types of files the filter should be applied to. The filters have two phases, clean
which is applied when adding files to the index, and smudge
which is applied when adding them to the working directory.
好的,这是解决这个问题的新方法……我的方法是不使用任何钩子,而是使用过滤器和 git 属性。这允许您做的是,在您开发的每台机器上设置一组过滤器,这些过滤器将在提交文件之前去除文件末尾的额外尾随空白和额外空白行。然后设置一个 .gitattributes 文件,说明过滤器应该应用于哪些类型的文件。过滤器有两个阶段,clean
在将文件添加到索引时应用,在将文件smudge
添加到工作目录时应用。
Tell your git to look for a global attributes file
告诉您的 git 查找全局属性文件
First, tell your global config to use a global attributes file:
首先,告诉您的全局配置使用全局属性文件:
git config --global core.attributesfile ~/.gitattributes_global
Create global filters
创建全局过滤器
Now, create the filter:
现在,创建过滤器:
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
Add the sed scripting magic
添加 sed 脚本魔法
Finally, put the fixup-eol-eof
script somewhere on your path, and make it executable. The script uses sed to do some on the fly editing (remove spaces and blanks at the end of lines, and extraneous blank lines at the end of the file)
最后,将fixup-eol-eof
脚本放在路径上的某个位置,并使其可执行。该脚本使用 sed 进行一些动态编辑(删除行尾的空格和空格,以及文件末尾的无关空行)
fixup-eol-eof should look like this:
fixup-eol-eof 应如下所示:
#!/bin/bash
sed -e 's/[ ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}'
Tell git which file types to apply your newly created filter to
告诉 git 将新创建的过滤器应用到哪些文件类型
Lastly, create or open ~/.gitattributes_global in your favorite editor and add lines like:
最后,在您喜欢的编辑器中创建或打开 ~/.gitattributes_global 并添加如下行:
pattern attr1 [attr2 [attr3 […]]]
So if we want to fix the whitespace issue, for all of our c source files we would add a line that looks like this:
因此,如果我们想修复空格问题,对于我们所有的 c 源文件,我们将添加如下所示的一行:
*.c filter=fix-eol-eof
Discussion of the filter
过滤器的讨论
The filter has two phases, the clean phase which is applied when things are added to the index or checked in, and the smudge phase when git puts stuff into your working directory. Here, our smudge is just running the contents through the cat
command which should leave them unchanged, with the exception of possibly adding a trailing newline character if there wasn't one at the end of the file. The clean command is the whitespace filtering which I cobbled together from notes at http://sed.sourceforge.net/sed1line.txt. It seems that it must be put into a shell script, I couldn't figure out how to inject the sed command, including the sanitation of the extraneous extra lines at the end of the file directly into the git-config file. (You CANget rid of trailing blanks, however, without the need of a separate sed script, just set the filter.fix-eol-eof
to something like sed 's/[ \t]*$//' %f
where the \t
is an actual tab, by pressing tab.)
过滤器有两个阶段,一个是在将内容添加到索引或签入时应用的清洁阶段,另一个是当 git 将内容放入您的工作目录时应用的涂抹阶段。在这里,我们的涂抹只是通过cat
命令运行内容,这应该使它们保持不变,除非文件末尾没有换行符,否则可能会添加一个尾随换行符。clean 命令是我从http://sed.sourceforge.net/sed1line.txt 上的笔记拼凑起来的空白过滤。看来必须要放到shell脚本里了,我想不通怎么把sed命令注入,包括把文件末尾多余的行的卫生直接注入到git-config文件中。(您CAN甩掉尾随空白,但是,而不需要单独的sed脚本的,只需设置filter.fix-eol-eof
喜欢的东西sed 's/[ \t]*$//' %f
,其中的\t
是一个实际的选项卡,按Tab键)。
The require = true causes an error to be raised if something goes wrong, to keep you out of trouble.
如果出现问题,require = true 会导致引发错误,以免您遇到麻烦。
Please forgive me if my language concerning git is imprecise. I think I have a fairly good grasp of the concepts but am still learning the terminology.
如果我关于 git 的语言不准确,请原谅我。我认为我对概念有很好的掌握,但仍在学习术语。
回答by urandom
I wrote this pre-commit hook, which only removes the trailing white-space from the lines which you've changed/added, since the previous suggestions tend to create unreadable commits if the target files have too much trailing white-space.
我写了这个 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
回答by oldman
Please try my pre-commithooks, it can auto detect trailing-whitespace and remove it. Thank you!
请尝试我的预提交钩子,它可以自动检测尾随空白并将其删除。谢谢!
it can work under GitBash(windows), Mac OS X and Linux
!
它可以在GitBash(windows), Mac OS X and Linux
!
Snapshot:
快照:
$ 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(-)
回答by sdepold
Here is an ubuntu+mac os x compatible version:
这是一个 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
Have fun
玩得开心
回答by Grant Murphy
Was thinking about this today. This is all I ended up doing for a java project:
今天一直在想这个。这就是我最终为一个 Java 项目所做的一切:
egrep -rl ' $' --include *.java * | xargs sed -i 's/\s\+$//g'