¿Cómo puedo ejecutar operaciones recursivas de búsqueda y reemploop en múltiples files en paralelo?

Estoy intentando replace datos de text en un repository git usando la funcionalidad git filter-branch.

Escribí un script simple para search varios términos y replacelos. Estaba funcionando extremadamente lento. Tenía varias líneas de código BASH ejecutándose para personalizar mis resultados de búsqueda y operación de reemploop. Sé que mi código no fue muy eficiente. Decidí seguir adelante y probar solo mi primera línea, que debería ser semi-eficiente. Todavía demora una eternidad recorrer el código base.

¿Es posible utilizar BASH u otro enfoque simple para search en mis files y ejecutar operaciones de Buscar y Reemplazar en paralelo para acelerar las cosas?

Si no, ¿hay alguna otra sugerencia sobre cómo manejar mejor esto?

Aquí está el command Git que estoy ejecutando:

git filter-branch --tree-filter "sh /home/kurtis/.bin/networkingact.sh || true" \ -- --all 

Aquí está el código que mi command esencialmente ejecuta:

 find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \ -type f -exec sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g' {} \; 

git filter-branch no puede procesar confirmaciones en paralelo, ya que necesita saber el hash (id) de la confirmación principal para calcular el hash actual.

Pero puede acelerar el procesamiento de cada compromiso:

Su código ejecuta sed para cada file. Eso es muy lento Use esto en su lugar:

 find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \ -type f -print0 \ | xargs -0 sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g' 

Esta versión hace exactamente lo mismo que la tuya, pero sed se ejecuta con tantos files (arguments) como sea posible. Find "-print0" y xargs "-0" significa "nombres de file separados con cero byte". Por lo tanto, no hay problemas cuando el nombre de file contiene espacios, nuevas líneas, basura binaria, etc.

Con GNU Parallel puedes paralelizar en cada CPU:

 find . -not -name "*.sql" -not -name "*.tsv" -not -name "*.class" \ -type f -print0 | parallel -q -0 sed -i 's/01dPassw0rd\!/HIDDENPASSWORD/g' 

Obtenga más información: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1.

Encontré este problema interesante, así que jugué un poco con él y comparto este script parcialmente funcional. Mi enfoque original fue un poco incorrecto, pero puede ser rápido (er).

Traté de mejorar el performance buscando files modificados en cada confirmación donde la modificación contiene la cadena que desea replace con git log -Sstring . Pero olvidé que si cambio solo esos, la modificación aparecerá en el próximo commit, así que tuve que ejecutar el script varias veces, pero no comtesting todos los files solo las modificaciones, así que puede ser más rápido ejecutar esto varias veces, luego su versión, pero no estoy seguro de cuánto time tarda la twig de filter si no hace nada.

Es posible que pueda usar partes de él, tal vez get todos los nombres de file primero con git log -S... Y puedes mejorarlo usando xargs antes de sed lugar del bucle for , pero durante el desarrollo me gusta más esta forma. No sé cómo descubrir a los padres correctamente, por eso lo hice de esta manera y tuve que manejar el caso de compromiso inicial por separado.

De todos modos, estoy aquí para aprender también, así que si encuentras una buena manera de lidiar con este problema, comparte 🙂

 #!/bin/bash commit=$1 pattern=$2 replace=$3 function replaceall() { for f in `git log -S$pattern --pretty="format:" --name-only $1 | egrep -v '.sql$|.class$|.tsv$'`; do echo "FILE $f" sed -i "s/$pattern/$replace/g" $f done } parents=`git log --pretty=%P -n 1 $commit` if test -z "$parents"; then echo "ROOT" replaceall $commit else for p in $parents; do echo "PARENT $p" replaceall $p..$commit done fi 

Uso: git filter-branch -f --tree-filter '/path/to/script.sh $commit 01dPassw0rd\! HIDDENPASSWORD' -- --all git filter-branch -f --tree-filter '/path/to/script.sh $commit 01dPassw0rd\! HIDDENPASSWORD' -- --all

Creo que el script no debería estar en su directory de trabajo git porque tree-filter agrega todo lo que encontró mientras reescribía, pero no estoy seguro de esto.

Desea el BFG Repo-Cleaner , una alternativa más rápida y sencilla a git-filter-branch que se ejecuta en la JVM y está explícitamente diseñada para eliminar datos privados de repositorys Git. Es multiprocess y optimizado para la tarea que está describiendo con precisión. Por lo general, es 10 a 50 veces más rápido que git-filter-branch ; cuanto más grande sea su repository, más rápido será.

Descargue Java jar, cree un file private.txt que private.txt las passwords, etc., que desea eliminar (una input por línea) y luego ejecute este command:

 $ java -jar bfg.jar --replace-text private.txt my-repo.git 

Se escanearán todos los files con un tamaño de umbral (1MB por defecto) en el historial de su repository, y cualquier cadena coincidente (que no esté en su último compromiso) será reemplazada con la cadena "*** REMOVED ***". A continuación, puede usar git gc para limpiar los datos muertos:

 $ git gc --prune=now --aggressive