Найти файлы, которых нет в .gitignore

12

У меня есть команда find, которая отображает файлы в моем проекте:

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

Как я могу отфильтровать файлы, чтобы они не отображали те, которые находятся в .gitignore?

Я думал, что я использую:

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

но файл .gitignore может иметь шаблоны глобуса (также он не будет работать с путями, если файл находится в .gitignore). Как я могу фильтровать файлы по шаблонам, которые могут иметь глобусы?

jcubic
источник

Ответы:

11

gitобеспечивает , git-check-ignoreчтобы проверить , является ли файл исключен .gitignore.

Таким образом, вы можете использовать:

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

Обратите внимание, что вы заплатите большую цену за это, потому что проверка была выполнена для каждого файла.

cuonglm
источник
Что find-sh {} +в конце?
jcubic
@jcubic, см. unix.stackexchange.com/q/12902/38906
cuonglm
Ок а что find-sh?
jcubic
@jcubic - это имя, которое вы дали для сценария inline-sh, поэтому в случае возникновения ошибки у вас будет значимое сообщение об ошибке
cuonglm
@jcubic Попробуйте find /tmp -exec sh -c ': "${non_existed_var:?foo}"' find-sh {} +например
cuonglm
9

для этого есть команда git: например

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

Как вы заявили, он будет выполнять базовые действия grep с большинством обычных опций grep, но он не будет искать .gitни один из файлов или папок в вашем .gitignoreфайле.
Для получения дополнительной информации см.man git-grep

подмодули:

Если у вас есть другие репозитории git внутри этого репозитория git (они должны быть в подмодулях), то вы также можете использовать флаг --recurse-submodulesдля поиска в подмодулях.

the_velour_fog
источник
Отлично, это почти работает, потому что у меня есть другие git-репозитории внутри текущей директории, поэтому у меня есть «* .git».
jcubic
8

Чтобы показать файлы, которые находятся в вашей проверке и которые отслеживаются Git, используйте

$ git ls-files

Эта команда имеет ряд параметров для отображения, например, кэшированные файлы, неотслеживаемые файлы, измененные файлы, игнорируемые файлы и т git ls-files --help. Д. См .

Кусалананда
источник
Я также думаю о, git ls-filesно не думаю, что у него есть возможность показать неотслеживаемые файлы, какой?
cuonglm
1
@cuonglm -o(другой). Например,git ls-files -o -X .gitignore
Кусалананда
Ах да, но не могу обработать случай, когда файл отслеживался ранее, но включить в .gitignore.
cuonglm
Небольшое примечание: здесь перечислены не фактические файлы из системы, а файлы, включенные в историю git. Это может быть небольшим отличием в системах, не учитывающих регистр (например, общие ресурсы Windows). Скажем, я зафиксировал ./foo.txt, но затем переименуйте его в ./Foo.txt. Некоторые git-клиенты не распознают это изменение и git ls-filesвыводят ./foo.txt, а выводили findбы ./Foo.txt
Griddo
2

Вы можете использовать массив, в котором будет выполняться bash glob.

Имея такие файлы:

touch file1 file2 file3 some more file here

И имея такой ignoreфайл

cat <<EOF >ignore
file*
here
EOF

С помощью

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

Приведет к этому:

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

Затем вы можете использовать любую технику для манипулирования этими данными.

Я лично предпочитаю что-то вроде этого:

awk 'NR==FNR{a[$1];next}(!($1 in a))'  <(printf '%s\n' "${arr[@]}") <(find . -type f -printf %f\\n)
#Output
some
more
ignore
Георгий Васильев
источник
gitignoreэто суперсет bashглобуса, вы пропустите что-то вроде!file*
cuonglm
@cuonglm Что ты имеешь в виду !file*? Как шаблон глобуса в файле игнорирования или как имя файла?
Георгий
gitignoreпринять файл шаблона, как !file*исключить файлы, начинающиеся с file, а также двойную звезду**
cuonglm
.gitignoreимеет множество функций, которые не всегда так просто реализовать в Bash: git-scm.com/docs/gitignore . Хотя игнорирование, состоящее только из простых шаров, должно быть выполнимо в простом Bash, без awk или чего-то подобного
ilkkachu
@cuonglm Вы имеете в виду перевод !как нет? Может быть, расширенная глобализация может справиться с этой ситуацией. О Doublestar, Bash может справиться с этим shopt -s globstar.
Георгий