让 Git 在提交前自动删除尾随空格
我正在与我的团队一起使用 Git,并且希望从我的差异、日志、合并等中删除空格更改。我假设最简单的方法是让 Git 自动删除尾随空格(以及其他应用时所有提交中的空白错误)。
我尝试将以下内容添加到 ~/.gitconfig
文件中,但是当我提交时它没有执行任何操作。 也许它是为不同的目的而设计的。 解决办法是什么?
[core]
whitespace = trailing-space,space-before-tab
[apply]
whitespace = fix
我正在使用 Ruby,以防有人有任何 Ruby 特定的想法。 下一步是在提交之前自动进行代码格式化,但这是一个难题,并且不会真正造成大问题。
I'm using Git with my team and would like to remove white space 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 white space (and other white space errors) from all commits as they are applied.
I have tried to add the following to the ~/.gitconfig
file, but it doesn't do anything when I commit. Maybe it's designed for something different. What's the solution?
[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 is not really causing a big problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
这些设置(
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
脚本(例如 这个),不是“删除尾随”功能”,而是“警告”功能,例如:然而可以构建一个更好的
预提交
钩子,特别是当您考虑到:例如,oldman 提议另一个答案 a
预提交 hook
检测并删除空格。
由于该钩子获取每个文件的文件名,因此我建议对某些类型的文件小心:您不想删除
.md
(markdown)文件中的尾随空格!另一种方法,由 hakre 在 评论:
然后是内容过滤器驱动程序:
Those settings (
core.whitespace
andapply.whitespace
) are not there to remove trailing whitespace but to:core.whitespace
: detect them, and raise errorsapply.whitespace
: and strip them, but only during patch, not "always automatically"I believe the
git hook pre-commit
would do a better job for that (includes removing trailing whitespace)Note that at any given time you can choose to not run the
pre-commit
hook:git commit --no-verify .
cd .git/hooks/ ; chmod -x pre-commit
Warning: by default, a
pre-commit
script (like this one), has not a "remove trailing" feature", but a "warning" feature like:You could however build a better
pre-commit
hook, especially when you consider that:For instance, oldman proposes in another answer a
pre-commit
hook which 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!Another approach, suggested by hakre in the comments:
Then a content filter driver:
您可以欺骗 Git 将您的更改视为补丁,从而为您修复空白。 与“预提交挂钩”解决方案相比,这些解决方案向 Git 添加了空格修复命令。
是的,这些都是黑客行为。
稳健的解决方案
以下 Git 别名取自
我的
~/.gitconfig
。我所说的“稳健”是指这些别名运行时没有错误,
正确的事情,无论树或索引是否脏。 但是,如果交互式 git rebase -i 已经在进行中,它们将不起作用; 有关其他信息,请参阅 我的
~/.gitconfig
检查您是否关心这个极端情况,最后描述的 git add -e 技巧应该起作用。如果你想直接在 shell 中运行它们,而不创建 Git
别名,只需复制并粘贴双引号之间的所有内容
(假设你的 shell 类似于 Bash)。
修复索引但不修复树
以下
fixws
Git 别名修复索引中的所有空白错误,如果有的话,但不触及树:
这个想法是在
git commit
之前运行git fixws
如果你有索引中的空格错误。
修复索引和树
以下
fixws-global-tree-and-index
Git 别名修复所有空格索引和树中的错误(如果有):
要修复未版本化文件中的空白,请执行
简单但不可靠的解决方案
这些版本更容易复制和粘贴,但它们不执行
如果不满足他们的附带条件,那就是正确的事情。
修复以当前目录为根的子树(但如果不为空则重置索引)
使用 git add -e 使用身份编辑器“编辑”补丁
:
:修复并保留索引(但如果树脏或索引为空则失败)
修复树和索引(但如果不为空则重置索引)
export GIT_EDITOR=: && 的说明 git -c apply.whitespace=fix add -ue .
技巧在我从 这个答案 我到处都在使用更复杂的
git add
技巧。如果我们手动执行:
将
apply.whitespace
设置为fix
(您只需执行一次):这告诉 Git 修复补丁中的空格。
说服 Git 将您的更改视为补丁:
点击a+enter选择每个文件的所有更改。 您将收到有关 Git 修复空白错误的警告。
(
git -c color.ui=auto diff
此时表明您的非索引更改正是空白错误)。从工作副本中删除空格错误:
带回您的更改(如果您还没有准备好提交它们):
GIT_EDITOR=:
表示使用:
作为编辑器,并作为命令:
是身份。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.
Yes, these are hacks.
Robust solutions
The following Git aliases are taken from
my
~/.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 thegit add -e
trick described at the end should work.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).
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:
The idea is to run
git fixws
beforegit commit
if you havewhitespace errors in the index.
Fix the index and the tree
The following
fixws-global-tree-and-index
Git alias fixes all whitespaceerrors in the index and the tree, if any:
To also fix whitespace in unversioned files, do
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:
:Fix and preserve the index (but fails if the tree is dirty or the index is empty)
Fix the tree and the index (but resets the index if it's not empty)
Explanation of the
export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
trickBefore I learned about the
git rebase --whitespace=fix
trick from this answer I was using the more complicatedgit add
trick everywhere.If we did it manually:
Set
apply.whitespace
tofix
(you only have to do this once):This tells Git to fix whitespace in patches.
Convince Git to treat your changes as a patch:
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:
Bring back your changes (if you aren't ready to commit them):
The
GIT_EDITOR=:
means to use:
as the editor, and as a command:
is the identity.我发现了一个 Git 预提交挂钩,可以删除尾随空白。
I found a Git pre-commit hook that removes trailing white space.
在 macOS(或者可能是任何 BSD)上,sed 命令参数必须略有不同。 试试这个:
将此文件另存为 .git/hooks/pre-commit ,或者查找已经存在的文件,并将底部块粘贴到其中的某个位置。 并且记住也
chmod a+x
它。或者为了全局使用(通过 将 git post-commit 挂钩应用于所有当前和未来的存储库),您可以将其放入
$GIT_PREFIX/git-core/templates/hooks
(其中 GIT_PREFIX 是 /usr 或 /usr/local 或 /usr/share 或 /opt/local/share)并在里面运行git init
您现有的存储库。根据 git help init :
On macOS (or, likely, any BSD), the sed command parameters have to be slightly different. Try this:
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 tochmod a+x
it too.Or for global use (via Applying a git post-commit hook to all current and future repos) 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 rungit init
inside your existing repos.According to
git help init
:使用 Git 属性,并通过 Git 配置设置过滤器
好吧,这是解决这个问题的新方法……我的方法是不使用任何钩子,而是使用过滤器和 Git 属性。 这允许您在开发的每台机器上设置一组过滤器,这些过滤器将在提交文件之前去除文件末尾的额外尾随空格和额外空行。
然后设置一个 .gitattributes 文件,说明过滤器应应用于哪些类型的文件。 过滤器有两个阶段,
clean
将文件添加到索引时应用,smudge
将文件添加到工作目录时应用。让您的 Git 查找全局属性文件
首先,告诉您的全局配置使用全局属性文件:
创建全局过滤器
现在,创建过滤器:
添加 sed 脚本魔法
最后,将
fixup-eol-eof
脚本放在路径上的某个位置,并使其可执行。 该脚本使用 sed 进行一些动态编辑(删除行末尾的空格和空白,以及文件末尾的无关空白行)fixup-eol-eof 应如下所示:
我的要点
告诉 Git 将新创建的过滤器应用到哪些文件类型
最后,创建或打开文件 ~/.在您最喜欢的文本编辑器中打开 .gitattributes_global 并添加如下行:
因此,如果我们想解决空白问题,对于所有 C 源文件,我们将添加如下行:
过滤器的讨论
过滤器有两个阶段。 clean 阶段在将内容添加到索引或签入时应用,而 smudge 阶段则在 Git 将内容放入工作目录时应用。
在这里,我们的污点只是通过 cat 命令运行内容,这应该使它们保持不变,但如果文件末尾没有换行符,可能会添加一个尾随换行符。
clean 命令是我根据 http://sed.sourceforge.net/ 上的注释拼凑而成的空白过滤。 sed1line.txt。 看来必须放到shell脚本里了。 我不知道如何注入 sed 命令,包括将文件末尾的无关额外行直接清理到 git-config 文件中。 (但是,您可以去掉尾随空白,而不需要单独的 sed 脚本。只需将
filter.fix-eol-eof
设置为类似/[ \t]*$//' %f
其中\t
是一个实际的制表符,按 Tab。)sed ' s 如果出现问题,>require = true 会引发错误,以免您遇到麻烦。
Using Git attributes, and filters setup with Git configuration
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. This allows you to set up, 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 set up 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, andsmudge
which is applied when adding them to the working directory.Tell your Git to look for a global attributes file
First, tell your global configuration to use a global attributes file:
Create global filters
Now, create the filter:
Add the sed scripting magic
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 should look like this:
My gist of this
Tell Git which file types to apply your newly created filter to
Lastly, create or open file ~/.gitattributes_global in your favorite text editor and add lines like:
So if we want to fix the white space issue, for all of our C source files we would add a line that looks like this:
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 white space 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 can get rid of trailing blanks, however, without the need of a separate sed script. Just set the
filter.fix-eol-eof
to something likesed 's/[ \t]*$//' %f
where the\t
is an actual tab, by pressing Tab.)The
require = true
causes an error to be raised if something goes wrong, to keep you out of trouble.我宁愿把这个任务留给你最喜欢的编辑。
只需设置一个命令在保存时删除尾随空格即可。
I'd rather leave this task to your favorite editor.
Just set a command to remove trailing spaces when saving.
我编写了这个预提交挂钩,它仅从您更改/添加的行中删除尾随空格,因为如果目标文件有太多尾随空格,前面的建议往往会创建不可读的提交。
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.
请尝试我的预提交挂钩。 它可以自动检测尾随空白并删除它。
它可以在 Git Bash (Windows)、Mac OS X 和Linux!
快照:
Please try my pre-commit hooks. It can auto detect trailing white space and remove it.
It can work under Git Bash (Windows), Mac OS X and Linux!
Snapshot:
这是 Ubuntu 和 Mac OS X 兼容版本:
Here is an Ubuntu and Mac OS X compatible version:
我今天正在思考这个问题。 这就是我最终为 Java 项目所做的一切:
I was thinking about this today. This is all I ended up doing for a Java project:
对于 Sublime Text 用户。
在您的设置-用户配置中正确设置以下内容。
For Sublime Text users.
Set the following properly in your Setting-User configuration.
这不会在提交之前自动删除空格,但它很容易实现。 我将以下 Perl 脚本放入名为 git-wsf (Git 空格修复)的文件中$PATH 中的一个目录,这样我就可以:
并且它仅从 Git 报告为差异的文件行中删除所有空格。
This doesn't remove white space automatically before a commit, but it is pretty easy to effect. I put the following Perl script in a file named git-wsf (Git white space fix) in a directory in $PATH, so I can:
And it removes all white space only from lines of files that Git reports as a diff.
文件的
for
循环使用$IFS
shell 变量。在给定的脚本中,其中包含 $IFS 变量中的字符的文件名将在
for
循环中被视为两个不同的文件。此脚本修复了它: sed 手册中给出的多行模式修饰符似乎没有默认情况下在我的 Ubuntu 机器上工作,所以我寻求不同的实现,并发现它带有迭代标签,本质上它只会在我正确理解的情况下开始替换文件的最后一行。
1 sed 替换模式:如何使用 sed 替换换行符 (\n)?
The
for
loop for files uses the$IFS
shell variable.In the given script, filenames with a character in them that also is in the $IFS-variable will be seen as two different files in the
for
loop.This script fixes it: multiline-mode modifier as given in the sed manual doesn't seem to work by default on my Ubuntu box, so I sought for a different implementation and found this with an iterating label, essentially it will only start substitution on the last line of the file if I've understood it correctly.
1 sed-substitution pattern: How can I replace a newline (\n) using sed?
Python 脚本获得相同的结果。
Python Script for the same result.
这可能不会直接解决您的问题,但您可能想通过 git-config< /a> 在您的实际项目空间中,它编辑文件 ./.git/config 而不是文件 ~/.gitconfig。 最好保持所有项目成员之间的设置一致。
This probably won't directly solve your problem, but you might want to set those via git-config in your actual project space, which edits file ./.git/config as opposed to file ~/.gitconfig. It is nice to keep the settings consistent among all project members.
在 Vim 中打开文件。 要将制表符替换为空格,请在 Vim 命令行中输入以下内容:
删除其他尾随空格
这对我来说几乎做到了。 如果您有很多文件需要编辑,这会很乏味。 但我发现它比预提交挂钩和使用多个文本编辑器更容易。
Open the file in Vim. To replace tabs with white spaces, type the following on the Vim command line:
To get rid of other trailing white spaces
This pretty much did it for me. It's tedious if you have a lot of files to edit. But I found it easier than pre-commit hooks and working with multiple text editors.
要可移植地删除文件中行尾的尾随空格,请使用
ed
:To delete trailing white space at the end of lines in a file portably, use
ed
: