ver tipos tag oneline modificados log etiquetas crear archivos git version-control substitution git-filter-branch git-rewrite-history

tipos - git ver archivos modificados



¿Cómo sustituir texto de archivos en el historial de git? (4)

Creé un archivo en /usr/local/git/findsed.sh, con el siguiente contenido:

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

Ejecuté el comando:

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

Explicación de comandos

Cuando ejecuta git filter-branch, esto pasa por cada revisión que haya realizado, una por una. --tree-filter ejecuta el script founded.sh en cada revisión confirmada, la guarda y luego pasa a la siguiente revisión.

El comando buscar encuentra un archivo o conjunto de archivos específico y ejecuta (-exec) el editor sed en ese archivo. sed es un comando que toma la expresión regular después de s / y la reemplaza con la cadena entre / y / g (en blanco en mi ejemplo). {} es una referencia a la ruta de los archivos que fue dada por el comando de búsqueda. La ruta del archivo se alimenta a sed, para que sed sepa en qué trabajar. /; solo termina el comando -exec.

Separar el script de shell y el comando en partes separadas permite menos complicaciones cuando se trata de comillas '''' o "".

Peculiaridades

Lo implementé exitosamente en una mac, y aparentemente sed es una versión particular (¿más antigua?) En macs. Esto importa, ya que a veces se comporta de manera diferente. Asegúrate de hacer sed -i '''' o, de lo contrario, estaba agregando una "-e" al final de los archivos, pensando que eso era lo que quería nombrar mis archivos de respaldo. -i '''' dice que no haga archivos de copia de seguridad, solo edite los archivos en su lugar y no necesita un archivo de copia de seguridad.

Especificar -name ''filename.sh'' me ayudó a evitar otro problema que no pude resolver. Había otro archivo con .sh y ese archivo terminó sin un carácter de nueva línea. por alguna razón, agregaría un carácter de nueva línea al final, a pesar de que ''s / blah / blah / g'' no coincide con nada en ese archivo. Así que, en lugar de resolver ese problema, le dije a la búsqueda que ignorara todos los demás archivos.

Comandos adicionales que funcionan

Además, encontré que estos comandos funcionan en el archivo founded.sh (solo un comando a la vez, no es múltiple, así que comente # los otros):

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

¡Disfrutar!

Siempre he usado una interfaz basada en el cliente git (smartGit) y, por lo tanto, no tengo mucha experiencia con la consola git.

Sin embargo, ahora me enfrento a la necesidad de sustituir una cadena en todos los archivos .txt del historial (no borrando todo el archivo sino simplemente sustituyendo una cadena). Encontré el siguiente comando:

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

Intenté esto y, desafortunadamente, noté que aunque la contraseña se cambió, todos los archivos binarios se corrompieron. Imágenes, etc. serían todas corrompidas.

¿Hay una mejor manera de hacer esto que no dañe mis archivos binarios?

Gracias.

EDITAR:

Me confundí con algo. El código real que causó que los archivos binarios se corrompieran fue:

$ git filter-branch --tree-filter "find . -type f -exec sed -i -e ''s/originalpassword/newpassword/g'' {} /;"

El código en la parte superior realmente eliminó todos los archivos con mi contraseña de forma bastante extraña.


Podría ser un problema de expansión de shell. Si filter-branch está perdiendo las comillas alrededor de "*.php" cuando evalúa el comando, puede expandirse a nada, por lo tanto git ls-files -z listando todos los archivos.

Podría verificar la fuente de la rama del filtro o probar diferentes trucos de cotización, pero lo que haría sería crear un script de shell de una línea que haga su filtro de árbol y pase ese script en su lugar.


Puede evitar tocar los archivos no deseados pasando el nombre -name "pattern" para find .

Esto funciona para mí:

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


Recomiendo usar BFG Repo-Cleaner , una alternativa más simple y rápida a git-filter-branch específicamente diseñada para reescribir archivos del historial de Git.

Debería seguir cuidadosamente estos pasos aquí: https://rtyley.github.io/bfg-repo-cleaner/#usage - pero el bit del núcleo es simplemente esto: descargue el archivo jar de BFG (requiere Java 7 o superior) y ejecute este comando :

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

El archivo replacements.txt debe contener todas las sustituciones que desea hacer, en un formato como este (una entrada por línea; tenga en cuenta que los comentarios no deben incluirse):

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

Se escaneará todo el historial del repositorio y se realizarán las sustituciones en los archivos .php (con un tamaño inferior a 1 MB): se reemplazará cualquier cadena coincidente (que no se encuentre en su última confirmación).

Revelación completa: soy el autor de BFG Repo-Cleaner.