Skip to content
This page has been auto-translated and may contain errors.View in English

Git में परिवर्तन और commits को वापस लाना

docs.scrimba.com

कुछ न कुछ हमेशा वापस लाने की जरूरत होती है। आपने एक संपादन किया जो आपको नहीं चाहिए था, एक फिक्स की कोशिश की जिससे चीजें और खराब हुईं, या ऐसा कुछ commit किया जो कोई नहीं देखना चाहेगा। Git आपके प्रोजेक्ट के लगभग हर संस्करण का रिकॉर्ड रखता है जो इसने कभी देखा है, इसलिए अधिकांश गलतियां उस समय की तुलना में अधिक सुधार योग्य होती हैं जब वे लगती हैं। कौन सा उपकरण आपको वापस लाता है यह इस बात पर निर्भर करता है कि गलती कितनी दूर गई है: अभी भी आपके संपादक में बैठी हुई है, पहले से ही staged है, पहले से ही commit है, या पहले से ही कहीं push है जहां एक टीम सदस्य इसे देख सकता है। यह अध्याय उस क्रम में प्रत्येक चरण के माध्यम से चलता है।

push और pull क्या हैं?

Push आपके commits को repository की एक साझा प्रति में भेजता है जहां से टीम के सदस्य भी काम करते हैं, और pull उनके commits को आपके पास नीचे लाता है। Remotes और GitHub दोनों को पूरी तरह से कवर करता है; इस अध्याय के लिए, "pushed" का अर्थ है commit आपकी मशीन छोड़ चुका है।

इसे commit करने से पहले एक परिवर्तन को त्यागना

मान लीजिए कि आप commit loop से weather-app में styles.css को restyling कर रहे हैं, और नया layout एक बुरा विचार साबित होता है। आपने इसे staged नहीं किया है, आपने इसे commit नहीं किया है। आप फाइल को वापस उसी तरह चाहते हैं जैसे यह आखिरी बार लगती थी, कुछ नहीं और। ठीक इसी काम के लिए कमांड git restore है:

bash
$ git status
On branch main
Changes not staged for commit:
        modified:   styles.css

$ git restore styles.css

$ git status
On branch main
nothing to commit, working tree clean

git restore <file> एक uncommitted संपादन को फेंक देता है और फाइल को इसकी अंतिम सहेजी गई स्थिति में डाल देता है। यदि आपने अपना विचार बदलने से पहले पहले से ही git add के साथ परिवर्तन को staged कर दिया है, तो सादा git restore इसे छूएगा नहीं, क्योंकि फाइल अब staging area में बैठी है केवल आपकी working directory में नहीं। पहले इसे unstage करें, फिर इसे restore करें:

bash
$ git add styles.css
$ git restore --staged styles.css
$ git restore styles.css

दो अलग-अलग क्षेत्रों के लिए दो अलग-अलग कदम: git restore --staged एक फाइल को staging area से वापस बाहर ले जाता है, और अपने आप git restore आपकी working directory में संपादन को त्याग देता है। git restore केवल uncommitted काम तक पहुंचता है, एक बार commit होने के बाद, एक अलग कमांड ले लेता है।

पुराने tutorials और scripts git restore <file> करता है जो git checkout -- <file> आजकल करता है उसी काम के लिए। checkout पहले "switch branches" और "restore a file" दोनों के रूप में दोहरा कार्य करता था, जो भ्रामक था, इसलिए Git ने दोनों को switch और restore में विभाजित किया। आप अभी भी पुरानी सामग्री में checkout मिलेगा, इसे पहचानें, लेकिन जो कुछ भी आप अब लिखते हैं उसमें restore तक पहुंचें। आप git restore . के साथ current folder में हर unstaged परिवर्तन को एक बार में त्याग सकते हैं, जो एक pause से लायक है क्योंकि यह एक बार में हर फाइल को साफ करता है।

restore की undo working directory पर दृढ़ता से रुकती है। एक commit एक सहेजी गई वस्तु है जो Git के garbage collection को हटाने तक इसके आसपास रहती है, यही कारण है कि एक बुरा commit एक hard reset के बाद भी reflog के माध्यम से recoverable है। एक uncommitted संपादन को कभी एक saved object में बदला नहीं गया था: restore एक फाइल के अंतिम सहेजे गए संस्करण को आपके संपादन पर चेक करता है, और कहीं भी कोई पहले की स्थिति नहीं है जहां से खोदने के लिए है। यह committing करने का व्यावहारिक कारण है जल्दी और अक्सर। एक messy commit लगभग हमेशा fixable है; एक संपादन जो आपने कभी सहेजा ही नहीं वह आमतौर पर नहीं है।

Junoएक uncommitted परिवर्तन को त्यागनाgit restore <file> एक edit को फेंक देता है जो आपने commit नहीं किया है और फाइल को वापस उसी तरह डाल देता है जैसे वह आखिरी बार थी। यदि आपने पहले से ही git add के साथ परिवर्तन को staged कर दिया है, तो पहले git restore --staged <file> के साथ इसे unstage करें, फिर फाइल को restore करें यदि आप संपादन को गायब करना चाहते हैं। यह केवल ऐसे परिवर्तनों पर काम करता है जिन्हें आपने अभी तक commit नहीं किया है, इसलिए यह एक गलती को बचा नहीं सकता जो आपने पहले से ही सहेजी है।
Junoएक uncommitted परिवर्तन को त्यागनाgit restore <file> git checkout -- <file> के लिए आधुनिक प्रतिस्थापन है, और git restore . folder में हर unstaged परिवर्तन को साफ करता है, इसलिए पहले git status चलाएं यह देखने के लिए कि वह क्या छूएगा। आप अभी भी पुराने उत्तरों और scripts में इस काम को करते हुए checkout देखेंगे, यह एक पुरानी, अधिक overloaded नाम के तहत एक ही विचार है।
Junoएक uncommitted परिवर्तन को त्यागनाrestore कभी भी एक commit नहीं बनाता या छूता है, यह केवल आपकी working directory को एक फाइल के अंतिम saved संस्करण से overwrite करता है। इसका मतलब है कि यदि आप गलत हैं तो यह recovery के लिए कोई trail नहीं छोड़ता है, लगभग सब कुछ और इस अध्याय में नहीं। छोटा और अक्सर commit करें, और "oops" एक समस्या में बदल जाता है जिसे reset या reflog fix कर सकते हैं, एक परिवर्तन की बजाय जो कभी return करने के लिए एक save point नहीं था।

git stash के साथ काम को एक तरफ रखना

कभी-कभी कोई गलती नहीं होती है fix करने के लिए, केवल बुरा timing होता है। आप styles.css पर mid-edit हैं और एक टीम सदस्य आपको अभी दूसरी branch पर चाहिए, लेकिन आप half-finished styling को commit करने के लिए तैयार नहीं हैं। git stash आपके परिवर्तनों को shelf करता है और आपको एक clean working directory देता है ताकि आप दूर हो सकें और बाद में वापस आ सकें।

bash
$ git status
On branch main
Changes not staged for commit:
        modified:   styles.css

$ git stash
Saved working directory and index state WIP on main: 8f3c7d1 Cache forecast responses in localStorage

$ git status
On branch main
nothing to commit, working tree clean

styles.css में संपादन गायब नहीं है, यह parked है। एक बार तैयार होने पर git stash pop के साथ इसे वापस लाएं:

bash
$ git stash pop
On branch main
Changes not staged for commit:
        modified:   styles.css

git stash उन परिवर्तनों के लिए है जिन्हें आप अभी तक commit करने के लिए तैयार नहीं हैं, यह कभी भी आपकी branch पर एक commit नहीं बनाता है।

एक single stash शायद ही कभी वास्तविक सप्ताह के काम को कवर करता है, इसलिए toolkit के बाकी हिस्से को जानें। git stash list सब कुछ दिखाता है जो आपने shelf किया है, सबसे recent पहले। git stash pop top entry को reapply करता है और इसे list से हटाता है; git stash apply इसे reapply करता है लेकिन इसे list में छोड़ता है, उपयोगी यदि आप एक ही shelved परिवर्तन को दो branches पर चाहते हैं। रास्ते में एक stash को नाम दें, तो list बाद में unlabeled entries की दीवार नहीं है:

bash
$ git stash push -m "wip: forecast card layout"
$ git stash list
stash@{0}: On main: wip: forecast card layout

एक stash Git में सब कुछ और के समान commit machinery से बना हुआ है। git stash आपकी staged और unstaged स्थिति को कुछ commit objects के रूप में सहेजता है और एक special reference, refs/stash, को इनकी ओर इशारा करता है, यही कारण है कि git stash list अपने आप में एक छोटे इतिहास की तरह पढ़ता है। reflog इसी समान trick पर निर्भर करता है, एक reference जो commits को point करता है जो कोई branch नहीं पहुंचता।

Junoकाम को एक तरफ रखनाgit stash ऐसे परिवर्तनों को shelf करता है जिन्हें आप commit करने के लिए तैयार नहीं हैं, इसलिए आपकी working directory clean हो जाती है, और git stash pop उन्हें बाद में वापस लाता है। कुछ भी commit नहीं होता है और कुछ भी खोता नहीं है, संपादन एक बिट के लिए parked रहता है। मैं लगातार इसे पहुंचता हूं जब भी एक टीम सदस्य मुझे अभी दूसरी branch पर चाहता है।
Junoकाम को एक तरफ रखनाgit stash list हर shelf किए गए परिवर्तन को दिखाता है, pop सबसे recent को reapply और remove करता है, apply इसे remove किए बिना reapply करता है। push -m के साथ रास्ते में stashes को नाम दें, एक stash list full unlabeled entries एक हफ्ते बाद किसी को भी मदद नहीं करता है, आपको शामिल करके।
Junoकाम को एक तरफ रखना एक stash कुछ commit objects है जो refs/stash point करता है, किसी भी branch से दूर बैठा है, यही कारण है कि यह अपने स्वयं के tiny history की तरह behave करता है। एक बार आप इसे इस तरह देख लें, stash जादू की तरह महसूस करना बंद कर देता है, यह सामान्य object model को एक बार फिर से करते हुए समान trick है।

git revert के साथ एक commit को undo करना

मान लीजिए commit 8f3c7d1, "Cache forecast responses in localStorage", गलत साबित होता है, और यह पहले से ही pushed है, इसलिए एक टीम सदस्य ने इसे भी pull किया है। इस commit को अब rewrite करना ऐसा कुछ बदलना है जो किसी और के पास पहले से ही है, और उनकी प्रति और आपकी अगली बार pull करने पर disagree करेगी। git revert यह हल करता है बिना कुछ बदले जो पहले से ही exist करता है: यह एक बिल्कुल नई commit बनाता है जो परिवर्तन के opposite को apply करता है।

bash
$ git revert 8f3c7d1
[main 2b6f0d1] Revert "Cache forecast responses in localStorage"

History अभी भी दोनों commits को दिखाता है, original और जो इसे undo करता है, क्रम में। किसी की प्रति को reshape करने की जरूरत नहीं है, एक टीम सदस्य किसी अन्य की तरह new revert commit को pull करता है।

git revert हमेशा एक commit पर safe है जो दूसरों के पास पहले से ही है, क्योंकि यह एक पुरानी को change करने की बजाय एक नई commit जोड़ता है।

एक परिवर्तन को revert करना जो बाद के commits के साथ overlap करता है एक conflict produce कर सकता है, merging और conflicts covers के समान प्रकार: Git <<<<<<<, =======, और >>>>>>> के साथ फाइल को mark करता है और आपको इसे resolve करने के लिए wait करता है। markers को fix करें, git add फाइल को, फिर git revert --continue के साथ finish करें।

bash
$ git revert 8f3c7d1
Auto-merging src/index.js
CONFLICT (content): Merge conflict in src/index.js

$ git add src/index.js
$ git revert --continue

Revert की safety shared history पर same idea पर rest करती है never rebasing a public branch के पीछे: एक commit को rewrite करना जो दूसरों ने पहले से ही pull किया है उनकी प्रति और आपकी out of sync के लिए force करता है, और किसी को बाद में mismatch के पास force करना पड़ता है। Revert हर existing commit को बिल्कुल वैसे ही रखता है जैसे यह था। यह केवल एक नई जोड़ता है, इसलिए किसी की प्रति को आपकी के साथ reconcile करने की जरूरत नहीं है।

Junorevert के साथ एक commit को undo करनाgit revert <commit> एक commit को undo करता है एक बिल्कुल नई commit जोड़कर जो इसे reverse करती है, original को erase करने की बजाय। यह safe pick है एक बार एक commit पहले से ही किसी और के साथ shared है, क्योंकि कुछ भी पहले से ही saved नहीं change होता है। History mistake और fix दोनों का एक record रखता है, जो मैं Git को जितना अधिक use करता हूं उतना अधिक like करता हूं।
Junorevert के साथ एक commit को undo करना Revert एक merge की तरह conflict कर सकता है जब बाद के commits ने समान lines को touch किया हो, इसे समान तरीके से resolve करें: markers को fix करें, फाइल को add करें, फिर git revert --continue। इसे किसी भी समय reach करें जब commit जो आप undo कर रहे हों वह पहले से ही pushed या shared हो।
Junorevert के साथ एक commit को undo करना Revert कभी भी एक existing commit को touch नहीं करता, इसलिए यह undo tool है जो एक branch पर nicely play करता है जो दूसरे लोग पहले से ही pull कर रहे हैं। इसे अपना default रखें जैसे ही एक बुरा commit आपकी मशीन छोड़ चुका हो।

git reset के साथ rewind करना: soft, mixed, और hard

एक commit को undo करने का एक तीसरा तरीका है, git reset, और यह revert से अलग काम करता है: एक नई commit जोड़ने की बजाय जो पुरानी को undo करती है, reset आपकी current branch को एक अलग commit की ओर point करने के लिए move करती है। यह uncommitted commits के लिए fast और clean बनाता है जो किसी और ने नहीं देखा है, और commits के लिए risky है जो उन्होंने देखा है।

Reset restore और revert का wider, easier to misuse cousin है। आप इसे अधिकांश day-to-day fixes के लिए reach नहीं करेंगे, restore, revert, और stash "help, undo this" moments का vast majority cover करते हैं। आप इसे दूसरे लोगों के instructions में अभी भी देखेंगे, तो यहाँ headline है: reset आपकी branch को history में backward move करता है, और इसके एक mode, --hard, uncommitted काम को बिना confirmation के throw away करता है। यदि कोई command जो आप कहीं से copy कर रहे हैं में git reset --hard शामिल है, तो इसे run करने से पहले read करें कि यह क्या करता है।

git reset <commit> आपकी branch को उस commit की ओर point करने के लिए move करता है, और --soft, --mixed, और --hard decide करते हैं कि कितना और move के साथ होता है। तीन layers को picture करें: आपकी commit history, जहां branch pointer बैठता है, staging area, जो commit के लिए lined up है, और आपकी working directory, disk पर files। नीचे short hashes History reads के same way cover करते हैं git log --oneline के साथ, और target HEAD~1 का मतलब है "one commit before HEAD", standard तरीका "newest commit को undo करने" के लिए कहने का।

bash
$ git log --oneline
8f3c7d1 Cache forecast responses in localStorage
4f2a1c9 Fix temperature conversion in Celsius-to-Fahrenheit formula
5f3d8b2 Add five-day forecast to the dashboard
1a2b3c4 Set up project structure

$ git reset --soft HEAD~1

--soft branch pointer को एक commit पीछे move करता है और वहीं stop करता है। Staging area और working directory untouched हैं, इसलिए undone commit से सब कुछ staged बैठा है, किसी भी तरीके से recommit करने के लिए तैयार है।

bash
$ git reset --mixed HEAD~1

--mixed वह है जो run होता है यदि आप flag को छोड़ देते हैं। यह branch pointer को पीछे move करता है और staging area को भी clear करता है, इसलिए undone commit के परिवर्तन आपकी working directory में unstaged edits के रूप में वापस आते हैं। कुछ नहीं खोता है, commit करने से पहले फिर से git add चलाएं।

bash
$ git reset --hard HEAD~1

git reset --hard branch pointer को move करता है और आपकी working directory को match करने के लिए overwrite करता है, तो कोई भी uncommitted काम और undone commit दोनों एक step में दृश्य से गायब हो जाते हैं, कोई prompt पूछे बिना कि आप sure हैं या नहीं। यह mode run करने से पहले pause का है।

यह भी explain करता है कि git commit --amend commit loop में क्या कर रहा था: amend एक reset --soft HEAD~1 के करीब है जिसके तुरंत बाद एक नई commit होती है, यही कारण है कि यह आपकी last commit को replace करती है एक के बजाय इसके top पर stacking के।

Reset केवल pointers को move करता है और, --hard mode में, working directory को match करने के लिए। यह कभी भी एक commit object को outright delete नहीं करता है। एक reset --hard जो पीछे छोड़ गया है वह अभी भी Git के object database में बैठा है, किसी भी branch से unreachable, जो matters क्योंकि इसे फिर से reach करने का एक तरीका है: git reflog, अगला। एक shared branch पर, आपकी branch को पीछे move करना और push करना का मतलब है force-pushing over commits जो आपकी teammates के पास पहले से ही हैं, तो उनका अगला pull reworked history से disagree करता है। यह practical reason है reset एक local cleanup tool रहता है जबकि revert cover करता है कुछ भी जो आपकी machine को पहले से ही छोड़ चुका है।

Junogit reset के साथ rewind करना आप अधिकांश day-to-day fixes में git reset reach नहीं करेंगे, restore, revert, और stash पहले से ही लगभग सब कुछ cover करते हैं। फिर भी, इसकी shape जानें: reset आपकी branch को एक पहले की commit में वापस move करता है, और इसका --hard mode आपकी working directory को match करने के लिए confirmation के बिना wipe करता है। किसी भी command को treat करें जो आप copy करते हैं जिसमें reset --hard शामिल है real caution के साथ।
Junogit reset के साथ rewind करनाgit reset --soft undone commit के परिवर्तन को staged रखता है, --mixed (default) उन्हें unstage करता है लेकिन edits रखता है, --hard edits को completely throw away करता है। commit --amend basically एक soft reset है जिसके तुरंत बाद एक नई commit होती है, यही कारण है कि यह last commit को replace करती है एक के बजाय इसके top पर stacking के।
Junogit reset के साथ rewind करना Reset केवल pointers move करता है, और --hard के साथ, आपकी working directory को match करने के लिए, यह कभी भी commit object को खुद delete नहीं करता है। वह object database में तब तक रहता है जब तक reflog और garbage collection इसे catch न करें। एक rewritten branch को push करें और आपकी teammates का अगला pull history के साथ collide करता है जो अब उनसे match नहीं करता है।

revert या reset को चुनना

rule जो decide करती है कि कौन सा tool reach करना है: क्या किसी और ने पहले से ही यह commit pull किया है? यदि हाँ, तो revert। यदि commit केवल आपकी machine पर exist करता है, एक branch पर जो आपने push नहीं किया, तो reset ठीक है और अक्सर tidier fix होता है। जब आप निश्चित नहीं हैं, revert हमेशा safe choice है, क्योंकि यह दोनों cases में काम करता है।

"Has anyone pulled it" वास्तव में "is this commit reachable from a reference someone else has" का मतलब है, जो practice में means whether यह एक branch पर बैठा है जो पहले से ही push किया गया है। एक local branch पर एक commit जो आपने पाँच मिनट पहले invent किया और कभी push नहीं किया वह open territory है reset के लिए। जैसे ही आप इसे push करते हैं, इसे shared के रूप में treat करें: इसे locally reset करना और force-push करना का मतलब है किसी और के साथ coordinate करना जो पहले उस branch को touches करता है।

Junorevert या reset को चुनना एक commit को undo करने से पहले एक question पूछें: क्या किसी और ने पहले से ही इसे pull किया है? यदि हाँ, तो revert को reach करें, यह हमेशा safe है। यदि commit केवल आपकी machine पर exist करता है, तो reset भी ठीक काम करता है। जब आप निश्चित नहीं हैं कि कौन सा apply होता है, तो revert safer default है।
Junorevert या reset को चुनना एक बार एक commit push हो जाने पर और किसी को भी इसका हो सकता है, revert को reach करें। जबकि यह अभी भी purely local है आपको, reset ठीक है और अक्सर tidier fix होता है, क्योंकि यह log में एक "revert of a revert" entry नहीं छोड़ता है।
Junorevert या reset को चुनना असली test reachability है: क्या यह commit एक reference पर बैठा है जो किसी और ने pull किया है? Local और unpushed, reset open territory है। Pushed और shared, इसे reset करने को coordinate करने के लिए कुछ के रूप में treat करें, क्योंकि एक बाद में force-push आपकी teammates के पास जो कुछ भी है से collide करता है।

git reflog के साथ एक commit को recover करना

एक reset --hard, एक messy rebase, या branch को accidentally delete करना एक commit को completely vanished जैसा लग सकता है। यह usually नहीं हुआ है। Git एक local log रखता है कि आपके HEAD और branches कहाँ point किए हैं, जिसे reflog कहा जाता है, और यह log लगभग हमेशा आपका तरीका है एक commit को वापस लाने का जो lost दिखता है।

आप इसकी आमतौर पर जरूरत नहीं करेंगे, लेकिन यहाँ headline है: Git शायद ही कभी कुछ को throw away करता है जैसे ही यह लगता है। यदि आप कभी reset --hard चलाते हैं और बाद में realize करते हैं कि आपको उस commit की जरूरत थी, तो बहुत संभावना है कि इसे वापस पाने का एक तरीका है, जो यहाँ cover किया गया है जब भी आप गहराई में जाने के लिए तैयार हों।

short version: git reflog हाल के HEAD positions को list करता है, हर एक के साथ एक short hash, और आप किसी भी उन hashes को git reset --hard कर सकते हैं उस exact state में वापस जाने के लिए। यह एक second history जैसा reads: हर जगह HEAD stands किया है, including commits जो आपकी branches अब point नहीं करते हैं।

एक commit जिसके पास कोई branch, tag, या HEAD नहीं है अब इसे point करता है वह unreachable है: repository में adrift, अभी भी saved, केवल एक label missing जो इसे वापस लाता है। reflog एक chronological list है जहाँ HEAD आपकी machine पर move किया गया है, यह branch switch, वह reset, वह rebase, हर entry keyed by एक short reference जैसे HEAD@{2}। गलती से right पहले का entry find करें और एक branch को इसकी ओर point करें:

bash
$ git reflog
2b6f0d1 HEAD@{0}: reset: moving to HEAD~1
8f3c7d1 HEAD@{1}: commit: Cache forecast responses in localStorage
4f2a1c9 HEAD@{2}: commit: Fix temperature conversion in Celsius-to-Fahrenheit formula

$ git reset --hard 8f3c7d1

यह commit है जो reset --hard को erase जैसा लगा, restored। दो limits जो जानने लायक हैं। पहला, reflog केवल आपकी मशीन पर live करता है, push और pull इसे कभी touch नहीं करते हैं, इसलिए यह एक commit नहीं recover कर सकता जो एक teammate ने उनके पर खो दिया है। दूसरा, यह हमेशा के लिए नहीं रहता है: Git eventually garbage collection चलाता है और unreachable commits को clear out करता है एक बार जब वे एक default cutoff के पास कुछ weeks की age के हैं, तो safety net recent mistakes को cover करती है project के पूरे जीवन की बजाय।

Junoएक lost commit को recover करना यदि आप कभी reset --hard चलाते हैं और बाद में realize करते हैं कि आपको वह commit की जरूरत थी, तो यह संभवतः अभी भी recoverable है। Git एक local record रखता है जिसे reflog कहा जाता है जहाँ आपका काम point किया गया है, और यह usually एक commit को वापस लाने के लिए काफी है जो gone दिखता है। यह deep-dive territory है, लेकिन यह reassuring है जानना कि यह there है।
Junoएक lost commit को recover करनाgit reflog हाल के HEAD positions को list करता है short hashes के साथ जिन्हें आप reset --hard back to कर सकते हैं, तो एक reset जो बहुत far गया है वह usually recoverable है। यह अपनी machine पर केवल live करता है लेकिन, तो यह एक commit नहीं rescue कर सकता जो एक teammate अपने पर खो दिया है।
Junoएक lost commit को recover करना reflog एक local, chronological record है हर जगह का जहाँ HEAD stand किया है, जो कैसे एक commit जो reset --hard को erase लगा वह फिर से appear करता है right HEAD@{n} entry की ओर एक branch को point करके। यह garbage collection के साथ eventually age out करता है, और यह केवल अपनी recent mistakes को cover करता है। एक teammate जो एक commit खो गया है को अपनी machine पर same recovery चलाने की जरूरत है।