जवाबों:
का उपयोग कर git rebase। यह सामान्य "ले कमिट (s) है और इसे एक अलग पैरेंट (बेस)" Git में कमांड / प्लेप करें।
हालांकि, कुछ बातें जानना:
चूंकि SH SHA में उनके माता-पिता शामिल होते हैं, जब आप किसी दिए गए प्रतिबद्ध के माता-पिता को बदल देते हैं, तो उसका SHA बदल जाएगा - जैसा कि सभी एसएचएएस करता है जो उसके बाद आने वाले (इससे अधिक हाल के) विकास की लाइन में है।
यदि आप अन्य लोगों के साथ काम कर रहे हैं, और आपने पहले ही प्रश्न को सार्वजनिक करने के लिए प्रतिबद्ध कर दिया है, जहाँ उन्होंने इसे खींच लिया है, तो कमिट को संशोधित करना शायद एक बुरा विचार है। ™ यह # 1 के कारण है, और इस प्रकार परिणामी भ्रम अन्य उपयोगकर्ताओं के रिपॉजिटरी का सामना करेंगे, जब यह पता लगाने की कोशिश की जाएगी कि आपके एसएचएएस के कारण क्या हुआ, "उसी" के लिए उनके मेल नहीं खाते। (विवरण के लिए लिंक किए गए मैन पेज का "उत्तर प्रदेश से प्राप्त करें" अनुभाग देखें।)
उस ने कहा, यदि आप वर्तमान में कुछ कमिटमेंट वाली शाखा में हैं, जिसे आप एक नए अभिभावक के पास ले जाना चाहते हैं, तो यह कुछ इस तरह दिखाई देगा:
git rebase --onto <new-parent> <old-parent>
इसके बजाय मौजूदा शाखा के बाद सब कुछ स्थानांतरित हो जाएगा ।<old-parent><new-parent>
--ontoलिए प्रयोग किया जाता है! प्रलेखन हमेशा मेरे लिए पूरी तरह से अस्पष्ट रहा है, इस उत्तर को पढ़ने के बाद भी !
git rebase --onto <new-parent> <old-parent>मुझे इस बारे में सब कुछ बताया rebase --ontoकि कैसे उपयोग किया जाता है जो मेरे द्वारा पढ़ा गया प्रत्येक प्रश्न और दस्तावेज़ अब तक विफल रहा है।
rebase this commit on that oneया git rebase --on <new-parent> <commit>। यहां पुराने माता-पिता का उपयोग करने से मुझे कोई मतलब नहीं है।
git rebase <new-parent>।
यदि यह पता चलता है कि आपको बाद में आने वाले कमिटिंग से बचने की आवश्यकता है (जैसे कि एक इतिहास फिर से लिखना अस्थिर होगा), तो आप गिट रिप्लेसमेंट (जीआईटी 1.6.5 और बाद में उपलब्ध ) का उपयोग कर सकते हैं ।
# …---o---A---o---o---…
#
# …---o---B---b---b---…
#
# We want to transplant B to be "on top of" A.
# The tree of descendants from B (and A) can be arbitrarily complex.
replace_first_parent() {
old_parent=$(git rev-parse --verify "${1}^1") || return 1
new_parent=$(git rev-parse --verify "${2}^0") || return 2
new_commit=$(
git cat-file commit "$1" |
sed -e '1,/^$/s/^parent '"$old_parent"'$/parent '"$new_parent"'/' |
git hash-object -t commit -w --stdin
) || return 3
git replace "$1" "$new_commit"
}
replace_first_parent B A
# …---o---A---o---o---…
# \
# C---b---b---…
#
# C is the replacement for B.
उपरोक्त प्रतिस्थापन के साथ, ऑब्जेक्ट B के लिए कोई भी अनुरोध वास्तव में ऑब्जेक्ट C को वापस कर देगा। C की सामग्री बिलकुल वैसी ही है, जैसे B की सामग्री पहले माता-पिता (एक ही माता-पिता को छोड़कर), एक ही पेड़, वही प्रतिबद्ध संदेश)।
प्रतिस्थापन डिफ़ॉल्ट रूप से सक्रिय होते हैं, लेकिन --no-replace-objectsविकल्प को git (कमांड नाम से पहले) का उपयोग करके या GIT_NO_REPLACE_OBJECTSपर्यावरण चर सेट करके चालू किया जा सकता है । प्रतिस्थापन refs/replace/*(सामान्य के अलावा refs/heads/*) को धक्का देकर साझा किया जा सकता है ।
आप पसंद नहीं है के लिए प्रतिबद्ध-munging (के साथ किया sed ऊपर), तो आप उच्च स्तर आदेशों का उपयोग करते हैं तो आपका प्रतिस्थापन बना सकते हैं:
git checkout B~0
git reset --soft A
git commit -C B
git replace B HEAD
git checkout -
बड़ा अंतर यह है कि यह अनुक्रम अतिरिक्त माता-पिता का प्रचार नहीं करता है यदि बी एक मर्ज कमिट है।
refs/replace/रेफ पदानुक्रम को पुश (और लाने) की व्यवस्था करने की आवश्यकता होगी । यदि आपको इसे एक बार करने की आवश्यकता है, तो आप git push yourremote 'refs/replace/*'स्रोत भंडार में, और git fetch yourremote 'refs/replace/*:refs/replace/*'गंतव्य रिपॉजिटरी में कर सकते हैं। यदि आपको इसे कई बार करने की आवश्यकता है, तो आप उन रिफ़ेक्सेस को एक remote.yourremote.pushकॉन्फ़िगर चर (स्रोत रिपॉजिटरी में) और एक remote.yourremote.fetchकॉन्फ़िगर चर (गंतव्य रिपॉजिटरी में) जोड़ सकते हैं।
git replace --grafts। निश्चित नहीं है कि यह कब जोड़ा गया था, लेकिन इसका पूरा उद्देश्य एक प्रतिस्थापन बनाना है जो प्रतिबद्ध बी के समान है लेकिन निर्दिष्ट माता-पिता के साथ है।
ध्यान दें कि Git में एक कमिट को बदलने के लिए यह आवश्यक है कि सभी कमेंट जो इसका पालन करते हैं उन्हें बदलना होगा। यदि आपने इतिहास के इस भाग को प्रकाशित किया है, तो यह हतोत्साहित किया जाता है, और हो सकता है कि किसी ने इतिहास पर अपने काम का निर्माण किया हो।
एम्बर की प्रतिक्रियाgit rebase में उल्लिखित वैकल्पिक समाधान का उपयोग करने के लिए ग्राफ्ट मैकेनिज्म का उपयोग करना है (देखें Git Glossary में Git Graft की परिभाषा और Git Repository Layout दस्तावेज़ीकरण में फ़ाइल के प्रलेखन), एक प्रतिबद्ध माता-पिता को बदलने के लिए, यह देखें कि उसने कुछ इतिहास दर्शक के लिए सही काम किया है ( , इत्यादि) और फिर इसे स्थायी बनाने के लिए (और इसके उदाहरण के "उदाहरण" खंड में वर्णित है ) का उपयोग करें (और फिर ग्राफ्ट को हटा दें, और वैकल्पिक रूप से उसके द्वारा समर्थित मूल रीफ़्रेश को हटा दें , या रिपॉजिटरी को पुनः प्राप्त करें):.git/info/graftsgitkgit log --graphgit filter-branchgit filter-branch
इको "$ कमिट-आईडी $ ग्राफ्ट-आईडी" >> .it / जानकारी / ग्राफ्ट git फ़िल्टर-शाखा $ graft-id..HEAD
ध्यान दें !!! यह समाधान रिबेस के समाधान से अलग है , जिसमें परिवर्तनgit rebase / ट्रांसप्लांट में बदलाव होगा , जबकि ग्राफ्ट-आधारित समाधान बस उतना ही प्रभावी होगा , जो पुराने माता-पिता और नए माता-पिता के बीच अंतर को ध्यान में नहीं रखता है!
git replaceने git graft को अधिगृहीत कर लिया है (यह मानते हुए कि आपके पास 1.6.5 या बाद का git है)।
git-replace+ का उपयोग क्यों नहीं कर सकता git-filter-branch? मेरे परीक्षण में, filter-branchप्रतिस्थापन का सम्मान करने के लिए लग रहा था, पूरे पेड़ को पुन: पेश कर रहा था।
git filter-branchइतिहास को फिर से लिखता है, ग्राफ्ट्स और प्रतिस्थापनों का सम्मान करता है (लेकिन फिर से लिखे गए इतिहास प्रतिस्थापनों में बदलाव किया जाएगा); धक्का गैर fasf- आगे परिवर्तन में परिणाम होगा। git replaceस्थानान्तरण योग्य स्थानापन्न प्रतिस्थापन बनाता है; धक्का तेजी से आगे होगा, लेकिन आपको refs/replaceइतिहास को सही करने के लिए प्रतिस्थापन को स्थानांतरित करने के लिए धक्का देना होगा । HTH
उपरोक्त उत्तरों को स्पष्ट करने के लिए और बेशर्मी से मेरी अपनी स्क्रिप्ट को प्लग करें:
यह इस बात पर निर्भर करता है कि आप "रिबेस" करना चाहते हैं या "रीपेरेंट"। एक रिबेस , के रूप में द्वारा सुझाए गए एम्बर , चारों ओर घूमती है डिफ । एक reparent , के रूप में द्वारा सुझाए गए जेकब और क्रिस , चारों ओर घूमती है स्नैपशॉट पूरे वृक्ष की। यदि आप पीछे हटना चाहते हैं, तो मैं git reparentकाम को मैन्युअल रूप से करने के बजाय उपयोग करने का सुझाव देता हूं ।
मान लीजिए कि आपके पास बाईं ओर की तस्वीर है और आप चाहते हैं कि वह दाईं ओर की तस्वीर की तरह दिखे:
C'
/
A---B---C A---B---C
रिबासिंग और रिप्रेंटिंग दोनों एक ही तस्वीर का उत्पादन करेंगे, लेकिन C'अलग-अलग की परिभाषा । इसके साथ git rebase --onto A B, C'इसमें कोई परिवर्तन नहीं होगा B। के साथ git reparent -p A, C'समान होगा C(सिवाय इसके कि Bइतिहास में नहीं होगा)।
reparentस्क्रिप्ट के साथ प्रयोग किया है ; यह खूबसूरती से काम करता है; अत्यधिक की सिफारिश की । मैं एक नया branchलेबल बनाने की भी सिफारिश करूंगा , और checkoutकॉल करने से पहले उस शाखा में (जैसा कि शाखा लेबल हट जाएगा)।
निश्चित रूप से @ जकूब के जवाब से मुझे कुछ घंटे पहले मदद मिली जब मैं ओपी के समान सटीक कोशिश कर रहा था।
हालांकि, git replace --graftअब ग्राफ्ट से संबंधित आसान उपाय है। इसके अलावा, उस समाधान के साथ एक बड़ी समस्या यह थी कि फ़िल्टर-शाखा ने मुझे हर उस शाखा को ढीला कर दिया था जिसे HEAD की शाखा में विलय नहीं किया गया था। फिर, git filter-repoपूरी तरह से और निर्दोष रूप से काम किया।
$ git replace --graft <commit> <new parent commit>
$ git filter-repo --force
अधिक जानकारी के लिए: डॉक्स में "री-ग्राफ्टिंग हिस्ट्री" सेक्शन को चेकआउट करें