วิธีแยกไดเรกทอรี / ไฟล์บางอย่างออกจากการค้นหา greit grep


144

มีวิธีในการแยกพา ธ / ไดเรกทอรี / ไฟล์บางอย่างเมื่อค้นหาที่เก็บ git git grepหรือไม่? สิ่งที่คล้ายกับ--excludeตัวเลือกในgrepคำสั่งปกติ?

ฉันต้องใช้git grepเพราะการใช้งานgrepโดยตรงช้าเกินไปบนที่เก็บ git ขนาดใหญ่


การทำเช่นนี้กับการทุบตีจะเป็นการแก้ปัญหาที่เป็นไปได้: stackoverflow.com/questions/216995/ …
Ciro Santilli 郝海东冠状病病六四事件法轮功

8
ฟีเจอร์นี้เพิ่มเข้ามาใน 1.9.0 ดูคำตอบของฉันด้านล่าง
ไม่มี

คำตอบ:


17

มันเป็นไปไม่ได้ แต่ได้รับการกล่าวเมื่อเร็ว ๆ นี้ วิธีแก้ปัญหาที่เสนอในลิงก์:

คุณสามารถใส่*.dllไฟล์. gitignore git grep --exclude-standardได้

แก้ไขเห็นเพียงคำตอบของไม่มีใครตั้งแต่ git 1.9.0 เป็นไปได้


2
เรื่องนี้เคยเป็นจริง แต่ไม่นานมันเป็นไปได้ในคอมไพล์ ดูว่าคำตอบที่แท้จริงควรเป็นอะไรด้านล่าง: stackoverflow.com/a/30084612/1391445
user1391445

206

ใน git 1.9.0 มีการเพิ่ม "คำวิเศษ" ไว้excludeในpathspecs ดังนั้นหากคุณต้องการค้นหาfoobarในทุกไฟล์ยกเว้นการจับคู่ที่*.javaคุณสามารถทำได้:

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

หรือใช้!"รูปแบบย่อ" เพื่อยกเว้น:

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

โปรดทราบว่าในรุ่น git จนถึง v2.12 เมื่อใช้การยกเว้นpathspecคุณต้องมี "รวม" อย่างน้อยหนึ่งpathspecรายการ ในตัวอย่างข้างต้นนี่คือ./*(รวมทุกอย่างซ้ำ ๆ ภายใต้ไดเรกทอรีปัจจุบัน) ใน v2.13 คอมไพล์ข้อ จำกัด นี้ถูกยกขึ้นและการทำงานโดยไม่ต้องgit grep foobar -- ':!*.java'./*

คุณสามารถใช้บางสิ่งเช่น:(top)(รูปแบบย่อ:) :/เพื่อรวมทุกอย่างจากด้านบนของ repo แต่คุณอาจต้องการปรับการแยกของคุณpathspecให้เริ่มจากด้านบนด้วย: :/!*.java(มิฉะนั้นจะเป็นการยกเว้นเฉพาะ*.javaไฟล์จากภายใต้ไดเรกทอรีปัจจุบันของคุณ)

มีการอ้างอิงที่ดีสำหรับ "คำวิเศษ" ทั้งหมดที่ได้รับอนุญาตในpathspecที่git-scm.com (หรือเพียงแค่git help glossary) ด้วยเหตุผลบางอย่างเอกสารที่kernel.org ล้าสมัยจริง ๆ แม้ว่าพวกเขามักจะปรากฏตัวครั้งแรกในการค้นหาของ Google


4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'เพื่อยกเว้นไดเรกทอรีทั้งหมดหลายรายการ ฉันไม่คิดว่ามันจะป้องกันการเรียกซ้ำ
Ciro Santilli 法轮功冠状病六四事件法轮功

2
git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'สำหรับการใช้งานบ่อยครั้งคุณสามารถทำให้นามแฝงคอมไพล์ด้วยการยกเว้น: git mygrep foobarแล้วก็ (ใช้นามแฝงshell # trickและdir ปัจจุบัน )
medmunds

ปัญหาที่ฉันไม่สามารถแก้ไขได้ด้วยวิธีนี้คือเส้นทางรายงานของไฟล์นั้นสัมพันธ์กับรูต WC ดังนั้นหากฉันอยู่ใน dir ย่อยของ WC ฉันไม่สามารถใช้พา ธ ของไฟล์ที่พบตามที่เป็น (เช่นน้อยกว่า) แต่ต้อง junc เส้นทางสามัญ มีวิธีแก้ปัญหานี้หรือไม่ (โดยที่ไม่ต้องทำตัวแย่ ๆ )? [คอมไพล์ทุบตีใน win7]
2560

1
@elonderin ในโซลูชันนี้ไม่มีส่วนเกี่ยวข้องกับวิธีการรายงานไฟล์ที่ตรงกัน แต่ฉันเพิ่งลอง a git grepและgit ls-filesจากไดเรกทอรีย่อยและชื่อไฟล์รายงานทั้งสองที่เกี่ยวข้องกับไดเรกทอรีปัจจุบัน (แม้ว่าคุณจะใช้':(top)'pathspec รวม) ทั้งสองคำสั่งมี--full-nameตัวเลือกในการรายงานชื่อที่สัมพันธ์กับรูท แต่จะปิดโดยปริยาย
เฉพาะ

1
ฉันไม่ได้ใช้ชื่อแทนคอมไพล์ดังนั้นฉันจึงใช้ฟังก์ชันทุบตี แต่อาจเป็นชื่อแทนคอมไพล์ได้ดีกว่าgist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D

62

อัปเดต:สำหรับ git> = 1.9 มีการรองรับรูปแบบที่ไม่รวมอยู่ในระบบให้ดูคำตอบของผู้ใช้เท่านั้น

สิ่งนี้อาจดูด้านหลัง แต่คุณสามารถส่งรายการไฟล์ที่ไม่ตรงกับรูปแบบการยกเว้นของคุณให้เป็นgit grepดังนี้:

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

grep -vส่งกลับทุกเส้นทางไม่<exclude-pattern>ตรงกับ โปรดทราบว่าgit ls-filesยังใช้--excludeพารามิเตอร์ แต่จะนำไปใช้กับไฟล์ที่ไม่ได้ติดตามเท่านั้น


ขอบคุณสำหรับสิ่งนี้! Git grep เร็วกว่า ack & co มาก แต่ไม่สามารถแยกเส้นทางโดยพลการได้มันไม่สะดวกเกินไปที่จะพูด :)
Tomasz Zieliński

2
น่าเสียดายที่ repo ของฉันมีไฟล์จำนวนมาก เมื่อฉันลองใช้วิธีการของ @ kynan ฉันจะได้รับ: "-bash: / usr / bin / git: รายการอาร์กิวเมนต์ยาวเกินไป"
Benissimo

2
สิ่งนี้ควรแก้ไขทั้งปัญหา "รายการอาร์กิวเมนต์ยาวเกินไป" ของ Benissimo และปัญหาของฉันกับ caracters ชื่อไฟล์ที่ตีความโดย bash (เช่น []) หรือชื่อไฟล์ที่มีช่องว่างในที่เก็บ: git ls-files | grep -v <exclue-pattern> | xargs -d '\ n' คอมไพล์ grep <รูปแบบ> -
ลูกเสือ

2
ตรวจสอบคำตอบเพียงอย่างเดียวเท่านั้นมันอาจเป็นไปได้ที่จะทำสิ่งนี้ภายใน (รุ่นที่ทันสมัย) คอมไพล์ในขณะนี้
David

ทำไมต้องลงคะแนน? คำตอบนี้ยังใช้กับเวอร์ชัน git ก่อนหน้า 1.9 ฉันได้เพิ่มบันทึกที่อ้างถึงคำตอบของคนเดียวเท่านั้น
kynan

5

คุณสามารถทำเครื่องหมายไฟล์หรือไดเรกทอรีเป็นเลขฐานสองโดยการสร้างไฟล์คุณลักษณะในที่เก็บของคุณเช่น

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

การจับคู่ในไฟล์ไบนารีจะแสดงรายการโดยไม่มีบรรทัดการรวมเช่น

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

2

ด้วยเช่นโดยการ @kynan เป็นฐานที่ผมทำสคริปต์นี้และวางไว้ในเส้นทางของฉัน ( ~/bin/) ggในฐานะ มันใช้git grepแต่หลีกเลี่ยงชนิดของไฟล์ที่ระบุ

ใน repo ของเรามีภาพจำนวนมากดังนั้นฉันจึงไม่รวม imagefiles และมันจะลดลงเหลือ 1/3 ถ้าฉันค้นหา repo ทั้งหมด แต่สคริปต์นั้นสามารถแก้ไขได้อย่างง่ายดายเพื่อไม่รวม filestypes หรือ geleralpatterns อื่น ๆ

#!/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                                                                      

หมายเหตุ 1

ตามนี้มันเป็นไปได้ที่จะตั้งชื่อสิ่งgit-ggและสามารถเรียกมันเป็นคำสั่ง git ปกติเช่น:

$ git gg searchstring

แต่ฉันไม่สามารถทำงานนี้ได้ ฉันสร้างสคริปต์ในของฉัน~/bin/และทำให้ที่git-ggsymlink /usr/lib/git-core/ใน

โน้ต 2

คำสั่งไม่สามารถทำเป็นshgit-alias ปกติได้เนื่องจากมันจะถูกเรียกใช้ที่รูทของ repo และนั่นไม่ใช่สิ่งที่ฉันต้องการ!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.