เป็นไปได้ไหมที่จะทำการ 'grep search' ในทุกสาขาของโครงการ Git


144

เป็นไปได้หรือไม่ที่จะทำงานgit grepภายในทุกสาขาของโครงการที่มาของตัวควบคุม Git หรือมีคำสั่งอื่นให้เรียกใช้?



คำตอบ:


195

คำถาม " วิธีการ grep (ค้นหา) คอมมิตโค้ดในประวัติคอมไพล์แนะนำ:

 git grep <regexp> $(git rev-list --all)

ที่ค้นหาผ่านการกระทำทั้งหมดซึ่งควรรวมทุกสาขา

อีกรูปแบบหนึ่งคือ:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

คุณสามารถค้นหาตัวอย่างเพิ่มเติมได้ในบทความนี้ :

ฉันลองข้างต้นในโครงการเดียวที่ใหญ่พอที่คอมไพล์บ่นเกี่ยวกับขนาดอาร์กิวเมนต์ดังนั้นหากคุณพบปัญหานี้ให้ทำสิ่งที่ชอบ:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(ดูทางเลือกอื่นในส่วนสุดท้ายของคำตอบด้านล่าง)

อย่าลืมการตั้งค่าเหล่านั้นหากคุณต้องการ:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

นามแฝงนี้สามารถช่วยได้เช่นกัน:

git config --global alias.g "grep --break --heading --line-number"

หมายเหตุ: chernjie แนะนำว่าgit rev-list --allเป็น overkill

คำสั่งที่ละเอียดยิ่งขึ้นสามารถ:

git branch -a | tr -d \* | xargs git grep <regexp>

ซึ่งจะช่วยให้คุณค้นหาเฉพาะสาขา (รวมถึงสาขาระยะไกล)

คุณสามารถสร้างนามแฝง bash / zsh ได้ด้วย:

alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

อัปเดตสิงหาคม 2559: RMแนะนำในความคิดเห็น

ฉันได้รับ " fatal: bad flag '->' used after filename" เมื่อลองใช้git branchเวอร์ชันนี้ ข้อผิดพลาดนี้เกี่ยวข้องกับHEADสัญกรณ์นามแฝง

ฉันแก้ไขได้โดยการเพิ่มsed '/->/d'ในท่อระหว่างtrและxargsคำสั่ง

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

นั่นคือ:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>

ไม่ควรไพพ์เอาต์พุตgit branchเป็น tr หรือ sed git branchเป็นคำสั่งเครื่องลายครามที่มีไว้สำหรับการบริโภคของมนุษย์ ดูstackoverflow.com/a/3847586/2562319สำหรับทางเลือกอื่นที่ต้องการ
jbyler

@jbyler จุดดี. กระแทกแดกดันผมโพสต์คำตอบเกี่ยวกับพอร์ซเลนนานก่อนที่คำตอบนี้: stackoverflow.com/a/6978402/6309 และฉันจะใช้มันเช่นในstackoverflow.com/a/19206916/6309
VonC

ใช่ดี เมื่อพิจารณาถึงคำตอบอื่น ๆ ฉันคิดว่าคำตอบของ @errordeveloper นั้นสะอาดที่สุด: stackoverflow.com/a/21284342/2562319 : "git grep <regexBR> $ (git for-each-ref --format = '% (refname) 'refs /) "
jbyler

2
มีวิธีใดบ้างที่จะแสดงชื่อสาขาที่ตรงกับการค้นหา
franksands

66

git log อาจเป็นวิธีที่มีประสิทธิภาพมากขึ้นในการค้นหาข้อความในทุกสาขาโดยเฉพาะอย่างยิ่งหากมีรายการที่ตรงกันมากและคุณต้องการดูการเปลี่ยนแปลงล่าสุด (ที่เกี่ยวข้อง) ก่อน

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

คำสั่งบันทึกเหล่านี้แสดงรายการคอมมิตที่เพิ่มหรือลบสตริงการค้นหา / regex ที่กำหนด (โดยทั่วไป) ล่าสุดก่อน -pตัวเลือกที่ทำให้เกิดความแตกต่างที่เกี่ยวข้องกับการแสดงที่รูปแบบที่ถูกเพิ่มหรือลบออกเพื่อให้คุณสามารถเห็นมันในบริบท

เมื่อพบการคอมมิตที่เกี่ยวข้องซึ่งเพิ่มข้อความที่คุณกำลังมองหา (เช่น 8beeff00d) ให้ค้นหาสาขาที่มีคอมมิต:

git branch -a --contains 8beeff00d

22

ฉันพบว่าสิ่งนี้มีประโยชน์ที่สุด:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

คุณจะต้องปรับอาร์กิวเมนต์สุดท้ายโดยขึ้นอยู่กับว่าคุณต้องการดูเฉพาะสาขาระยะไกลเทียบกับท้องถิ่นเท่านั้นเช่น:

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

นามแฝงที่ฉันสร้างขึ้นมีลักษณะดังนี้:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'

1
นามแฝงที่น่าสนใจ +1. แม่นยำกว่าในคำตอบของฉัน
VonC

จะทำให้นามแฝงของคุณทำงานสำหรับการค้นหาวลีได้อย่างไร เมื่อฉันส่ง "foo bar" เป็นพารามิเตอร์ฉันจะได้รับ: fatal: ambiguous อาร์กิวเมนต์ 'bar': การแก้ไขที่ไม่รู้จักหรือเส้นทางที่ไม่อยู่ในโครงสร้างการทำงาน ใช้ "-" เพื่อแยกเส้นทางจากการแก้ไข
jutky

ลองหนีจากอวกาศ: "foo \ bar"
Garry Gomez

นี่จะเป็นคำตอบที่ยอมรับอย่างชัดเจน) ฉันได้ขยายเพื่อค้นหาเฉพาะในสาขาล่าสุดของโครงการของฉัน (มีมากกว่า 500 อย่าถามและแต่ละ grep ใช้เวลาประมาณ 4 วินาทีดังนั้นฉันจึงไม่ต้องการหรือไม่ต้องการ ในการค้นหามากกว่าพูด 100 รายการล่าสุด) สำหรับสิ่งนี้ฉันได้อัปเดตgit for-each-refด้วย--sort=-committerdate --count=100! ขอบคุณสำหรับแนวคิดดั้งเดิม!
Vser

6

เป็นไปได้ที่จะทำสองวิธีทั่วไป: Bash หรือ Git นามแฝง

นี่คือสามคำสั่ง:

  1. git grep-branch - ค้นหาในทุกสาขาในพื้นที่และระยะไกล
  2. git grep-branch-local - ค้นหาในสาขาท้องถิ่นเท่านั้น
  3. git grep-branch-remote - สาขาห่างไกลเท่านั้น

การใช้งานจะเหมือนกับ git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

GREP โดยใช้: ชื่อแทน Git

ไฟล์ ~ / .gitconfig

ควรเพิ่มคำสั่งลงใน~/.gitconfigไฟล์ด้วยตนเองเนื่องจากgit config --global aliasประเมินโค้ดที่ซับซ้อนที่คุณเพิ่มและทำให้มันยุ่งเหยิง


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

หมายเหตุ: เมื่อคุณเพิ่มนามแฝงและไม่สามารถรันได้ให้ตรวจสอบแบ็กสแลช\อาจต้องใช้ Escape เพิ่มเติม\\เมื่อเทียบกับคำสั่งbash

  • git branch -a - แสดงทุกสาขา
  • sed -e 's/[ \\*]*//'- ตัดช่องว่าง (จากbranch -a) และ * (มีชื่อสาขาที่ใช้งานอยู่);
  • grep -v -e '\\->'- ละเว้นชื่อที่ซับซ้อนเช่นremotes/origin/HEAD -> origin/master;
  • grep '^remotes' - รับทุกสาขาที่ห่างไกล
  • grep -v -e '^remotes'- รับสาขายกเว้นสาขาห่างไกล

ตัวอย่าง git grep-branch-local -n getTastyCookies

-n นำหน้าหมายเลขบรรทัดกับบรรทัดที่ตรงกัน

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

โครงสร้างปัจจุบันคือ:

: - ตัวคั่น

  1. สาขา: dev
  2. หมายเลขบรรทัด: 53
  3. เส้นทางไฟล์: modules/factory/getters.php
  4. สายการจับคู่: function getTastyCookies($user)

GREP โดยใช้: BASH

ดังที่คุณควรทราบ: คำสั่ง Bash ควรเก็บไว้ใน.shสคริปต์หรือเรียกใช้ในเชลล์

สาขาในพื้นที่เท่านั้น

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

สาขาที่อยู่ห่างไกลเท่านั้น

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

สาขาในพื้นที่และห่างไกล

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"

ฟังดูดี แต่ฉันได้รับข้อผิดพลาดนี้จากgit grep-branch "find my text":fatal: ambiguous argument 'client': both revision and filename
nealmcb

ทำไมต้องใช้เสมอ-aซึ่งแสดงทุกสาขา? ฉันขอแนะนำให้ใช้ตัวเลือกสำหรับgit branchคำสั่งเพื่อแยกวงเล็บ เมื่อมองไปที่สาขาในท้องถิ่นมีเพียงสาขาเดียว*ดังนั้นไม่จำเป็นต้องหลีกเลี่ยง ดังนั้น: git branch | sed -e 's/*/ /' | xargs git grep "TEXT"สำหรับสาขาในพื้นที่เท่านั้นgit branch -r | grep -v -- "->" | xargs git grep "TEXT"สำหรับสาขาที่ห่างไกลเท่านั้นและgit branch -a | grep -v -- "->" | xargs git grep "TEXT"สำหรับทุกสาขา
มกราคม


4

หากคุณให้ค่าแฮช SHA-1 ใด ๆ กับgit grepคุณให้ค้นหาในนั้นแทนการใช้สำเนาที่ใช้งานได้

ในการค้นหาทุกสาขา, คุณจะได้รับทุกgit rev-list --allต้นไม้ด้วย ใส่ทั้งหมดด้วย

git grep "regexp" $(git rev-list --all)

... และมีความอดทน

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