我正在和我的团队一起使用Git,并希望从我的差异、日志、合并等中删除空白更改。我假设做到这一点最简单的方法是Git在应用所有提交时自动删除尾随空白(和其他空白错误)。

我已经尝试将以下内容添加到~/。gitconfig文件,但是当我提交时它什么也不做。也许它是为别的东西设计的。解决方案是什么?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

我使用Ruby,以防有人对Ruby有任何具体的想法。在提交之前自动格式化代码将是下一步,但这是一个困难的问题,并不是真正造成大问题。


当前回答

我宁愿把这个任务留给你最喜欢的编辑。

只需设置一个命令,在保存时删除尾随空格。

其他回答

您可以欺骗Git将您的更改视为补丁,从而让Git为您修复空白。与“预提交钩子”解决方案相比,这些解决方案向Git添加了空格修复命令。

是的,这些都是黑客。


健壮的解决方案

以下Git别名取自 我的~ / .gitconfig。

我所说的“健壮”是指这些别名运行时没有错误 正确的事情,不管树或索引是否脏。然而,如果交互式git rebase -i已经在进行中,它们就不起作用;看我的~/。如果您关心这种极端情况,可以使用Gitconfig进行额外检查,在这种情况下,最后描述的git add -e技巧应该可以工作。

如果您想直接在shell中运行它们,而不创建Git 别名,复制粘贴双引号之间的所有内容 (假设您的shell类似Bash)。

修正索引,但不修正树

以下修复Git别名修复索引中的所有空白错误, 如果有,但不碰树:

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

这个想法是在git提交之前运行git fixws 索引中的空白错误。

修正索引和树

下面的fixws-global-tree-and-index Git别名修复所有空白 索引和树中的错误(如果有的话):

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

若要修复未版本控制文件中的空白,请执行

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

简单但不健壮的解决方案

这些版本更容易复制和粘贴,但他们不做 如果他们的条件不满足,这是正确的。

修复当前目录下的子树(但如果不为空则重置索引)

使用git add -e使用身份编辑器“编辑”补丁::

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

修复并保存索引(但如果树是脏的或索引为空则失败)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

修复树和索引(但如果索引不为空则重置索引)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

export GIT_EDITOR=: && git -c apply的解释。空格=fix add -ue。技巧

在我从这个答案中了解git rebase -whitespace=fix技巧之前,我在任何地方都使用更复杂的git添加技巧。

如果我们手动操作:

Set apply.whitespace to fix (you only have to do this once): git config apply.whitespace fix This tells Git to fix whitespace in patches. Convince Git to treat your changes as a patch: git add -up . 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: git checkout . Bring back your changes (if you aren't ready to commit them): git reset

GIT_EDITOR=:表示使用:作为编辑器和命令 :是恒等式。

要删除文件中行尾的空格,使用ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file

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

请试试我的预提交钩子。它可以自动检测尾随空白并删除它。

它可以在Git Bash (Windows), Mac OS X和Linux下工作!


快照:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)

文件的for循环使用$IFS shell变量。 在给定的脚本中,包含$ ifs变量中的字符的文件名将被视为for循环中的两个不同文件。

这个脚本修复了它:sed手册中给出的多行模式修饰符似乎在我的Ubuntu盒子上默认不工作,所以我寻找了一个不同的实现,并发现了一个迭代标签,本质上它只会在文件的最后一行开始替换,如果我正确理解它。

#!/bin/sh
#

# A Git hook script to find and fix trailing white space
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

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

SAVEIFS="$IFS"
# only use new-line character as separator, introduces EOL-bug?
IFS='
'
# Find files with trailing white space
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one (Mac OS X version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to Git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# Exit script with the exit-code of git's check for white space characters
exec git diff-index --check --cached $against --

如何使用sed替换换行符(\n) ?