仅添加非空白更改


343

我有我的文本编辑器,可以在保存文件时自动修剪尾随空格,而且我正在为一个开源项目提供帮助,该项目在尾随空格方面存在严重问题。

每次尝试提交补丁程序时,我都必须首先手动忽略所有仅限空白的更改,仅选择相关信息。不仅如此,而且在我跑步时,git rebase由于这些原因,我通常会遇到一些问题。

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

有谁知道如何做到这一点?

编辑:我无法更改项目的工作方式,在邮件列表上进行讨论之后,他们决定忽略此问题。

Answers:


395

@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不是必需的,但是由于我将颜色设置为始终,因此必须使用它。无论如何,安全胜过遗憾。


7
这对我来说效果很好,但是git apply --ignore-whitespace由于明显的原因,我不得不使用该补丁。
jupp0r 2012年

106
确实应该有一个git add选项,就像git add -w这样做。
Jarl 2014年

7
这给我patch does not applyerror while searching for... 带来了问题,有什么想法吗?
DTI-Matt

18
没有为我工作。得到了一个patch does not apply错误。
杰里·萨拉维亚

13
如果您收到上下文“补丁失败”由于空格作为@bronson指出,修订后的指令作品(它会产生一个补丁,没有上下文): git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero。这没有风险,因为索引已经尽可能地是最新的,因此它是该补丁程序的可靠基础。
void.pointer 2016年

36

这对我有用:

如果您想藏起来,这可行

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

我不喜欢的藏匿处,但我已经在混帐+ cygwin的,我失去的变化,所以要确保这些东西去了,至少我设置以下的引用日志碰上了一个错误:

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

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


1
+1。您可能希望做一个git stash而不是签出操作,以备份所做的更改,至少在测试完成之前。
圣保罗Ebermann

1
您最终将获得很多藏匿处,并且基本上您并不需要做所有这些事情。它有效,但我认为它有点混乱
Colin Hebert

3
我同意科林的观点。如果脚本有效,则无需创建存储。最好考虑先运行存储,然后运行存储弹出。可以根据需要恢复弹出的存储库,但是否则最终不会得到很多存储库。这也留下了一个多余的文件
Casebash 2012年

如何跳过二进制文件?尝试应用上述代码段时,出现以下错误:没有完整的索引行,无法应用补丁!让我感到震惊的是,我一开始甚至都没有触摸过这些文件/二进制文件!
tver3305

1
我认为在第一个命令“ git rm foo.patch”的末尾应该只是“ rm foo.patch”。否则非常有帮助,谢谢。
杰克·凯西

33

创建仅包含实际更改(不包括仅包含空格更改的行)的补丁文件,然后清理工作区并应用该补丁文件:

git diff>备份
git diff -w>更改
git reset --hard
patch <更改

查看剩余的分歧,然后addcommit正常。

Mercurial的等效方法是:

hg diff>备份
hg diff -w>更改
hg还原-所有
hg导入-无提交更改


什么是“受保护的”问题?我也回答。我认为这甚至都不符合我的答案,因为看来问题
出乎意料了

4
@jww原始张贴者问题的核心是“如何避免仅将空白更改提交到源代码管理中”。OP恰好正在使用Git,但这也适用于我曾经使用过的每个源代码控制系统。如果有人碰巧正在使用Mercurial,此答案将显示正确的过程。我可以想象其他人也可能为使用Sublesion等的人提供解决方案。–
Steve

1
@jww和@ pagid:我使用与Mercurial解决方案相同的方法来编辑答案,以专门解决Git。在我看来,StackOverflow 不只是另一个Q + A论坛 -它还具有知识库的作用。原始海报以外的其他人可能会从给出的答案中受益,并且他们的情况有所不同。这就是为什么我认为传达一般原则的答案是有效的,而不是仅针对单个特定情况。
史蒂夫·投手

@Steve- “我编辑了我的答案,专门针对Git ...” -您为什么不在询问时提出一个新问题,然后将您自己的答案添加到新问题中?
jww

8
实际上,这是我所见过的最干净,最易懂和最坚不可摧的方法。
喀恰

12

根据评论中的用户,由于补丁程序上下文中存在空格,因此投票表决的答案并非在所有情况下都有效。

我将命令修改如下:

$ 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' -

要仅忽略缩进更改,我必须使用--ignore-space-change代替-wgit diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
安迪

警告不要使用这种可爱的无上下文技巧,--ignore-blank-lines否则,如果您要忽略的某些“空白”更改是空行删除/添加,您将发现diff块以不正确的偏移量进行了修补。
elbeardmorez '18

12

将以下内容添加到您的.gitconfig

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

感谢@Colin Herbert的启发。

语法说明

最后的#引号必须加引号,这样就不会将其视为内的注释.gitconfig,而是传递给它,并当作外壳内的注释来处理-将其插入的末尾git apply和用户提供的参数之间,这些参数会git自动放在命令行的结尾。在这里不需要这些参数-我们不想git apply使用它们,因此不需要前面的注释字符。您可能需要运行此命令GIT_TRACE=1 git anw以查看其实际效果。

--论点信号结束,并允许的情况下,你有一个文件名为-w或东西看起来像一个开关git diff

需要使用转义的双引号$@来保留用户提供的任何带引号的参数。如果"字符未转义,则.gitconfig解析器将使用该字符,而不会到达外壳。

注:.gitconfig别名解析不承认单引号的任何特殊-它的唯一的特殊字符"\\n,和;(一个外"-quoted字符串)。这就是为什么"必须始终将其转义的原因,即使它看起来像在单引号的字符串中(git完全不可知)。

这很重要,例如。如果您有方便的别名来bash在工作树的根目录中执行命令。错误的公式是:

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

正确的是:

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

优秀的。这使我可以一次添加一个文件。除了为参数添加根目录外,还有没有办法像git add -A这样工作?
Chucky

7

怎么样:

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

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


2
或只是git add `git diff -w |grep '^+++' |cut -c7-`如果未使用子模块
karmakaze 2013年

-1

您应该首先考虑尾随空格是否是故意的。许多项目,包括Linux内核,Mozilla,Drupal和Kerberos(仅在样式上的Wikipedia页面上仅举几例)都禁止尾随空格。从Linux内核文档中:

得到一个体面的编辑,不要在行尾留空白。

在您的情况下,问题是相反的:以前的提交(可能是当前的提交)未遵循此准则。

我敢打赌,没人真正想要尾随空格,并且解决问题可能是一个可喜的变化。其他用户可能也会遇到与您相同的问题。添加尾随空格的贡献者也可能没有意识到自己正在这样做。

我不会尝试重新配置git来忽略该问题,也不会在编辑器中禁用本来希望的功能,而是从向项目邮件列表中解释该问题的帖子开始。许多编辑器(以及git本身)都可以配置为处理尾随空白。


16
这不是故意的,但我无法改变100个以上贡献该项目的人员的想法。他们不介意,也不接受带有1000多个更改的补丁,这些补丁仅处理尾随空白。他们知道这个问题,并决定忽略它。该讨论已在列表中进行,因此已关闭。在这种情况下,是我需要适应它们。
Edu Felipe

19
然后配置您的编辑器,使其在处理该项目的代码时不会修剪尾随空白。
jamessan

-2

我发现了一个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"
  done
  exit

4
这个问题问如何保留尾随空白。
道格拉斯

@Douglas:一个人可能可以使用这个答案在一个临时分支上创建一个提交,在那提交真正的补丁,然后以某种方式仅将差异添加到工作分支中……
Tobias Kienzler 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.