कैसे grep (खोज) Git इतिहास में कोड प्रतिबद्ध है


1432

मैंने पिछले दिनों किसी फ़ाइल में कोई फ़ाइल या कोई कोड हटा दिया है। क्या मैं सामग्री में कमी कर सकता हूं (प्रतिबद्ध संदेशों में नहीं)?

एक बहुत ही खराब समाधान लॉग को टटोलना है:

git log -p | grep <pattern>

हालाँकि, यह कमिट हैश को सीधे वापस नहीं करता है। मैंने git grepकोई फायदा नहीं हुआ।


2
जूनियो सी हमानो (git अनुचर) के ये ब्लॉग पोस्ट आपके लिए दिलचस्प हो सकते हैं: * लिनुस का परम कंटेंट ट्रैकिंग टूल ( git log -Sपिकैक्स सर्च अर्थात और दोष के बारे में) * ["git log --grep" के साथ मज़ा] [2] (सर्च कमिट मैसेजेस) ) * ["Git grep" के साथ मज़ा] [3] [२]: gitster.livejournal.com/30195.html [३]: gitster.livejournal.com/27674.html
जैकब नरबसकी २10


उत्तर से संभव डुप्लिकेट वास्तव में काम करता है: stackoverflow.com/a/1340245/492
CAD ब्लॉके

इस के साथ मुद्दा यह है कि यह परिवर्तन को कोई संदर्भ नहीं देता है .. अर्थात जो / जब
सोनिक सोल

जवाबों:


1888

प्रतिबद्ध सामग्री की खोज करने के लिए (यानी, स्रोत की वास्तविक पंक्तियाँ, जैसा कि संदेश और इसी तरह का विरोध किया जाता है), आपको करने की आवश्यकता है:

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

git rev-list --all | xargs git grep <expression> यदि आप "तर्क सूची बहुत लंबी" त्रुटि में काम करते हैं।

यदि आप खोज को कुछ rev-listउप- सीमा (उदाहरण के लिए, "लिब / उपयोग") तक सीमित करना चाहते हैं, तो आपको उसे उप-क्रम में और grepसाथ ही पास करना होगा:

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

यह आपके सभी के लिए प्रतिबद्ध पाठ के माध्यम से grep होगा regexp

दोनों आदेशों में मार्ग पारित करने का कारण rev-listयह है कि संशोधन सूची वापस आ जाएगी जहां सभी परिवर्तन हुए हैं lib/util, लेकिन आपको यह भी पारित करने की आवश्यकता है grepकि यह केवल खोज करेगा lib/util

केवल निम्नलिखित परिदृश्य की कल्पना करें: अन्य फ़ाइलों पर grepसमान मिल सकती है <regexp>जो उसी संशोधन में निहित हैं rev-list(भले ही उस संशोधन में उस फ़ाइल में कोई बदलाव नहीं हुआ हो)।

अपने स्रोत को खोजने के कुछ अन्य उपयोगी तरीके यहां दिए गए हैं:

पाठ से मेल खाने वाले पेड़ की तलाश करें जो नियमित अभिव्यक्ति से मेल खाता हो

git grep <regexp>

नियमित अभिव्यक्ति regexp1 या regexp2 से मेल खाने वाली पंक्तियों के लिए कार्यशील पेड़ खोजें:

git grep -e <regexp1> [--or] -e <regexp2>

नियमित अभिव्यक्ति regexp1 और regexp2 से मेल खाते टेक्स्ट लाइनों की खोज के लिए काम करने वाले पेड़ की खोज करें, केवल फ़ाइल पथों की रिपोर्टिंग करें:

git grep -l -e <regexp1> --and -e <regexp2>

उन फ़ाइलों के लिए कार्यशील ट्री खोजें जिनमें टेक्स्ट की पंक्तियाँ नियमित अभिव्यक्ति regexp1 से मेल खाती हैं और पाठ की पंक्तियाँ नियमित अभिव्यक्ति regexp2 से मेल खाती हैं:

git grep -l --all-match -e <regexp1> -e <regexp2>

पाठ मिलान पैटर्न की बदली हुई रेखाओं के लिए कार्यशील पेड़ खोजें:

git diff --unified=0 | grep <pattern>

पाठ से मेल खाने वाले नियमित अभिव्यक्ति के लिए सभी संशोधन खोजें:

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

पाठ के लिए Rev1 और rev2 के बीच सभी संशोधन खोजें

git grep <regexp> $(git rev-list <rev1>..<rev2>)

61
धन्यवाद, बढ़िया काम करता है! हालांकि यह दुःखद है कि "$ (git rev-list --all)" की आवश्यकता है और शाखा के पूरे इतिहास में खोज को निर्दिष्ट करने के लिए कोई सुविधाजनक स्विच नहीं है।
ऑर्टविन Gentz ​​28:10

3
अति उत्कृष्ट। +1। GitBook कुछ विवरण ( book.git-scm.com/4_finding_with_git_grep.html ) जोड़ता है , और जूनियो सी हमानो
VonC

18
दुर्भाग्य से, मैं इसे msysgit-1.7.4 के साथ नहीं जा सकता। यह मुझे बताता है sh.exe": /bin/git: Bad file number। VonC का उत्तर भी msysgit के साथ काम करता है।
Eckes

4
यदि आपको रीव-लिस्ट के साथ git grep इतिहास प्राप्त करने में "ट्री पढ़ने में असमर्थ" त्रुटि मिलती है, तो आपको सफाई करने की आवश्यकता हो सकती है। आज़माएँ git gcया देखें: stackoverflow.com/questions/1507463/…
एंथनी पनोजो

8
हाँ, यह विंडोज के रूप में अच्छी तरह से विफल करने के लिए लगता है, अफसोस।
मिलीलीटर

551

आपको उपयोग करना चाहिए पिकैक्स ( -S) विकल्प काgit log

के लिए खोज करने के लिए Foo:

git log -SFoo -- path_containing_change
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change

देख इतिहास - अधिक के लिए कीवर्ड द्वारा खोई हुई रेखा खोजें


जैसा जैकब नारुबस्की ने टिप्पणी की:

  • इस उन अंतरों की तलाश करता है जो एक उदाहरण प्रस्तुत करते हैं या निकालते हैं<string> । इसका आमतौर पर मतलब है "संशोधन जिसमें आपने 'फू' के साथ लाइन जोड़ी या हटा दी।"

  • --pickaxe-regexविकल्प आपको बढ़ाया POSIX बजाय एक स्ट्रिंग के लिए खोज की regex का उपयोग करने के लिए अनुमति देता है। उदाहरण (से git log):git log -S"frotz\(nitfol" --pickaxe-regex


जैसा कि रोब ने टिप्पणी की, यह खोज केस-संवेदी है - उन्होंने केस-असंवेदनशील खोज करने के लिए एक अनुवर्ती प्रश्न खोला ।


3
धन्यवाद, मुझे इस विकल्प की जानकारी नहीं थी। यदि आप प्रतिबद्ध संदेशों में रुचि रखते हैं तो यह सबसे अच्छा समाधान है और यदि आप शुद्ध लाइन मिलान के पारंपरिक UNIX grep व्यवहार की आवश्यकता है तो Jeet का समाधान सबसे उपयुक्त है।
ऑर्टविन गेंट्ज़

@ ऑर्टविन: सहमत (और मैंने चुने हुए समाधान को उखाड़ दिया है)। git logअपने प्रश्न में थोड़ा मुझे उलझन में था,)
VonC

12
-pझंडे के साथ इसे अलग-अलग आउटपुट देने के लिए मिलाएं ।
सैंडर

क्या गिट लॉग-एस का उपयोग करके विशिष्ट पैटर्न से मेल खाते सभी निर्देशिकाओं को बाहर करने का कोई तरीका है?
बकाकुना

3
@Anentropic आपको --branches --allसभी रेपो की खोज के लिए विकल्पों की आवश्यकता होगी ।
VONC

249

यह करने के लिए मेरा पसंदीदा तरीके के साथ है git logके -Gविकल्प (संस्करण 1.7.4 में जोड़ा)।

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

यदि कोई मिलान करता है तो विकल्प -Gऔर -Sविकल्प निर्धारित करने के तरीके के बीच एक सूक्ष्म अंतर है :

  • -Sविकल्प अनिवार्य रूप से पहले और एक प्रतिबद्ध के बाद एक फाइल में कई बार अपनी खोज मैचों की संख्या में गिना जाता है। यदि लॉग पहले और बाद में अलग हैं, तो कमिट लॉग में दिखाया गया है। उदाहरण के लिए, यह प्रदर्शित नहीं करेगा कि आपकी खोज से मेल खाने वाली रेखा कहां स्थानांतरित हुई है।
  • उसके साथ -Gविकल्प के , कमिट लॉग में दिखाया गया है यदि आपकी खोज किसी भी लाइन से मेल खाती है, जिसे जोड़ा, हटाया या बदला गया है।

इसे एक उदाहरण के रूप में लें:

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

क्योंकि फ़ाइल में "हैलो" दिखाई देने के पहले और बाद में इस कमिटमेंट की संख्या समान है, यह प्रयोग से मेल नहीं खाएगा -Shello। हालाँकि, चूंकि एक मेल मिलान करने के लिए एक परिवर्तन था hello, इसलिए प्रतिबद्ध का उपयोग करके दिखाया जाएगा -Ghello


2
क्या गिट लॉग आउटपुट में मिलान परिवर्तन संदर्भ दिखाने का कोई तरीका है?
थिलो-एलेक्जेंडर जिंकेल

13
@ थिलो-एलेक्जेंडरगिंकेल - मैं आमतौर पर -pप्रत्येक कमिट के लिए एक फॉर्म दिखाने का विकल्प जोड़ता हूं । फिर जब मेरे पेजर में लॉग खोला जाता है, तो मैं जो कुछ भी खोज रहा हूं उसे खोज रहा हूं। अपने पेजर है lessऔर आप git log -Ghello -p, आप टाइप कर सकते हैं /hello, प्रेस Enter, और प्रयोग nऔर Nकी "हैलो" अगले / पिछले घटनाओं को खोजने के लिए।
टायलर होलियन

मुझे -Gऔर रेगेक्स के साथ एक दिलचस्प मुद्दा मिला : यदि कमांड लाइन यूटीएफ -8 का उपयोग करती है और जिस फाइल को आप देख रहे हैं वह कुछ आईएसओ-लैटिन (8 बिट) एन्कोडिंग का उपयोग करती है, .*विफल रहती है। उदाहरण के लिए, मेरे पास एक परिवर्तन है Vierter Entwurf-> Fünfter Entwurf, और 'V.*ter Entwurf'एक मैच का निर्माण करते समय , 'F.*ter Entwurf'नहीं करता है।
यू। विंडल

51

यदि आप कोड परिवर्तन ब्राउज़ करना चाहते हैं (देखें कि पूरे इतिहास में दिए गए शब्द के साथ वास्तव में क्या बदल गया है) patchमोड के लिए जाएं - मुझे ऐसा करने का एक बहुत ही उपयोगी संयोजन मिला:

git log -p
# Hit '/' for search mode.
# Type in the word you are searching.
# If the first search is not relevant, hit 'n' for next (like in Vim ;) )

11
Accepeted समाधान मेरे लिए न तो काम करता है और न ही लॉग लॉग-एस। यह एक किया!
रॉडव्लोप्स

29

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

नमस्ते, इन लाइनों को काम करने के लिए प्रतीत नहीं होता है। मेरा आदेश है> git log -p --all -S 'public string DOB {get; सेट; } = string.Empty;) और हर बार जब मैं इसे चलाने की कोशिश करता हूं तो मुझे मिलता है> घातक: अस्पष्ट तर्क 'स्ट्रिंग': अज्ञात संशोधन या काम करने वाले पेड़ में नहीं। > 'का उपयोग करें -' संशोधन से पथों को अलग करने के लिए, इस तरह:> 'git <कमांड> [<revision> ...] - [<file> ...]
user216652

@ user216652 किन्हीं कारणों से 'उद्धरण आपके खोज स्ट्रिंग को एक एकल तर्क के रूप में समूहबद्ध नहीं कर रहे हैं। इसके बजाय, 'publicयह तर्क है -S, और यह बाकी को अलग तर्क के रूप में मान रहा है। मुझे यकीन नहीं है कि आप किस वातावरण में चल रहे हैं, लेकिन समस्या निवारण में मदद के लिए यह संदर्भ आवश्यक होगा। मेरा सुझाव है कि यदि आप अपने git कमांड को शेल में भेजा जा रहा है, तो उसके संदर्भ में समस्या निवारण में मदद करने के लिए एक अलग StackOverflow प्रश्न खोलने की आवश्यकता होगी। ऐसा लगता है कि यह किसी अन्य कमांड के माध्यम से भेजा जा रहा है? यहाँ टिप्पणियाँ यह पता लगाने के लिए सही जगह नहीं हैं।
एडवर्ड एंडरसन

26

मैंने जीनत का उत्तर लिया और इसे विंडोज के लिए अनुकूलित किया ( इस उत्तर के लिए धन्यवाद ):

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

ध्यान दें कि मेरे लिए, किसी कारण से, इस regex को हटाने वाली वास्तविक कमिटमेंट कमांड के आउटपुट में नहीं दिखाई देती है, बल्कि इसके पहले एक कमिट होती है।


2
+1 - और यदि आप प्रत्येक खोज के बाद "q" मारने से बचना चाहते हैं, --no-pagerतो अंत में git कमांड में जोड़ें
cgp

2
इसके अलावा, मैं ध्यान दूंगा कि टेक्स्ट फाइल में अप्लाई करने से वास्तव में मैचिंग टेक्स्ट को प्रदर्शित करने का अतिरिक्त फायदा होता है। ( >>results.txtविंडोज पाइपिंग में निपुण नहीं उन लोगों के लिए उपयोग कर एक पाठ फ़ाइल के लिए संलग्न ...
cgp

1
और मैंने सोचा कि बैश का सिंटैक्स बदसूरत है :)
18'18

23

किसी भी संशोधन, किसी भी फ़ाइल में खोजें :

git rev-list --all | xargs git grep <regexp>

केवल कुछ दी गई फ़ाइलों में खोजें, उदाहरण के लिए XML फ़ाइलें:

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

परिणाम लाइनें इस तरह दिखनी चाहिए: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: उस पंक्ति का पाठ जो इसे मिला ...

फिर आप लेखक, तिथि और जानकारी का उपयोग करके अधिक जानकारी प्राप्त कर सकते हैं git show:

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

11

सरलता के लिए, मैं GUI: gitk - Git रिपॉजिटरी ब्राउज़र का उपयोग करने का सुझाव दूंगा । यह काफी लचीला है

  1. कोड खोजने के लिए:

    यहां छवि विवरण दर्ज करें
  2. फ़ाइलों को खोजने के लिए:

    यहां छवि विवरण दर्ज करें
  3. बेशक, यह नियमित अभिव्यक्ति का भी समर्थन करता है:

    यहां छवि विवरण दर्ज करें

और आप ऊपर / नीचे तीर का उपयोग करके परिणामों के माध्यम से नेविगेट कर सकते हैं।


6

किसी और के लिए सॉर्सेट्री में ऐसा करने की कोशिश कर रहा है , इसके लिए यूआई में कोई प्रत्यक्ष कमांड नहीं है (संस्करण 1.6.2.1.0 के रूप में)। हालाँकि, आप टर्मिनल खोलकर स्वीकृत उत्तर में निर्दिष्ट आदेशों का उपयोग कर सकते हैं विंडो (मुख्य टूलबार में उपलब्ध बटन) और उन्हें कॉपी / पेस्ट कर सकते हैं।

नोट: Sourcetree का खोज दृश्य आंशिक रूप से आपके लिए पाठ खोज कर सकता है। खोज दृश्य पर जाने के लिए Ctrl+ दबाएं 3(या तल पर उपलब्ध खोज टैब पर क्लिक करें)। दाईं ओर से, फ़ाइल प्रकारों में खोज प्रकार सेट करें और फिर वह स्ट्रिंग टाइप करें जिसे आप खोजना चाहते हैं। इस विधि में उपरोक्त कमांड की तुलना में निम्नलिखित सीमाएँ हैं:

  1. सॉरीसेट्री केवल कमिट्स दिखाती है है जिनमें परिवर्तित फ़ाइलों में से एक में खोज शब्द होता है। खोज फ़ाइल में शामिल सटीक फ़ाइल को खोजना फिर से एक मैनुअल कार्य है।
  2. RegEx समर्थित नहीं है।

4

जब भी मैं खुद को आपकी जगह पर पाता हूं, मैं निम्नलिखित कमांड लाइन का उपयोग करता हूं:

git log -S "<words/phrases i am trying to find>" --all --oneline  --graph

स्पष्टीकरण:

  1. git log- आवश्यकता है कि मैं यहां और लिखूं; यह कालानुक्रमिक क्रम में लॉग दिखाता है।
  2. -S "<words/phrases i am trying to find>" - यह उन सभी Git को दिखाता है जहां किसी भी फ़ाइल (जोड़े / संशोधित / हटाए गए) में वे शब्द / वाक्यांश हैं जो मैं '<>' प्रतीकों के बिना खोजने की कोशिश कर रहा हूं।
  3. --all - सभी शाखाओं में लागू करने और खोजने के लिए।
  4. --oneline - यह एक लाइन में गिट लॉग को संपीड़ित करता है।
  5. --graph - यह कालानुक्रमिक रूप से आदेशित आवागमन का ग्राफ बनाता है।

1
"जब भी मैं खुद को आपकी जगह पर पाता हूं, मुझे गिट का उपयोग करने की आवश्यकता महसूस होती है!"
सेबी

1
यह एक महान जवाब है!
अल्फ ईटन

@AlfEaton मेरी खुशी!
surajs1n

2

Jeet का जवाब PowerShell में काम करता है।

git grep -n <regex> $(git rev-list --all)

निम्नलिखित सभी फाइलों को प्रदर्शित करता है, किसी भी कमिट में, जिसमें ए password

# Store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# Display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }

1

तो क्या आप कोड के पुराने संस्करणों के माध्यम से देखने की कोशिश कर रहे हैं कि यह देखने के लिए कि कुछ कहाँ मौजूद है?

अगर मैं ऐसा कर रहा था, तो मैं शायद गिट बायसेक्ट का उपयोग करूंगा । बाइसेक्ट का उपयोग करके, आप एक ज्ञात अच्छा संस्करण, एक ज्ञात ख़राब संस्करण और एक सरल स्क्रिप्ट निर्दिष्ट कर सकते हैं जो यह देखने के लिए जाँच करता है कि संस्करण अच्छा है या बुरा (इस मामले में यह देखने के लिए कि क्या आप जिस कोड को देख रहे हैं वह मौजूद है )। इसे चलाने पर कोड हटा दिया गया था।


2
हां, लेकिन आपका "परीक्षण" एक स्क्रिप्ट हो सकता है जो कोड के लिए पकड़ लेता है और "सच" लौटाता है यदि कोड मौजूद है और "गलत" यदि यह नहीं है।
रॉब डी मार्को

2
ठीक है, अगर संशोधन 10 में कोड खराब था, तो संशोधन 11 में अच्छा बन गया और संशोधन 15 में फिर से खराब हो गया ...
पाओलो

2
मैं पाओलो से सहमत हूं। बाइनरी खोज केवल "ऑर्डर किए गए" मूल्यों के लिए उपयुक्त है। गिट बायसेक्ट के मामले में, इसका मतलब है कि सभी "अच्छे" संशोधन सभी "खराब" संशोधनों से पहले आते हैं, संदर्भ बिंदु से शुरू होते हैं, लेकिन ट्रांज़िटरी कोड की तलाश करते समय यह धारणा नहीं बनाई जा सकती है। यह समाधान कुछ मामलों में काम कर सकता है, लेकिन यह एक अच्छा सामान्य उद्देश्य समाधान नहीं है।
केंट

मुझे लगता है कि यह अत्यधिक अक्षम है क्योंकि पूरे पेड़ को कई बार बिसेक्ट के लिए चेक आउट किया जाता है।
यू विंडल

0

परिदृश्य: आपने अपनी IDE का उपयोग करके अपने कोड की एक बड़ी सफाई की। समस्या: आईडीई को इससे अधिक सफाई करनी चाहिए और अब आप कोड (अनुपलब्ध संसाधन, आदि) का संकलन नहीं करते हैं।

समाधान:

git grep --cached "text_to_find"

यह उस फ़ाइल को खोजेगा जहाँ "text_to_find" को बदला गया था।

अब आप इस परिवर्तन को पूर्ववत कर सकते हैं और अपना कोड संकलित कर सकते हैं।


0
git rev-list --all | xargs -n 5 git grep EXPRESSION

Jeet के समाधान के लिए एक ट्विक है , इसलिए यह परिणामों को दिखाता है जबकि यह खोज करता है और न केवल अंत में (जो एक बड़े भंडार में लंबा समय ले सकता है)।


-1

मेरे मामले में मुझे एक छोटे से कमिटमेंट की जरूरत थी और सूचीबद्ध समाधान दुर्भाग्य से काम नहीं कर रहे थे।

मैं इसे करने में कामयाब रहा ( REGEX टोकन की जगह ):

for commit in $(git rev-list --all --abbrev-commit)
do
    if [[ $commit =~ __REGEX__ ]]; then 
        git --no-pager show -s --format='%h %an - %s' $commit
    fi
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.