如何配置Git在提交之前删除特定行,无论是本地文件还是提交?

3
因为我使用的工具,某些注释行不断被添加到我的代码中。
// Added by blahblah

由于我无法关闭这个行为,我想要配置Git以自动从本地文件和提交中删除该注释行。

我想要配置Git执行以下操作:

  1. 删除// Added by blahblah注释行
    注释行前面可以有多个制表符或空格。
    这些注释必须同时从本地文件和提交中删除。
  2. 重新暂存修改过的文件
    我不确定是否需要这样做,但如果需要,应该这样操作。

因此,在Git完成其任务后,注释行必须从本地文件和提交中删除(还包括远程代码库)。


首先我尝试使用IDEA的File Watchers插件。
如果我注册一个移除注释行的脚本,问题就会解决,因为在Git创建提交之前,注释行会被移除,提交中就不会有那个注释行了。 所以说'本地文件没有注释,提交也没有注释'。
我为此编写了一个bash脚本。
#!/bin/bash
# this script is located at '.script' directory
scriptdir="$(dirname -- "$0")"
cd "$scriptdir/../src" || exit

java_files=$(find . -type f -name "*.java")

for java_file in $java_files; do
  sed -i '/^[[:space:]]*\/\/ Added by blahblah/d' "$java_file"
done

但是当我启用我的观察者任务时,文件观察器仍然在运行。 我期望任务只会在每次保存文件时运行一次,但它却无限运行。 由于文件观察器任务每秒执行一次,它与当前打开的编辑器内容发生冲突。这导致我无法编辑代码。 所以我放弃使用文件观察器插件。
下一件我尝试过的事情是使用Git Hooks。
根据我的理论,如果我正确设置了Git Hooks,Git会在进行任何提交之前编辑我的本地文件。由于在提交之前编辑了本地文件,因此提交中的文件和本地文件都不会有这样的注释行。
我像这样编写了`prepare-commit-msg`。
#!/bin/bash
# this script is located at '.git/hooks' directory
print "$PWD"
scriptdir="$(dirname -- "$0")"
cd "$scriptdir/../../src" || exit
echo "$PWD"
java_files=$(find . -type f -name "*.java")

for java_file in $java_files; do
  sed -i '/^[[:space:]]*\/\/ Added by blahblah/d' "$java_file"
done

但是好像什么都没有改变,就好像没有这样的钩子存在一样。`pre-commit`也没有起作用。
这是更新版本的`prepare-commit-msg`,但是这个也不起作用。
#!/bin/bash

TMP_FILE=$(mktemp)

for FILE in $(git diff --cached --name-only --diff-filter=AM); do
  if [[ $FILE == *.java ]]; then
    sed -e '/^[[:space:]]*\/\/ Added by blahblah/d' "$FILE" > "$TMP_FILE"
    cat "$TMP_FILE" > "$FILE"
    git add "$FILE"
    # This doesn't work neither
    #sed -i -e '/^[[:space:]]*\/\/ Added by blahblah/d' "$FILE"
    #git add "$FILE"
  fi
done

exit 0

我最后尝试的是使用`.gitattributes`的`filter`。
我将这些行添加到了`.gitconfig`中。
[filter "nocomment"]
    clean = "sed -i -e '/^[[:space:]]*\\/\\/ Added by blahblah/d' %f"
    smudge = ""
    required = true

将这行代码添加到.gitattributes文件中。
*.java filter=nocomment

由于我只需要“删除”行而不是“恢复”它们,所以我将smudge留空。
但这并没有从本地文件中删除注释行。Git可能会在提交时删除该行,但这不是我想要的。
(我正在使用Git for Windows,这可能是某些功能无法正常工作的原因...?)
这是工作中的pre-commit脚本内容。
#!/bin/bash
set -x # This thing is new... Thanks for the information!
for FILE in $(git diff --cached --name-only --diff-filter=ACM); do # '--diff-filter' is needed
  if [[ $FILE == *.java ]]; then # I only have to process java file
    echo Removing comment from ${FILE}
    sed -i '/^[[:space:]]*\/\/ Added by blahblah/d' "$FILE"
    git add "$FILE" # This line was already in second attempt
  fi
done

Git钩子没有运行的原因是我之前设置了git config --global core.hooksPath。这会阻止.git/hooks中的钩子运行...
现在一切都按预期工作了。谢谢!

你的过滤器对我很有效。我创建了一个新的测试仓库,将你的过滤器描述(直接从你的问题中复制)添加到.git/config文件中,创建了一个包含内容*.txt filter=nocomment.gitattributes文件,创建了一个xxx.txt文件,其中随机内容与// Added by blahblah的注释交错出现,并提交了该文件。所有的注释都从本地文件中消失了(我必须承认我没有检查提交的文件)。 - phd
@phd 这非常奇怪,因为我遇到了一些错误提示:sed: 无法重命名 src/sedUcOsWa: 设备或资源忙error: 外部过滤器 'sed -i -e '/^[[:space:]]*\/\/ Added by blahblah/d' %f' 失败了 4 - tetratheta
1
prepare-commit-msg用于设置提交信息,而不是修改暂存文件。文档明确表示它不应作为pre-commit钩子的替代品。 - Useless
当您设置了如上所示的pre-commit钩子后,输出是什么?您打印了很多状态信息,但没有与我们分享任何内容。 - Useless
@Useless 这是因为实际上没有什么可以分享的内容。就像输出信息告诉我提交已完成一样,例如 [main 57c993d] test21个文件已更改,插入了1行,删除了1行,这就是我得到的全部信息。没有错误消息,提交也没有被中止等等。但是我想要删除的注释行仍然存在。 - tetratheta
显示剩余2条评论
1个回答

0

我不会对 IDEA FileWatcher 插件发表评论,因为 IDE 不能替代适当的自动化。

接下来我尝试使用 Git Hooks。

这些都有很好的文档 在这里

我写了类似这样的 prepare-commit-msg

但链接的文档明确说

它不应该被用作 pre-commit 钩子的替代。

它只是用于在暂存更改最终完成后修改消息。假设你将你的脚本写成正确的钩子,即 pre-commit

你两次尝试中都有一些错误,但你可以通过在顶部添加 set -x 并运行脚本来快速调试所有问题。你不需要依赖 git 来调用它,可以自己测试它。

如果我们合并两段连续的部分,只缺少一件事:你改变了工作树,但没有将更改暂存以包含在提交中。

useless@stackoverflow:~/Source/so/pchook $ cat .git/hooks/pre-commit
#!/bin/sh
#
set -x
for FILE in $(git diff --cached --name-only)
do
  sed -i '/^[[:space:]]*\/\/ Added by blahblah/d' "$FILE"
  git add "$FILE" ### this was missing
done

证明:

useless@stackoverflow:~/Source/so/pchook $ git diff
diff --git a/test.txt b/test.txt
index f2affac..d8767dd 100644
--- a/test.txt
+++ b/test.txt
@@ -5,7 +5,7 @@ should be
 unaffected // or with comments excluding the special phrase
 // added by "blahblah"
 except without quotes. // like // Added by blahblah
-
+    // Added by blahblah
 EOF or something
 
 
useless@stackoverflow:~/Source/so/pchook $ git commit -am'test'
+ git diff --cached --name-only
+ sed -i /^[[:space:]]*\/\/ Added by blahblah/d test.txt
+ git add test.txt
[master 7ba7949] test
 1 file changed, 1 deletion(-)
useless@stackoverflow:~/Source/so/pchook $ git show HEAD
commit 7ba79490edbf9afc54ac5e4458323f25803ddba3 (HEAD -> master)
Author: Useless <useless@stackoverflow.com>
Date:   Wed Aug 16 21:23:45 2023 +0100

    test

diff --git a/test.txt b/test.txt
index f2affac..66b45b6 100644
--- a/test.txt
+++ b/test.txt
@@ -5,7 +5,6 @@ should be
 unaffected // or with comments excluding the special phrase
 // added by "blahblah"
 except without quotes. // like // Added by blahblah
-
 EOF or something
 
 
useless@stackoverflow:~/Source/so/pchook $ 

我之前设置了 git config --global core.hooksPath,这就是为什么我的 Git 钩子没有起作用的原因。我已经更新了关于“工作脚本”的问题。非常感谢! - tetratheta

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