Как настроить Git для удаления определенных строк перед фиксацией как для локальных файлов, так и для фиксации?

Из-за инструмента, который я использую, в мой код постоянно добавляются определенные строки комментариев.

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

Но наблюдатели за файлами продолжали работать, когда я включаю свою задачу наблюдателя.
Я ожидал, что задача будет запускаться только один раз для каждого сохранения файла, но она продолжала работать бесконечно.
Поскольку задача 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, чтобы понять, почему он не работает.

Gaël J 16.08.2023 20:19

Ваши фильтры работают на меня. Я создал новый тестовый репозиторий, добавил описание вашего фильтра (только что скопированное с помощью мыши из вашего вопроса) в .git/config, создал .gitattributes с содержимым *.txt filter=nocomment, создал xxx.txt файл со случайным содержимым, чередующимся с // Added by blahblah комментариями с пробелами и вкладками, и зафиксировал файл . Все комментарии исчезли из локального файла (признаюсь, я не проверял зафиксированный).

phd 16.08.2023 20:51

@GaëlJ Я обновил вопрос для другого сценария крючка prepare-commit-msg. К сожалению, несмотря на то, что я проверил вывод какой-то строки, это не сработало.

tetratheta 16.08.2023 21:13

@phd Это очень странно, потому что я получаю сообщение об ошибке: sed: cannot rename src/sedUcOsWa: Device or resource busy и error: external filter 'sed -i -e '/^[[:space:]]*// Added by blahblah/d' %f' failed 4.

tetratheta 16.08.2023 21:14
prepare-commit-msg предназначен для настройки сообщения, а не для изменения промежуточных файлов. В документации даже прямо сказано, что его не следует использовать в качестве замены хука перед фиксацией.
Useless 16.08.2023 21:29

Когда вы настроили хук pre-commit, как показано, что получилось на выходе? Вы напечатали много состояния, но не поделились с нами

Useless 16.08.2023 21:30

@Useless Это потому, что действительно нечем было поделиться. Точно так же, как выходное сообщение о том, что коммит выполнен, например [main 57c993d] test2, 1 file changed, 1 insertion(+), 1 deletion(-), и это все, что я получаю. Нет сообщения об ошибке, фиксация не была прервана и т. д. Но строки комментариев, которые я хочу удалить, все еще там.

tetratheta 16.08.2023 21:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
7
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не буду комментировать плагин 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 не работали. Я обновил вопрос для «рабочего сценария». Большое спасибо!

tetratheta 17.08.2023 05:25

Другие вопросы по теме