提交前在新文件中删除尾部空白符 (Git)

16

我知道可以使用pre-commit挂钩来去除尾随空格。 我有兴趣手动完成它。 我在这里阅读了问题:
Make git automatically remove trailing whitespace before committing - Stack Overflow
最接近我想要的答案是ntc2的“自动版本”

(export VISUAL=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset


除了似乎只适用于已经在存储库中的文件更改外,该命令运行良好,对于那些还没有添加到存储库中的新文件则无效。我有一堆新文件,意味着它们尚未添加到存储库中。我想从这些文件中删除空格,因此我尝试使用add -A而不是-u,但是这并没有任何区别。


1
你的意思是 "git add -Ae 根本没有添加新文件" 吗?还是说:"文件已经被添加,但没有被固定"? - VonC
@VonC 它无法处理未跟踪或新增(第一次添加但尚未提交)的文件。对我来说,它会显示“致命错误:空补丁。已中止。”我正在使用 git 版本 1.8.3.msysgit.0。 - loop
@test:如果您在我的原始答案上留下了评论,询问如何使我的命令工作或链接到您的问题,我将收到通知并可以告诉您有关“add -N”的信息。但是,SO足够聪明,将您的问题放在“相关”部分中,因此当我今天编辑答案时看到了它。 - ntc2
vim用户可能也会喜欢这个:https://dev59.com/9HRC5IYBdhLWcg3wROtQ#13795287 - Michael Durrant
4个回答

33
要手动清理最近三次提交的空格,您可以执行以下操作:
git rebase --whitespace=fix HEAD~3
当我在一个主题分支上工作时,我会跟踪上游分支(通常通过像这样创建它)
git checkout -b topic -t
这使我可以从 git rebase 中删除最后一个参数。因此,一旦我完成并准备好合并,我可以快速清理整个主题分支:
git ws # 别名为 rebase --whitespace=fix
请注意,与 HEAD~3 示例不同,如果上游分支发生更改,这实际上将重新应用您的更改!(但这也是我的工作流程所需要的。)

Luke,这个方法可以用,但你知道为什么我不能使用我在问题中提到的命令吗? - loop
我不知道,很抱歉;但是考虑到 whitespace=fix 旨在应用补丁(包括 rebase),所以出现问题并不奇怪。从未跟踪的文件中删除空格类似于在存储库外编辑文件:这不是 Git 的工作。 - Luke Usherwood
2
嘿,这是我刚刚从基本命令中想出来的东西,用于梳理暂存更改(在此之后保留添加文件的选择):git commit -mTemp && git stash && git rebase HEAD~ --whitespace=fix && git reset --soft HEAD~ && git stash pop - Luke Usherwood
你是我的英雄。由于有缺陷的Eclipse格式化程序/保存操作,我刚刚不得不修复数百个空格错误。 :) - James
2
这是一个好时机,提醒一下,如果您需要修复初始提交,那么咒语变成了git rebase --whitespace=fix --root(当然,如果您关心您的存储库的克隆,请不要这样做) - badp
显示剩余4条评论

8

我喜欢卢克的回答,除了需要手动指定基础提交或使用重新基于工作流程的限制之外,你需要将历史线性化。我提出的修改不需要额外的参数,也不会改变您的提交图拓扑结构。以下是一个Shell命令示例:

git rebase --whitespace=fix --onto $(git merge-base HEAD @{u})

作为一个~/.gitconfig别名:
ws = "!git rebase --whitespace=fix --onto $(git merge-base HEAD @{u})"

我喜欢这种方法,因为有时候我想要变基我的修改,但是如果我认为可能会出现合并冲突,我更愿意合并,这样我的原始修改和解决冲突的记录都会被记录在历史记录中。这样我以后可以重新考虑冲突解决方案,如果需要的话可以重新执行。
考虑到我并不总是变基,我不喜欢把空格修复和变基混在一起;因此,我修改了Luke的答案。
此外,我启用了默认的预提交挂钩,它会在出现空格错误时中止操作:
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit

这里提供了以下工作流程,我喜欢它,因为它足够手动化,让我知道正在发生什么,但自动化程度又足够高,不会妨碍到我:
  1. 进行编码,引入空格错误
  2. 尝试提交
  3. 由于预提交挂钩而提交失败,出现空格错误
  4. git commit --no-verify 进行提交
  5. git ws 使用别名进行修复
关于使用--onto的说明:这里并不需要,但我发现这样更容易理解rebase的工作方式。在Luke的版本中,HEAD~3是man页面中的<upstream>,而在我的版本中,<upstream>保持其默认值为分支的真实上游。无论哪种方式,最终结果都是相同的。

很好地使用了 --onto。+1 - VonC

2

简单修复

您引用的命令如下:

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

如果你想要修复的文件在使用git add -N <files you want to fix>命令之前就已经存在,那么这个方法就会奏效。而add -N则是告诉Git假定你之前提交过一个空版本的该文件。

你遇到的错误

我不理解为什么你会使用add -Ae命令时出现fatal: Empty patch. Aborted.错误,但看起来像是一个bug,因为使用普通的git add -A . && git diff --cached命令可以显示patch实际上并不为空。

更好的空格修复工具

最近,我更新了你引用的答案,提供了一个更好的Git别名来修复空格。以下是重写该别名的方式,并使用Luke's rebase trick以及更少冗余的控制流:

fixws =!"\
  if (! git diff-index --quiet --cached HEAD); then \
    \
    git diff-files --quiet `git rev-parse --show-toplevel` ; \
    export NEED_TO_STASH=$? ; \
    \
    git commit -m FIXWS_SAVE_INDEX && \
    if [ 1 = $NEED_TO_STASH ] ; then git stash save FIXWS_SAVE_TREE; fi && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ && \
    if [ 1 = $NEED_TO_STASH ] ; then git stash pop; fi ; \
  fi"

这个修复了索引中的空格,同时保留了索引,让树保持不变。使用这个别名,你可以修复版本库中未被追踪的文件。

git add --all :/ && git fixws && git reset

但是,它还可以处理在你正在处理的提交中修复空白的常见情况。这很复杂,因为即使索引或树干净,它也能正常工作。


如果这样做不会影响树的状态,那么这是否意味着索引中任何空格修复都会在 git diff 中以相反的方式显示,并且当您将受影响的文件添加到索引时将被还原?我猜这就是为什么您的流程中有 git reset,但这似乎抵消了保持树状态不变的好处。 - jbyler
如果你指的是 addfixwsreset 组合中的 reset,那么它的目的是撤销最初的 add。请注意,默认的重置是 --mixed,它仅会涉及到索引,而不会影响树。 - ntc2
嗨,我今天添加了你的别名,并尝试了你的更好的空格修复命令行。最初它没有起作用,因为我之前启用了预提交钩子来捕获空格违规。我怀疑发生了什么,所以我禁用了它,然后运行了你的命令,它就起作用了。再次感谢! - loop

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接