2012-05-25 13 views
10

मैं समझता हूं कि यह कई परिदृश्यों के लिए एक बुरा विचार है। मैं गिट सीख रहा हूं और प्रयोग कर रहा हूं। इस अभ्यास में कोई कोड नुकसान नहीं पहुंचाएगा।गिट में प्रतिबद्ध संदेशों का नाम कैसे बदलें?

मैं इस तरह एक संरचना बनाई है:

* [cf0149e] (HEAD, branch_2) more editing 
* [8fcc106] some edit 
| 
| * [59e643e] (branch_2b) branch 2b 
|/
|/ 
| * [0f4c880] (branch_2_a) branch 2a 
|/
|/ 
* [a74eb2a] checkout 1 
* [9a8dd6a] added branch_2 line 
| 
| 
| * [bb903de] (branch_3) branch 3 
|/ 
| 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

अब मैं इस ग्राफ के माध्यम से जाने के लिए और विभिन्न प्रतिबद्ध नाम बदलने ताकि वे समझ बनाने के लिए चाहते हैं।

उदाहरण के लिए:

* | [a74eb2a] checkout 1 
    * | [9a8dd6a] added branch_2 line 

renamed to: 

    * | [a74eb2a] branch 2 commit 2 
    * | [9a8dd6a] branch 2 commit 1 

ध्यान दें कि:

[cf0149e] (HEAD, branch_2) more editing 
[59e643e] (branch_2b) branch 2b 
[0f4c880] (branch_2_a) branch 2a 

सभी शाखाओं कर रहे हैं बाहर की:

[a74eb2a] checkout 1 

मैं

git rebase -i 328454f 
के साथ प्रयोग किया गया है 363,210

तो बदलते प्रतिबद्ध है कि मैं संशोधित करने के लिए और बाद में

git commit --amend -m "the new message" 

चल के रूप में रिबेस प्रक्रिया जारी रखा चाहते थे पर करने के लिए "संपादित करें" "लेने"।

इस दृष्टिकोण के साथ समस्या यह है कि, अंतिम git rebase --continue के बाद मैं उस शाखा पर दो नए कामों (दो नामों का डुप्लीकेट) नाम बदलना चाहता था।

* [cf0149e] (HEAD, branch_2) more editing 
* [8fcc106] some edit 
* [3ff23f0] branch 2 commit 2 
* [2f287a1] branch 2 commit 1 
| 
| * [59e643e] (branch_2b) branch 2b 
| /
|/
| | * [0f4c880] (branch_2_a) branch 2a 
| |/
| |/ 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| 
| * [bb903de] (branch_3) branch 3 
|/ 
| 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

दूसरे शब्दों में मैं अब प्रतिबद्ध है कि ठीक उसी कोड राज्य का प्रतिनिधित्व के दो सेट है: उदाहरण के लिए, अगर मैं रिबेस भाग गया, जबकि हेड "branch_2" पर था ग्राफ कुछ इस तरह लग सकता है।

मैं बस इतना करना चाहता था कि प्रतिबद्ध संदेश बदल दें।

मैं "परीक्षण" से शुरुआती संदेश का नाम बदलना चाहता हूं जैसे "प्रारंभिक संस्करण"। मुझे git commit --amend -m "Initial version" के साथ ऐसा प्रतीत नहीं होता है क्योंकि अगर मैं चेकआउट करता हूं तो मैं हेडलेस मोड में एंड-अप करता हूं।

मैं क्या गलत कर रहा हूं? निश्चित रूप से यह मुश्किल नहीं हो सकता है।

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

शाखा को संशोधित करने के लिए चेकआउट करें। पैच फ़ाइलें बनाएँ:

git format-patch HEAD~x // Where x is how far back from HEAD you need to patch 

संपादित पैच फ़ाइलें प्रतिबद्ध संदेश बदलने के लिए। अब सिर को रीसेट करें।

git reset --hard HEAD~x // Same x as before 

पैच लागू करें:

git am 000* 

न्यू प्रतिबद्ध नई SHA1 के साथ बनाया जाएगा। यदि किसी भी शाखा को अब सही संदेशों के साथ नए कामों का संदर्भ देने की आवश्यकता है तो आपको उन्हें स्थानांतरित करने के लिए git rebase का उपयोग करना होगा।

इस के साथ पैच प्रक्रिया मैं समाप्त हो गया-अप लागू करने के बाद अपने ही उदाहरण का उपयोग करने के लिए,:

* [7761415] (HEAD, branch_2) branch 2 commit 4 
* [286e1b5] branch 2 commit 3 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [59e643e] (branch_2b) branch 2b 
| | * [0f4c880] (branch_2_a) branch 2a 
| |/ 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

तो, मैं अपने branch_2 अच्छी तरह से लेबल करता है। अब मैं branch_2a स्थानांतरित करने के लिए इतना है कि यह [53d638c] branch 2 commit 2

चेकआउट branch_2a से बाहर शाखाओं

git checkout branch_2a 

यह रिबेस

git rebase 53d638c 

चाहते अब मेरे पास है:

* [fb4d1c5] (HEAD, branch_2a) branch 2a 
| * [7761415] (branch_2) branch 2 commit 4 
| * [286e1b5] branch 2 commit 3 
|/ 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [59e643e] (branch_2b) branch 2b 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

के साथ भी यही प्रक्रिया शाखा_2b में परिणाम:

* [ca9ff6c] (HEAD, branch_2b) branch 2b 
| * [fb4d1c5] (branch_2a) branch 2a 
|/ 
| * [7761415] (branch_2) branch 2 commit 4 
| * [286e1b5] branch 2 commit 3 
|/ 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

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

अब पहली प्रतिबद्धता का नाम बदलने के लिए।

+0

आप नहीं कर सकते। गिट सर्वर-उन्मुख नहीं माना जाता है। यदि आप इसे कहीं और धक्का देते हैं, तो यह है। –

+3

आप अपनी शाखाओं के उन अच्छे आरेखों को कैसे प्राप्त करते हैं? क्या वह एक गिट कमांड था या आपने इसे ASCII का उपयोग करके बाहर निकाला था? –

उत्तर

16

आप वास्तव में कभी भी प्रतिबद्धता नहीं बदल सकते हैं। यदि आप कहीं भी सबसे छोटा एकल-बिट परिवर्तन करते हैं, तो ईमेल लाइन में नाम की वर्तनी से प्रतिबद्ध टाइमस्टैम्प के सटीक दूसरे तक, आपको एक नया, अलग-अलग SHA1 के साथ एक नया, अलग-अलग प्रतिबद्धता मिलती है (SHA1 "सत्य है नाम ", जैसा कि यह गिट डेटाबेस में प्रत्येक" ऑब्जेक्ट "था, जिसमें चार प्रकार के ऑब्जेक्ट में से एक होता है)।

प्रतिबद्धता के अपरिवर्तनीय टुकड़ों में से एक यह है कि यह "मूल काम करता है", जो सबसे हालिया प्रतिबद्धता से पुरानी प्रतिबद्धता के पीछे श्रृंखला का निर्माण करता है।

इसलिए, क्या git rebase -i करता है एक नई प्रतिबद्ध श्रृंखला बनाने के लिए, के साथ प्रत्येक श्रृंखला में प्रतिबद्ध एक ही सामग्री चल रहा है/मूल रूप प्रभाव प्रतिबद्ध प्लस या माइनस आप बातचीत के दौरान किए जाने वाले परिवर्तन। जब यह सब किया जाता है तो यह पुरानी प्रतिबद्धता श्रृंखला के अंत से लेबल (चिपचिपा-नोट, जैसा था) हटा देता है और इसे नई प्रतिबद्धता श्रृंखला के अंत में पेस्ट करता है। यह संशोधित/पुन: संशोधित करने के लिए सबसे पुरानी प्रतिबद्धता की एक प्रति बनाकर शुरू होता है। इस पर एक विवाहित माता-पिता है (जो मूल चेन में एक ही मूल अभिभावक हो सकता है, या एक अलग माता-पिता: किसी भी तरह से यह ठीक है क्योंकि यह नया प्रतिबद्ध है)। फिर यह पुरानी श्रृंखला में अगले की एक प्रति बनाता है, लेकिन नई श्रृंखला को इंगित करता है। यह पुरानी श्रृंखला के अंत तक सभी तरह से दोहराता है।

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

एक शक्तिशाली स्विस-आर्मी-चेनसॉ-ईश कमांड, git filter-branch है, जिसका उपयोग आप "बहुत सारी चीजों को दोबारा करने के लिए कर सकते हैं, जो कि सभी नई प्रतिबद्धताओं (ज्यादातर) समान सामग्री के रूप में करते हैं मूल ", स्टेरॉयड पर git rebase की तरह, जैसा कि आप इस उद्देश्य के लिए उपयोग कर सकते हैं। (सभी शाखाओं को प्रभावित करने के लिए इसे --all के साथ चलाएं।) बेशक, चूंकि यह वास्तव में सभी कामों को फिर से शुरू करता है, इसलिए आप मूल रेपो से मूल रूप से असंबंधित एक रेपो के साथ हवा में उतरते हैं।

प्रारंभिक प्रतिबद्धता (असंभव नहीं) को फिर से लिखना मुश्किल है क्योंकि इसमें कोई अभिभावक नहीं है, इसलिए rebase नियमित रूप से ऐसा नहीं करेगा। (filter-branch कर सकते हैं।) क्योंकि ये परिवर्तन SHA1 आईडी हैं, और जो भी आपके रेपो को क्लोन कर चुका है, उन पर निर्भर/निर्भर करता है, यह आमतौर पर एक विशेषता है कि आप इस तरह के काम करने के साथ झुकाव नहीं कर सकते हैं। जब आप जानते हैं कि कोई और काम किसी विशेष सेट के आधार पर नहीं है, तो आप rebase को अपनी पसंद के अनुसार कर सकते हैं, लेकिन आप प्रारंभिक प्रतिबद्धता पर वापस नहीं जायेंगे क्योंकि यह रेपो के साझा हिस्सों में होगा। यह बहुत दुर्लभ है (बेशक निश्चित रूप से "कभी नहीं") कि पूरी चीज "प्रारंभिक प्रतिबद्धता" पर वापस आने वाली पूरी तरह से आपकी निजी सामग्री है।


जब से मैं यह लिखा, git rebase एक रूट कॉपी करने के लिए सीखा है प्रतिबद्ध तरह प्रारंभिक प्रतिबद्ध। परंपरागत git rebase सिंटैक्स का उपयोग करके, आपको रूट की मूल प्रतिबद्धता का नाम देना होगा, और निश्चित रूप से कोई अभिभावक नहीं है (यही वह ग्राफ में "रूट" बनाता है)। इसलिए rebase इस मामले को कवर करने के लिए एक तर्क के रूप में --root का उपयोग करता है।

कई जड़ें संभव है; उदाहरण के लिए git checkout --orphan का उपयोग करें, इसके बाद git commit, एक नई रूट प्रतिबद्धता बनाने के लिए। इनके पास थोड़ा असामान्य है, हालांकि गिट स्रोत स्वयं को कई जड़ों के साथ एक गिट रेपो में रखा जाता है।

+0

ठीक है, यह समझ में आता है। मैंने पूरे दिन प्रयोग और असफल रहा। खैर, वास्तव में, मैंने नहीं किया, मैंने बहुत कुछ सीखा। मुझे लगता है कि संदेश भेजने की बात आती है जब से यह एक महत्वपूर्ण दूर है "बुद्धिमानी से चुनें"। जबकि मैं समझता हूं कि यह क्यों हो रहा है मैं यह भी सोचने में मदद नहीं कर सकता कि यह संपादन करने के साधनों को प्रदान करना बहुत उपयोगी होगा - चौगुनी चेतावनी के साथ। यदि आप अपने प्रतिबद्ध संदेश में कोई गलती करते हैं तो आप तरह से छिपे हुए हैं। मेरा प्रयोग एक चरम मामला है जहां मैंने सिर्फ संदेशों को फेंक दिया और फिर फैसला किया "अरे, चलो अब उन्हें समझ में आते हैं", जो, ज़ाहिर है, यह बहुत मुश्किल है। –

+3

हाँ! यही कारण है कि गिट के साथ मेरी सामान्य प्रक्रिया एक निजी शाखा (या कई निजी शाखाओं) पर काम करना है और सुनिश्चित करें कि वे निजी रहें, फिर जब चीजें तैयार हों, फिर से जांचें और यदि आवश्यक हो तो सभी प्रतिबद्धताओं को फिर से लिखें प्रकाशित किया। जैसा कि यह था, सब कुछ का एक आखिरी "rebase -i"। – torek

+0

@torek अधिकांश परियोजनाओं के लिए सभी कामों को फिर से जांचने के लिए ओवरकिल की तरह लगता है ... इसके बजाय, तैयार होने तक केवल प्रतिबद्ध न करें, और यदि आप कोई गलती करते हैं, तो बस नई प्रतिबद्धता बनाएं। अधिकांश उपयोग मामलों के लिए बहुत आसान लगता है – Paul

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