Bagaimana aturan pengecualian .gitignore berfungsi?

146

Saya mencoba untuk memecahkan masalah gitignore pada struktur direktori besar, tetapi untuk menyederhanakan pertanyaan saya, saya telah mengurangi itu sebagai berikut.

Saya memiliki struktur direktori berikut dari dua file (foo, bar) di repositori git baru (tidak ada komitmen sejauh ini):

a/b/c/foo
a/b/c/bar

Jelas, 'git status -u' menunjukkan:

# Untracked files:
...
#       a/b/c/bar
#       a/b/c/foo

Yang ingin saya lakukan adalah membuat file .gitignore yang mengabaikan segala sesuatu di dalam a / b / c tetapi tidak mengabaikan file 'foo'.

Jika saya membuat .gitignore demikian:

c/

Kemudian 'git status -u' menunjukkan foo dan bar sebagai diabaikan:

# Untracked files:
...
#       .gitignore

Seperti yang saya harapkan.

Sekarang jika saya menambahkan aturan pengecualian untuk foo, dengan demikian:

c/
!foo

Menurut halaman gitignore, saya berharap ini bekerja. Tetapi tidak - masih mengabaikan foo:

# Untracked files:
...
#       .gitignore

Ini juga tidak bekerja:

c/
!a/b/c/foo

Ini juga tidak:

c/*
!foo

Memberi:

# Untracked files:
...
#       .gitignore
#       a/b/c/bar
#       a/b/c/foo

Dalam hal ini, meskipun foo tidak lagi diabaikan, bilah juga tidak diabaikan.

Urutan aturan di .gitignore juga tidak masalah.

Ini juga tidak melakukan apa yang saya harapkan:

a/b/c/
!a/b/c/foo

Yang itu mengabaikan foo dan bar.

Satu situasi yang berhasil adalah jika saya membuat file a / b / c / .gitignore dan dimasukkan ke sana:

*
!foo

Tetapi masalah dengan ini adalah bahwa pada akhirnya akan ada subdirektori lain di bawah a / b / c dan saya tidak ingin harus meletakkan .gitignore terpisah ke setiap satu - saya berharap untuk membuat 'berbasis proyek' .gitignore file yang dapat duduk di direktori teratas dari setiap proyek, dan mencakup semua struktur subdirektori 'standar'.

Ini juga tampaknya setara:

a/b/c/*
!a/b/c/foo

Ini mungkin hal yang paling dekat dengan "bekerja" yang dapat saya capai, tetapi jalur relatif penuh dan pengecualian eksplisit perlu dinyatakan, yang akan menyebalkan jika saya memiliki banyak file nama 'foo' di tingkat yang berbeda dari pohon subdirektori.

Bagaimanapun, entah saya tidak begitu mengerti bagaimana aturan pengecualian bekerja, atau mereka tidak bekerja sama sekali ketika direktori (bukan wildcard) diabaikan - oleh aturan yang berakhiran a /

Adakah yang bisa menjelaskan hal ini?

Apakah ada cara untuk membuat gitignore menggunakan sesuatu yang masuk akal seperti ekspresi reguler alih-alih sintaksis berbasis canggung yang canggung ini?

Saya menggunakan dan mengamati ini dengan git-1.6.6.1 di Cygwin / bash3 dan git-1.7.1 di Ubuntu / bash3.

davidA
sumber
pertanyaan terkait: stackoverflow.com/questions/2820255/…
Cascabel
4
Pertanyaan yang ditulis dengan sangat baik! Jumlah kasus yang Anda coba benar-benar membantu saya memahami apa yang saya lakukan salah dalam kasus yang sama. Terima kasih Tuhan, saya sudah lama mencari hari ini.
Alex G

Jawaban:

153
/ a / b / c / *
! foo

Tampaknya bekerja untuk saya (git 1.7.0.4 di Linux). Ini *penting karena jika tidak Anda mengabaikan direktori itu sendiri (jadi git tidak akan melihat ke dalam) alih-alih file dalam direktori (yang memungkinkan untuk pengecualian).

Pikirkan pengecualian yang mengatakan "tetapi bukan yang ini" daripada "tetapi sertakan ini" - "abaikan direktori ini ( /a/b/c/) tetapi bukan yang ini ( foo)" tidak masuk akal; "abaikan semua file dalam direktori ini ( /a/b/c/*) tetapi tidak yang ini ( foo)" tidak Mengutip halaman manual:

Awalan opsional! yang meniadakan pola; setiap file yang cocok dikecualikan oleh pola sebelumnya akan dimasukkan lagi.

yaitu, file tersebut harus sudah dikecualikan untuk dimasukkan lagi. Harapan yang memberi sedikit cahaya.

Chris
sumber
Ya, contoh yang Anda berikan tidak bekerja dengan baik untuk saya juga. Masalahnya adalah bahwa / a / b / * tidak berfungsi jika foo ada di c, yang berarti jika saya memiliki banyak file foo di berbagai subdirektori di bawah c (mis. D /, e /, f / g / h /, i / j /, dll) maka aturan negate '! foo' tidak akan menangkap mereka.
davidA
1
@mequequeak Memang tidak. Jika Anda mengabaikan / a / b / * maka tidak ada direktori untuk foo berada! Jika Anda mencoba mengabaikan seluruh pohon direktori di bawah / a / b tetapi sertakan file apa pun yang bernama "foo" yang dapat berada di mana saja di dalam pohon, saya tidak berpikir itu bisa dilakukan dengan pola .gitignore: \
Chris
Sebenarnya ini mungkin menjelaskan mengapa ini tidak berhasil untuk saya - aturan berikut tidak berfungsi: "/ a / b / *", "! C / foo". Jika itu berhasil, mungkin tidak ada masalah.
davidA
5
"Saya tidak berpikir itu bisa dilakukan dengan pola .gitignore" - Saya pikir Anda benar, sayangnya.
davidA
@mequequeak Anda mungkin bisa mengabaikan /a/b/cdan kemudian menulis sebuah kail ke git add --forcefile pra-komit yang cocok atau apa
Chris
24

Saya memiliki situasi yang serupa, solusi saya adalah menggunakan:

/a/**/*
!/a/**/foo

Itu harus bekerja untuk sejumlah direktori perantara jika saya membaca **dengan benar.

medge799
sumber
6

ini jelas tidak jelas dari halaman manual .gitignore. Ini bekerja:

*
!/a
!/a/b
!/a/b/c
!/a/b/c/foo

# don't forget this one
!.gitignore

Seperti disebutkan oleh Chris direktori bahkan tidak dibuka jika dikecualikan. Jadi jika Anda ingin dapat mengabaikan * tetapi beberapa file, Anda harus membangun path ke file-file seperti di atas. Bagi saya ini nyaman, karena saya ingin melakukan review kode pada 1 file perpustakaan dan jika saya ingin melakukan yang lain nanti saya hanya menambahkannya, dan semuanya diabaikan.


sumber
6

Berikut ini pilihan lain:

*
!/a*
!/a/*
!/a/*/*
!/a/*/*/*

Itu akan mengabaikan setiap file dan direktori, kecuali file / direktori sedalam tiga level dalam.

Peter Petrik
sumber
5

Pada catatan yang lebih umum, git1.8.2 akan menyertakan tambalan (juga dalam v4-nya , yang ditanyakan oleh beberapa pertanyaan Stack Overflow ) dari Adam Spires tentang menentukan gitignoreaturan mana yang benar-benar mengabaikan file Anda.

Lihat catatan rilis git1.8.2 dan pertanyaan SO " aturan gitignore yang mengabaikan file saya ":
itu akan menjadi perintah git check-ignore.

VONC
sumber
1
Terima kasih telah menyiarkan informasi ini. check-ignorejuga akan memberi tahu Anda aturan mana yang mencegah file Anda diabaikan, jika itu masalahnya.
Adam Spires
@AdamSpiers terdengar hebat. Saya pasti harus bermain dengannya.
VonC