Jak zastąpić tekst z plików w historii Gita?

Zawsze używałem klienta git opartego na interfejsie (smartGit) i dlatego nie mam dużego doświadczenia z konsolą git.

Jednak teraz stoję przed potrzebą zastąpienia łańcucha we wszystkich .pliki txt z historii (czyli nie kasowanie całego pliku, a jedynie podstawianie ciągu znaków). Znalazłem następujące polecenie:

git filter-branch --tree-filter 'git ls-files -z "*.php" |xargs -0 perl -p -i -e "s#(PASSWORD1|PASSWORD2|PASSWORD3)#xXxXxXxXxXx#g"' -- --all

Próbowałem tego i niestety zauważyłem, że podczas gdy hasło zostało zmienione, wszystkie pliki binarne zostały uszkodzone. Obrazy itp. wszystko będzie zepsute.

Jest czy istnieje lepszy sposób, aby to zrobić, który nie uszkodzi moich plików binarnych?

Dzięki.

EDIT:

Coś mi się pomieszało. Rzeczywisty kod, który spowodował uszkodzenie plików binarnych, to:
$ git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/originalpassword/newpassword/g' {} \;"

KOD u góry faktycznie usunął {[20] } wszystkie pliki z moim hasłem.

Author: Roberto Tyley, 2010-11-06

4 answers

Możesz uniknąć dotykania niepożądanych plików, przechodząc -name "pattern" do find.

To działa dla mnie:

git filter-branch --tree-filter "find . -name '*.php' -exec sed -i -e \
    's/originalpassword/newpassword/g' {} \;"
 31
Author: jweyrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-06 17:04:27

Zalecałbym użycie BFG Repo-Cleaner, prostszej i szybszej alternatywy dla git-filter-branch specjalnie zaprojektowanej do przepisywania plików z historii Gita.

Należy uważnie wykonać następujące kroki tutaj: https://rtyley.github.io/bfg-repo-cleaner/#usage - ale bit rdzenia jest taki: Pobierz BFG ' s jar (wymaga Javy 7 lub wyższej) i uruchom następujące polecenie:

$ java -jar bfg.jar  --replace-text replacements.txt -fi *.php  my-repo.git

Plik replacements.txt powinien zawierać wszystkie zastępstwa, które chcesz wykonać, w formacie takim jak ten (jeden wpis na linijkę-Uwaga komentarze nie powinny być dołączane):

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

Cała historia repozytorium zostanie zeskanowana, a pliki .php (O rozmiarze poniżej 1MB) będą miały wykonane zastępowania: każdy pasujący ciąg znaków (który nie znajduje się w ostatnim zatwierdzeniu ) zostanie zastąpiony.

pełne ujawnienie: jestem autorem BFG Repo-Cleaner.

 63
Author: Roberto Tyley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-28 21:06:45

Utworzyłem plik w /usr/local/git/findsed.sh , o następującej treści:

find . -name 'githubDirToSubmodule.sh' -exec sed -i '' -e 's/What I want to remove//g' {} \;

Uruchomiłem komendę:

git filter-branch --tree-filter "sh /usr/local/git/findsed.sh"

Wyjaśnienie poleceń

Kiedy uruchamiasz git filter-branch, przechodzi to przez każdą rewizję, którą kiedykolwiek popełniłeś, jedna po drugiej. -- tree-filter uruchamia findsed.sh skrypt przy każdej zatwierdzonej rewizji, zapisuje ją, a następnie przechodzi do następnej rewizji.

Polecenie find wyszukuje określony plik lub zestaw plików i wykonuje (- exec) sed edytor tego pliku. sed jest poleceniem, które pobiera Wyrażenie regularne PO s / i zastępuje je ciągiem pomiędzy / i / g(puste w moim przykładzie). {} jest odniesieniem do ścieżki plików, która została podana przez polecenie find. Ścieżka pliku jest przekazywana do sed, aby sed wiedział, nad czym pracować. \ ; kończy polecenie-exec.

Rozdzielenie skryptu powłoki i polecenia na oddzielne kawałki pozwala na mniej komplikacji, jeśli chodzi o cudzysłowy "lub"".

Osobliwości

I udało się to zaimplementować na Macu, a widocznie sed jest konkretny (starszy?) wersja na Macach. Ma to znaczenie, ponieważ czasami zachowuje się inaczej. Upewnij się, że robisz sed-i", albo dodajesz "- e " na końcu plików, myśląc, że tak chciałem nazwać moje pliki kopii zapasowych. - i " mówi dont tworzenia kopii zapasowych plików, po prostu Edytuj pliki w miejscu i nie Plik kopii zapasowej potrzebne.

Określenie-nazwa "filename.sh" pomógł mi uniknąć kolejnego problemu, którego nie mogłem rozwiązać. Był inny Plik z .sh i ten plik zakończył się bez znaku nowej linii. sed z jakiegoś powodu dodałby znak nowej linii na końcu, mimo że' s/bla/bla / g ' nie pasuje do niczego w tym pliku. Więc zamiast rozgryźć ten problem, po prostu powiedziałem znalezisku, aby zignorował wszystkie inne pliki.

Dodatkowe polecenia działające

Dodatkowo znalazłem te polecenia do pracy w findsed.sh plik (tylko jedno polecenie na raz, a nie multple, więc skomentuj # Pozostałe out): {]}

find . -name '.publishNewZenPackFromGithub.sh.swp' -exec rm -f {} \;
find . -name '*' -exec grep -H PassToRemove {} \;
Smacznego!
 4
Author: Nay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-03 18:57:38

Może to być problem z rozszerzeniem powłoki. Jeśli filter-branch traci cudzysłowy wokół "*.php" w czasie, gdy wykonuje polecenie, może rozszerzyć się do zera, więc git ls-files -z wypisuje wszystkie pliki.

Możesz sprawdzić źródło filter-branch lub wypróbować różne sztuczki cytowania, ale zrobiłbym tylko jednolinijkowy skrypt powłoki, który robi twój tree-filter i zamiast tego przekazał ten skrypt.

 1
Author: Ben Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-05 22:56:52