2012-12-18 7 views
9

सामान्य समस्या: प्रतिबद्धताओं के एक समूह को देखते हुए, मैं उन सभी कामों की सूची कैसे प्राप्त करूं जो सभी पूर्वजों के रूप में या संबंधित रूप से पहले प्रतिबद्ध हैं, जिनमें सभी शामिल हैं वे काम करता है।गिट प्रतिबद्धताएं खोजें जिनमें कई विशिष्ट प्रतिबद्धताएं हैं

मैं शाखाओं (इसी तरह टैग) कि शाखाओं कि सेट में सभी प्रतिबद्ध के लिए git branch --contains <commit> द्वारा दिया जाता है की तलाश द्वारा प्रतिबद्ध होते हैं पा सकते हैं, लेकिन git rev-list एक --contains विकल्प नहीं है। प्रभावी रूप से, मैं तर्क git rev-list के साथ नियमित के साथ संयोजन करने का एक तरीका ढूंढ रहा हूं, और आउटपुट को सीमित करता है जिसमें सभी सूचीबद्ध काम करता है, उनमें से कोई भी नहीं (जो --contains सामान्य रूप से काम करता है)।

विशिष्ट उदाहरण: को देखते हुए करता है a, b, c, मैं कैसे पा सकते हैं पहले प्रतिबद्ध है कि इसके वंश में सभी तीन करता है?

उदाहरण के लिए, नीचे दिए गए पेड़ को देखते हुए, मैं एक्स को चिह्नित चिह्नित कैसे पा सकता हूं?

* (master) 
| 
X 
|\ 
a * 
| | 
b c 
|/ 
* 
| 
* 

मैं वहाँ कुछ जादू मैं git rev-list साथ कर सकते हैं, और संभवतः <commit1>...<commit2> अंकन शामिल है मान लेते हैं, लेकिन मैं उस से आगे काम नहीं कर सकते हैं।

+0

मैं एक आसान (कुशल) तरीका यह है के बारे में सोच नहीं सकते हैं, सभी की सूची तैयार की कमी विलय करता है, और हर एक का परीक्षण व्यक्तिगत रूप से यह देखने के लिए कि प्रश्न में से प्रत्येक कार्य वहां से पहुंच योग्य है या नहीं। अपेक्षाकृत आसानी से लिपि जा सकता है, लेकिन यह * धीमा * होगा। मुझे लगता है कि 'गिट' के हालिया (यानी 1.8+) संस्करण ने कुछ स्थानों में '--contains' विकल्प जोड़ा जो इससे थोड़ा आसान हो सकता है। – twalberg

+0

क्या बी और सी विभिन्न शाखाओं से संबंधित हैं? – ShadyKiller

+0

@ShadyKiller: विशिष्ट उदाहरण में, हाँ; सामान्य में, नहीं। सभी तीन एक ही शाखा में हो सकते हैं (जिस स्थिति में उत्तर केवल जो भी प्रतिबद्ध होगा वह नवीनतम होगा), या विभिन्न शाखाएं। नरक, तीन से कम या कम हो सकता है; वह एक अपेक्षाकृत मनमाना संख्या थी। –

उत्तर

1

एक संभव समाधान:

प्रयोग करें 'Git मर्ज आधार a b c' प्राप्त करने के लिए एक कॉल में प्रारंभिक बिंदु के रूप में उपयोग ओर रेव-सूची के लिए प्रतिबद्ध; हम इसे $ MERGE_BASE कहते हैं।

'गिट रेव-लिस्ट $ MERGE_BASE..HEAD' कॉल का उपयोग अपने सामान्य पूर्वजों से हेड तक सभी चीजों को सूचीबद्ध करने के लिए करें। इस उत्पादन के माध्यम से लूप (स्यूडोकोड):

if commit == a || b || c 
    break 
else 
    $OLDEST_DESCENDANT = commit 
return $OLDEST_DESCENDANT 

यह ऊपर अपना उदाहरण के लिए काम करेंगे, लेकिन अगर वे, कभी नहीं मिला दिया गया तुरंत प्रतिबद्ध एक के सबसे कम उम्र के बाद, ख में विलय कर दिया नहीं कर रहे थे एक झूठी सकारात्मक दे देंगे , सी, या यदि एकाधिक विलय एक, बी, और सी (यदि वे प्रत्येक अपनी शाखा में रहते हैं) लाने के लिए प्रतिबद्ध होते हैं। उस सबसे पुराने वंशज को खोजने के लिए कुछ काम बाकी है।

आपको उपरोक्त का पालन करना चाहिए OLDEST_DESCENDANT के साथ कुछ शुरू होता है और डीएजी में पीछे की ओर हेड की ओर जाता है (rev-list --reverse $ OLDEST_DESCENDANT ~ ..HEAD), यह देखने के लिए कि 'rev $ $ MERGE_BASE ~ .. $ OLDEST में सभी वांछित ए, बी, और सी शामिल हैं (शायद यह जांचने का एक बेहतर तरीका है कि वे पुन: सूची की तुलना में पहुंच योग्य हैं)।

जैसा कि twalberg का उल्लेख है, व्यक्तिगत रूप से काम करता है परीक्षण करना इष्टतम और धीमी गति से कम लगता है, लेकिन यह एक शुरुआत है। इस दृष्टिकोण का विलय प्रतिबद्धता सूची विधि पर इसका लाभ है कि यह एक वैध प्रतिक्रिया प्रदान करेगा जब सभी इनपुट एक ही शाखा में हों।

प्रदर्शन मर्ज बेस, हेड, एक्स और वांछित प्रतिबद्ध सेट (ए, बी, और सी) के सबसे छोटे बीच के बीच की दूरी से अधिक प्रभावित होगा।

+0

यह अच्छा लग रहा है, मैं बस गया है नहीं, बैठ जाओ स्यूडोकोड ठीक से लिखते हैं, और देखो क्या होता है करने का मौका था। –

-1

कैसे के बारे में:

MERGE_BASE=`git merge-base A B C` 
git log $MERGE_BASE...HEAD --merges 

मान लिया जाये कि आप केवल 1 मर्ज की है।यहां तक ​​कि यदि आपके पास अधिक विलय हो, तो सबसे पुराना व्यक्ति है जिसमें सभी तीन कामों में से एक है

+0

यह केवल बहुत ही सरल परिदृश्यों में काम करता है, अगर संशोधन ग्राफ में गंभीर जटिलता है (जिसे वास्तव में इस तरह के कमांड की आवश्यकता होती है), तो आपको केवल एक संभावित विलय की एक छोटी सूची मिल सकती है जो कि हो सकती है। और जो भी आप चाहते हैं वह प्रतिबद्धता भी एक विलय नहीं है, लेकिन सूचीबद्ध लोगों में से एक हो सकता है। – Chronial

+1

आपको मुझे अभी भी -1 देने की आवश्यकता नहीं थी :(। मैं कम से कम आंशिक रूप से सही था – ShadyKiller

2

मुझे लगता है कि उस प्रश्न का उत्तर यह है कि इसके लिए गिट नहीं बनाया गया था। गिट वास्तव में "प्रतिबद्धता के बच्चों" के विचार को पसंद नहीं करता है, और इसके लिए एक बहुत अच्छा कारण है: यह बहुत अच्छी तरह से परिभाषित नहीं है। क्योंकि एक प्रतिबद्धता अपने बच्चों के बारे में नहीं जानता है, यह एक बहुत ही अस्पष्ट सेट है। आपके पास वास्तव में आपके रेपो में सभी शाखाएं नहीं हो सकती हैं और इसलिए कुछ बच्चे गायब हैं।

गिट्स आंतरिक स्टोरेज स्ट्रक्चर भी एक प्रतिबद्धता के बच्चों को एक महंगे ऑपरेशन ढूंढने में मदद करता है, क्योंकि आपको सभी प्रमुखों के संशोधित ग्राफ को या तो अपनी संबंधित जड़ों तक चलना पड़ता है या जब तक आप उन सभी कामों को नहीं देखते जिनके बच्चे आप जानना चाहते हैं के बारे में।

गिट का समर्थन करने वाली उस तरह की एकमात्र अवधारणा में युक्त एक प्रतिबद्धता का विचार है। लेकिन यह सुविधा केवल बहुत कम गिट कमांड द्वारा समर्थित है (git branch उनमें से एक है)। और जहां गिट इसका समर्थन करता है, यह मनमाने ढंग से काम करने के लिए इसका समर्थन नहीं करता है, बल्कि केवल शाखा प्रमुख है।

यह सब गिट की बजाय कठोर सीमा की तरह प्रतीत हो सकता है, लेकिन व्यावहारिक रूप से यह पता चला है कि आपको प्रतिबद्धता के "बच्चों" की आवश्यकता नहीं है, लेकिन आमतौर पर केवल यह जानने की आवश्यकता होती है कि किन शाखाओं में एक विशिष्ट प्रतिबद्धता है।


सभी ने कहा: यदि आप वास्तव में अपने प्रश्न का उत्तर प्राप्त करना चाहते हैं, तो आपको अपनी खुद की स्क्रिप्ट लिखनी होगी जो इसे पाती है। इसके द्वारा जाने का सबसे आसान तरीका git rev-list --parents --reverse --all के आउटपुट से शुरू करना है। रेखा से उस पंक्ति को पार करते हुए, आप एक पेड़ का निर्माण करेंगे, और प्रत्येक नोड के लिए यह चिह्नित करेगा कि यह उस काम का बच्चा है जिसे आप ढूंढ रहे हैं। एक बार जब आप उनसे मिलते हैं और फिर उस संपत्ति को अपने सभी बच्चों को ले जाते हैं, तो आप इसे स्वयं करते हुए चिह्नित करते हैं।

एक बार जब आपके पास कोई प्रतिबद्धता है जो सभी कामों के रूप में चिह्नित है, तो आप इसे अपनी "समाधान सूची" में जोड़ दें और अपने सभी बच्चों को मृत के रूप में चिह्नित करें - उनमें कोई भी पहला काम नहीं हो सकता है। यह संपत्ति तब भी अपने सभी वंशजों को दी जाएगी।

यदि आप पेड़ के किसी भी हिस्से को स्टोर नहीं करते हैं तो आप यहां कुछ मेमोरी सहेज सकते हैं जिसमें आपके द्वारा मांगी गई कोई भी काम नहीं है।


संपादित हैक कर लिया गया कुछ अजगर कोड

#!/usr/bin/python -O 
import os 
import sys 

if len(sys.argv) < 2: 
    print ("USAGE: {0} <list-of-revs>".format([sys.argv[0]])) 
    exit(1) 

rev_list = os.popen('git rev-list --parents --reverse --all') 

looking_for = os.popen('git rev-parse {0}' 
         .format(" ".join(sys.argv[1:]))).read().splitlines() 
solutions = set() 
commits = {} 

for line in rev_list: 
    line = line.strip().split(" ") 
    commit = set() 
    sha = line[0] 
    for parent in line[1:]: 
     if not parent in commits: 
      continue 
     commit.update(commits[parent]) 
     if parent in solutions: 
      commit.add("dead") 
    if sha in looking_for: 
     commit.add(sha) 
    if not "dead" in commit and commit.issuperset(looking_for): 
     solutions.add(sha) 
    # only keep commit if it's a child of looking_for 
    if len(commit) > 0: 
     commits[sha] = commit 

print "\n".join(solutions) 
संबंधित मुद्दे