एक निर्दिष्ट प्रतिबद्ध को कैसे संशोधित किया जाए?


2231

मैं आमतौर पर समीक्षा के लिए आवागमन की एक सूची प्रस्तुत करता हूं। यदि मेरे पास निम्नलिखित कार्य हैं:

  1. HEAD
  2. Commit3
  3. Commit2
  4. Commit1

... मुझे पता है कि मैं सिर प्रतिबद्ध के साथ संशोधित कर सकता हूं git commit --amend। लेकिन मैं कैसे संशोधित कर सकता हूं Commit1, यह देखते हुए कि यह HEADप्रतिबद्ध नहीं है ?


31
यहां एक वैकल्पिक उत्तर देखें: stackoverflow.com/a/18150592/520567 आपका स्वीकृत उत्तर वास्तव में आपके प्रश्न का सटीक उत्तर है, लेकिन यदि आपने संपादन का उपयोग करने का निर्णय लेने से पहले अपनी नई प्रतिबद्ध तैयार की है, तो यह उत्तर अधिक सीधा होगा। यह कई कमिट्स के साथ भी काम कर सकता है जिन्हें आप किसी पुराने के साथ मिलाना / स्क्वैश करना चाहते हैं।
akostadinov

6
इसके अलावा आप सिर्फ Git Tools में एक कमिट स्प्लिटिंग देख सकते हैं - अधिक जानकारी के लिए इतिहास को फिर से लिखना
हकरे

जवाबों:


2951

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

$ git rebase --interactive 'bbc643cd^'

कृपया ^कमांड के अंत में कैरेट पर ध्यान दें , क्योंकि आपको संशोधित करने की इच्छा होने से पहले वास्तव में वापस प्रतिबद्ध करने की आवश्यकता है

डिफ़ॉल्ट संपादक में, 'bbc643cd' का उल्लेख करने वाली पंक्ति में संशोधन pickकरें edit

फ़ाइल सहेजें और बाहर निकलें: git व्याख्या करेगा और स्वचालित रूप से फ़ाइल में कमांड निष्पादित करेगा। आप खुद को पिछली स्थिति में पाएंगे जिसमें आपने अभी-अभी कमिटमेंट किया था bbc643cd

इस बिंदु पर, bbc643cdआपकी अंतिम प्रतिबद्धता है और आप इसे आसानी से संशोधित कर सकते हैं : अपने बदलाव करें और फिर उन्हें कमांड के साथ प्रतिबद्ध करें:

$ git commit --all --amend --no-edit

उसके बाद टाइप करें:

$ git rebase --continue

पिछली हेड कमिट पर वापस जाने के लिए।

चेतावनी : ध्यान दें कि इससे उस एसएचए -1 के साथ-साथ सभी बच्चों को भी बदल दिया जाएगा - दूसरे शब्दों में, यह उस बिंदु से आगे के इतिहास को फिर से लिखता है। यदि आप कमांड का उपयोग करके धक्का देते हैं तो आप ऐसा करने वाले रेपो को तोड़ सकते हैंgit push --force


125
इस प्रवाह के भीतर एक और दिलचस्प विकल्प यह है कि एक बार जब आप उन फाइलों को संशोधित करना चाहते हैं, जिन्हें संशोधित करने के बजाय आप फाइलों को संशोधित करना चाहते हैं और शीर्ष पर दिए गए कमिटमेंट (जिसे आप संपादित कर रहे हैं) पर अमल करते हैं, तो आप उस कमिट को दो अलग-अलग तरीकों से विभाजित करना चाह सकते हैं। (या इससे भी अधिक)। उस स्थिति में, संपादन के लिए वापस जाएँ, और "git रीसेट HEAD ^" चलाएं। जो मंच में उस प्रतिबद्ध की संशोधित फ़ाइलों को डाल देगा। अब अपनी इच्छानुसार कोई भी फाइल उठाएं और कमिट करें। यह प्रवाह "गिट-रिबेस" मैन पेज में काफी अच्छी तरह से समझाया गया है। अनुभाग देखें "विभाजन करना"। bit.ly/d50w1M
डिएगो पिनो

200
Git 1.6.6 और नए में आप इसके बजाय rewordएक्शन का उपयोग कर सकते हैं (यह स्वचालित रूप से संपादक को खोलता है और बाकी के रिबेस चरण के साथ जारी रहता है; यह उपयोग को कम करता है और जब आपको केवल प्रतिबद्ध संदेश को बदलने की आवश्यकता होती है और सामग्री की नहीं; )। git rebase -ieditgit commit --ammendgit rebase --continue
क्रिस जॉन्सन

108
यह ध्यान देने योग्य है कि आपके पास लंबित परिवर्तन git stashहोने से पहले git rebaseऔर git stash popबाद में चलाने की आवश्यकता हो सकती है ।
user123444555621

3
क्या संपादक को खोले बगैर इंटरएक्टिव रीबेस में एक विशिष्ट कमिट को संपादित करने के लिए एक शार्टकुट कमांड है, जिसे कमिट करना, उसे एडिट करना, फिर कमांड लाइन पर वापस जाना है?
sstur

15
ध्यान दें कि नए git के साथ, git commit --all --amend --no-editयहाँ आँख बंद करके उपयोग करने के बजाय शीघ्र निर्देशों का पालन करना समझदारी होगी । इसके बाद मुझे जो करना git rebase -i ...था, वह सब git commit --amendसामान्य रूप से करना था git rebase --continue
एरिक चेन

452

भयानक इंटरैक्टिव रिबेस का उपयोग करें:

git rebase -i @~9   # Show the last 9 commits in a text editor

प्रतिबद्ध आप चाहते हैं, परिवर्तन का पता लगाएं pickकरने के लिए e( edit), और बचाने के लिए और करीब फ़ाइल। Git उस कमिट पर वापस आएगा, जिससे आपको या तो अनुमति मिलेगी:

  • उपयोग git commit --amendपरिवर्तन करने के लिए , या
  • git reset @~अंतिम कमिट को त्यागने के लिए उपयोग करें, लेकिन फ़ाइलों में परिवर्तन नहीं (यानी आपको उस बिंदु पर ले जाएं जब आप फ़ाइलों को संपादित करते थे, लेकिन अभी तक प्रतिबद्ध नहीं थे)।

उत्तरार्द्ध अधिक जटिल सामानों को विभाजित करने के लिए उपयोगी है जैसे कि कई हिट में विभाजित करना।

फिर भागो git rebase --continue , और Git आपके संशोधित कमिट के शीर्ष पर बाद के बदलावों को फिर से करेगा। आपको कुछ मर्ज संघर्षों को ठीक करने के लिए कहा जा सकता है।

नोट: के @लिए आशुलिपि है HEAD, और ~निर्दिष्ट प्रतिबद्ध से पहले प्रतिबद्ध है।

गिट डॉक्स में इतिहास को फिर से लिखने के बारे में और पढ़ें ।


फिर से डरो मत

ProTip ™: इतिहास को फिर से लिखने वाले "खतरनाक" आदेशों के साथ प्रयोग करने से डरो मत; - Git डिफ़ॉल्ट रूप से 90 दिनों के लिए आपके कमिट को नहीं हटाता है; आप उन्हें रिफ्लॉग में पा सकते हैं:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* जैसे विकल्पों के लिए बाहर देखो --hardऔर --forceयद्यपि - वे डेटा को त्याग सकते हैं।
* इसके अलावा, आप जिन भी शाखाओं में सहयोग कर रहे हैं, उन पर इतिहास को फिर से न लिखें।



कई प्रणालियों पर, git rebase -iडिफ़ॉल्ट रूप से विम खोल देगा। विम अधिकांश आधुनिक पाठ संपादकों की तरह काम नहीं करता है, इसलिए विम का उपयोग करके रिबास करने का तरीका देखें । यदि आप एक अलग संपादक का उपयोग करते हैं, तो इसे बदल दें git config --global core.editor your-favorite-text-editor


29
आपके उत्तर के बीच में एक अजीब जगह है जिसे मैं केवल वीआईएम के लिए एक विज्ञापन विज्ञापन के रूप में वर्णित कर सकता हूं। यह सवाल के लिए अप्रासंगिक है और सिर्फ आपके जवाब को टटोलता है।
Intentss

21
@ संकेत: आह, मैं देख सकता हूँ कि अजीब क्यों देखा। इसके पीछे तर्क यह था कि विम कई प्रणालियों पर डिफ़ॉल्ट टेक्स्ट एडिटर है, इसलिए कई लोगों का इंटरेक्टिव रिबासिंग का पहला अनुभव एक स्क्रीन है जहां टाइपिंग कर्सर को चारों ओर से उड़ती है। फिर, वे अपने संपादक को किसी अन्य चीज़ पर स्विच करते हैं, और इंटरैक्टिव रिबासिंग का उनका दूसरा अनुभव काफी सामान्य है, लेकिन उन्हें यह सोचकर छोड़ देता है कि यह GUI के बजाय पाठ फ़ाइल का उपयोग क्यों करता है। रिबासिंग के साथ प्रवाह को प्राप्त करने के लिए, आपको विम, या एमाक्स के रिबेस-मोड जैसी किसी चीज़ की आवश्यकता होती है।
ज़ाज़

9
ठीक है। यह देखते हुए कि बहुत से लोग उस हिस्से को अप्रासंगिक पाते हैं, मैंने इसे 3 लाइनों तक सीमित कर दिया है और यह भी बताया है कि संपादक को कैसे बदलना चाहिए।
ज़ाज़

17
बहुत बढ़िया! मुझे नहीं पता था कि आप @शॉर्टहैंड के रूप में इस्तेमाल कर सकते हैं HEAD। इसे पोस्ट करने के लिए धन्यवाद।
जेम्स

3
git reset @~वास्तव में मैं कमिटमेंट चुनने के बाद क्या करना चाहता था git rebase ...। तुम मेरे हीरो हो)
18 वीं

79

इंटरएक्टिव विद्रोह के साथ--autosquashजब मैं अक्सर इतिहास में गहराई से पिछले कॉमप को ठीक करने की आवश्यकता होती है, तो कुछ के मैं उपयोग करता हूं। यह अनिवार्य रूप से उस प्रक्रिया को गति देता है जो ज़ेलुएक्स का उत्तर दिखाता है, और विशेष रूप से तब काम करता है जब आपके पास एक से अधिक प्रतिबद्ध हों जिन्हें आपको संपादित करने की आवश्यकता होती है।

प्रलेखन से:

--autosquash

जब कमिट लॉग मैसेज "स्क्वैश! ..." (या "फ़िक्अप! ...") से शुरू होता है, और एक ऐसा कमिटमेंट होता है जिसका शीर्षक उसी के साथ शुरू होता है ... स्वचालित रूप से रीबेस-टू की टूडू सूची को संशोधित करें ताकि कमिट स्क्वैशिंग के लिए चिह्नित करने के बाद संशोधित किए जाने के लिए प्रतिबद्ध है

मान लें कि आपके पास एक इतिहास है जो इस तरह दिखता है:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

और आपके पास ऐसे बदलाव हैं जो आप कमिट 2 में संशोधन करना चाहते हैं और फिर अपने बदलावों का उपयोग करके

$ git commit -m "fixup! Commit2"

वैकल्पिक रूप से आप कमिट-मैसेज के बजाय कमिट-शम का उपयोग कर सकते हैं, इसलिए "fixup! e8adec4 या कमिट मैसेज का एक उपसर्ग भी।

फिर पहले की ओर से एक इंटरैक्टिव रिबेट आरंभ करें

$ git rebase e8adec4^ -i --autosquash

आपका संपादक पहले से ही सही ढंग से ऑर्डर किए गए कमिट के साथ खुल जाएगा

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

आपको बस इतना करना है कि बचना है और बाहर निकलना है


21
तुम भी उपयोग कर सकते हैं git commit --fixup=@~के बजाय git commit -m "fixup! Commit2"। यह विशेष रूप से उपयोगी है जब आपके प्रतिबद्ध संदेश लंबे होते हैं और यह पूरी बात को टाइप करने के लिए एक दर्द होगा।
ज़ाज़

42

Daud:

$ git rebase --interactive commit_hash^

प्रत्येक ^इंगित करता है कि आप कितने संपादन करना चाहते हैं, यदि यह केवल एक है (आपके द्वारा निर्दिष्ट किया गया हैश), तो आप सिर्फ एक जोड़ते हैं^

विम का उपयोग करके आप उन कमिटों के लिए शब्दों pickको बदलते हैं जिन्हें आप बदलना rewordचाहते हैं, सहेजना और छोड़ना ( :wq)। फिर git आपको प्रत्येक कमिट के साथ संकेत देगा कि आपने reword के रूप में चिह्नित किया है ताकि आप प्रतिबद्ध संदेश को बदल सकें।

प्रत्येक प्रतिबद्ध संदेश को आपको :wqअगले प्रतिबद्ध संदेश पर जाने के लिए सहेजना और छोड़ना ( ) है

यदि आप परिवर्तनों को लागू किए बिना बाहर निकलना चाहते हैं, तो दबाएँ :q!

संपादित करें : vimआप में नेविगेट jकरने के लिए ऊपर जाने के लिए, kनीचे जाने के लिए, hबाएं जाने के लिए, और lदाएं जाने के लिए उपयोग करें (यह सब NORMALमोड में, मोड ESCपर जाने के लिए दबाएं NORMAL)। पाठ को संपादित करने के लिए, दबाएं iताकि आप उस INSERTमोड में प्रवेश करें, जहां आप पाठ सम्मिलित करते हैं। ESCवापस NORMALमोड पर जाने के लिए दबाएं :)

UPDATE : यहाँ github लिस्टिंग से एक बढ़िया लिंक है कि git के साथ कुछ भी कैसे करें (पूर्व में) पूर्ववत करें


4
मेरे लिए पूरी तरह से काम किया। उल्लेख के लायक git push --force?
u01jmg3

क्या git push --forceकरता है अपने स्थानीय कमिट्स के साथ रीमोट्स कॉमेट्स को ओवरराइट करें। यह इस विषय का मामला नहीं है :)
betoharres

@BetuUuUu बेशक अगर आपके कमिट को रिमोट से पुश किया जाता है और आपने स्थानीय रूप से कमिटेड मैसेज को संशोधित कर दिया है, तो आप रिमोट को पुश करने के लिए बाध्य करना चाहेंगे, है ना?
सुदीप भंडारी

@ सुदीपभंडारी यही भाव मुझे मिलता है। मैंने बल नहीं दिया, और अब मेरे पास एक अतिरिक्त शाखा है, सभी कमिट्स को वापस उसी पर प्रतिबिंबित करना है जिसका संदेश मैंने बदल दिया है, जो सुपर-बदसूरत है।
रफिन

2
@ ग्रीनहाउस यदि आप संशोधित करते हैं और बल-पुश करते हैं, तो टीम के अन्य सदस्य संभवतः विलय के संघर्षों का सामना करेंगे। इसलिए आपको इसके बारे में आम तौर पर सतर्क रहना चाहिए। लेकिन अगर आप किसी ऐसी चीज को संशोधित करते हैं जो किसी और ने नहीं ली है, तो यह ठीक होना चाहिए (इसे ध्यान नहीं दिया जाएगा)। इसलिए मैं विचार करूंगा - अंतिम उपाय के रूप में लागू करता हूं और हमेशा अन्य सदस्यों के साथ रेपो की स्थिति के बारे में परामर्श करता हूं।
टोमाज़ कैक्ज़मरज़िक

18

यदि किसी कारण से आपको इंटरएक्टिव संपादक पसंद नहीं हैं, तो आप उपयोग कर सकते हैं git rebase --onto

कहते हैं कि आप संशोधित करना चाहते हैं Commit1। पहले, पहले से शाखा Commit1:

git checkout -b amending [commit before Commit1]

दूसरा, इसके Commit1साथ पकड़ो cherry-pick:

git cherry-pick Commit1

अब, अपने परिवर्तनों में संशोधन करें, जिससे Commit1':

git add ...
git commit --amend -m "new message for Commit1"

और अंत में, किसी भी अन्य परिवर्तन को रोकने के बाद, अपनी शेष प्रतिबद्धताओं masterको अपनी नई प्रतिबद्धताओं के शीर्ष पर ट्रांसप्लांट करें :

git rebase --onto amending Commit1 master

पढ़ें: ", शाखा पर amending, सभी Commit1(गैर-समावेशी) और master(समावेशी) के बीच में छूट"। वह है, कमिट 2 और कमिट 3, पुरानी कमेटी को पूरी तरह से काट देना। आप उन्हें केवल चुन सकते हैं, लेकिन यह तरीका आसान है।

अपनी शाखाओं को साफ करना याद रखें!

git branch -d amending

4
आप git checkout -b amending Commit1~1पूर्व प्रतिबद्ध पाने के लिए उपयोग कर सकते हैं
टेलर

क्या पहले दो चरण बराबर हैं git checkout -b amending Commit1?
हाशु

16

प्रलेखन के आधार पर

पुराने या कई प्रतिबद्ध संदेशों के संदेश को संशोधित करना

git rebase -i HEAD~3 

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

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

बदलें लेने के साथ reword से पहले प्रत्येक आप बदलना चाहते हैं संदेश के लिए प्रतिबद्ध। मान लीजिए कि आप सूची में दूसरी कमेटी बदलते हैं, आपकी फाइल निम्नलिखित की तरह दिखाई देगी:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

प्रतिबद्ध सूची फ़ाइल को सहेजें और बंद करें, यह आपके प्रतिबद्ध संदेश को बदलने, प्रतिबद्ध संदेश को बदलने और बचाने के लिए आपके लिए एक नया एडिटर पॉप अप करेगा।

अंतिम बल-संशोधित संशोधनों को आगे बढ़ाता है।

git push --force

मुझे निम्न त्रुटि मिलती है: त्रुटि: संपादक 'vi' के साथ एक समस्या थी। कृपया -m या -F विकल्प का उपयोग करके संदेश की आपूर्ति करें।
एरिक मेनार्ड

12

पूरी तरह से गैर-इंटरैक्टिव कमांड (1)

मैंने सोचा था कि मैं एक उपनाम साझा करूंगा जो मैं इसके लिए उपयोग कर रहा हूं। यह गैर-संवादात्मक इंटरैक्टिव रिबेस पर आधारित है । इसे अपने git में जोड़ने के लिए, इस कमांड को चलाएं (नीचे दिया गया स्पष्टीकरण):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

इस कमांड का सबसे बड़ा फायदा यह है कि यह नो-विम है


(1) यह देखते हुए कि निश्चित रूप से रिबेज के दौरान कोई संघर्ष नहीं होता है

प्रयोग

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

नाम amend-toउपयुक्त IMHO लगता है। प्रवाह की तुलना करें --amend:

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

व्याख्या

  • git config --global alias.<NAME> '!<COMMAND>'- एक वैश्विक git उपनाम बनाता है जिसका नाम <NAME>गैर-git कमांड निष्पादित करेगा<COMMAND>
  • f() { <BODY> }; f - एक "अनाम" बैश फ़ंक्शन।
  • SHA=`git rev-parse "$1"`; - तर्क में परिवर्तन करने के लिए तर्क को रूपांतरित करता है, और परिणाम को चर में निर्दिष्ट करता है SHA
  • git commit --fixup "$SHA"- के लिए निर्धारण SHAडॉक्स देखेंgit-commit
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" भाग को अन्य उत्तरों द्वारा कवर किया गया है।
    • --autosquashके साथ संयोजन में क्या उपयोग किया जाता है git commit --fixup, अधिक जानकारी के लिए git-rebaseडॉक्स देखें
    • GIT_SEQUENCE_EDITOR=trueवह है जो पूरी चीज़ को गैर-संवादात्मक बनाता है। यह हैक मैंने इस ब्लॉग पोस्ट से सीखा है

1
एक amend-toहैंडल न की गई फ़ाइलों को भी बना सकता है : git config --global alias.amend-to '!f() { SHA=git Rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
डेट्रायेल

2
इस पद्धति के साथ एक चिंता यह है कि यह असंबंधित फ़िक्सअप लागू कर सकता है।
सिरो सेंटिल्ली 冠状 i i i

क्या प्रश्न का मुद्दा प्रतिबद्ध संदेश को बदलना नहीं है? क्योंकि इस जवाब से पता नहीं चलता है, या कम से कम सीधे नहीं।
10

@ इस प्रश्न को कमिट मैसेज को बदलने के बारे में नहीं पूछता है, यह कमिट को संशोधित करने के बारे में नहीं है कि हेड नहीं है। तो आपके प्रश्न का उत्तर होगा "नहीं, यह प्रश्न का बिंदु नहीं है"
डेट्रायेल

मैं भ्रमित हूं, इसलिए हम प्रतिबद्ध संदेश कैसे बदलते हैं?
ggb667

8

स्वचालित इंटरएक्टिव रिबेट संपादित करें जिसके बाद कम-ओवर के लिए तैयार रहना है

मैंने खुद को एक बार फिर से अतीत की प्रतिबद्धताओं को ठीक करते हुए पाया कि मैंने इसके लिए एक पटकथा लिखी है।

यहाँ वर्कफ़्लो है:

  1. git commit-edit <commit-hash>
    

    यह आपको उस कमिट पर छोड़ देगा जिसे आप संपादित करना चाहते हैं।

  2. जैसा कि आप चाहते हैं, उसे ठीक करें और चरणबद्ध करें।

    (आप ऐसी git stash saveकिसी भी फ़ाइल को रखने के लिए उपयोग करना चाह सकते हैं जिसे आप कमिट नहीं कर रहे हैं)

  3. इसके साथ कमिट करें --amend, जैसे:

    git commit --amend
    
  4. रिबेस पूरा करें:

    git rebase --continue
    

उपरोक्त कार्य करने के लिए, नीचे दी गई स्क्रिप्ट को एक निष्पादन योग्य फ़ाइल में डालें, जिसे git-commit-editआपके नाम से कहीं बुलाया गया है $PATH:

#!/bin/bash

set -euo pipefail

script_name=${0##*/}

warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }

[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"

# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")

if [[ $OSTYPE =~ ^darwin ]]; then
  sed_inplace=(sed -Ei "")
else
  sed_inplace=(sed -Ei)
fi

export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)"  # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty  #  Commit an empty commit so that that cache diffs are un-reversed

echo
echo "Editing commit: $message" >&2
echo

7

इस दृष्टिकोण के लिए आया (और यह संभवतः इंटरैक्टिव रिबास का उपयोग करने के समान है) लेकिन मेरे लिए यह एक तरह से सीधा है।

नोट: मैं इस दृष्टिकोण को उदाहरण के लिए प्रस्तुत करता हूं कि आप हर रोज़ विकल्प के बजाय क्या कर सकते हैं। चूंकि इसके कई चरण हैं (और संभवत: कुछ कैविट्स।)

कहते हैं कि आप प्रतिबद्ध बदलना चाहते हैं 0और आप वर्तमान में हैंfeature-branch

some-commit---0---1---2---(feature-branch)HEAD

इस कमिट के लिए चेकआउट करें और बनाएं quick-branch। आप अपनी सुविधा शाखा को पुनर्प्राप्ति बिंदु (आरंभ करने से पहले) के रूप में भी क्लोन कर सकते हैं।

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

अब आपके पास कुछ इस तरह होगा:

0(quick-branch)HEAD---1---2---(feature-branch)

मंच परिवर्तन, बाकी सब को छिपाने के लिए।

git add ./example.txt
git stash

परिवर्तन करें और वापस चेकआउट करें feature-branch

git commit --amend
git checkout feature-branch

अब आपके पास कुछ इस तरह होगा:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

रीबेस feature-branchपर quick-branch(किसी भी तरह से संघर्ष का समाधान)। स्टेश लगाओ और हटाओ quick-branch

git rebase quick-branch
git stash pop
git branch -D quick-branch

और आप के साथ अंत:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git डुप्लिकेट नहीं होगा (हालांकि मैं वास्तव में किस हद तक नहीं कह सकता) 0 रीबासिंग करते समय।

नोट: सभी प्रतिबद्ध हैश को उस कमिट से शुरू किया जाता है जिसे हम मूल रूप से बदलना चाहते हैं।


6

एक गैर-संवादात्मक आदेश प्राप्त करने के लिए, इस सामग्री के साथ एक स्क्रिप्ट को अपने पथ में रखें:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

अपने परिवर्तनों (साथ git add) और फिर चलाकर इसका उपयोग करें git fixup <commit-to-modify>। बेशक, अगर आप संघर्ष करते हैं, तो यह अभी भी इंटरैक्टिव होगा।


1
यह अच्छा काम करता है। मैंने एक प्रतिबद्ध सेट को पूरा करने के लिए एक गंदे पेड़ के टुकड़ों को ठीक करने के लिए कुछ अतिरिक्त कार्यक्षमता जोड़ी। `गंदी = $ (गिट भिन्न); अगर ["$ {गंदा डिनर}"! = ""]; फिर प्रतिध्वनि "गंदे पेड़ को घूरना"> & 2; git stash; फाई;
सिमोन फेल्टमैन 22

6

git stash+ rebaseस्वचालन

जब मुझे Gerrit समीक्षाओं के लिए एक पुरानी प्रतिबद्ध को संशोधित करने की आवश्यकता होती है, तो मैं कर रहा हूं:

git-amend-old() (
  # Stash, apply to past commit, and rebase the current branch on to of the result.
  current_branch="$(git rev-parse --abbrev-ref HEAD)"
  apply_to="$1"
  git stash
  git checkout "$apply_to"
  git stash apply
  git add -u
  git commit --amend --no-edit
  new_sha="$(git log --format="%H" -n 1)"
  git checkout "$current_branch"
  git rebase --onto "$new_sha" "$apply_to"
)

गिटहब ऊपर

उपयोग:

  • स्रोत फ़ाइल को संशोधित करें, git addअगर पहले से ही रेपो में कोई ज़रूरत नहीं है
  • git-amend-old $old_sha

मुझे यह पसंद है --autosquashक्योंकि यह अन्य असंबंधित फिक्सअप को स्क्वैश नहीं करता है।


बहुत अच्छा वर्कअराउंड, यह git amendमौजूदा स्‍टैश का उपयोग करके किसी विशेष कमिट में बदलाव को लागू करने के लिए एक डिफ़ॉल्ट विकल्प होना चाहिए , बहुत ही चतुर!
कोइहोमामुरा

5

मैंने इसे हल किया,

1) मैं चाहता हूँ कि परिवर्तन के साथ नई प्रतिबद्धता बनाकर ..

r8gs4r commit 0

2) मुझे पता है कि मुझे किस कमिटमेंट के साथ विलय करना है। जो 3 प्रतिबद्ध है।

इसलिए, git rebase -i HEAD~4# 4 हाल की 4 प्रतिबद्धताओं का प्रतिनिधित्व करता है (यहां प्रतिबद्ध 3 वें 4 वें स्थान पर है)

3) इंटरएक्टिव रिबेस में हाल ही में प्रतिबद्ध नीचे स्थित होगा। यह एक जैसे दिखेंगे,

pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0

4) यहां हमें कमिटमेंट को फिर से व्यवस्थित करने की जरूरत है अगर आप विशिष्ट के साथ विलय करना चाहते हैं। यह जैसा होना चाहिए,

parent
|_child

pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1

पुनर्व्यवस्थित करने के बाद आप को बदलने के लिए की जरूरत p pickके साथ f( Fixup बिना संदेश प्रतिबद्ध मर्ज हो जाएगा) या s( स्क्वैश संदेश प्रतिबद्ध के साथ मर्ज रन टाइम में बदल सकते हैं)

और फिर अपने पेड़ को बचाओ।

अब मौजूदा कमिट के साथ मर्ज किया गया।

नोट: जब तक आप अपने दम पर बनाए नहीं रखते, तब तक यह बेहतर तरीका नहीं है। यदि आपके पास बड़ी टीम का आकार है, तो गिट पेड़ को फिर से लिखने के लिए एक स्वीकार्य तरीका नहीं है जो संघर्षों में समाप्त हो जाएगा जिसे आप अन्य अभ्यस्त जानते हैं। यदि आप कम परिश्रम के साथ आपको पेड़ को बनाए रखना चाहते हैं, तो यह कोशिश कर सकते हैं और अगर इसकी छोटी टीम अन्यथा इसके बेहतर नहीं हैं ....।


यह एक अच्छा समाधान है यदि आप एक इंटरैक्टिव रिबेस के दौरान लाइव-संशोधन नहीं करना चाहते हैं।
डुनाटोटोस

4

सबसे अच्छा विकल्प "इंटरएक्टिव रिबेस कमांड" का उपयोग करना है

git rebaseआदेश अविश्वसनीय रूप से शक्तिशाली है। यह आपको प्रतिबद्ध संदेशों को संपादित करने , कमिट्स को संयोजित करने, उन्हें पुनः व्यवस्थित करने ... आदि के लिए अनुमति देता है ।

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

backupरिबासिंग करने से पहले एक शाखा बनाने की सिफारिश की जाती है ताकि जब भी आपको नियंत्रण से बाहर की चीजें मिलें तो आप पिछली स्थिति में वापस आ सकें।

अब इस कमांड का उपयोग कैसे करें?

git rebase -i <base> 

-i"इंटरैक्टिव" के लिए खड़े हो जाओ । ध्यान दें कि आप गैर-संवादात्मक मोड में एक रिबेस कर सकते हैं। उदाहरण के लिए:

#interactivly rebase the n commits from the current position, n is a given number(2,3 ...etc)
git rebase -i HEAD~n 

HEADआपके वर्तमान स्थान को इंगित करता है (शाख नाम या प्रतिबद्ध SHA भी हो सकता है)। इसका ~nमतलब है "n पहले, इसलिए HEAD~n" n "की सूची उस समय से पहले शुरू हो जाएगी जब आप वर्तमान में हैं।

git rebase जैसे अलग कमांड है:

  • pया pickजैसा है वैसा ही रखना।
  • rया reword: कमिट की सामग्री रखने के लिए लेकिन कमिट मैसेज को बदल दें।
  • sया squash: इस कमेटी के बदलावों को पिछली कमेटी (सूची में इसके ऊपर का कमिट) में मिलाने के लिए।
  • ... आदि।

    नोट: चीजों को सरल बनाने के लिए Git को अपने कोड संपादक के साथ काम करना बेहतर है। उदाहरण के लिए यदि आप दृश्य कोड का उपयोग करते हैं तो आप इस तरह जोड़ सकते हैं git config --global core.editor "code --wait"। या आप Google में खोज सकते हैं कि कैसे आप अपने कोड संपादक को जीआईटी के साथ जोड़ सकते हैं।

इसका उदाहरण git rebase

मैं अंतिम 2 बदलाव करना चाहता था जो मैंने किए इसलिए मैंने इस तरह की प्रक्रिया की:

  1. वर्तमान आवागमन प्रदर्शित करें:
    #This to show all the commits on one line
    $git log --oneline
    4f3d0c8 (HEAD -> documentation) docs: Add project description and included files"
    4d95e08 docs: Add created date and project title"
    eaf7978 (origin/master , origin/HEAD, master) Inital commit
    46a5819 Create README.md
    
  2. अब मैं git rebase2 अंतिम संदेश भेजने के लिए उपयोग करता हूं : $git rebase -i HEAD~2 यह कोड संपादक को खोलता है और यह दिखाता है:

    pick 4d95e08 docs: Add created date and project title
    pick 4f3d0c8 docs: Add project description and included files
    
    # Rebase eaf7978..4f3d0c8 onto eaf7978 (2 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    ...
    

    चूंकि मैं इस 2 के लिए प्रतिबद्ध संदेश बदलना चाहता हूं। इसलिए मैं टाइप करूंगा rया उसके rewordस्थान पर pick। फिर फ़ाइल सहेजें और टैब बंद करें। ध्यान दें कि rebaseएक बहु-चरण प्रक्रिया में निष्पादित किया जाता है इसलिए अगला कदम संदेशों को अपडेट करना है। यह भी ध्यान दें कि कमिट रिवर्स कालानुक्रमिक क्रम में प्रदर्शित किए जाते हैं इसलिए अंतिम प्रतिबद्ध उस एक में प्रदर्शित होता है और पहली पंक्ति में पहला कमिट।

  3. संदेशों को अपडेट करें: पहले संदेश को अपडेट करें:

    docs: Add created date and project title to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    सहेजें और दूसरा संदेश संपादित करें बंद करें

    docs: Add project description and included files to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...
    

    सहेजें और बंद करें।

  4. आपको रिबास के अंत तक इस तरह का एक संदेश मिलेगा: Successfully rebased and updated refs/heads/documentationजिसका अर्थ है कि आप सफल होते हैं। आप परिवर्तन प्रदर्शित कर सकते हैं:

    5dff827 (HEAD -> documentation) docs: Add project description and included files to the documentation "README.md"
    4585c68 docs: Add created date and project title to the documentation "README.md"
    eaf7978 (origin/master, origin/HEAD, master) Inital commit
    46a5819 Create README.md
    

    मेरी इच्छा है कि नए उपयोगकर्ताओं की मदद करें :)।


2

मेरे लिए यह रेपो से कुछ साख को हटाने के लिए था। मैंने रिबासिंग की कोशिश की और जिस तरह से रिजेक्ट करने की कोशिश कर रहा था, उस रास्ते से एक टन असंबंधित टकराव हुआ। अपने आप को रिबेट करने के प्रयास को परेशान न करें, मैक पर BFG (brew install bfg) नामक टूल का उपयोग करें।


0

यदि आपने पहले से ही कमिट्स को आगे नहीं बढ़ाया है तो आप पिछली कमिट का उपयोग करके वापस जा सकते हैं git reset HEAD^[1,2,3,4...]

उदाहरण के लिए

git commit <file1> -m "Updated files 1 and 2"
git commit <file3> -m "Updated file 3"

ओह, पहली बार करने के लिए file2 जोड़ना भूल गया ...

git reset HEAD^1 // because I only need to go back 1 commit

git add <file2>

यह पहले कमिट में file2 जोड़ देगा।


0

ठीक है, यह समाधान बहुत मूर्खतापूर्ण लग सकता है, लेकिन कुछ स्थितियों में आपको बचा सकता है।

मेरा एक दोस्त बस गलती से बहुत बड़ी फ़ाइलों (हर 3GB से 5GB के बीच की चार ऑटो-जनरेट की गई फ़ाइलों) के लिए भाग गया और फिर कुछ अतिरिक्त कोड बना दिया जिससे समस्या का एहसास होने से पहले जो git pushअब काम नहीं कर रहा था!

फ़ाइलों को सूचीबद्ध किया गया था, .gitignoreलेकिन कंटेनर फ़ोल्डर का नाम बदलने के बाद, वे उजागर हो गए और प्रतिबद्ध हो गए! और अब उसके ऊपर कोड के कुछ और हिट थे, लेकिन pushहमेशा के लिए चल रहा था (जीबी डेटा अपलोड करने की कोशिश कर रहा था!) ​​और आखिरकार गितूब की फ़ाइल आकार सीमाओं के कारण विफल हो जाएगा ।

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

इसलिए, मैं जिस समाधान के साथ आया था वह था:

  1. वर्तमान git फ़ोल्डर का नाम बदलें ~/Project-old
  2. Gitub (से ~/Project) से फिर से git फ़ोल्डर को क्लोन करें ।
  3. उसी शाखा को चेकआउट करें।
  4. मैन्युअल रूप cp -rसे फ़ाइलों को ~/Project-oldफ़ोल्डर से ~/Project
  5. सुनिश्चित करें कि बड़े पैमाने पर फाइलें, जिन्हें mvएड में चेक करने की जरूरत नहीं है , और .gitignoreठीक से शामिल हैं ।
  6. यह भी सुनिश्चित करें कि आपने .gitहाल ही में क्लोन में फ़ोल्डर को अधिलेखित नहीं किया है~/Project पुराने द्वारा गए । यही वह जगह है जहाँ समस्याग्रस्त इतिहास के लॉग रहते हैं!
  7. अब परिवर्तनों की समीक्षा करें। यह समस्याग्रस्त फाइलों को छोड़कर, हाल ही के सभी कमिट्स का मिलन होना चाहिए।
  8. अंत में बदलाव करें, और push'एड' होना अच्छा है ।

इस समाधान के साथ सबसे बड़ी समस्या यह है कि यह कुछ फाइलों को कॉपी करने के मैनुअल के साथ काम करता है, और यह हाल के सभी कमिट्स को एक में मिला देता है (जाहिर है एक नई कमिट-हैश के साथ।)

बड़े लाभ यह हैं कि, यह हर चरण में बहुत स्पष्ट है, यह बड़ी फ़ाइलों (साथ ही संवेदनशील लोगों) के लिए बहुत अच्छा काम करता है , और यह इतिहास के किसी भी निशान को पीछे नहीं छोड़ता है!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.