仅添加非空白更改

Posted

技术标签:

【中文标题】仅添加非空白更改【英文标题】:Add only non-whitespace changes 【发布时间】:2011-03-31 17:52:33 【问题描述】:

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

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

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

有人知道怎么做吗?

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

【问题讨论】:

【参考方案1】:

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

您的编辑器没有 proj / dir 特定设置吗?可以禁用此项目的空白首选项。似乎更容易解决...

【讨论】:

【参考方案2】:

@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 -

更新

根据this comment,分别添加了选项-U0--unidiff-zero来解决上下文匹配问题。

基本上,它会应用与add 一起应用的补丁,而不会更改空格。您会注意到在git addnw your/file 之后仍然会有未分级的更改,它是剩下的空格。

--no-color 不是必需的,但由于我将颜色设置为 always,所以我必须使用它。无论如何,安全总比后悔好。

警告

虽然这个技巧按原样工作,但如果您尝试使用它来删除带有--ignore-blank-lines 的空白行更改,那么事情就会变得复杂。使用此选项,git diff 将仅删除一些块,从而使生成的补丁成为虚假,因为目标文件中的行号将被关闭。

【讨论】:

这对我来说效果很好,但是我必须使用git apply --ignore-whitespace 否则补丁将因明显原因而无法应用。 确实应该有一个 git add 选项,例如 git add -w 这样做。 这给我带来了patch does not applyerror while searching for 的问题...有什么想法吗? 对我不起作用。收到 patch does not apply 错误。 如果@bronson 指出,由于上下文中的空格而导致“补丁失败”,则此修改后的命令有效(它会生成一个没有上下文的补丁):git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero。这没有风险,因为索引已经尽可能地保持最新状态,因此它是补丁的可靠基础。【参考方案3】:

这是我的秘诀。

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

git diff -w 只显示非空白更改的文件,

【讨论】:

【参考方案4】:

它对我有用:

git config apply.whitespace fix

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

git add -up .

【讨论】:

【参考方案5】:

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

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

感谢@Colin Herbert's answer 的启发。

语法解释

最后的# 必须被引用,这样它就不会被视为.gitconfig 中的注释,而是被传递并被视为shell 中的注释——它被插入到@987654326 的末尾之间@ 和 git 自动放置在命令行末尾的用户提供的参数。这里不需要这些参数 - 我们不希望 git apply 使用它们,因此前面的注释字符。您可能希望以 GIT_TRACE=1 git anw 的身份运行此命令以查看实际情况。

-- 表示参数结束,并允许您有一个名为 -w 的文件或看起来像切换到 git diff 的文件。

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

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

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

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

虽然正确的是:

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

【讨论】:

优秀。这允许我一次添加一个文件。除了为参数添加根目录之外,有没有办法像 'git add -A' 这样工作?【参考方案6】:

根据 cmets 中的用户,由于补丁上下文中存在空格,因此票数最高的答案并非在所有情况下都有效。

我修改命令如下:

$ 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 中使用这种可爱的无上下文技巧,否则如果某些“空白”,您会发现差异块被修补在不正确的偏移量您希望忽略的更改是空行删除/添加。【参考方案7】:

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

git diff > 备份 git diff -w > 更改 git reset --hard 补丁

查看其余差异,然后照常查看addcommit

Mercurial 的等价物是这样做:

hg diff > 备份 hg diff -w > 改变 hg 还原 --all hg import --no-commit 更改

【讨论】:

What is a “protected” question? 和 Me Too 回答。我认为这甚至不符合我的回答,因为看起来这个问题是凭空提出来的...... @jww 原始发帖人问题的核心是“如何避免仅将空白更改提交到源代码管理”。 OP 恰好在使用 Git,但这也适用于我曾经使用过的每个源代码控制系统。如果有人碰巧使用 Mercurial,此答案显示了正确的程序。我可以想象其他人也可能为使用 Sublesion 等的人提供解决方案。 @jww 和 @pagid:我使用与 Mercurial 解决方案相同的方法编辑了我的答案以专门针对 Git。在我看来,*** 是more than just another Q+A forum - 它还具有知识库的作用。原始发帖人以外的人可能会从给出的答案中受益,并且他们的情况各不相同。这就是为什么我认为传达一般原则的答案是有效的,而不是只针对一个特定的情况。 @Steve - “我编辑了我的答案以专门针对 Git...” - 你为什么不在 mercurial 的上下文中提出一个新问题,然后添加你自己对新问题的回答??? 这实际上是我见过的最干净、最容易理解、最牢不可破的方法。【参考方案8】:

这对我有用:

如果你想保留一个藏匿处,这行得通

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

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

【讨论】:

+1。您可能希望使用git stash 而不是结帐,以备份您的更改,至少在测试之前备份。 你最终会得到很多存储,基本上你不需要做所有这些。它有效,但我认为它有点乱 我同意科林的观点。如果脚本有效,则不需要创建存储。可能需要考虑的是运行 stash,然后 stash pop。如有必要,可以恢复弹出的存储,但否则您不会得到很多存储。这也会留下一个额外的文件 跳过二进制文件怎么样?尝试应用上述 sn-p 时,我收到错误提示,如果没有完整的索引行,则无法应用补丁!让我感到震惊的是,我什至一开始都没有接触过这些文件/二进制文件! 我认为在第一个命令“git rm foo.patch”的末尾应该只是“rm foo.patch”。否则非常有帮助,谢谢。【参考方案9】:

以下内容如何:

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

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

【讨论】:

如果没有使用子模块,则只需 git add `git diff -w |grep '^+++' |cut -c7-`【参考方案10】:

我找到了一个 git pre-commit hook that removes trailing whitespace。但是,如果您不能让其他人使用它,那么它可能不是一个有效的解决方案。

  #!/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

【讨论】:

这个问题是问如何保留尾随空格。 @Douglas:人们可能会使用这个答案在一个临时分支上创建一个提交,在那里提交真正的补丁,然后以某种方式只将差异挑选到工作分支中......【参考方案11】:

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

找一个像样的编辑器,不要离开 行尾的空格。

在您的情况下,问题是相反的:以前的提交(可能还有当前的提交)没有遵循这个准则。

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

与其尝试重新配置 git 以忽略该问题,或者禁用编辑器中原本需要的功能,不如从项目邮件列表中的帖子开始解释问题。许多编辑器(和 git 本身)可以配置为处理尾随空格。

【讨论】:

这不是故意的,但我无法改变 100 多个贡献该项目的人的思维方式。他们不介意,并且不会接受具有 1000 多个更改的补丁,这些更改仅处理尾随空格。他们知道这个问题并决定忽略它。此讨论已在列表中进行并已关闭。在这种情况下,我需要适应他们。 然后配置您的编辑器,使其在处理此项目的代码时不会修剪尾随空格。

以上是关于仅添加非空白更改的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询以填补跨时间缺失的空白并获取最后一个非空值

使用已填充的模型添加非空和唯一字段

仅更新非空字段

仅发送非空文件

如何在数组php中仅获取非空元素计数

Django:仅使用 annotate() 和 values() 计算非空 CharField