प्रारंभिक नोट्स
यहाँ अवलोकन यह है कि, जब आप काम करना शुरू करते हैं branch1
(यह भूलकर या यह महसूस नहीं करते कि branch2
पहले एक अलग शाखा में जाना अच्छा होगा ), तो आप दौड़ें:
git checkout branch2
कभी-कभी Git कहता है "ठीक है, आप अभी Branch2 पर हैं!" कभी-कभी, गिट कहता है "मैं ऐसा नहीं कर सकता, मैं आपके कुछ बदलावों को खो दूँगा।"
अगर Git आपको ऐसा नहीं करने देगा, तो आपको अपने परिवर्तनों को करने के लिए, उन्हें कहीं स्थायी रूप से सहेजना होगा। आप git stash
उन्हें बचाने के लिए उपयोग करना चाह सकते हैं ; यह उन चीजों में से एक है जिनके लिए इसे डिज़ाइन किया गया है। ध्यान दें कि git stash save
या git stash push
वास्तव में इसका मतलब है "सभी परिवर्तनों को कमिट करें, लेकिन किसी भी शाखा पर बिल्कुल नहीं, फिर उन्हें हटा दें जहां मैं अभी हूं।" यह स्विच करना संभव बनाता है: आपके पास अब कोई प्रगति नहीं है। आप git stash apply
उन्हें स्विच करने के बाद कर सकते हैं ।
साइडबार: git stash save
पुराना सिंटैक्स है; git stash push
Git संस्करण 2.13 में पेश किया गया था, ताकि git stash
नए विकल्पों के लिए तर्कों के साथ कुछ समस्याओं को ठीक किया जा सके। दोनों एक ही काम करते हैं, जब बुनियादी तरीकों से उपयोग किया जाता है।
आप चाहें तो यहाँ पढ़ना बंद कर सकते हैं!
यदि Git आपको स्विच नहीं करने देगा , तो आपके पास पहले से ही एक उपाय है: उपयोग git stash
या git commit
; या, यदि आपके परिवर्तन फिर से बनाने के लिए तुच्छ हैं, तो git checkout -f
इसे मजबूर करने के लिए उपयोग करें। यह उत्तर सभी के बारे में है जब Git आपको तबgit checkout branch2
भी देगा जब आपने कुछ बदलाव करना शुरू किया था। यह कभी-कभी क्यों काम करता है , और अन्य बार क्यों नहीं ?
यहाँ नियम एक तरह से सरल है, और जटिल / कठिन दूसरे में व्याख्या करना:
आप कार्य-वृक्ष में बिना किसी परिवर्तन के शाखाओं को बदल सकते हैं यदि और केवल कहा जाए तो स्विचिंग को उन परिवर्तनों की क्लोबिंग की आवश्यकता नहीं है।
यह है - और कृपया ध्यान दें कि यह अभी भी सरलीकृत है; कुछ अतिरिक्त-कठिन कोने वाले मामले हैं, जिनमें मंच पर git add
s, git rm
s और ऐसे हैं - मान लीजिए कि आप चालू हैं branch1
। A git checkout branch2
को यह करना होगा:
- हर फ़ाइल है कि के लिए है में
branch1
और नहीं में branch2
, 1 निकालने उस फ़ाइल।
- हर फ़ाइल है कि के लिए है में
branch2
और नहीं में branch1
, उस फ़ाइल (उपयुक्त सामग्री के साथ) पैदा करते हैं।
- प्रत्येक फ़ाइल के लिए जो दोनों शाखाओं में है, यदि संस्करण
branch2
अलग है, तो कार्यशील ट्री संस्करण को अपडेट करें।
इनमें से प्रत्येक चरण आपके कार्य-वृक्ष में कुछ स्पष्ट कर सकता है:
- किसी फ़ाइल को निकालना "सुरक्षित" है यदि वर्क-ट्री में संस्करण प्रतिबद्ध संस्करण के समान है
branch1
; यदि आपने बदलाव किए हैं तो यह "असुरक्षित" है।
branch2
यदि यह अभी मौजूद नहीं है, तो फ़ाइल को बनाने का तरीका "सुरक्षित" है। 2 यह "असुरक्षित" है यदि यह अभी मौजूद है लेकिन इसमें "गलत" सामग्री है।
- और निश्चित रूप से, फ़ाइल के वर्क-ट्री संस्करण को एक अलग संस्करण के साथ बदलना "सुरक्षित" है यदि वर्क-ट्री संस्करण पहले से ही इसके लिए प्रतिबद्ध है
branch1
।
एक नई शाखा ( git checkout -b newbranch
) को हमेशा "सुरक्षित" माना जाता है: इस प्रक्रिया के हिस्से के रूप में कोई फाइल नहीं जोड़ी जाएगी, हटा दी जाएगी या बदल दी जाएगी, और सूचकांक / स्टेजिंग-क्षेत्र भी अछूता नहीं है। (कैविएट: नई शाखा के शुरुआती बिंदु को बदलने के बिना एक नई शाखा बनाते समय यह सुरक्षित है; लेकिन यदि आप एक और तर्क जोड़ते हैं, उदाहरण के लिए git checkout -b newbranch different-start-point
, इसे चीजों को बदलना पड़ सकता है, स्थानांतरित करने के लिए different-start-point
। गिट फिर चेकआउट सुरक्षा नियमों को हमेशा की तरह लागू करेगा। ।)
1 इसके लिए आवश्यक है कि हम परिभाषित करें कि किसी शाखा में फ़ाइल के लिए इसका क्या अर्थ है, जिसके लिए शब्द शाखा को ठीक से परिभाषित करने की आवश्यकता है। (यह भी देखें वास्तव में क्या हम "शाखा" द्वारा मतलब है? ) यहाँ, क्या मैं वास्तव में मतलब है जो करने के लिए प्रतिबद्ध शाखा-नाम को हल: एक फ़ाइल जिसका मार्ग है है में अगर एक हैश पैदा करता है। यदि आप इसके बजाय त्रुटि संदेश प्राप्त करते हैं तो वह फ़ाइल नहीं है । इस विशेष प्रश्न का उत्तर देते समय आपके सूचकांक या कार्य-वृक्ष में पथ का अस्तित्व प्रासंगिक नहीं है। इस प्रकार, यहां का रहस्य प्रत्येक के परिणाम की जांच करना हैP
branch1
git rev-parse branch1:P
branch1
P
git rev-parse
branch-name:path
। यह या तो विफल हो जाता है क्योंकि फ़ाइल एक ही शाखा में "इन" है, या हमें दो हैश आईडी देता है। यदि दो हैश आईडी समान हैं , तो फ़ाइल दोनों शाखाओं में समान है। किसी भी परिवर्तन की आवश्यकता नहीं है। यदि हैश आईडी अलग है, तो फ़ाइल दो शाखाओं में अलग है, और शाखाओं को बदलने के लिए इसे बदला जाना चाहिए।
यहां मुख्य धारणा यह है कि कमिट में फाइलें हमेशा के लिए जमी होती हैं। आपके द्वारा संपादित की गई फाइलें स्पष्ट रूप से जमी नहीं होंगी । हम कम से कम शुरू में, केवल दो जमे हुए आवागमन के बीच बेमेल को देखते हैं। दुर्भाग्य से, हमें - या Git - को भी उन फ़ाइलों से निपटना पड़ता है, जोउस प्रतिबद्धताओं में नहीं हैं जिनसेआप दूर जा रहे हैं और जिस प्रतिबद्धता के साथ आप स्विच करने जा रहे हैं। यह शेष जटिलताओं की ओर जाता है, क्योंकि फ़ाइलें भी सूचकांक में और / या कार्य-वृक्ष में मौजूद हो सकती हैं, बिना इन दो विशेष रूप से जमे हुए संचार मौजूद होने के बिना हम साथ काम कर रहे हैं।
2 यदि इसे "सही सामग्री" के साथ पहले से मौजूद है, तो इसे "सॉर्ट-ऑफ-सेफ" माना जा सकता है, ताकि गिट के बाद इसे बनाने की जरूरत न हो। मैं इसे अनुमति देने वाले कम से कम कुछ संस्करणों को याद करता हूं, लेकिन अभी परीक्षण करने से पता चलता है कि इसे Git 1.8.5.4 में "असुरक्षित" माना जाएगा। एक ही तर्क एक संशोधित फ़ाइल पर लागू होता है जो होने वाली स्विच-टू-ब्रांच से मिलान करने के लिए संशोधित होता है। हालांकि, 1.8.5.4 बस कहती है, "ओवरराइट किया जाएगा", हालांकि। तकनीकी नोटों के अंत को भी देखें: मेरी स्मृति दोषपूर्ण हो सकती है क्योंकि मुझे नहीं लगता कि रीड-ट्री के नियम बदल गए हैं क्योंकि मैंने पहली बार संस्करण 1.5 पर Git का उपयोग करना शुरू किया था।
क्या इससे कोई फर्क पड़ता है कि परिवर्तन मंचित हैं या अस्थिर हैं?
हाँ, कुछ मायनों में। विशेष रूप से, आप परिवर्तन को चरणबद्ध कर सकते हैं, फिर कार्य ट्री फ़ाइल को "डी-संशोधित" कर सकते हैं। यहाँ दो शाखाओं में एक फ़ाइल, कि में अलग है branch1
और branch2
:
$ git show branch1:inboth
this file is in both branches
$ git show branch2:inboth
this file is in both branches
but it has more stuff in branch2 now
$ git checkout branch1
Switched to branch 'branch1'
$ echo 'but it has more stuff in branch2 now' >> inboth
इस बिंदु पर, वर्किंग ट्री फ़ाइल inboth
एक से मेल खाती है branch2
, भले ही हम चालू हों branch1
। यह परिवर्तन प्रतिबद्ध नहीं है, जो git status --short
यहाँ दिखाता है:
$ git status --short
M inboth
स्पेस-तब-एम का अर्थ है "संशोधित लेकिन मंचन नहीं किया गया" (या अधिक सटीक, काम करने वाली ट्री कॉपी का मंचन / इंडेक्स कॉपी से भिन्न होता है)।
$ git checkout branch2
error: Your local changes ...
ठीक है, अब कार्यशील-ट्री कॉपी को चरणबद्ध करें, जिसे हम पहले से ही जानते हैं कि कॉपी में भी मेल खाता है branch2
।
$ git add inboth
$ git status --short
M inboth
$ git checkout branch2
Switched to branch 'branch2'
यहां मंचन और काम करने वाली प्रतियां दोनों में मेल खाती थीं branch2
, इसलिए चेकआउट की अनुमति थी।
चलिए एक और कदम उठाते हैं:
$ git checkout branch1
Switched to branch 'branch1'
$ cat inboth
this file is in both branches
मैंने जो बदलाव किया है वह स्टेजिंग क्षेत्र से अब खो गया है (क्योंकि चेकआउट स्टेजिंग क्षेत्र के माध्यम से लिखता है)। यह एक कोने का मामला है। परिवर्तन समाप्त नहीं हुई है, लेकिन तथ्य यह है कि मैं इसे का मंचन किया था, है चला गया।
आइए, फ़ाइल के तीसरे संस्करण को चरणबद्ध करें, या तो शाखा-प्रतिलिपि से अलग करें, फिर वर्तमान शाखा संस्करण से मिलान करने के लिए कार्य की प्रतिलिपि सेट करें:
$ echo 'staged version different from all' > inboth
$ git add inboth
$ git show branch1:inboth > inboth
$ git status --short
MM inboth
यहाँ दो M
का मतलब है: चरणबद्ध फ़ाइल फ़ाइल से भिन्न होती है HEAD
, और , कार्य-ट्री फ़ाइल मंचित फ़ाइल से भिन्न होती है। वर्किंग-ट्री संस्करण branch1
(aka HEAD
) संस्करण से मेल खाता है :
$ git diff HEAD
$
लेकिन git checkout
चेकआउट की अनुमति नहीं होगी:
$ git checkout branch2
error: Your local changes ...
branch2
संस्करण को कार्यशील संस्करण के रूप में सेट करते हैं :
$ git show branch2:inboth > inboth
$ git status --short
MM inboth
$ git diff HEAD
diff --git a/inboth b/inboth
index ecb07f7..aee20fb 100644
--- a/inboth
+++ b/inboth
@@ -1 +1,2 @@
this file is in both branches
+but it has more stuff in branch2 now
$ git diff branch2 -- inboth
$ git checkout branch2
error: Your local changes ...
भले ही वर्तमान में काम करने वाली प्रतिलिपि एक से मेल खाती है branch2
, लेकिन चरणबद्ध फ़ाइल नहीं होती है, इसलिए git checkout
उस प्रतिलिपि को खोना होगा, और git checkout
इसे अस्वीकार कर दिया जाएगा।
तकनीकी नोट्स - केवल जिज्ञासु के लिए :-)
इस सभी के लिए अंतर्निहित कार्यान्वयन तंत्र Git का सूचकांक है । सूचकांक, जिसे "स्टेजिंग क्षेत्र" भी कहा जाता है, जहां आप अगली कमिट बनाते हैं: यह वर्तमान कमेटी से मेल खाना शुरू कर देता है, अर्थात, आपने अभी जो भी चेक-आउट किया है, और उसके बाद हर बार जब आप git add
एक फाइल बनाते हैं, तो आप इंडेक्स वर्जन को बदल देते हैं आपके काम के पेड़ में जो कुछ भी है।
याद रखें, कार्य-वृक्ष वह है जहाँ आप अपनी फ़ाइलों पर काम करते हैं। यहां, उनके पास अपना सामान्य रूप है, कुछ विशेष केवल उपयोगी-से-गिट फॉर्म की तरह, जैसे वे कमिट और इंडेक्स में करते हैं। यदि आप एक फ़ाइल निकालने तो से एक, प्रतिबद्ध के माध्यम से सूचकांक, और फिर काम के पेड़ में पर। इसे बदलने के बाद, आप git add
इसे इंडेक्स पर ले जाते हैं। इसलिए प्रत्येक फ़ाइल के लिए वास्तव में तीन स्थान हैं: वर्तमान प्रतिबद्ध, सूचकांक और कार्य-वृक्ष।
जब आप दौड़ते हैं git checkout branch2
, तो Git कवर के नीचे जो कुछ करता है वह टिप कमिटमेंट की तुलना करने के branch2
लिए होता है जो कि वर्तमान कमिट और इंडेक्स दोनों में है। कोई भी फ़ाइल जो अभी वहां मौजूद है, Git उसे अकेला छोड़ सकती है। यह सब अछूता है। कोई भी फ़ाइल जो दोनों के लिए समान है , Git भी अकेला छोड़ सकती है - और ये वही हैं जो आपको शाखाओं को स्विच करने देती हैं।
इस सूचकांक की वजह से कमिट-स्विचिंग सहित अधिकांश Git अपेक्षाकृत तेज़ है । इंडेक्स में वास्तव में प्रत्येक फ़ाइल स्वयं नहीं है, बल्कि प्रत्येक फ़ाइल का हैश है । फ़ाइल की प्रतिलिपि को ही संग्रहीत किया जाता है जिसे Git एक ब्लॉब ऑब्जेक्ट कहता है , रिपॉजिटरी में। यह उसी तरह है जैसे फाइलों को कमिट में संग्रहीत किया जाता है: कमिट्स में वास्तव में फाइलें शामिल नहीं होती हैं , वे बस प्रत्येक फाइल के हैश आईडी पर Git का नेतृत्व करते हैं। इसलिए Git हैश आईडी की तुलना कर सकता है - वर्तमान में 160-बिट-लंबी स्ट्रिंग्स - यह तय करने के लिए कि क्या X और Y में समान फ़ाइल है या नहीं। यह सूचकांक में उन हैश आईडी की हैश आईडी से तुलना कर सकता है, भी।
यह वही है जो ऊपर के सभी विषमकोण के मामलों की ओर जाता है। हमारे पास एक्स और वाई है जो दोनों के पास फाइल है path/to/name.txt
, और हमारे पास एक इंडेक्स प्रविष्टि है path/to/name.txt
। शायद तीनों हैश मैच। शायद उनमें से दो मैच करते हैं और एक नहीं है। शायद तीनों अलग हैं। और, हमारे पास another/file.txt
यह भी हो सकता है कि केवल X में या केवल Y में हो और अभी सूचकांक में नहीं है या नहीं है। इन विभिन्न मामलों से प्रत्येक की अपनी अलग विचार करने की आवश्यकता: करता Git जरूरत से फाइल कॉपी करने के लिए बाहर सूचकांक करने के लिए प्रतिबद्ध है, या यह से, सूचकांक से हटा दें स्विच करने के लिए एक्स के लिए वाई ? यदि हां, तो यह भी करना होगाफ़ाइल को कार्य-ट्री में कॉपी करें, या उसे कार्य-ट्री से निकालें। और अगर यह मामला है, तो सूचकांक और वर्क-ट्री संस्करणों का कम से कम एक प्रतिबद्ध संस्करण से बेहतर मेल था; अन्यथा Git कुछ डेटा को क्लोब कर रहा होगा।
(इस सब के लिए पूर्ण नियमों में, नहीं वर्णित हैं git checkout
प्रलेखन के रूप में आप उम्मीद कर सकते हैं, बल्कि दस्तावेज़ "दो पेड़ मर्ज" शीर्षक खंड के अंतर्गत ।)git read-tree
git checkout -m
, जो आपके वर्कट्री और इंडेक्स परिवर्तनों को नए चेकआउट में विलय करता है।