只添加非空白的更改

我让我的文本编辑器在保存文件时自动修剪尾随空格,而且我正在为一个开源项目做贡献,该项目在尾随空格方面存在严重问题。

每次我尝试提交一个补丁时,我必须首先手动忽略所有只有空白的更改,只选择相关信息。不仅如此,当我运行git rebase时,我通常会遇到几个问题。

因此,我希望能够以类似于git add -p的方式,仅向索引中添加非空格的更改,但不必自己选择所有更改。

有人知道怎么做吗?

编辑:我不能改变了项目的工作方式,他们已经决定,在邮件列表上讨论后,忽略这一点。

110055 次浏览

首先应该考虑后面的空格是否是有意的。许多项目,包括Linux内核、Mozilla、Drupal和Kerberos(仅列举维基百科页面上关于样式的几个例子)禁止尾随空格。来自Linux内核文档:

找个像样的编辑,别走

.行末空格

在您的情况下,问题是反过来的:以前的提交(可能是当前的提交)没有遵循这个指导原则。

我敢打赌,没有人真的想要后面的空格,解决这个问题可能是一个受欢迎的改变。其他用户可能也遇到了与您相同的问题。也有可能添加尾随空格的贡献者没有意识到他们正在这样做。

与其试图重新配置git来忽略这个问题,或者在编辑器中禁用其他理想的功能,我宁愿先在项目邮件列表中发布一篇文章来解释这个问题。许多编辑器(以及git本身)都可以配置为处理尾随空格。

我找到了一个git 删除尾随空格的预提交钩子。但是,如果您不能让其他人使用它,那么它可能不是一个有效的解决方案。

  #!/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"
done
exit

这对我来说很管用:

如果你想藏点,这招管用

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

我不喜欢这些存储,但是我在git + cygwin中遇到了一个错误,在那里我丢失了更改,所以为了确保这些东西去了reflog,至少我设置了以下内容:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

基本上,我们创建了一个不包括空格更改的diff,还原所有更改,然后应用diff。

下面这个怎么样:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

反引号内的命令获取有非空格更改的文件名。

@Frew解决方案不是我所需要的,所以这是我为完全相同的问题所做的别名:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

或者你可以简单地运行:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

更新

根据这样的评论,分别添加选项-U0--unidiff-zero来解决上下文匹配问题。

基本上,它应用的补丁将应用于add,没有空格更改。你会注意到在git addnw your/file之后,仍然会有未分阶段的变化,这是留下的空白。

no-color不是必需的,但我把颜色设置为always,我必须使用它。总之,小心总比后悔好。

警告

虽然这个技巧按原样工作,但如果你试图用它来删除--ignore-blank-lines的空行更改,那么事情就会变得复杂。使用此选项,git diff将只删除一些块,使结果补丁伪造,因为目标文件中的行号将是关闭的。

创建一个只包含真正更改的补丁文件(不包括只有空白更改的行),然后清理工作空间并应用该补丁文件:

git diff > backup
Git diff -w > changes
Git reset—hard
. txt 补丁& lt;修改< / p >

检查剩余的差异,然后addcommit正常。

Mercurial的等效功能是这样做的:

hg diff > backup
Hg diff -w >变化
Hg恢复—所有
Hg import -no-commit changes

投票最多的答案并不适用于所有情况,因为根据评论中的用户,补丁上下文中有空白。

我将命令修改如下:

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

这会生成一个没有上下文的补丁。应该不是问题,因为补丁是短暂的。

对应的别名,同样是其他用户已经提供的内容的修订:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -

.gitconfig中添加以下内容:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

感谢科林·赫伯特的回答的灵感。

语法解释

最后的#必须被引用,这样它就不会被当作.gitconfig中的注释,而是被传递并被当作shell中的注释——它被插入git apply的末尾和用户提供的参数之间,git自动将这些参数放在命令行的末尾。这里不需要这些参数——我们不希望git apply使用它们,因此使用前面的注释字符。你可能想要以GIT_TRACE=1 git anw的形式运行这个命令来查看它的作用。

--表示参数结束,并允许你有一个名为-w的文件或类似git diff的文件。

对于$@周围的转义双引号,需要保留任何用户提供的带引号参数。如果"字符没有转义,它将被.gitconfig解析器使用,而不会到达shell。

注意:.gitconfig别名解析不会将单引号识别为任何特殊字符——它唯一的特殊字符是"\\n;(在"-引号字符串之外)。这就是为什么"必须总是转义,即使它看起来像是在单引号字符串中(git完全不知道这一点)。

这很重要。如果你有一个方便的别名,可以在工作树的根执行bash命令。不正确的说法是:

sh = !bash -c '"$@"' -

而正确的答案是:

sh = !bash -c '\"$@\"' -

这对我来说很管用:

git config apply.whitespace fix

在每次提交使用命令之前:

git add -up .

这是我的黑客。

git diff -w | grep "diff --git a/*" | sed -r 's#diff --git a/(.*) b(.*)#\1#g' | xargs git add

Git diff -w只显示没有空格的文件,

我让我的文本编辑器在保存文件时自动修剪尾随空格

你的编辑器没有proj / dir特定的设置吗?可以禁用此项目的空白首选项。似乎是一个更简单的解决方案…

类似于@void。指针的答案,但修复最近的提交。

git reset --mixed HEAD^
git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

这将使空白更改不进行,而其余更改将进行。