bashgitgit-commitgitattributes

How to configure Git to remove certain lines before commit, for both local files and commit?


Because of a tool that I use, certain comment lines keeps being added to my code.

// Added by blahblah

Since I can't turn off this behavior, I want to configure Git to automatically remove that comment line from both local file and commit.

I want to configure Git to do these:

  1. Remove // Added by blahblah comment lines
    There can be multiple Tab or Space in front of the comments I want to remove.
    The comments must be removed for both local files and commit.
  2. Re-stage modified files
    I'm not sure if this is needed or not, but if it is needed, it should do so.

So, after Git completes its job, the comment lines must be removed from both local file and commit (and remote repository too).


First thing I've tried was using IDEA's File Watchers plugin.

If I register a script that removes that comment line, the problem would be solved because the comment line is removed before Git creates commit and the commit won't have that comment line.
So 'No comment in local file, No comment in commit too'.

I wrote a bash script for it.

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

But File Watchers kept running when I enable my watcher task.
I expected the task to be run only once for every file save, but it kept running infinitely.
Because File Watchers task is executed every seconds, it conflicted with currently opened editor's content. This prevented me to edit code at all.

So I gave up using File Watchers plugin.


Next thing I've tried was using Git Hooks.

In my theory, if I set Git Hooks correctly, Git would edit my local files before making any commit. Since my local files are edited before commit, both local files and files in the commit won't have such comment lines.

I wrote prepare-commit-msg like this.

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

But nothing were changed as if there was no such hook present. pre-commit also didn't work.

Here is updated version of the prepare-commit-msg, but this doesn't work either.

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

Last thing I've tried was to use .gitattributes's filter.

I added these line into .gitconfig.

[filter "nocomment"]
    clean = "sed -i -e '/^[[:space:]]*\\/\\/ Added by blahblah/d' %f"
    smudge = ""
    required = true

And this line to .gitattributes.

*.java filter=nocomment

Since I only need to 'remove' lines, not 'restore' them, I left smudge as empty.

But this didn't remove the comment line from local file. Git might remove that line for commit, but that's not what I want.

(I'm using Git for Windows, and this might be the reason of something doesn't work properly...?)


Here is working pre-commit script's content.

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

The reason that Git hooks didn't run as if they weren't present was I set git config --global core.hooksPath before. This prevented hooks in .git/hooks from running...

Now everything works as intended. Thank you!


Solution

  • I'm not going to comment on the IDEA FileWatcher plugin, because an IDE is not a substitute for proper automation.

    Next thing I've tried was using Git Hooks.

    These are well-documented, here.

    I wrote prepare-commit-msg like this

    But the linked docs explicitly say

    It should not be used as replacement for pre-commit hook.

    It's just for altering the message, after the staged changes are final. Let's pretend you wrote your script as the correct hook instead, pre-commit.

    There are a few mistakes in both of your attempts, but you could have debugged them all quickly by adding set -x at the top and just running the script. You don't need git to invoke it for you, just test it yourself.

    If we combine the unbroken parts of both, it is only missing one thing: you changed the working tree, but didn't stage your changes for inclusion in the commit.

    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
    

    Proof:

    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 $