Wie ersetze ich eine Zeichenfolge im gesamten Git-Verlauf?

Lesezeit: 7 Minuten

Benutzeravatar von Karol Selak
Karl Selak

Ich habe eines meiner Passwörter in wahrscheinlich wenigen Dateien in meinem Git-Repo festgeschrieben. Gibt es eine Möglichkeit, dieses Passwort automatisch durch eine andere Zeichenfolge im gesamten Verlauf zu ersetzen, damit es keine Spur davon gibt? Idealerweise könnte ich ein einfaches Bash-Skript schreiben, das Zeichenfolgen zum Suchen und Ersetzen empfängt und die ganze Arbeit selbst erledigt, so etwas wie:

./replaceStringInWholeGitHistory.sh "my_password" "xxxxxxxx"

Bearbeiten: Diese Frage ist kein Duplikat dieser Frage, da ich nach dem Ersetzen von Zeichenfolgen frage, ohne ganze Dateien zu entfernen.

  • Es kann getan werden. Haben Sie Ihr Repo auf einem Remote-Server (Github, Gitlab, andere …) veröffentlicht? Gibt es andere Personen, die damit arbeiten?

    – Technik

    26. Oktober 2017 um 9:42 Uhr

  • Mögliches Duplikat von Entfernen Sie vertrauliche Dateien und ihre Commits aus dem Git-Verlauf

    – kowsky

    26. Oktober 2017 um 9:44 Uhr

  • Um genau zu sein, dies ist unser Firmenkonto, nur wenige Leute haben Zugriff darauf, und wir verwenden ein internes GitHub-Repo auf einem eigenen Server. Aber im Allgemeinen wird jeder Person, die Zugang zu Repos hat, vorerst vertraut.

    – Karol Selak

    26. Oktober 2017 um 9:46 Uhr

Benutzeravatar von ElpieKay
ElpieKay

Suchen Sie zuerst alle Dateien, die das Passwort enthalten könnten. Angenommen, das Passwort ist abc123 und der Zweig ist master. Möglicherweise müssen Sie diese Dateien ausschließen abc123 nur als normale Saite.

git log -S "abc123" master --name-only --pretty=format: | sort -u

Ersetzen Sie dann “abc123” durch “******”. Angenommen, eine der Dateien ist foo/bar.txt.

git filter-branch --tree-filter "if [ -f foo/bar.txt ];then sed -i s/abc123/******/g foo/bar.txt;fi"

Zum Schluss Druck erzwingen master zum Remote-Repository, falls vorhanden.

git push origin -f master:master

Ich habe einen einfachen Test gemacht und es hat funktioniert, aber ich bin mir nicht sicher, ob es in Ihrem Fall in Ordnung ist. Sie müssen sich mit allen Dateien aus allen Zweigen befassen. Was die Tags betrifft, müssen Sie möglicherweise alle alten löschen und neue erstellen.

  • Hm, okay, es funktioniert für den eigentlichen Zweig, aber da ich mehr habe, muss ich das wahrscheinlich für jeden von ihnen tun.

    – Karol Selak

    26. Oktober 2017 um 10:40 Uhr

  • Ich habe ein Problem mit anderen Zweigen als dem Master. Wenn ich es versuche git log -S "abc123" test --name-only --pretty=format: | sort -u Ich bekomme Fehler: fatal: ambiguous argument 'test': both revision and filename. Kann ich das irgendwie vermeiden?

    – Karol Selak

    6. November 2017 um 17:05 Uhr

  • @KarolSelak Der Fehler besagt, dass Sie einen Ref namens haben test und auch eine Datei namens test. Es ist ein Namenskonflikt. Wenn Sie erwarten, dass Git interpretiert test als ref, dann verwenden git log -S "abc123" test --name-only --pretty=format: -- | sort -u. Wenn es als Datei interpretiert wird, verwenden Sie git log -S "abc123" --name-only --pretty=format: -- test | sort -u. Wenn du beides brauchst, dann git log -S "abc123" test --name-only --pretty=format: -- test | sort -u. Es gibt Räume um die --. Sehen git-scm.com/docs/gitcli#_description für mehr.

    – ElpieKay

    6. November 2017 um 22:57 Uhr


  • Vielen Dank, endlich habe ich geschrieben, was ich brauche, aber das ist hauptsächlich Ihr Verdienst. Ich hoffe, dass diese endgültige Lösung anderen noch lange dienen wird 🙂

    – Karol Selak

    7. November 2017 um 12:47 Uhr


  • @KarolSelak Freut mich, dass es hilft =). Vergessen Sie nicht, gepushte Tags zu löschen und neu zu erstellen. Sie verweisen immer noch auf die alten Commits, die möglicherweise Ihr Passwort enthalten.

    – ElpieKay

    7. November 2017 um 13:08 Uhr


Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

git filter-repo --replace-text

Git2.25 man git-filter-branch empfiehlt bereits klar die Verwendung git filter-repo anstatt git filter-treeAuf geht’s.

Installieren https://superuser.com/questions/1563034/how-do-you-install-git-filter-repo/1589985#1589985

python3 -m pip install --user git-filter-repo

und dann verwenden:

echo 'my_password==>xxxxxxxx' > replace.txt
git filter-repo --replace-text replace.txt

oder gleichwertig mit Bash-Magie:

git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')

Getestet mit diesem einfachen Test-Repository: https://github.com/cirosantilli/test-git-filter-repository und Ersatzsaiten:

d1==>asdf
d2==>qwer

Das obige wirkt standardmäßig auf alle Zweige (so invasiv!!!), um nur auf ausgewählte Zweige zu wirken, verwenden Sie: git filter-repo: kann es auf einem bestimmten Zweig verwendet werden? z.B:

--refs HEAD
--refs refs/heads/master

Die Option --replace-text Option ist dokumentiert unter: https://github.com/newren/git-filter-repo/blob/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/Documentation/git-filter-repo.txt#L155

–replace-text ::

Eine Datei mit Ausdrücken, die, wenn sie gefunden werden, ersetzt werden. Standardmäßig wird jeder Ausdruck als wörtlicher Text behandelt, aber
regex: und glob: Präfixe werden unterstützt. Sie können die Zeile mit beenden ==> und etwas Ersatztext, um eine andere Ersatzoption als die Standardeinstellung auszuwählen ***REMOVED***.

Sobald Sie ein Passwort öffentlich weitergegeben haben, ist es natürlich immer zu spät und Sie müssen das Passwort ändern, also würde ich mich in diesem Fall nicht einmal um das Ersetzen kümmern: Entfernen Sie vertrauliche Dateien und ihre Commits aus dem Git-Verlauf

Verwandte: Wie ersetzt man Text aus Dateien im Git-Verlauf?

Getestet auf git-filter-repo ac039ecc095d.

Benutzeravatar von Karol Selak
Karl Selak

Am Anfang möchte ich ElpieKay danken, die Kernfunktionen meiner Lösungen gepostet hat, die ich nur automatisiert habe.

Endlich habe ich das Drehbuch, das ich haben wollte. Ich habe es in Teile aufgeteilt, die voneinander abhängen und als unabhängige Skripte dienen können. Es sieht aus wie das:

censorStringsInWholeGitHistory.sh:

#!/bin/bash
#arguments are strings to censore

for string in "$@"
do
  echo ""
  echo "================ Censoring string "$string": ================"
  ~/replaceStringInWholeGitHistory.sh "$string" "********"
done

Verwendung:

~/censorStringsInWholeGitHistory.sh "my_password1" "my_password2" "some_f_word"

replaceStringInWholeGitHistory.sh:

#!/bin/bash
# $1 - string to find
# $2 - string to replace with

for branch in $(git branch | cut -c 3-); do
  echo ""
  echo ">>> Replacing strings in branch $branch:"
  echo ""
  ~/replaceStringInBranch.sh "$branch" "$1" "$2"
done

Verwendung:

~/replaceStringInWholeGitHistory.sh "my_password" "********"

replaceStringInBranch.sh:

#!/bin/bash
# $1 - branch
# $2 - string to find
# $3 - string to replace with

git checkout $1
for file in $(~/findFilesContainingStringInBranch.sh "$2"); do
  echo "          Filtering file $file:"
  ~/changeStringsInFileInCurrentBranch.sh "$file" "$2" "$3"
done

Verwendung:

~/replaceStringInBranch.sh master "my_password" "********"

findFilesContainingStringInBranch.sh:

#!/bin/bash

# $1 - string to find
# $2 - branch name or nothing (current branch in that case)

git log -S "$1" $2 --name-only --pretty=format: -- | sort -u

Verwendung:

~/findFilesContainingStringInBranch.sh "my_password" master

changeStringsInFileInCurrentBranch.sh:

#!/bin/bash

# $1 - file name
# $2 - string to find
# $3 - string to replace

git filter-branch -f --tree-filter "if [ -f $1 ];then sed -i s/$2/$3/g $1;fi"

Verwendung:

~/changeStringsInFileInCurrentBranch.sh "abc.txt" "my_password" "********"

Ich habe all diese Skripte in meinem Home-Ordner, die für das ordnungsgemäße Arbeiten in dieser Version erforderlich sind. Ich bin mir nicht sicher, ob das die beste Option ist, aber im Moment kann ich keine bessere finden. Natürlich muss jedes Skript ausführbar sein, was wir erreichen können chmod +x ~/myscript.sh.

Wahrscheinlich ist mein Skript nicht optimal, für große Repos wird es sehr lange abarbeiten, aber es funktioniert 🙂

Und ganz am Ende können wir unser zensiertes Repo auf jede Fernbedienung übertragen mit:

git push <remote> -f --all

Bearbeiten: wichtiger Hinweis von ElpieKay:

Vergessen Sie nicht, gepushte Tags zu löschen und neu zu erstellen. Sie verweisen immer noch auf die alten Commits, die möglicherweise Ihr Passwort enthalten.

Vielleicht werde ich mein Skript in Zukunft verbessern, um dies automatisch zu tun.

  • Funktionieren diese Skripte tatsächlich? Ich konnte sie nicht zum Laufen bringen: sed: -e expression #1, char 7: nicht abgeschlossener `s’-Befehlsbaumfilter fehlgeschlagen:

    – ET

    29. April 2020 um 21:42 Uhr

  • Ja, ich habe es gerade überprüft und es funktioniert jetzt bei mir. Obwohl ich Git v2.17.1 verwende, bin ich mir nicht sicher, was mit neueren Versionen ist. Und ich benutze Ubuntu.

    – Karol Selak

    29. April 2020 um 22:02 Uhr


  • Ist das Problem zufällig, dass der sed-String wirklich maskiert werden sollte? Ich sehe nicht, wie dies funktionieren könnte, wenn es Leerzeichen, Schrägstriche oder ähnliches enthält

    – ET

    29. April 2020 um 23:14 Uhr

  • Ich weiß nicht, meine Antwort basiert auf der von ElpieKay (stackoverflow.com/a/46951323/3668967), also kann er dir vielleicht helfen.

    – Karol Selak

    1. Mai 2020 um 15:27 Uhr

1440780cookie-checkWie ersetze ich eine Zeichenfolge im gesamten Git-Verlauf?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy