Как заменить текст из файлов в истории git?

Я всегда использовал интерфейс на основе 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' {} ;"

код в верхней части на самом деле удалены все файлы с моим паролем, как ни странно.

4 ответов


вы можете избежать прикосновения к нежелательным файлам, передавая -name "pattern" to 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 - но основной бит таков: загрузите банка БДВ (требуется 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)==>               # Replace Windows newlines with Unix newlines

вся история репозитория будет отсканирована, и .php файлы (размером менее 1 МБ) будут иметь выполненные замены: любая соответствующая строка (которая не находится в вашем последний commit) будет заменен.

полное раскрытие информации: я автор РЕПО-очистителя BFG.


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

команда find находит определенный файл или набор файлов и выполняет (- exec) редактор sed на этом файле. sed-это команда, которая принимает регулярное выражение после s / и заменяет его строкой между /и / g (пустой в моем примере). {}- ссылка на путь к файлам, заданный командой find. Путь к файлу подается в sed, чтобы sed знал, над чем работать. \; просто завершает команду-exec.

разделение сценария оболочки и команды на отдельные части позволяет меньше осложнений, когда дело доходит до кавычек " или "".

особенности

я успешно реализовал это на mac, и, по-видимому, sed является конкретным (старше?) версия на Mac. Это имеет значение, так как иногда ведет себя по-другому. Обязательно сделайте sed-i ", или он добавлял "- e " в конец файлов, думая, что это то, что я хотел назвать мои резервные файлы. - я " говорит, Не делайте резервные копии файлов, просто отредактируйте файлы на месте и не требуется файл резервной копии.

указание-name 'filename.sh" помог мне избежать еще одной проблемы, которую я не смог решить. Был еще один файл .sh и этот файл закончился без символа новой строки. sed по какой-то причине добавит символ новой строки в конец, несмотря на то, что "S/blah/blah/g" ничего не соответствует в этом файле. Поэтому вместо того, чтобы выяснить эту проблему, я просто сказал find игнорировать все другие файлы.

дополнительные команды, которые работают

кроме того, я нашел эти команды для работы в findsed.sh напильник (только одна команда за раз, а не multple, поэтому прокомментируйте # другие):

find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;

наслаждайтесь!


может быть проблема расширения оболочки. Если filter-branch теряет кавычки вокруг "*.php" к тому времени, когда он оценивает команду, она может расширяться до ничего, таким образом git ls-files -z список всех файлов.

вы можете проверить источник ветви фильтра или попробовать разные трюки цитирования, но я бы просто сделал однострочный сценарий оболочки, который делает ваш древовидный фильтр и передает этот скрипт вместо этого.