जीआईटी रीसेट - सॉफ्ट के व्यावहारिक उपयोग?


136

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

मैं समझता हूं कि मैं इंडेक्स या वर्किंग डायरेक्टरी में बदलाव किए बिना एक कमिट को संपादित करने के लिए सॉफ्ट रीसेट का उपयोग कर सकता हूं, जैसा कि मैं करूंगा git commit --amend

क्या ये दोनों आज्ञाएं वास्तव में एक जैसी हैं ( reset --softबनाम commit --amend)? व्यावहारिक रूप में एक या दूसरे का उपयोग करने का कोई कारण? और इससे भी महत्वपूर्ण बात यह है कि क्या कोई reset --softसंशोधन करने के अलावा कोई अन्य उपयोग हैं?

जवाबों:


110

git resetसब चल रहा है HEAD, और आम तौर पर शाखा रेफरी
प्रश्न: वर्किंग ट्री और इंडेक्स का क्या?
जब साथ रोजगार --soft, चाल HEAD, सबसे अधिक बार शाखा रेफरी को अद्यतन करने, और केवलHEAD
यह इस प्रकार है commit --amend:

  • यह एक नई प्रतिबद्धता नहीं बनाता है।
  • यह वास्तव में किसी भी प्रतिबद्ध के लिए हेड को स्थानांतरित कर सकता है (जैसा commit --amendकि केवल चालू नहीं है , जबकि चालू प्रतिबद्ध को फिर से करने की अनुमति है)

केवल संयोजन का यह उदाहरण मिला:

  • एक क्लासिक मर्ज
  • एक उप-मर्ज

सभी एक में (ऑक्टोपस, क्योंकि दो से अधिक शाखाएँ हैं) विलय।

टॉमस "थेम्पी" कार्नेकी अपने "सबट्री ऑक्टोपस मर्ज" लेख में बताते हैं :

  • यदि आप किसी परियोजना को किसी अन्य परियोजना के उपनिर्देशिका में मर्ज करना चाहते हैं, और बाद में सबप्रोजेक्ट को अद्यतित रखना चाहते हैं, तो उप-मर्ज रणनीति का उपयोग किया जा सकता है। यह गिट सबमॉडल्स का एक विकल्प है।
  • ऑक्टोपस मर्ज की रणनीति का उपयोग तीन या अधिक शाखाओं को मर्ज करने के लिए किया जा सकता है। सामान्य रणनीति केवल दो शाखाओं को मिला सकती है और यदि आप इससे अधिक विलय करने का प्रयास करते हैं, तो गिट स्वतः ऑक्टोपस रणनीति पर वापस आ जाता है।

समस्या यह है कि आप केवल एक रणनीति चुन सकते हैं। लेकिन मैं एक साफ इतिहास पाने के लिए दोनों को जोड़ना चाहता था जिसमें पूरे भंडार को एक नए संस्करण में अद्यतन किया जाता है।

मेरे पास एक सुपरप्रोजेक्ट है, चलो इसे कॉल करें projectA, और एक सबप्रोजेक्ट projectB, जिसे मैं एक उपनिर्देशिका में विलय कर दिया projectA

(यह सबट्री मर्ज हिस्सा है)

मैं कुछ स्थानीय कमिट्स भी बना रहा हूं।
ProjectAनियमित रूप से अपडेट किया जाता है, projectBहर दो दिन या सप्ताह में एक नया संस्करण होता है और आमतौर पर एक विशेष संस्करण पर निर्भर करता है projectA

जब मैं दोनों परियोजनाओं को अपडेट करने का फैसला करता हूं, तो मैं बस से नहीं खींचता projectAऔर projectB जैसा कि पूरे प्रोजेक्ट का परमाणु अद्यतन होना चाहिए, इसके लिए दो कमिट बनाएंगे
इसके बजाय, मैं एक एकल मर्ज कमिट बनाता हूं जो जोड़ती है projectA, projectBऔर मेरा स्थानीय कमिट करता है
यहाँ मुश्किल हिस्सा यह है कि यह एक ऑक्टोपस मर्ज (तीन सिर) है, लेकिन projectBइसे सबट्री रणनीति के साथ विलय करने की आवश्यकता है । तो यह है कि मैं क्या:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

यहाँ लेखक ने एक प्रयोग किया reset --hard, और फिर read-treeकाम करने वाले पेड़ और सूचकांक के लिए पहले दो मर्जों को बहाल करने के लिए, लेकिन यह वह जगह है जहाँ reset --softमदद कर सकता है:
मैं उन दो मर्जों को फिर से कैसे करूं , जिन्होंने काम किया है, अर्थात मेरे काम करने वाले पेड़ और सूचकांक हैं ठीक है, लेकिन उन दोनों को रिकॉर्ड करने के लिए बिना?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

अब, हम टॉमस के समाधान को फिर से शुरू कर सकते हैं:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

तो, हर बार:

  • आप जो काम करते हैं (कार्यशील पेड़ और सूचकांक में) से संतुष्ट हैं
  • आप उन सभी कमिटों से संतुष्ट नहीं हैं जो आपको वहाँ ले जाने के लिए ले गईं:

git reset --soft जवाब है।


8
स्वयं पर ध्यान दें: स्क्वैवरफ़्लो का सरल उदाहरण git reset --soft: stackoverflow.com/questions/6869705/…
VonC

3
यदि आप गलत शाखा के लिए प्रतिबद्ध हैं तो भी यह उपयोगी है। सभी परिवर्तन स्टेजिंग क्षेत्र में वापस चले जाते हैं और सही शाखा की जांच करते समय आपके साथ आगे बढ़ते हैं।
18

44

केस का उपयोग करें - स्थानीय आवागमन की एक श्रृंखला को मिलाएं

"उफ़। वे तीन कमिट्स सिर्फ एक हो सकते हैं।"

तो, पिछले 3 (या जो कुछ भी) पूर्ववत करें (सूचकांक को प्रभावित किए बिना और न ही कार्यशील निर्देशिका)। फिर सभी परिवर्तनों को एक के रूप में करें।

उदाहरण के लिए

> git add -A; git commit -m "Start here."
> git add -A; git commit -m "One"
> git add -A; git commit -m "Two"
> git add -A' git commit -m "Three"
> git log --oneline --graph -4 --decorate

> * da883dc (HEAD, master) Three
> * 92d3eb7 Two
> * c6e82d3 One
> * e1e8042 Start here.

> git reset --soft HEAD~3
> git log --oneline --graph -1 --decorate

> * e1e8042 Start here.

अब आपके सभी परिवर्तन संरक्षित हैं और एक के रूप में प्रतिबद्ध होने के लिए तैयार हैं।

आपके प्रश्नों के संक्षिप्त उत्तर

क्या ये दोनों आज्ञाएं वास्तव में एक जैसी हैं ( reset --softबनाम commit --amend)?

  • नहीं।

व्यावहारिक रूप से एक या दूसरे का उपयोग करने का कोई कारण?

  • commit --amend बहुत अंतिम प्रतिबद्ध से या अपने संदेश को बदलने के लिए / rm फ़ाइलों को जोड़ने के लिए।
  • reset --soft <commit> एक नए में कई अनुक्रमिक संयोजन करने के लिए।

और इससे भी महत्वपूर्ण बात यह है कि क्या कोई reset --softसंशोधन करने के अलावा कोई अन्य उपयोग हैं?

  • अन्य उत्तर देखें :)

2
"के लिए कोई अन्य उपयोग कर रहे reset --softहैं के अलावा अन्य जवाब के लिए एक कमिट में संशोधन के अलावा कोई और उपयोग करता है - नहीं"
एंटनी हैचकिंस

अंतिम टिप्पणी के जवाब में - भाग में सहमति व्यक्त की गई, लेकिन मैं कहूंगा कि एक ही प्रतिबद्ध संशोधन बहुत विशिष्ट है। उदाहरण के लिए, आप चाहते हैं कि एक बार एक फीचर लिखे जाने के बाद, सब कुछ स्क्वैश करें और नए कमिट करें, जो समीक्षकों के लिए अधिक उपयोगी हों। मैं कहूंगा कि नरम रीसेट (सादे सहित git reset) तब अच्छा होता है जब आप (ए) इतिहास को फिर से लिखना चाहते हैं, (बी) पुराने कमिट्स के बारे में परवाह नहीं करते हैं (इसलिए आप इंटरएक्टिव छूट के झंझट से बच सकते हैं), और (सी) बदलने के लिए एक से अधिक प्रतिबद्ध हैं (अन्यथा, commit --amendसरल है)।
शाम

18

मैं इसका उपयोग केवल अंतिम प्रतिबद्ध से अधिक संशोधन करने के लिए करता हूं ।

मान लीजिए कि मैंने ए में गलती की है और फिर बी प्रतिबद्ध किया है। अब मैं केवल बी में संशोधन कर सकता हूं। इसलिए git reset --soft HEAD^^मैं सही करता हूं और ए को फिर से प्रतिबद्ध करता हूं और फिर बी को फिर से प्रतिबद्ध करता हूं।

बेशक, यह बड़े कमिट्स के लिए बहुत सुविधाजनक नहीं है ... लेकिन आपको वैसे भी बड़े कमिट नहीं करना चाहिए ;-)


3
git commit --fixup HEAD^^ git rebase --autosquash HEAD~Xअच्छा भी काम करता है।
निकल्स

3
git rebase --interactive HEAD^^जहां आप दोनों ए और बी को संपादित करने का विकल्प चुनते हैं । इस तरह से ए और बी के प्रतिबद्ध संदेश रहते हैं, अगर जरूरत है तो आप अभी भी उन्हें संशोधित कर सकते हैं।
पॉल प्लेजिज 17

2
A को रीसेट करने के बाद मैं B को फिर से कैसे करूँ?
उत्तरबेन

1
एक और तरीका है शायद कम काम है कि: अपने Git लॉग जाँच, बी के हैश प्रतिबद्ध मिलता है, तो git reset A, बनाने के लिए और परिवर्तन जोड़ने, git commit --amend, git cherry-pick <B-commit-hash>
n

15

एक अन्य संभावित उपयोग स्टैशिंग के विकल्प के रूप में है (जो कुछ लोगों को पसंद नहीं है, उदाहरण के लिए देखें https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/ )।

उदाहरण के लिए, अगर मैं एक शाखा पर काम कर रहा हूं और मास्टर पर तत्काल कुछ ठीक करने की आवश्यकता है, तो मैं बस कर सकता हूं:

git commit -am "In progress."

फिर मास्टर चेकआउट करें और ठीक करें। जब मैं पूरा हो जाता हूं, मैं अपनी शाखा में लौटता हूं और करता हूं

git reset --soft HEAD~1

काम करना जारी रखने के लिए जहां मैंने छोड़ा था।


3
अपडेट (अब जब मुझे समझ में आया है कि बेहतर है): --softवास्तव में यहां अनावश्यक है, जब तक कि आप वास्तव में परिवर्तनों के तुरंत होने के बारे में परवाह नहीं करते हैं। मैं अब सिर्फ यह करते git reset HEAD~समय उपयोग करता हूं । तो मेरे पास है कुछ परिवर्तन का मंचन किया जब मैं शाखाओं स्विच करने की आवश्यकता है, और यह कि जिस तरह से रखना चाहते हैं, तो मुझे क्या करना git commit -m "staged changes"है, तो git commit -am "unstaged changes", तो बाद में git reset HEAD~द्वारा पीछा git reset --soft HEAD~करने के लिए पूरी तरह से काम कर रहे राज्य को बहाल। हालाँकि, ईमानदारी से कहूं तो मैं इन दोनों चीजों को बहुत कम करता हूं, जिनके बारे में मुझे पता है git-worktree:)
deltacrux

7

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

एक व्यावहारिक उदाहरण के लिए VonC द्वारा यह उत्तर देखें: Git में पहले दो हिट्स को स्क्वैश करें?


यह एक अच्छा सवाल है जो मुझे पहले नहीं मिला था। लेकिन मुझे यकीन नहीं है कि मैं रीसेट सॉफ्ट का उपयोग करके किसी अन्य शाखा में परिवर्तन कैसे देख सकता हूं। तो मेरे पास चेकआउट ब्रांच है, फिर मैं git reset --soft anotherBranchवहां इस्तेमाल करता हूं और फिर कमिट करता हूं ? लेकिन आप वास्तव में cckckout शाखा को नहीं बदलते हैं, तो क्या आप शाखा या किसी अन्य शाखा के लिए प्रतिबद्ध होंगे ?
एजेजे

ऐसा करते समय यह महत्वपूर्ण है कि आप गिट चेकआउट का उपयोग न करें क्योंकि यह आपके पेड़ को बदल देगा। Git रीसेट के बारे में सोचें - केवल संशोधन HEAD बिंदुओं में हेरफेर करने के तरीके के रूप में।
जोहान्स रुडोल्फ

7

एक संभव उपयोग तब होगा जब आप एक अलग मशीन पर अपना काम जारी रखना चाहते हैं। यह इस तरह काम करेगा:

  1. एक नई शाखा की जांच करें जैसे नाम,

    git checkout -b <branchname>_stash
    
  2. अपनी कड़ी शाखा को धक्का दें,

    git push -u origin <branchname>_stash
    
  3. अपनी दूसरी मशीन पर स्विच करें।

  4. अपनी कड़ी और मौजूदा दोनों शाखाओं को नीचे खींचो,

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. अब आपको अपनी मौजूदा शाखा पर होना चाहिए। स्लैश शाखा से परिवर्तनों में विलय करें,

    git merge <branchname>_stash
    
  6. शीतल अपनी मौजूदा शाखा को अपने मर्ज से पहले 1 पर रीसेट करें,

    git reset --soft HEAD^
    
  7. अपनी स्‍टैश शाखा निकालें,

    git branch -d <branchname>_stash
    
  8. अपनी मूल शाखा को भी मूल से हटा दें,

    git push origin :<branchname>_stash
    
  9. अपने परिवर्तनों के साथ काम करना जारी रखें जैसे कि आपने उन्हें सामान्य रूप से रोक दिया था।

मुझे लगता है, भविष्य में, GitHub और सह। कम चरणों में यह "रिमोट स्टैश" कार्यक्षमता प्रदान करना चाहिए।


2
मैं यह बताना चाहता हूं कि आपकी पहली मशीन पर पहला स्लैश और पॉप पूरी तरह से अनावश्यक है, आप बस एक गंदे काम की नकल से सीधे एक नई शाखा बना सकते हैं, प्रतिबद्ध कर सकते हैं, और फिर परिवर्तनों को रिमोट तक धकेल सकते हैं।

7

एक व्यावहारिक उपयोग यह है कि अगर आपने अपने स्थानीय रेपो के लिए पहले से ही प्रतिबद्ध है (यानी git कमिट-एम) तो आप git रीसेट करके उस अंतिम प्रतिबद्ध को उल्टा कर सकते हैं --soft HEAD ~ 1

अपने ज्ञान के लिए, यदि आपने पहले ही अपने बदलावों का मंचन कर लिया है (यानी git ऐड के साथ।) तो आप git रीसेट करके स्टैगिंग को उल्टा कर सकते हैं - अमिट हेड या मैं आमतौर पर सिर्फ इस्तेमाल किया जाता हैgit reset

अंत में, जीआईटी रीसेट - भार आपके स्थानीय परिवर्तनों सहित सब कुछ मिटा देता है। सिर के बाद ~ आपको बताता है कि ऊपर से जाने के लिए कितने कमिट हैं।


1
git reset --soft HEAD ~1मुझे fatal: Cannot do soft reset with paths.लगता है कि मुझे लगता है कि हमें HEAD के बाद अंतरिक्ष को हटाने की आवश्यकता है ताकि यह होगाgit reset --soft HEAD~1
एंड्रयू लॉहर

6

' git reset --soft <sha1>' का उपयोग करने का एक बड़ा कारण HEADनंगे रेपो में स्थानांतरित करना है।

यदि आप --mixedया --hardविकल्प का उपयोग करने का प्रयास करते हैं , तो आपको एक त्रुटि मिलेगी क्योंकि आप पेड़ और / या सूचकांक को संशोधित करने और काम करने की कोशिश कर रहे हैं जो मौजूद नहीं है।

नोट: आपको इसे सीधे नंगे रेपो से करने की आवश्यकता होगी।

नोट फिर: आपको यह सुनिश्चित करने की आवश्यकता होगी कि जिस शाखा को आप नंगे रेपो में रीसेट करना चाहते हैं वह सक्रिय शाखा है। यदि नहीं, तो आप रेपो के लिए सीधी पहुँच होने पर नंगे रेपो में सक्रिय शाखा को कैसे अपडेट करें, इस पर VonC के उत्तर का पालन करें ।


1
जैसा कि आपके पिछले उत्तर में उल्लेख किया गया है ( stackoverflow.com/questions/4624881/… ), यह सच है जब आपके पास नंगे रेपो (जिसका आप यहां उल्लेख करते हैं) तक सीधी पहुंच है। हालांकि +1।
VonC

@VonC हां, नोट जोड़ने के लिए बिल्कुल सही और धन्यवाद! मैं यह जोड़ना भूल गया कि चूंकि मैं मान रहा हूं कि रेपो से सीधे काम किया जाता है। इसके अलावा, मैं यह मान रहा हूं कि जिस व्यक्ति को नंगे रेपो में रीसेट करना है, वह उनकी सक्रिय शाखा है। यदि शाखा उनकी सक्रिय शाखा नहीं है, तो नंगे रेपो के लिए सक्रिय शाखा को कैसे अपडेट किया जाए, इस पर आपके उत्तर ( stackoverflow.com/questions/3301956/… ) के अनुसार अपडेट करने की आवश्यकता है । मैं सक्रिय शाखा जानकारी के साथ उत्तर को भी अपडेट करूंगा। एक बार फिर धन्यवाद!!!
हेजोक

2

SourceTree एक git GUI है जिसमें आपके इच्छित बिट्स के मंचन के लिए एक बहुत ही सुविधाजनक इंटरफ़ेस है। एक उचित संशोधन में संशोधन के लिए इसके समान दूरस्थ रूप से कुछ भी नहीं है।

तो इस परिदृश्य की git reset --soft HEAD~1तुलना commit --amendमें बहुत अधिक उपयोगी है। मैं प्रतिबद्ध को पूर्ववत कर सकता हूं, सभी परिवर्तनों को मचान क्षेत्र में वापस ला सकता हूं, और SourceTree का उपयोग करके मंचित बिट्स को फिर से शुरू कर सकता हूं।

वास्तव में, यह मुझे लगता है कि commit --amendदोनों की अधिक निरर्थक आज्ञा है, लेकिन गिट गिट है और समान आदेशों से दूर नहीं हटते हैं जो थोड़ा अलग काम करते हैं।


1

जबकि मुझे वास्तव में इस धागे में उत्तर पसंद हैं, मैं git reset --softथोड़ा अलग है, लेकिन फिर भी एक बहुत ही व्यावहारिक परिदृश्य के लिए उपयोग करता हूं ।

मैं विकास के लिए एक आईडीई का उपयोग करता हूं जिसमें मेरी पिछली प्रतिबद्धताओं के बाद परिवर्तन (मंचित और अस्थिर) दिखाने के लिए एक अच्छा उपकरण है। अब, मेरे अधिकांश कार्यों में कई कमिट शामिल हैं। उदाहरण के लिए, मान लें कि मैं किसी विशेष कार्य को पूरा करने के लिए 5 कमिट करता हूं। मैं आईडीई में अंतिम टूल से अपने परिवर्तन को देखने के लिए 1-5 से प्रत्येक वृद्धिशील कमिट के दौरान अलग-अलग टूल का उपयोग करता हूं। मैं इसे करने से पहले अपने परिवर्तनों की समीक्षा करने के लिए एक बहुत ही उपयोगी तरीका है।

लेकिन अपने कार्य के अंत में, जब मैं अपने सभी परिवर्तनों को एक साथ (पहली प्रतिबद्ध से पहले) देखना चाहता हूं, तो एक पुल अनुरोध करने से पहले एक स्व-कोड-समीक्षा करने के लिए, मैं केवल अपनी पिछली प्रतिबद्धताओं (बाद के प्रतिबद्ध) से बदलाव देखूंगा 4) और मेरे वर्तमान कार्य के सभी परिवर्तनों से नहीं।

इसलिए मैं git reset --soft HEAD~44 कमिट्स वापस जाने के लिए उपयोग करता हूं । यह मुझे सभी परिवर्तनों को एक साथ देखने देता है। जब मुझे अपने परिवर्तनों पर विश्वास हो जाता है, तब मैं कर सकता हूं git reset HEAD@{1}और इसे आत्मविश्वास से दूरस्थ रूप से आगे बढ़ा सकता हूं ।


1
... तो फिर करो git add --patchऔर git commitबार-बार आपके द्वारा बनाई गई प्रतिबद्ध श्रृंखला का निर्माण करने के लिए यदि आप जानते थे कि आप सभी के साथ क्या कर रहे थे। आपके पहले कमिट्स आपके डेस्क पर मौजूद नोट्स या मेमो के पहले ड्राफ्ट की तरह हैं, वे आपकी सोच को व्यवस्थित करने के लिए हैं, प्रकाशन के लिए नहीं।
jthill

अरे, मुझे वह नहीं मिला जो आप सुझा रहे हैं।
स्वंय कोडर

1
बस git reset @{1}अपनी पहली-ड्राफ्ट श्रृंखला को पुनर्स्थापित करने के लिए करने के बजाय, आप इसके बजाय git add -pऔर से-प्रकाशन श्रृंखला का निर्माण कर सकते हैं git commit
jthill

हाँ सही। एक अन्य तरीका है (एक मैं आमतौर पर पालन करता हूं) अपस्ट्रीम / मास्टर पर रीबेस करने के लिए और एक ही बार में स्क्वैश करता हूं।
स्वंय कोडर

1

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

आप अगले संस्करण के साथ विकसित हो रहे हैं और आप:

  • हटाए गए सुविधा बी

  • जोड़ा सुविधा डी

इस प्रक्रिया में, सुविधा बी के लिए बस जोड़े गए हॉटफ़िक्स विकसित करें।

आप अगले में विलय कर सकते हैं, लेकिन यह कभी-कभी गड़बड़ हो सकता है, लेकिन आप git reset --soft origin/developअपने परिवर्तनों के साथ भी उपयोग कर सकते हैं और एक प्रतिबद्ध बना सकते हैं और शाखा बिना किसी संघर्ष के विलय योग्य है और अपने परिवर्तनों को बनाए रखें।

यह पता चला है कि git reset --softएक आसान कमांड है। मैं व्यक्तिगत रूप से इसे स्क्वैश करने के लिए बहुत उपयोग करता हूं कि "WIP" की तरह "पूरा काम" नहीं होता है, इसलिए जब मैं पुल अनुरोध को खोलता हूं, तो मेरे सभी कमिट समझ में आते हैं।

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