अधिकांश पिछले उत्तर खतरनाक रूप से गलत हैं!
यह मत करो:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
अगली बार जब आप दौड़ेंगे git rebase(या git pull --rebase) उन 3 कमिट्स को चुपचाप छोड़ दिया जाएगा newbranch! (नीचे स्पष्टीकरण देखें)
इसके बजाय यह करें:
git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
- सबसे पहले यह 3 सबसे हाल के हिट (
--keepजैसा है --hard, लेकिन सुरक्षित है, के रूप में विफल रहता है के बजाय असम्पीडित परिवर्तन फेंक)।
- तब यह बंद हो जाता है
newbranch।
- फिर यह उन 3 को वापस चुनता है जो चेरी-पिक करता है
newbranch। चूंकि वे अब किसी शाखा द्वारा संदर्भित नहीं हैं, इसलिए ऐसा होता है कि git के reflog का उपयोग करके : HEAD@{2}यह वह प्रतिबद्धता है HEADजिसका उपयोग 2 ऑपरेशनों से पहले करने के लिए किया गया था, अर्थात इससे पहले कि हमने 1. चेक आउट किया था newbranchऔर 2. git reset3 कमिट्स को छोड़ने के लिए उपयोग किया गया था।
चेतावनी: डिफ़ॉल्ट रूप से फिर से सक्षम किया जाता है, लेकिन यदि आपने इसे मैन्युअल रूप से अक्षम कर दिया है (जैसे कि "नंगे" गिट रिपॉजिटरी का उपयोग करके), तो आप चलने के बाद 3 कमिट्स वापस प्राप्त नहीं कर पाएंगे git reset --keep HEAD~3।
एक विकल्प जो रिफ्लॉग पर निर्भर नहीं करता है वह है:
# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3
(यदि आप चाहें तो आप लिख सकते हैं @{-1}- पहले से चेक की गई शाखा - के बजाय oldbranch)।
तकनीकी व्याख्या
git rebaseपहले उदाहरण के बाद 3 कमिट्स क्यों छोड़ेंगे? ऐसा इसलिए है क्योंकि git rebaseकोई भी तर्क --fork-pointडिफ़ॉल्ट रूप से विकल्प को सक्षम नहीं करता है, जो अपस्ट्रीम शाखा के बल-धक्का के खिलाफ मजबूत होने की कोशिश करने के लिए स्थानीय रिफ्लॉग का उपयोग करता है।
मान लीजिए कि आपने मूल / मास्टर को बंद कर दिया है, जब इसमें एम 1, एम 2, एम 3 शामिल है, तो तीन ने खुद को बनाया:
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
लेकिन तब कोई व्यक्ति M2 को हटाने के लिए बल-धक्का मूल / मास्टर द्वारा इतिहास को फिर से लिखता है:
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
अपने स्थानीय रिफ्लॉग का उपयोग करते हुए, git rebaseआप देख सकते हैं कि आपने मूल / मास्टर शाखा के पहले अवतार से कांटा था, और इसलिए कि एम 2 और एम 3 कमिट्स वास्तव में आपकी विषय शाखा का हिस्सा नहीं हैं। इसलिए यह यथोचित रूप से मानता है कि चूंकि M2 को अपस्ट्रीम शाखा से हटा दिया गया था, इसलिए अब आप अपनी विषय शाखा में या तो यह नहीं चाहते कि विषय शाखा में एक बार छूट हो:
M1--M3' <-- origin/master
\
T1'--T2'--T3' <-- topic (rebased)
यह व्यवहार समझ में आता है, और आम तौर पर रिबासिंग करते समय सही काम होता है।
तो यह कारण है कि निम्नलिखित आदेश विफल:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
ऐसा इसलिए है क्योंकि वे गलत स्थिति में शरण छोड़ देते हैं। Git newbranchएक संशोधन में अपस्ट्रीम शाखा को बंद करने के रूप में देखता है जिसमें 3 कमिट शामिल हैं, फिर reset --hardअपस्ट्रीम के इतिहास को कमिट्स को हटाने के लिए फिर से लिखता है, और इसलिए अगली बार जब आप git rebaseइसे चलाते हैं तो उन्हें किसी भी अन्य प्रतिबद्ध की तरह हटा देता है जो अपस्ट्रीम से हटा दिया गया है।
लेकिन इस विशेष मामले में हम चाहते हैं कि उन 3 विषयों को विषय शाखा का हिस्सा माना जाए। इसे प्राप्त करने के लिए, हमें पहले के संशोधन में अपस्ट्रीम बंद करने की आवश्यकता है जिसमें 3 कमिट शामिल नहीं हैं। मेरे सुझाए गए समाधान यही करते हैं, इसलिए वे दोनों सही स्थिति में रिफ्लोग छोड़ देते हैं।
अधिक जानकारी के लिए, की परिभाषा को देखने --fork-pointमें Git रिबेस और Git मर्ज आधार डॉक्स।