Rechercher des fichiers qui ne sont pas dans .gitignore

12

J'ai la commande find qui affiche les fichiers dans mon projet:

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

Comment puis-je filtrer les fichiers pour ne pas afficher ceux qui sont dans .gitignore?

J'ai pensé utiliser:

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

mais le fichier .gitignore peut avoir des modèles glob (également il ne fonctionnera pas avec les chemins si le fichier est en .gitignore), comment puis-je filtrer les fichiers en fonction des modèles qui peuvent avoir des globs?

jcubic
la source

Réponses:

11

gitpermet git-check-ignorede vérifier si un fichier est exclu par .gitignore.

Vous pouvez donc utiliser:

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 {} +

Notez que cela vous coûterait cher, car la vérification a été effectuée pour chaque fichier.

cuonglm
la source
Qu'est-ce que c'est find-sh {} +à la fin?
jcubic
D'accord, et quoi find-sh?
jcubic
@jcubic c'est le nom que vous avez donné pour le script inline-sh, donc en cas d'erreur, vous aurez un message d'erreur significatif
cuonglm
@jcubic Essayez find /tmp -exec sh -c ': "${non_existed_var:?foo}"' find-sh {} +par exemple
cuonglm
9

il y a une commande git pour faire exactement cela: par exemple

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

Comme vous l'avez dit, il effectuera un grep de base avec la plupart des options normales de grep, mais il ne recherchera .gitni les fichiers ni les dossiers de votre .gitignorefichier.
Pour plus de détails, voirman git-grep

Sous-modules:

Si vous avez d'autres dépôts git à l'intérieur de ce dépôt git (ils devraient être dans des sous-modules), vous pouvez également utiliser l'indicateur --recurse-submodulespour rechercher dans les sous-modules

the_velour_fog
la source
Génial, cela fonctionne presque parce que j'ai d'autres dépôts git dans le répertoire courant, c'est pourquoi j'ai "* .git".
jcubic
8

Pour afficher les fichiers qui sont dans votre caisse et qui sont suivis par Git, utilisez

$ git ls-files

Cette commande a un certain nombre d'options pour afficher, par exemple les fichiers mis en cache, les fichiers non suivis, les fichiers modifiés, les fichiers ignorés, etc. Voir git ls-files --help.

Kusalananda
la source
Je pense aussi à git ls-filesmais ne pense pas qu'il a la possibilité d'afficher les fichiers non suivis, lequel?
cuonglm
1
@cuonglm -o(autre). Par exemple,git ls-files -o -X .gitignore
Kusalananda
Ah oui, mais je ne peux pas gérer le cas où le fichier a été suivi auparavant mais inclus .gitignore.
cuonglm
Remarque mineure: cela ne répertorie pas les fichiers réels du système mais les fichiers inclus dans l'historique git. Cela peut être une différence subtile sur les systèmes insensibles à la casse (par exemple les partages Windows). Dites, j'ai commis ./foo.txt mais je l'ai renommé en ./Foo.txt. Certains clients git ne reconnaîtront pas ce changement et git ls-filesgénèreront ./foo.txt tandis findque généreraient ./Foo.txt
Griddo
2

Vous pouvez utiliser un tableau dans lequel bash glob sera effectué.

Avoir des fichiers comme celui-ci:

touch file1 file2 file3 some more file here

Et avoir un ignorefichier comme celui-ci

cat <<EOF >ignore
file*
here
EOF

En utilisant

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

En résultera:

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

Vous pouvez ensuite utiliser n'importe quelle technique pour manipuler ces données.

Personnellement, je préfère quelque chose comme ça:

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
la source
gitignoreest un surensemble de bashglob, vous allez manquer pour quelque chose comme!file*
cuonglm
@cuonglm Qu'entendez-vous par !file*? En tant que modèle global dans un fichier ignoré ou en tant que nom de fichier?
George Vasiliou
gitignoreaccepter le modèle de fichier comme !file*pour exclure les fichiers commencer par file, et aussi double étoile**
cuonglm
.gitignorea un tas de fonctionnalités, qui ne sont pas toutes faciles à implémenter directement dans Bash: git-scm.com/docs/gitignore . Bien que les ignorés constitués de simples globes devraient être réalisables en plaine Bash, sans awk ou autre
ilkkachu
@cuonglm Vous voulez dire la traduction de !as not? Peut-être que la globalisation étendue peut gérer cette situation. À propos de doublestar, bash peut le gérer avec shopt -s globstar.
George Vasiliou