Ответ 1
Вы можете избежать касания нежелательных файлов, передав -name "pattern"
в find
.
Это работает для меня:
git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
's/originalpassword/newpassword/g' {} \;"
Я всегда использовал клиентский интерфейс git на основе интерфейса (smartGit) и, таким образом, не имел большого опыта работы с консолью git.
Однако теперь мне приходится заменять строку во всех файлах .txt из истории (поэтому, не удаляя весь файл, а просто заменяя строку). Я нашел следующую команду:
git filter-branch --tree-filter 'git ls-files -z "*.php" |xargs -0 perl -p -i -e "s#(PASSWORD1|PASSWORD2|PASSWORD3)#xXxXxXxXxXx#g"' -- --all
Я попробовал это и, к сожалению, заметил, что, хотя пароль и изменился, все двоичные файлы были повреждены. Изображения и т.д. Будут повреждены.
Есть ли лучший способ сделать это, что не повредит мои двоичные файлы?
Спасибо.
EDIT:
Я что-то перепутал. Фактический код, из-за которого повреждены двоичные файлы, был:
$ git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/originalpassword/newpassword/g' {} \;"
Код наверху действительно удалил все файлы с моим паролем странно.
Вы можете избежать касания нежелательных файлов, передав -name "pattern"
в find
.
Это работает для меня:
git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
's/originalpassword/newpassword/g' {} \;"
Я бы рекомендовал использовать BFG Repo-Cleaner, более быструю и быструю альтернативу git-filter-branch
, специально предназначенную для перезаписи файлов из истории Git.
Вы должны внимательно выполнить следующие шаги здесь: https://rtyley.github.io/bfg-repo-cleaner/#usage - но бит ядра - это просто: загрузите BFG jar (требуется Java 7 или выше) и выполните следующую команду:
$ java -jar bfg.jar --replace-text replacements.txt -fi *.php my-repo.git
Файл replacements.txt
должен содержать все подстановки, которые вы хотите сделать, в таком формате (по одной записи в строке - обратите внимание, что комментарии не должны быть включены):
PASSWORD1 # Replace literal string 'PASSWORD1' with '***REMOVED***' (default)
PASSWORD2==>examplePass # replace with 'examplePass' instead
PASSWORD3==> # replace with the empty string
regex:password=\w+==>password= # Replace, using a regex
regex:\r(\n)==>$1 # Replace Windows newlines with Unix newlines
Вся ваша история репозитория будет отсканирована, а .php
файлы (размером менее 1 МБ) будут иметь выполненные замены: любая соответствующая строка (которая не находится в последнем фиксации) будет заменена.
Полное раскрытие: я являюсь автором BFG Repo-Cleaner.
Я создал файл в /usr/local/ git/findsed.sh со следующим содержимым:
find . -name 'githubDirToSubmodule.sh' -exec sed -i '' -e 's/What I want to remove//g' {} \;
Я выполнил команду:
git filter-branch --tree-filter "sh /usr/local/git/findsed.sh"
Объяснение команд
Когда вы запускаете ветвь git filter-branch, это проходит через каждую ревизию, которую вы когда-либо совершали, один за другим. --tree-filter запускает finded.sh script для каждой фиксированной версии, сохраняет его, а затем переходит к следующей ревизии.
Команда find находит определенный файл или набор файлов и выполняет (-exec) редактор sed в этом файле. sed - команда, которая принимает регулярное выражение после s/и заменяет его строкой между/и/g (пустой в моем примере). {} является ссылкой на путь файлов, который был задан командой find. Путь к файлу передается sed, так что sed знает, над чем работать. \; просто завершает команду -exec.
Отделяя оболочку script и выставляя команду на отдельные части, это позволяет сделать меньше осложнений, когда дело доходит до цитат '' или "".
Особенности
Я успешно реализовал это на mac, и, по-видимому, sed является конкретной (более старой?) версией для mac. Это имеет значение, поскольку оно иногда ведет себя по-разному. Не забудьте сделать sed -i '', иначе он добавит "-e" в конец файлов, думая, что это то, что я хотел назвать мои файлы резервных копий. -i '' говорит, что не делайте резервные файлы, просто редактируйте файлы на месте и не нужно делать резервный файл.
Задание-name 'filename.sh' помогло мне избежать другой проблемы, которую я не мог решить. Был еще один файл с .sh, и этот файл закончился без символа новой строки. sed по какой-то причине добавит символ новой строки в конец, несмотря на то, что 's/blah/blah/g' не соответствует чему-либо в этом файле. Поэтому вместо того, чтобы разобраться с этой проблемой, я просто сказал find, чтобы игнорировать все остальные файлы.
Дополнительные команды, которые работают
Кроме того, я обнаружил, что эти команды работают в файле founded.sh(только одна команда за раз, а не multple, поэтому комментарий # остальные):
find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;
Наслаждайтесь!
Может быть проблемой расширения оболочки. Если ветвь фильтра теряет кавычки вокруг "*.php"
к тому времени, когда она оценивает команду, она может расширяться до нуля, таким образом git ls-files -z
перечисляет все файлы.
Вы можете проверить источник ветки фильтра или попробовать разные трюки с кавычками, но я бы просто сделал однострочную оболочку script, которая выполняет ваш древовидный фильтр и передает вместо этого script.
С Git 2.24 (Q4 2019), git filter-branch
(и BFG) устарела.
Эквивалент будет, используя newren/git-filter-repo
и его пример раздела:
cd repo
git filter-repo --path-glob '*.txt' --replace-text expressions.txt
с expressions.txt
:
literal:originalpassword=>newpassword