Làm cách nào để loại trừ các thư mục / tệp nhất định khỏi tìm kiếm git grep


144

Có cách nào để loại trừ các đường dẫn / thư mục / tệp nhất định khi tìm kiếm kho git bằng cách sử dụng git grepkhông? Một cái gì đó tương tự như --excludetùy chọn trong greplệnh bình thường ?

Tôi cần sử dụng git grepvì sử dụng greptrực tiếp chạy quá chậm trên kho git lớn.


Làm điều đó trên bash sẽ là một cách giải quyết khả thi: stackoverflow.com/questions/216995/iêu
Ciro Santilli 冠状 病 六四 事件

8
Tính năng này đã được thêm vào 1.9.0, xem câu trả lời của tôi bên dưới
chỉ trong

Câu trả lời:


17

Điều đó là không thể, nhưng đã được thảo luận gần đây . Giải pháp đề xuất trong liên kết:

Bạn có thể đặt *.dllvào tập tin .gitignore sau đó git grep --exclude-standard.

EDIT chỉ thấy câu trả lời của một người , vì git 1.9.0 là có thể.


2
Điều này đã từng đúng nhưng không còn nữa, giờ đây nó đã có thể trong git. Xem những gì nên là câu trả lời thực sự dưới đây: stackoverflow.com/a/30084612/1391445
user1391445

204

Trong git 1.9.0, "từ ma thuật" excludeđã được thêm vào pathspecs. Vì vậy, nếu bạn muốn tìm kiếm foobartrong mọi tệp ngoại trừ những kết quả khớp *.javabạn có thể làm:

git grep foobar -- './*' ':(exclude)*.java'

Hoặc sử dụng !"biểu mẫu ngắn" để loại trừ:

git grep foobar -- './*' ':!*.java'

Lưu ý rằng trong các phiên bản git lên đến v2.12, khi sử dụng loại trừ pathspec, bạn phải có ít nhất một "bao gồm" pathspec. Trong các ví dụ trên đây là ./*(đệ quy bao gồm mọi thứ trong thư mục hiện tại). Trong git v2.13, hạn chế này đã được gỡ bỏ và git grep foobar -- ':!*.java'hoạt động mà không có ./*.

Bạn cũng có thể sử dụng một cái gì đó như :(top)(dạng ngắn :/:) để bao gồm mọi thứ từ đầu repo. Nhưng sau đó, có lẽ bạn cũng muốn điều chỉnh loại trừ của mình pathspecđể bắt đầu từ đầu: :/!*.java(nếu không, nó sẽ chỉ loại trừ *.javacác tệp trong thư mục hiện tại của bạn).

Có một tài liệu tham khảo tốt cho tất cả các "từ ma thuật" được cho phép pathspectại git-scm.com (hoặc chỉ git help glossary). Vì một số lý do, các tài liệu tại kernel.org thực sự đã lỗi thời mặc dù chúng thường xuất hiện đầu tiên trong các tìm kiếm của google.


4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'để loại trừ nhiều toàn bộ thư mục. Tôi không nghĩ rằng nó ngăn ngừa đệ quy mặc dù.
Ciro Santilli 郝海东 冠状 病 事件

2
Để sử dụng thường xuyên, bạn có thể tạo bí danh git với các loại trừ : git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'. Sau đó chỉ là git mygrep foobar. (Sử dụng bí danh shell # lừathư mục hiện hành .)
medmunds

vấn đề tôi không thể giải quyết với giải pháp này là các đường dẫn được báo cáo của các tệp có liên quan đến gốc WC. Vì vậy, nếu tôi đang ở trong một thư mục con của WC, tôi không thể chỉ sử dụng đường dẫn của tệp tìm thấy (ví dụ như ít hơn) mà phải cắt các đường dẫn chung. Có một giải pháp cho vấn đề này (w / o phải tự ám chỉ sed)? [git bash on win7]
elonderin

1
@elonderin giải pháp này không liên quan gì đến cách báo cáo các tệp phù hợp. Nhưng tôi chỉ thử một git grepgit ls-filestừ các thư mục con và cả hai báo cáo tên tệp liên quan đến thư mục hiện tại (ngay cả khi bạn sử dụng ':(top)'pathspec bao gồm). Cả hai lệnh đều có --full-nametùy chọn báo cáo tên liên quan đến thư mục gốc, nhưng theo mặc định thì nó bị tắt.
chỉ

1
Tôi không sử dụng bí danh git vì vậy tôi đã tạo một hàm bash, nhưng có lẽ bí danh git là tốt hơn gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D

62

Cập nhật: Đối với git> = 1.9 có hỗ trợ riêng cho các mẫu loại trừ, hãy xem câu trả lời của onlyone .

Điều này có vẻ ngược, nhưng bạn có thể chuyển một danh sách các tệp không khớp với mẫu loại trừ của bạn để git grepnhư thế này:

git grep <pattern> -- `git ls-files | grep -v <exclude-pattern>`

grep -vtrả mỗi con đường không phù hợp <exclude-pattern>. Lưu ý rằng git ls-filescũng có một --excludetham số, nhưng điều đó chỉ được áp dụng cho các tệp không bị theo dõi .


Cảm ơn vì điều đó! Git grep nhanh hơn nhiều so với ack & co nhưng không thể loại trừ các đường dẫn tùy ý là một điều quá bất tiện nên có thể nói :)
Tomasz Zieliński

2
Thật không may repo của tôi có rất nhiều tập tin. Khi tôi thử cách tiếp cận của @ kynan, tôi nhận được: "-bash: / usr / bin / git: Danh sách đối số quá dài"
Benissimo

2
Điều này sẽ giải quyết cả vấn đề "Danh sách đối số quá dài" của Benissimo và vấn đề của tôi với các ký tự tên tệp được giải thích bởi bash (như []) hoặc tên tệp chứa khoảng trắng trong kho: git ls-files | grep -v <exclue-mẫu> | xargs -d '\ n' git grep <mẫu> -
Hướng đạo

2
Kiểm tra câu trả lời duy nhất, bây giờ có thể thực hiện việc này hoàn toàn trong (phiên bản hiện đại) của git.
David

Tại sao các downvote? Câu trả lời này vẫn áp dụng cho các phiên bản git trước 1.9. Tôi đã thêm một ghi chú đề cập đến câu trả lời của onlyone.
kynan

5

Bạn có thể đánh dấu các tệp hoặc thư mục là nhị phân bằng cách tạo tệp thuộc tính trong kho lưu trữ của mình, ví dụ:

$ cat .git/info/attributes 
directory/to/ignore/*.* binary
directory/to/ignore/*/*.* binary
another_directory/to/also/ignore/*.* binary

Các kết quả khớp trong tệp nhị phân được liệt kê mà không có dòng bao gồm, ví dụ:

$ git grep "bar"
Binary file directory/to/ignore/filename matches
other_directory/other_filename:      foo << bar - bazz[:whatnot]

2

Với ví dụ của @kynan làm cơ sở, tôi đã tạo kịch bản này và đặt nó vào đường dẫn của tôi ( ~/bin/) là gg. Nó không sử dụng git grepnhưng tránh một số filetypes được chỉ định.

Trong repo của chúng tôi có rất nhiều hình ảnh nên tôi đã loại trừ các tệp hình ảnh, và điều này làm giảm thời gian serch xuống còn 1/3 nếu tôi tìm kiếm toàn bộ repo. Nhưng kịch bản có thể dễ dàng được sửa đổi để loại trừ các filestypes hoặc geleralpotype khác.

#!/bin/bash                                                                    
#                                                                              
# Wrapper of git-grep that excludes certain filetypes.                         
# NOTE: The filetypes to exclude is hardcoded for my specific needs.           
#                                                                              
# The basic setup of this script is from here:                                 
#   https://stackoverflow.com/a/14226610/42580                                  
# But there is issues with giving extra path information to the script         
# therefor I crafted the while-thing that moves path-parts to the other side   
# of the '--'.                                                                 

# Declare the filetypes to ignore here                                         
EXCLUDES="png xcf jpg jpeg pdf ps"                                             

# Rebuild the list of fileendings to a good regexp                             
EXCLUDES=`echo $EXCLUDES | sed -e 's/ /\\\|/g' -e 's/.*/\\\.\\\(\0\\\)/'`      

# Store the stuff that is moved from the arguments.                            
moved=                                                                         

# If git-grep returns this "fatal..." then move the last element of the        
# arg-list to the list of files to search.                                     
err="fatal: bad flag '--' used after filename"                                 
while [ "$err" = "fatal: bad flag '--' used after filename" ]; do              
    {                                                                          
        err=$(git grep "$@" -- `git ls-files $moved | grep -iv "$EXCLUDES"` \  
            2>&1 1>&3-)                                                        
    } 3>&1                                                                     

    # The rest of the code in this loop is here to move the last argument in   
    # the arglist to a separate list $moved. I had issues with whitespace in   
    # the search-string, so this is loosely based on:                          
    #   http://www.linuxjournal.com/content/bash-preserving-whitespace-using-set-and-eval
    x=1                                                                        
    items=                                                                     
    for i in "$@"; do                                                          
        if [ $x -lt $# ]; then                                                 
            items="$items \"$i\""                                              
        else                                                                   
            moved="$i $moved"                                                  
        fi                                                                     
        x=$(($x+1))                                                            
    done                                                                       
    eval set -- $items                                                         
done                                                                           
# Show the error if there was any                                              
echo $err                                                                      

Lưu ý 1

Theo này chúng ta có thể đặt tên cho điều git-ggvà có thể gọi nó như là một lệnh git thường xuyên như:

$ git gg searchstring

Nhưng tôi không thể làm việc này. Tôi đã tạo tập lệnh trong ~/bin/và tạo một git-ggliên kết tượng trưng /usr/lib/git-core/.

Lưu ý 2

Lệnh không thể được tạo thành một shbí danh thông thường vì sau đó nó sẽ được gọi ở gốc của repo. Và đó không phải là điều tôi muốn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.