2010-06-08 40 views
123

Tôi đang cố gắng giải quyết vấn đề gitignore trên một cấu trúc thư mục lớn, nhưng để đơn giản hóa câu hỏi của tôi, tôi đã giảm nó xuống như sau.Quy tắc loại trừ gitignore thực sự hoạt động như thế nào?

Tôi có cấu trúc sau đây thư mục của hai tập tin (foo, bar) trong một kho git thương hiệu mới (không cam kết cho đến nay):

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

Rõ ràng, một 'git status -u' show:

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

Điều tôi muốn làm là tạo tệp .gitignore bỏ qua mọi thứ bên trong/b/c nhưng không bỏ qua tệp 'foo'.

Nếu tôi tạo ra một .gitignore như sau:

c/ 

Sau đó, một 'git status -u' cho thấy cả hai foo và bar như bỏ qua:

# Untracked files: 
... 
#  .gitignore 

Đó là như tôi mong đợi.

Bây giờ nếu tôi thêm một quy tắc loại trừ cho foo, như sau:

c/ 
!foo 

Theo manpage gitignore, tôi mong đợi này để làm việc. Nhưng nó không - nó vẫn bỏ qua foo:

# Untracked files: 
... 
#  .gitignore 

này không làm việc một trong hai:

c/ 
!a/b/c/foo 

Không thực hiện điều này:

c/* 
!foo 

Cung cấp:

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

Trong trường hợp đó, mặc dù foo không còn là người bỏ qua ed, bar cũng không bị bỏ qua.

Thứ tự của các quy tắc trong .gitignore dường như không quan trọng.

này cũng không làm những gì tôi mong đợi:

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

Đó là một bỏ qua cả hai foo và bar.

Một tình huống mà không làm việc là nếu tôi có thể tạo các tập tin a/b/c/.gitignore và đặt trong đó:

* 
!foo 

Nhưng vấn đề với điều này là cuối cùng sẽ có thư mục con khác dưới một/b/c và tôi không muốn phải đặt một .gitignore riêng biệt vào từng đơn lẻ - tôi đã hy vọng tạo ra các tệp'gitignore 'dựa trên dự án có thể nằm trong thư mục trên cùng của mỗi dự án và bao gồm tất cả cấu trúc thư mục con 'chuẩn'.

này cũng có vẻ là tương đương:

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

Đây có thể là điều gần gũi nhất để "làm việc" mà tôi có thể đạt được, nhưng đường dẫn tương đối đầy đủ và ngoại lệ rõ ràng cần phải được nêu rõ, đó là sẽ là một nỗi đau nếu tôi có rất nhiều tập tin của tên 'foo' ở các cấp độ khác nhau của cây thư mục con.

Dù sao, hoặc là tôi không hoàn toàn hiểu cách quy tắc loại trừ việc, hoặc họ không làm việc ở tất cả khi thư mục (chứ không phải là ký tự đại diện) sẽ được bỏ qua - bởi một quy tắc kết thúc bằng một/

Bất cứ ai có xin vui lòng làm sáng tỏ điều này?

Có cách nào để làm cho gitignore sử dụng một cái gì đó hợp lý như biểu thức thông thường thay vì cú pháp dựa trên vỏ vụng về này không?

Tôi đang sử dụng và quan sát điều này với git-1.6.6.1 trên Cygwin/bash3 và git-1.7.1 trên Ubuntu/bash3.

+0

câu hỏi có liên quan: http://stackoverflow.com/questions/2820255/how-do-negated-patterns-work-in-gitignore/2820310#2820310 – Cascabel

Trả lời

121
/a/b/c/* 
!foo

Dường như làm việc cho tôi (git 1.7.0.4 trên Linux). * rất quan trọng vì nếu không bạn sẽ bỏ qua thư mục (vì vậy git sẽ không nhìn vào bên trong) thay vì các tệp trong thư mục (cho phép loại trừ).

Hãy suy nghĩ về các loại trừ khi nói "nhưng không phải cái này" thay vì "nhưng bao gồm" - "bỏ qua thư mục này (/a/b/c/) nhưng không phải cái này (foo)". "bỏ qua tất cả các tệp trong thư mục này (/a/b/c/*) nhưng không phải là tệp này (foo)". Để trích dẫn trang người đàn ông:

Tiền tố tùy chọn! phủ nhận mẫu; bất kỳ tệp trùng khớp nào bị loại trừ bởi mẫu trước đó sẽ được bao gồm lại.

tức là, tệp phải được loại trừ đã được bao gồm lại. Hy vọng rằng một số ánh sáng.

+0

Vâng, ví dụ bạn đưa ra cũng có tác dụng tốt cho tôi. Vấn đề là/a/b/* không hoạt động nếu foo ở trong c, có nghĩa là nếu tôi có nhiều tệp foo trong các thư mục con khác nhau trong c (ví dụ: d /, e /, f/g/h /, i/j /, vv) thì quy tắc phủ định '! foo' sẽ không bắt được quy tắc đó. – meowsqueak

+0

@meowsqueak Thật vậy nó sẽ không. Nếu bạn bỏ qua/a/b/* thì không có thư mục nào cho foo vào! Nếu bạn đang cố gắng bỏ qua toàn bộ cây thư mục trong/a/b nhưng bao gồm bất kỳ tệp nào có tên "foo" có thể ở bất kỳ đâu trong cây, tôi không nghĩ rằng nó có thể thực hiện được với các mẫu .gitignore: \ – Chris

+0

Thực ra điều này có thể giải thích tại sao điều này không làm việc cho tôi - các quy tắc sau không hoạt động: "/ a/b/*", "! c/foo". Nếu điều đó có hiệu quả, có thể không có vấn đề gì. – meowsqueak

4

điều này chắc chắn không rõ ràng từ trang người dùng .gitignore. Công trình này:

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

# don't forget this one 
!.gitignore 

Như đã đề cập bởi Chris, một thư mục thậm chí không được mở nếu nó bị loại trừ. Vì vậy, nếu bạn muốn để có thể bỏ qua * nhưng một số tập tin, bạn phải xây dựng đường dẫn đến những tập tin như trên. Đối với tôi điều này là thuận tiện, bởi vì tôi muốn làm một đánh giá mã trên 1 tập tin của một thư viện và nếu tôi muốn làm một sau này tôi chỉ cần thêm nó, và tất cả những người khác bị bỏ qua.

6

Dưới đây là một lựa chọn:

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

Điều đó sẽ bỏ qua tất cả các tập tin và thư mục, ngoại trừ các file/thư mục ba cấp độ sâu bên trong a.

19

Tôi có một tình huống tương tự, giải pháp của tôi là sử dụng:

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

Điều đó sẽ làm việc cho một số tùy ý các thư mục trung gian nếu tôi đọc ** một cách chính xác.

+0

Thiên tài! cảm ơn bạn điều này chỉ giúp tôi giải quyết vấn đề tôi đã đánh đầu của tôi chống lại trong một giờ qua. – Baggers

+0

Hoàn hảo, hoạt động như một sự quyến rũ! – hungdoan

+0

Đẹp, điều này đã làm cho tôi! –

4

Trên một lưu ý tổng quát hơn, git1.8.2 sẽ bao gồm các patch (còn in its v4, prompted by some Stack Overflow question) từ Adam Spiers về việc xác định đó gitignore quy tắc thực sự bỏ qua tập tin của bạn.

Xem git1.8.2 release notes và câu hỏi SO "which gitignore rule is ignoring my file":
sẽ là lệnh git check-ignore.

+0

Cảm ơn bạn đã phát sóng thông tin này. 'check-ignore' cũng sẽ cho bạn biết quy tắc nào là * ngăn chặn * tệp của bạn bị bỏ qua, nếu đó là trường hợp. –

+0

@AdamSpiers âm thanh tuyệt vời. Tôi chắc chắn sẽ phải chơi với nó. – VonC

Các vấn đề liên quan