Подтвердить что ты не робот

Как заменить текст из файлов в истории 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' {} \;"

Код наверху действительно удалил все файлы с моим паролем странно.

4b9b3361

Ответ 1

Вы можете избежать касания нежелательных файлов, передав -name "pattern" в find.

Это работает для меня:

git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
    's/originalpassword/newpassword/g' {} \;"

Ответ 2

Я бы рекомендовал использовать 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.

Ответ 3

Я создал файл в /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 {} \;

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

Ответ 4

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

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