2012-03-16 13 views
11

मैं एक गिट रिपोजिटरी में संग्रहीत एक बहु-वर्ष के इतिहास से “ हीटमैप ” बनाने का प्रयास कर रहा हूं जहां ग्रैन्युलरिटी की इकाई व्यक्तिगत कार्य है। कार्य अधिक गर्म हो जाते हैं, अधिक बार, और अधिक गैर-खाली रेखाओं के साथ बदलते हैं।मैं सी कोड के गिट रिपोजिटरी में फ़ंक्शंस के साथ बदली गई लाइनों को कैसे जोड़ूं?

एक शुरुआत के रूप में, मैं

git log --patch -M --find-renames --find-copies-harder --function-context -- *.c 

के उत्पादन में मैं Hackage से Language.C का उपयोग कर को देखा की जांच की है, लेकिन यह पूरी तरह से अनुवाद इकाई — विस्तार हेडर चाहते करने लगता है और सभी — बल्कि एक से निपटने के लिए सक्षम किया जा रहा स्रोत खंड

--function-context विकल्प संस्करण 1.7.8 के बाद नया है। कार्यान्वयन in v1.7.9.4 is a regex की नींव:

PATTERNS("cpp", 
     /* Jump targets or access declarations */ 
     "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n" 
     /* C/++ functions/methods at top level */ 
     "^([A-Za-z_][A-Za-z_0-9]*([ \t*]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n" 
     /* compound type at top level */ 
     "^((struct|class|enum)[^;]*)$", 
     /* -- */ 
     "[a-zA-Z_][a-zA-Z0-9_]*" 
     "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" 
     "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), 

यह सीमाओं पहचान करने के लिए काफी अच्छा है, लेकिन हमेशा diff हंक, जैसे की पहली पंक्ति के रूप में कार्य छोड़ ’ टी नहीं करता है लगता है, #include शीर्ष पर या एक हंक के साथ निर्देश जिसमें कई फ़ंक्शन परिभाषाएं हैं। प्रत्येक समारोह के लिए अलग-अलग शिकारी उत्सर्जित करने के लिए भिन्नता बताने का विकल्प वास्तव में उपयोगी होगा।

यह ’ टी सुरक्षा-महत्वपूर्ण है, इसलिए मैं कुछ यादों को सहन कर सकता हूं। क्या इसका मतलब है कि मेरे पास ज़विंस्की ’ एस “two problems” है?

+2

बहुत ही रोचक सवाल! अंत में कुछ "मैं गिट करने के लिए नया हूं, मैं एक प्रतिबद्धता पूर्ववत कैसे करूं?" के अलावा कुछ और। भारी तोपखाने के लिए इंतजार कर रहे हैं (यानी वॉनसी) :) – ralphtheninja

+0

क्या आप कृपया स्रोत भाषा की पुष्टि करेंगे सी या सी ++? – gbulmer

+0

@gbulmer स्रोत भाषा सी है 'गिट diff' सी और सी ++ में फ़ंक्शन परिभाषाओं को पहचानने के लिए आंतरिक रूप से समान पैटर्न का उपयोग करती है। –

उत्तर

1

मुझे एहसास है कि यह सुझाव थोड़ा स्पर्शपूर्ण है, लेकिन यह आवश्यकताओं को स्पष्ट करने और रैंक करने में मदद कर सकता है। यह सी या सी ++ के लिए काम करेगा ...

टेक्स्ट ब्लॉक ढूंढने की कोशिश करने और उन्हें तुलना करने की बजाय, बाइनरी ब्लॉक बनाने के लिए कंपाइलर का उपयोग करें। विशेष रूप से, एक परिवर्तन सेट में प्रत्येक सी/सी ++ स्रोत फ़ाइल के लिए, इसे किसी ऑब्जेक्ट पर संकलित करें। फिर ऑब्जेक्ट कोड को तुलना के आधार के रूप में उपयोग करें।

यह आपके लिए संभव नहीं हो सकता है, लेकिन आईआईआरसी संकलन के लिए जीसीसी पर एक विकल्प है ताकि प्रत्येक फ़ंक्शन जेनरेट ऑब्जेक्ट कोड फ़ाइल में 'स्वतंत्र खंड' में संकलित हो। लिंकर प्रत्येक 'खंड' को एक प्रोग्राम में खींच सकता है। (यह बहुत देर हो रही है, इसलिए यदि आप इस विचार में रूचि रखते हैं, तो मैं इसे सुबह में देखूंगा।)

तो, मान लीजिए कि हम ऐसा कर सकते हैं, आपके पास बहुत सारे फ़ंक्शन परिभाषित किए जाएंगे बाइनरी कोड, तो एक साधारण 'गर्मी' तुलना 'किसी भी समारोह के लिए संस्करणों के बीच कोड कितना लंबा या छोटा है?'

मैं यह भी सोच रहा हूं कि कार्यों के लिए असेंबलर का पुनर्निर्माण करने के लिए ओबजडम्प का उपयोग करना व्यावहारिक हो सकता है। मैं रजिस्टर नामों को ट्रिम करने के लिए इस चरण में कुछ नियमित अभिव्यक्तियों का उपयोग कर सकता हूं, ताकि आवंटन में परिवर्तन में परिवर्तन बहुत अधिक सकारात्मक सकारात्मक (परिवर्तन) न हो।

मैं फ़ंक्शन निकायों में असेंबलर निर्देशों को सॉर्ट करने का प्रयास भी कर सकता हूं, और उन्हें दो फ़ंक्शन कार्यान्वयन के बीच "हटाए गए" बनाम "जोड़ा" का पैटर्न प्राप्त करने के लिए अलग कर सकता हूं। इससे बदलाव का एक उपाय मिलेगा जो कि लेआउट से काफी स्वतंत्र है, और यहां तक ​​कि कुछ स्रोतों के आदेश से कुछ हद तक स्वतंत्र है।

तो यह देखना दिलचस्प हो सकता है कि एक ही फ़ंक्शन के दो वैकल्पिक कार्यान्वयन (यानी।अलग-अलग परिवर्तन सेट से) एक ही निर्देश हैं :-)

यह दृष्टिकोण सी ++ के लिए भी काम करना चाहिए क्योंकि सभी नामों को उचित रूप से उलझाया गया है, जो कि समान कार्यों की तुलना की जानी चाहिए।

तो, नियमित अभिव्यक्ति रखा जा सकता है बहुत ही सरल :-)

मान लिया जाये कि यह सब स्पष्ट है, इस दृष्टिकोण आप देने के लिए क्या असफल हो सकता है?

साइड नोट: यह मूल रणनीति किसी भी भाषा के लिए काम कर सकती है जो मशीन कोड को लक्षित करती है, साथ ही वीएम निर्देश सेट जावा वीएम बाइटकोड, .NET CLR कोड इत्यादि जैसे भी।

+0

इसे इनलाइनिंग और ऑप्टिमाइज़र सेटिंग्स –

+0

द्वारा फेंक दिया जाएगा यह एक दिलचस्प दृष्टिकोण है। यह विशेष रेपो एक अन्य रेपो में लाइब्रेरी पर निर्भर करता है, इसलिए क्लाइंट रेपो संकलित करने योग्य (* यानी *, उचित घोषणाएं और शीर्षलेख उपलब्ध) रखने के लिए मुझे अलग-अलग दरों पर दोनों इतिहासों के माध्यम से वापस जाना होगा। –

+0

@ बेन वोगेट - मुझे लगता है कि संकलन विकल्प समान होंगे, और यह व्यवस्थित करने के लिए सीधा होना चाहिए। मुझे लगता है कि संकलक बहुत अराजक नहीं है (फ्रैक्टल अर्थ में)। किसी फ़ंक्शन के भीतर ऑपकोड को सॉर्ट करके, और पंजीकरण नामों को हटाने से वास्तविक कोड में अंतर यह इंगित करेंगे कि "प्रभावी" परिवर्तन कितना हुआ है। यह सही नहीं है, लेकिन आईएमएचओ एक पाठ तुलना के लिए एक दिलचस्प विकल्प है।उसी कंपाइलर विकल्पों के लिए, जेनरेट कोड स्तर पर वास्तव में परिवर्तित नहीं किए गए फ़ंक्शंस, लेकिन टेक्स्ट में बदलाव हुए हैं, यह भी एक दिलचस्प विश्लेषण हो सकता है। – gbulmer

0

नियमित अभिव्यक्तियों का उपयोग करने के बजाए, सामान्य टूल में से एक का उपयोग करके, एक सरल पार्सर बनाने पर विचार करना उचित हो सकता है। जाहिर है कि आप जिस चीज से परिचित हैं, या जो आपका संगठन पहले से उपयोग कर रहा है उसे चुनना बेहतर है।

इस समस्या के लिए, एक पार्सर को वास्तव में कोड को सत्यापित करने की आवश्यकता नहीं है (मुझे लगता है कि यह चेक होने पर मान्य है), और इसे कोड को समझने की आवश्यकता नहीं है, इसलिए यह काफी गूंगा हो सकता है।

यह टिप्पणियां दूर कर सकता है (नई लाइनों को बनाए रख सकता है), पाठ तारों की सामग्री को अनदेखा कर सकता है, और प्रोग्राम टेक्स्ट को एक बहुत ही सरल तरीके से इलाज कर सकता है। इसे मुख्य रूप से संतुलित '{' '}', संतुलित '(' ')' का ट्रैक रखने की आवश्यकता होती है और अन्य सभी वैध प्रोग्राम टेक्स्ट केवल व्यक्तिगत टोकन होते हैं जिन्हें 'सीधे माध्यम' से पारित किया जा सकता है।

यह आउटपुट ट्रैकिंग को आसान बनाने के लिए एक अलग फ़ाइल/फ़ंक्शन हो सकता है।

यदि भाषा सी या सी ++ है, और डेवलपर्स उचित रूप से अनुशासित हैं, तो वे कभी भी 'गैर-वाक्य रचनात्मक मैक्रोज़' का उपयोग नहीं कर सकते हैं। यदि ऐसा है, तो फ़ाइलों को preprocessed होने की आवश्यकता नहीं है।

फिर एक पार्सर ज्यादातर सिर्फ एक समारोह का नाम (एक पहचानकर्ता) फ़ाइल दायरे में (पैरामीटर-सूची) के बाद की तलाश में है {... कोड ...}

मैं लूट था यह होगा कुछ दिन yacc & लेक्स/फ्लेक्स & बाइसन का उपयोग करके काम करते हैं, और यह इतना आसान हो सकता है कि उन्हें पार्सर जनरेटर की आवश्यकता नहीं है।

यदि कोड जावा है, तो एएनटीएलआर एक संभव है, और मुझे लगता है कि एक सरल जावा पार्सर उदाहरण था।

यदि हास्केल आपका ध्यान केंद्रित है, तो वे छात्र परियोजनाएं प्रकाशित हो सकती हैं, जिन्होंने एक पार्सर पर उचित स्टैब बनाया है।

+0

यह उस दृष्टिकोण के समान लगता है जो मैं स्केचिंग कर रहा हूं। मैं किसी दिए गए फ़ंक्शन परिभाषा से संबंधित diff hunk में रेखाओं की सीमा जानना चाहता हूं। लाइनों को जोड़ा या हटाए जाने के कारण बाहरी असंतुलित ब्रेसिज़ को मिलान करना अतिरिक्त असंतुलित ब्रेसिज़ की वजह से है। –

+0

@ ग्रेग बेकन - आह! मुझे लगता है मैं समझ गया! मैं एक और दृष्टिकोण के बारे में सोच रहा हूं, लेकिन मुझे खाने के लिए कुछ चाहिए। मैं एक 'तीसरा रास्ता "प्रस्तावित कर सकता हूं? – gbulmer

संबंधित मुद्दे

 संबंधित मुद्दे