Encuentra archivos que no están en .gitignore

12

Tengo un comando de búsqueda que muestra archivos en mi proyecto:

find . -type f -not -path './node_modules*' -a -not -path '*.git*' \
       -a -not -path './coverage*' -a -not -path './bower_components*' \
       -a -not -name '*~'

¿Cómo puedo filtrar los archivos para que no muestren los que están en .gitignore?

Pensé que uso:

while read file; do
    grep $file .gitignore > /dev/null && echo $file;
done

pero el archivo .gitignore puede tener patrones globales (tampoco funcionará con rutas si el archivo está en .gitignore). ¿Cómo puedo filtrar archivos basados ​​en patrones que pueden tener niveles globales?

jcubic
fuente

Respuestas:

11

gitproporciona git-check-ignorepara verificar si un archivo está excluido por .gitignore.

Entonces podrías usar:

find . -type f -not -path './node_modules*' \
       -a -not -path '*.git*'               \
       -a -not -path './coverage*'          \
       -a -not -path './bower_components*'  \
       -a -not -name '*~'                   \
       -exec sh -c '
         for f do
           git check-ignore -q "$f" ||
           printf '%s\n' "$f"
         done
       ' find-sh {} +

Tenga en cuenta que pagaría un gran costo por esto porque la verificación se realizó para cada archivo.

Cuonglm
fuente
¿Qué hay find-sh {} +al final?
jcubic
Ok, y que es find-sh?
jcubic
@jcubic es el nombre que le dio a la escritura en línea-sh, por lo que en caso de error se produce, usted tendría un mensaje de error significativo
cuonglm
@jcubic Probar find /tmp -exec sh -c ': "${non_existed_var:?foo}"' find-sh {} +por ejemplo
cuonglm
9

hay un comando git para hacer exactamente esto: por ejemplo

my_git_repo % git grep --line-number TODO                                                                                         
desktop/includes/controllers/user_applications.sh:126:  # TODO try running this without sudo
desktop/includes/controllers/web_tools.sh:52:   TODO: detail the actual steps here:
desktop/includes/controllers/web_tools.sh:57:   TODO: check if, at this point, the menurc file exists. i.e. it  was created

Como dijiste, hará un grep básico con la mayoría de las opciones grep normales, pero no buscará .gitni ninguno de los archivos o carpetas en tu .gitignorearchivo.
Para más detalles, verman git-grep

Submódulos:

Si tiene otros repositorios de git dentro de este repositorio de git (deben estar en submódulos), también puede usar la bandera --recurse-submodulespara buscar en los submódulos

the_velour_fog
fuente
Genial, casi funciona porque tengo otros repositorios git dentro del directorio actual, por eso tengo "* .git".
jcubic
8

Para mostrar los archivos que están en su caja y que Git rastrea, use

$ git ls-files

Este comando tiene varias opciones para mostrar, por ejemplo, archivos en caché, archivos sin seguimiento, archivos modificados, archivos ignorados, etc. Consulte git ls-files --help.

Kusalananda
fuente
También pienso git ls-filespero no creo que tenga la opción de mostrar archivos sin seguimiento, ¿cuál?
Cuonglm
1
@cuonglm -o(otro). Ej .git ls-files -o -X .gitignore
Kusalananda
Ah sí, pero no puedo manejar el caso donde el archivo fue rastreado antes pero incluirlo .gitignore.
cuonglm
Nota menor: esto no enumera los archivos reales del sistema, sino los archivos incluidos en el historial de git. Esto puede ser una sutil diferencia en sistemas que no distinguen entre mayúsculas y minúsculas (por ejemplo, recursos compartidos de Windows). Digamos que cometí ./foo.txt pero luego renómbrelo a ./Foo.txt. Algunos clientes de git no reconocerán este cambio y git ls-filesgenerarán ./foo.txt mientras que findgenerarían ./Foo.txt
Griddo
2

Puede usar una matriz en la que se realizará bash glob.

Tener archivos como este:

touch file1 file2 file3 some more file here

Y tener un ignorearchivo como este

cat <<EOF >ignore
file*
here
EOF

Utilizando

arr=($(cat ignore));declare -p arr

Resultará a esto:

declare -a arr='([0]="file" [1]="file1" [2]="file2" [3]="file3" [4]="here")'

Luego puede usar cualquier técnica para manipular esos datos.

Personalmente prefiero algo como esto:

awk 'NR==FNR{a[$1];next}(!($1 in a))'  <(printf '%s\n' "${arr[@]}") <(find . -type f -printf %f\\n)
#Output
some
more
ignore
George Vasiliou
fuente
gitignorees superconjunto de bashglob, te perderás por algo como!file*
cuonglm
@cuonglm ¿Qué quieres decir con !file*? ¿Como un patrón global en ignorar archivo o como un nombre de archivo?
George Vasiliou
gitignoreaceptar el patrón de archivo !file*para excluir archivos que comienzan con file, y también doble estrella**
cuonglm
.gitignoretiene un montón de características, todas las cuales podrían no ser tan fáciles de implementar directamente en Bash: git-scm.com/docs/gitignore . Aunque ignora que consta de sólo simples globos deben ser factible en la llanura Bash, sin awk o tal
ilkkachu
@cuonglm ¿Te refieres a la traducción de !no? Tal vez el gloging extendido pueda manejar esta situación. Sobre doublestar, bash puede manejarlo shopt -s globstar.
George Vasiliou