Из-за инструмента, который я использую, в мой код постоянно добавляются определенные строки комментариев.
// Added by blahblah
Поскольку я не могу отключить это поведение, я хочу настроить Git для автоматического удаления этой строки комментария как из локального файла, так и из коммита.
Я хочу настроить Git для этого:
// Added by blahblah
строки комментариевИтак, после того, как 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
Но наблюдатели за файлами продолжали работать, когда я включаю свою задачу наблюдателя.
Я ожидал, что задача будет запускаться только один раз для каждого сохранения файла, но она продолжала работать бесконечно.
Поскольку задача File Watchers выполняется каждую секунду, она конфликтует с текущим открытым содержимым редактора. Это мешало мне редактировать код вообще.
Поэтому я отказался от использования плагина File Watchers.
Следующим, что я попробовал, было использование 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
's filter
.
Я добавил эту строку в .gitconfig
.
[filter "nocomment"]
clean = "sed -i -e '/^[[:space:]]*\/\/ Added by blahblah/d' %f"
smudge = ""
required = true
И эта строка в .gitattributes
.
*.java filter=nocomment
Поскольку мне нужно только «удалить» строки, а не «восстановить» их, я оставил smudge
пустым.
Но это не удалило строку комментария из локального файла. Git может удалить эту строку для фиксации, но я этого не хочу.
(Я использую Git для 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
, создал .gitattributes
с содержимым *.txt filter=nocomment
, создал xxx.txt
файл со случайным содержимым, чередующимся с // Added by blahblah
комментариями с пробелами и вкладками, и зафиксировал файл . Все комментарии исчезли из локального файла (признаюсь, я не проверял зафиксированный).
@GaëlJ Я обновил вопрос для другого сценария крючка prepare-commit-msg
. К сожалению, несмотря на то, что я проверил вывод какой-то строки, это не сработало.
@phd Это очень странно, потому что я получаю сообщение об ошибке: sed: cannot rename src/sedUcOsWa: Device or resource busy
и error: external filter 'sed -i -e '/^[[:space:]]*// Added by blahblah/d' %f' failed 4
.
prepare-commit-msg
предназначен для настройки сообщения, а не для изменения промежуточных файлов. В документации даже прямо сказано, что его не следует использовать в качестве замены хука перед фиксацией.
Когда вы настроили хук pre-commit
, как показано, что получилось на выходе? Вы напечатали много состояния, но не поделились с нами
@Useless Это потому, что действительно нечем было поделиться. Точно так же, как выходное сообщение о том, что коммит выполнен, например [main 57c993d] test2
, 1 file changed, 1 insertion(+), 1 deletion(-)
, и это все, что я получаю. Нет сообщения об ошибке, фиксация не была прервана и т. д. Но строки комментариев, которые я хочу удалить, все еще там.
Я не буду комментировать плагин 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 <[email protected]>
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 не работали. Я обновил вопрос для «рабочего сценария». Большое спасибо!
Я бы больше смотрел в сторону хука git, чтобы понять, почему он не работает.