.gitignore Sintaks: bin vs bin / vs. bin / * vs. bin / **

89

Apa perbedaan antara menambahkan bin, bin/, bin/*dan bin/**dalam file Gitignore saya? Saya telah menggunakan bin/, tetapi melihat file .gitignore lainnya (dalam file gerhana bintang ganda dan bintang tunggal bahkan digunakan bersamaan seperti ini: ada apa dengan itu?) Saya melihat bahwa dua pola pertama juga banyak digunakan. Bisakah seseorang menjelaskan perbedaan antara ketiganya?tmp/**/*

Chandsie
sumber
4
@unutbu: Jawaban yang diterima untuk pertanyaan itu tampaknya diperdebatkan. Salah satu komentar teratas mengklaim bahwa jawabannya sebenarnya adalah mitos yang lengkap.
chandsie
Perilakunya benar-benar ditentukan di halaman manual, dan saya yakin ada pertanyaan / jawaban di sini (atau sepuluh) yang mencakup semua informasi itu.
Cascabel
3
Sehubungan dengan **: stackoverflow.com/questions/1470572/…
Cascabel

Jawaban:

84

bincocok dengan file atau direktori apa pun yang bernama 'bin'.

bin/cocok dengan semua direktori bernama 'bin', yang artinya semua isinya karena Git tidak melacak direktori saja.

bin/*cocok dengan semua file dan direktori secara langsung di sembarang bin/. Hal ini mencegah Git secara otomatis menemukan file apa pun dalam subdirektorinya, tetapi jika, misalnya bin/foosubdirektori dibuat, aturan ini tidak akan cocok foodengan kontennya.

bin/**cocok dengan semua file dan direktori dalam bin/direktori manapun dan semua subdirektorinya.

Kata "any" sangat penting di sini karena aturan tidak berhubungan dengan root repositori dan berlaku di mana saja di pohon sistem file. Anda harus memulai aturan dengan /(atau !/untuk membatalkan pengabaian) yang berarti root repositori, bukan root sistem, untuk mencocokkan hanya yang dimaksudkan.

PERINGATAN: Anda harus tidak pernah menggunakan aturan seperti dir/*, /dir/**, dll saja kecuali Anda juga un-mengabaikan sesuatu yang ada di dalam direktori tersebut . Hilangkan tanda bintang atau Anda dapat kehilangan banyak data secara permanen dari pemanggilan tertentu git gc, git stashdan banyak lagi.

Saya tidak begitu tahu apa tmp/**/*yang harus saya lakukan. Awalnya saya mengira ini dapat digunakan untuk mencocokkan file di sub-direktori tmp/tetapi bukan file yang langsung ada di dalamnya tmp/. Tetapi tes sederhana tampaknya menunjukkan bahwa ini mengabaikan semua file di tmp/.

Siddhartha Reddy
sumber
10
hanya untuk memperjelas, apa perbedaan antara bin/dan bin/**?
chandsie
1
Saya curiga bin/akan mengabaikan direktori bin, sedangkan bin/**akan menyertakan direktori bin tetapi tidak ada isinya
Robin Winslow
1
Itu sepertinya tidak sesuai dengan jawaban Siddhartha. Menggambar dari jawabannya, bin/akan mengabaikan direktori itu sendiri (termasuk semua sub-direktori dan file), sedangkan bin/**akan mengabaikan semua file dalam direktori bin dan sub-direktorinya, tetapi tidak pada direktori bin itu sendiri. Apakah itu akurat atau tidak, saya tidak yakin.
Christopher Berman
3
perhatikan bahwa, jika Anda ingin melacak semua file di direktori bin / tetapi mengabaikan semua file di subdirektorinya, Anda dapat melakukannya (pada baris berikutnya) bin/** \n !bin/*(karena saya tidak dapat melihat cara memaksa
pemecah baris dalam
9
Jawaban ini salah dalam banyak hal. Pertama, git tidak melacak direktori, jadi entri .gitignore hanya bisa mencocokkan konten direktori, tidak pernah direktori seperti itu. Kedua, bincocok baik sebuah file bernama bin dan isi dari binfolder. Ketiga, bin/* cocok dengan semua file di subdirektorinya. Apakah kalian pernah menguji ini?
ThomasR
46

bindan bin/hanya berbeda dalam hal ini yang terakhir hanya akan cocok dengan direktori.

bin/**/*sama dengan bin/**(tampaknya sejak 1.8.2, menurut jawaban @ VonC).

Yang rumit, bahwa saya hanya menghabiskan satu jam atau lebih merobek rambut saya, adalah itu bin/dan bin/**tidak persis sama! Karena sebelumnya mengabaikan direktori secara keseluruhan, dan yang terakhir mengabaikan setiap file di dalamnya, dan git di hampir semua kasus tidak peduli dengan direktori, biasanya tidak ada perbedaan. Namun, jika Anda mencoba menggunakan !untuk tidak mengabaikan sub jalur, Anda akan mendapati bahwa git (ahem) mengabaikannya jika Anda mengabaikan direktori induk! (sekali lagi, bukan isi direktori)

Ini paling jelas dengan contoh, jadi untuk repositori yang baru diinit, atur begitu:

$ cat .gitignore
ignored-file
or-dir
dir-only/
!dir-only/cant-reinclude
dir-contents/**
!dir-contents/can-reinclude

$ mkdir or-dir dir-only dir-contents

$ touch file ignored-file or-dir/ignored-file dir-only/cant-reinclude dir-contents/can-reinclude

Ada file yang tidak terlacak berikut:

$ git ls-files --other
.gitignore
dir-contents/can-reinclude
dir-only/cant-reinclude
file
ignored-file
or-dir/ignored-file

Tetapi Anda dapat melihat file-file berikut tidak diabaikan:

$ git ls-files --other --exclude-standard
.gitignore
dir-contents/can-reinclude
file

Dan jika Anda mencoba menambahkan, Anda mendapatkan:

$ git add dir-only/cant-reinclude
The following paths are ignored by one of your .gitignore files:
dir-only/cant-reinclude
Use -f if you really want to add them.
fatal: no files added

Saya menganggap perilaku ini sebagai bug. (Ini semua aktif git version 1.8.4.msysgit.0)

Simon Buchan
sumber
1
+1, memang. Anda harus mempertimbangkan untuk mengajukan laporan bug sebenarnya tentang ini karena perilakunya memang tampak tidak terduga.
chandsie
1
Persis kasus penggunaan saya. Terima kasih!
Sebastian Graf
3
Perilaku yang berbeda dari dir/dan dir/**kembali. un-ignoring with !terjadi karena "Tidak mungkin untuk menyertakan kembali file jika direktori induk dari file tersebut dikecualikan" [sumber ]. Membingungkan, tetapi dilakukan karena alasan kinerja. Lihat pertanyaan SO terkait .
tanius
23

Perhatikan bahwa, secara tegas, git tidak melacak direktori, hanya file. Oleh karena itu, tidak mungkin untuk menambahkan direktori, hanya isinya .

.gitignoreNamun dalam konteksnya , git berpura-pura memahami direktori hanya untuk alasan itu

Tidak mungkin untuk memasukkan kembali file jika direktori induk dari file itu dikecualikan.
https://git-scm.com/docs/gitignore#_pattern_format

Apa artinya ini untuk pola pengecualian? Mari kita bahas secara detail:

bin

Ini mengabaikan

  • file bernama bin.
  • isi folder bernama bin

Anda dapat memasukkan binfile dan folder yang diabaikan ke dalam daftar putih dengan menambahkan !entri berikutnya , tetapi Anda tidak dapat memasukkan konten folder bernamabin

bin

!bin/file_in_bin # has no effect, since bin/ is blacklisted!
!bin/* # has no effect, since bin/ is blacklisted!
!file_in_bin # has no effect, since bin/ is blacklisted!

!bin # this works

bin/

Sama seperti di atas, hanya saja tidak cocok dengan file bernama bin. Menambahkan sebuah trailing /memberitahu git untuk mencocokkan direktori saja.

bin/*

Ini mengabaikan

  • file yang terdapat dalam folder bernamabin
  • isi subfolder langsung dari folder bernama bin
bin/*  # blacklists bin/file_in_bin and bin/subfolder/

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted!
!bin # whitelists files named bin/bin, since bin/ itself is not blacklisted
!bin/ # has no effect, since bin/ itself is not blacklisted


!bin/file_in_bin # works since bin/ itself is not blacklisted
!file_in_bin # works too
!bin/subfolder # works (so implicitly whitelists bin/subfolder/file_in_sub)
!bin/subfolder/ # works just as well
!bin/* # works for file_in_bin and subfolder/

bin/**

Ini mengabaikan

  • Isi dari bin
  • konten subfolder (tingkat penumpukan apa pun) di dalamnya bin
bin/**  # blacklists bin/file_in_bin and
        # bin/subfolder/ and bin/subfolder/file_in_sub and
        # bin/subfolder/2/ and bin/subfolder/2/file_in_sub_2

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/ # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/file_in_sub_2 # has no effect, since bin/subfolder is blacklisted

!bin/subfolder # works only in combinations with other whitelist entries,
               # since all contents of subfolder are blacklisted (1)

!bin/file_in_bin # works since bin itself is not blacklisted
!bin/* # works for file_in_bin and subfolder; see (1)
ThomasR
sumber
9

Saya baru saja membuat repo baru dan mencoba beberapa hal. Ini hasil saya:

HASIL BARU

git versi 2.10.1.windows.1

  1. Inisialisasi repo yang hampir kosong. Hanya file README
  2. Isi bindirektori sedalam beberapa lapisan
    • bin.txt
    • Test.txt
    • bin/a/b/bin.txt
    • bin/a/b/Test.txt
    • bin/a/bin/bin.txt
    • bin/a/bin/Test.txt
    • bin/a/bin.txt
    • bin/a/Test.txt
    • bin/bin.txt
    • bin/Test.txt
  3. Tambahkan binke gitignore: Hasil
    • Semua yang ada di bawah bindirektori (dan lebih dalam) sekarang diabaikan
    • Level root tidak diabaikan (/bin.txt dan /Test.txt masih ditampilkan)
  4. Edit binke bin/di gitignore: Hasil
    • Tidak ada perubahan
  5. Edit bin/kebin/*
    • Tidak ada perubahan
  6. Edit bin/*kebin/**
    • Tidak ada perubahan
  7. Edit bin/**kebin/**/
    • bin/bin.txtdan bin/Test.txttidak lagi diabaikan
  8. Edit bin/**/kebin/**/*
    • bin/bin.txtdan bin/Test.txtkembali diabaikan

HASIL LAMA

versi git: 2.7.0.windows.1

  1. Inisialisasi repo yang hampir kosong. Hanya file README
  2. Isi bindirektori sedalam beberapa lapisan
    • bin/a/b/Test.txt
    • bin/a/bin/Test.txt
    • bin/a/Test.txt
    • bin/Test.txt
  3. Tambahkan binke gitignore: Hasil
    • Semua yang ada di bawah bindirektori (dan lebih dalam) sekarang diabaikan
  4. Edit binke bin/di gitignore: Hasil
    • Segala sesuatu di bawah bindirektori (dan lebih dalam) masih diabaikan (tidak ada perubahan)
  5. Edit bin/kebin/*
    • Segala sesuatu di bawah bindirektori (dan lebih dalam) masih diabaikan (tidak ada perubahan)
  6. Edit bin/*kebin/**
    • Segala sesuatu di bawah bindirektori (dan lebih dalam) masih diabaikan (tidak ada perubahan)
  7. Edit bin/**kebin/**/
    • bin/Test.txt tidak lagi diabaikan
  8. Edit bin/**/kebin/**/*
    • Segala sesuatu di bawah bindirektori (dan lebih dalam) akan diabaikan lagi
Joe Phillips
sumber
1
Ini adalah tes yang bagus, menurut saya mengganti nama text.txt menjadi bin.txt akan menunjukkan beberapa perbedaan utama. Jika Anda melakukan ini, saya akan memilih jawaban ini.
Matt Johnson
@MattJohnson Benar ... sayangnya saya menggunakan versi git yang lebih baru saat ini
Joe Phillips
@MattJohnson Akhirnya saya sempat membahas ini
Joe Phillips
8

Perhatikan bahwa ' **', jika digabungkan dengan sub-direktori ( **/bar), pasti sudah berubah dari perilaku defaultnya, karena catatan rilis untuk git1.8.2 sekarang menyebutkan:

Pola dalam .gitignoredan .gitattributesfile dapat memiliki **/, sebagai pola yang cocok dengan 0 atau lebih tingkat subdirektori.

Misalnya " foo/**/bar" cocok " bar" dalam " foo" itu sendiri atau dalam subdirektori " foo".


Aturan yang harus diingat (dan yang membantu memahami perbedaan maksud di balik sintaks tersebut) adalah:

Tidak mungkin untuk memasukkan kembali file jika direktori induk dari file itu dikecualikan.


Biasanya, jika Anda ingin mengecualikan file dari subfolder dari folder abaikan f, Anda akan melakukan:

f/**
!f/**/
!f/a/sub/folder/someFile.txt

Itu adalah:

  • Jika aturan pertama adalah f/, folder f/akan diabaikan dan aturan di bawah fini tidak akan menjadi masalah.
  • f/**mencapai hal yang sama f/, tetapi abaikan semua sub-elemen (file dan subfolder).
    Yang memberikan Anda kesempatan untuk daftar putih (mengecualikan dari gitignore) subfolder: !f/**/.
  • Karena semua fsubfolder tidak diabaikan, Anda bisa menambahkan aturan untuk mengecualikan file ( !f/a/sub/folder/someFile.txt)
VonC
sumber
Bagaimana ini menjawab pertanyaan?
ThomasR
0

Ada perbedaan lain antara bin/*dan bin/.

bin/cocok foo/bin/test.txt(seperti yang diharapkan), tetapi bin/*tidak, yang tampaknya aneh, tetapi ini didokumentasikan: https://git-scm.com/docs/gitignore

"Documentation / *. Html" cocok dengan "Documentation / git.html" tetapi tidak dengan "Documentation / ppc / ppc.html" atau "tools / perf / Documentation / perf.html".

Alasannya tampaknya karena aturan ini:

  • Jika pola diakhiri dengan garis miring, itu dihapus untuk tujuan deskripsi berikut ...

  • Jika pola tidak mengandung garis miring /, Git akan memperlakukannya sebagai pola shell glob dan memeriksa kecocokan dengan nama path yang berhubungan dengan lokasi file .gitignore…

  • Jika tidak, Git akan memperlakukan pola sebagai shell glob yang cocok untuk dikonsumsi oleh fnmatch (3) dengan flag FNM_PATHNAME…

Jadi jika polanya diakhiri dengan garis miring, garis miring tersebut akan dihapus dan diperlakukan sebagai pola shell glob, dalam hal ini bincocok foo/bin/test.txt. Jika diakhiri dengan /*, garis miring tidak dihapus dan diteruskan ke fnmatch, yang tidak cocok di subdirektori.

Namun, hal yang sama tidak berlaku untuk foo/bin/dan foo/bin/*, karena bahkan setelah menghapus garis miring dari foo/bin/, itu masih berisi garis miring, jadi itu diperlakukan sebagai pola fnmatch, bukan bola. Yaitu tidak akan cocokbar/foo/bin/test.txt

pengguna1431317
sumber