Temukan file yang tidak ada dalam .gitignore

12

Saya telah menemukan perintah yang menampilkan file di proyek saya:

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

Bagaimana saya bisa memfilter file sehingga tidak menunjukkan yang ada di .gitignore?

Saya pikir saya menggunakan:

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

tetapi file .gitignore dapat memiliki pola glob (juga tidak akan bekerja dengan path jika file ada di .gitignore), Bagaimana saya bisa memfilter file berdasarkan pola yang mungkin memiliki gumpalan?

jcubic
sumber

Jawaban:

11

gitmenyediakan git-check-ignoreuntuk memeriksa apakah suatu file dikecualikan oleh .gitignore.

Jadi Anda bisa menggunakan:

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

Perhatikan bahwa Anda akan membayar biaya besar untuk ini karena pemeriksaan dilakukan untuk setiap file.

cuonglm
sumber
Apa find-sh {} +akhirnya?
jcubic
@ jcubic lihat unix.stackexchange.com/q/12902/38906
cuonglm
Oke, dan apa find-sh?
jcubic
@ jcubic itu nama yang Anda berikan untuk skrip inline-sh, jadi jika terjadi kesalahan, Anda akan memiliki pesan kesalahan yang bermakna
cuonglm
@ jcubic Coba find /tmp -exec sh -c ': "${non_existed_var:?foo}"' find-sh {} +misalnya
cuonglm
9

ada perintah git untuk melakukan hal ini: mis

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

Seperti yang Anda nyatakan, itu akan melakukan grep dasar akan sebagian besar opsi grep normal, tetapi itu tidak akan mencari .gitatau file atau folder di .gitignorefile Anda .
Untuk lebih jelasnya, lihatman git-grep

Submodules:

Jika Anda memiliki repo git lain di dalam repo git ini, (mereka harus dalam submodul) maka Anda dapat menggunakan flag --recurse-submodulesuntuk mencari dalam submodul juga

the_velour_fog
sumber
Hebat, hampir berhasil karena saya punya repositori git lain di dalam direktori saat ini, itu sebabnya saya punya "* .git".
jcubic
8

Untuk menampilkan file yang ada di checkout Anda dan yang dilacak oleh Git, gunakan

$ git ls-files

Perintah ini memiliki sejumlah opsi untuk ditampilkan, misalnya file dalam cache, file yang tidak dilacak, file yang dimodifikasi, file yang diabaikan dll git ls-files --help. Lihat .

Kusalananda
sumber
Saya juga memikirkan git ls-filestetapi tidak berpikir itu memiliki opsi untuk menampilkan file yang tidak terlacak, yang mana?
cuonglm
1
@cuonglm -o(lainnya). Misalnya,git ls-files -o -X .gitignore
Kusalananda
Ah ya, tetapi tidak dapat menangani kasus di mana file dilacak sebelumnya tetapi termasuk dalam .gitignore.
cuonglm
Catatan kecil: ini tidak mencantumkan file aktual dari sistem tetapi file yang termasuk dalam sejarah git. Ini bisa menjadi perbedaan yang halus pada sistem case-insensitive (misalnya Windows share). Katakan, saya melakukan ./foo.txt tapi kemudian ganti namanya menjadi ./Foo.txt. Beberapa klien git tidak akan mengakui perubahan ini dan git ls-filesoutput ./foo.txt sementara findakan output ./Foo.txt
Griddo
2

Anda bisa menggunakan array di mana bash glob akan dijalankan.

Memiliki file seperti ini:

touch file1 file2 file3 some more file here

Dan memiliki ignorefile seperti ini

cat <<EOF >ignore
file*
here
EOF

Menggunakan

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

Akan menghasilkan ini:

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

Anda kemudian dapat menggunakan teknik apa pun untuk memanipulasi data tersebut.

Saya pribadi lebih suka yang seperti ini:

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
sumber
gitignoreadalah superset dari bashglob, Anda akan melewatkan sesuatu seperti!file*
cuonglm
@cuonglm Apa maksudmu !file*? Sebagai pola gumpalan dalam mengabaikan file atau sebagai nama file?
George Vasiliou
gitignoremenerima pola file seperti !file*untuk mengecualikan file mulai dengan file, dan juga double star**
cuonglm
.gitignorememiliki banyak fitur, yang semuanya mungkin tidak mudah diimplementasikan secara langsung di Bash: git-scm.com/docs/gitignore . Meskipun pengabaian yang hanya terdiri dari gumpalan sederhana harus dapat dilakukan dalam Bash biasa, tanpa awk atau semacamnya
ilkkachu
@cuonglm Maksud Anda terjemahan !bukan? Mungkin globing yang diperluas dapat menangani situasi ini. Tentang doublestar, bash dapat mengatasinya shopt -s globstar.
George Vasiliou