मेरे Git Submodule HEAD को मास्टर से अलग क्यों किया गया है?


162

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

क्यों होता है?

मुझे हमेशा करना है:

git branch
git checkout master

मैं यह कैसे सुनिश्चित कर सकता हूं कि मेरा सबमॉडल हमेशा मास्टर शाखा की ओर इशारा करता है?


1
क्या आपने इसका जवाब पढ़ा? stackoverflow.com/questions/1777854/…
जॉनी जेड

@bitoiu मैंने सबट्री और Google रेपो को देखा। मुझे अभी तक सही समाधान नहीं मिला है :(
om471987

1
एक सीआई वातावरण में gitsubmodules के साथ मेरा अनुभव भयानक है, शायद कुछ अन्य लोगों को बेहतर अनुभव है।
बिटोयू

@ जॉननी थैंक्स मैं समझ गया कि सबमॉडल एक कमिट की ओर इशारा करता है न कि पेड़ का सिर। लेकिन शाखा से अलग क्यों किया गया। यदि आपके पास एक शाखा है, तो उसे डिफ़ॉल्ट रूप से संलग्न नहीं किया जाना चाहिए
om471987

3
सबमॉडल्स को खारिज करने के लिए बहुत जल्दी मत बनो क्योंकि आपने सुना है कि वे खराब हैं। यदि आप निरंतर एकीकरण चाहते हैं, तो वे एक खराब समाधान हैं, लेकिन यदि आप किसी बाहरी परियोजना से कोड एम्बेड करना चाहते हैं और आप सभी खींचों को स्पष्ट रूप से प्रबंधित करना चाहते हैं तो वे एक सही समाधान हैं। यह अक्सर सबसे अच्छा अभ्यास होता है यदि आप एक गैर-कांटेक्टेड मॉड्यूल के साथ एकीकरण कर रहे हैं जो आपके संगठन द्वारा नियंत्रित नहीं है। समस्या यह है कि वे सभी प्रकार की अन्य स्थितियों में एक लुभावना समाधान हैं, जहाँ वे बहुत अच्छी तरह से काम नहीं करते हैं। सबसे अच्छी सलाह यह है कि वे कैसे काम करें और अपने परिदृश्य का मूल्यांकन करें।
सारा जी

जवाबों:


176

संपादित करें:

वैध समाधान के लिए @ सिंबा उत्तर देखें

submodule.<name>.updateवह है जो आप बदलना चाहते हैं, डॉक्स देखें - डिफ़ॉल्टcheckout
submodule.<name>.branch शाखा को ट्रैक करने के लिए निर्दिष्ट करें - डिफ़ॉल्टmaster


पुराने उत्तर:

व्यक्तिगत रूप से मुझे यहाँ उन उत्तरों से घृणा है जो बाहरी लिंक से प्रत्यक्ष करते हैं जो समय के साथ काम करना बंद कर सकते हैं और मेरे उत्तर की जाँच यहाँ कर सकते हैं (जब तक कि प्रश्न डुप्लिकेट नहीं है) - प्रश्न को निर्देशित करना जो अन्य विषय की पंक्तियों के बीच विषय को कवर करता है, लेकिन कुल मिलाकर बराबर है: "मैं हूँ जवाब नहीं दे रहा है, प्रलेखन पढ़ें। "

तो वापस सवाल पर: ऐसा क्यों होता है?

आपके द्वारा वर्णित स्थिति

सर्वर से परिवर्तन खींचने के बाद, कई बार मेरा सबमॉड्यूल हेड मास्टर ब्रांच से अलग हो जाता है।

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

  • कारण: आपका सबमॉडल सही शाखा (डिफ़ॉल्ट मास्टर) पर नज़र नहीं रख रहा है।
    समाधान: सुनिश्चित करें कि आपका सबमॉडल सही शाखा पर नज़र रख रहा है
$ cd <submodule-path>
# if the master branch already exists locally:
# (From git docs - branch)
# -u <upstream>
# --set-upstream-to=<upstream>
#    Set up <branchname>'s tracking information so <upstream>
#    is considered <branchname>'s upstream branch.
#    If no <branchname> is specified, then it defaults to the current branch.
$ git branch -u <origin>/<branch> <branch>
# else:
$ git checkout -b <branch> --track <origin>/<branch>
  • कारण: आपका माता-पिता रेपो सबमॉडल्स शाखा को ट्रैक करने के लिए कॉन्फ़िगर नहीं किया गया है।
    समाधान: अपने सबमॉड्यूल को निम्नलिखित दो कमांड्स के साथ नए सबमॉड्यूल जोड़कर अपनी दूरस्थ शाखा को ट्रैक करें।
    • पहले आप अपने रिमोट को ट्रैक करने के लिए गिट बताएं <branch>
    • आप चेकआउट के बजाय रीबेस या मर्ज करने के लिए गिट को बताते हैं
    • आप अपने रिमोट से अपने सबमॉड्यूल को अपडेट करने के लिए गिट बताएं।
    $ git submodule add -b <branch> <repository> [<submodule-path>]
    $ git config -f .gitmodules submodule.<submodule-path>.update rebase
    $ git submodule update --remote
  • यदि आपने अपने मौजूदा सबमॉड्यूल को इस तरह नहीं जोड़ा है तो आप इसे आसानी से ठीक कर सकते हैं:
    • सबसे पहले आप यह सुनिश्चित करना चाहते हैं कि आपके सबमॉड्यूल में शाखा की जाँच है जिसे आप ट्रैक करना चाहते हैं।
    $ cd <submodule-path>
    $ git checkout <branch>
    $ cd <parent-repo-path>
    # <submodule-path> is here path releative to parent repo root
    # without starting path separator
    $ git config -f .gitmodules submodule.<submodule-path>.branch <branch>
    $ git config -f .gitmodules submodule.<submodule-path>.update <rebase|merge>

सामान्य मामलों में, आप पहले से ही अब तक अपने विस्तृत हेड को ठीक कर चुके हैं क्योंकि यह ऊपर दिए गए कॉन्फ़िगरेशन मुद्दों में से एक से संबंधित था।

तय किए गए HEAD को ठीक कर रहा है .update = checkout

$ cd <submodule-path> # and make modification to your submodule
$ git add .
$ git commit -m"Your modification" # Let's say you forgot to push it to remote.
$ cd <parent-repo-path>
$ git status # you will get
Your branch is up-to-date with '<origin>/<branch>'.
Changes not staged for commit:
    modified:   path/to/submodule (new commits)
# As normally you would commit new commit hash to your parent repo
$ git add -A
$ git commit -m"Updated submodule"
$ git push <origin> <branch>.
$ git status
Your branch is up-to-date with '<origin>/<branch>'.
nothing to commit, working directory clean
# If you now update your submodule
$ git submodule update --remote
Submodule path 'path/to/submodule': checked out 'commit-hash'
$ git status # will show again that (submodule has new commits)
$ cd <submodule-path>
$ git status
HEAD detached at <hash>
# as you see you are DETACHED and you are lucky if you found out now
# since at this point you just asked git to update your submodule
# from remote master which is 1 commit behind your local branch
# since you did not push you submodule chage commit to remote. 
# Here you can fix it simply by. (in submodules path)
$ git checkout <branch>
$ git push <origin>/<branch>
# which will fix the states for both submodule and parent since 
# you told already parent repo which is the submodules commit hash 
# to track so you don't see it anymore as untracked.

लेकिन अगर आप स्थानीय रूप से सबमॉड्यूल के लिए पहले से ही कुछ बदलाव करने में कामयाब रहे और कमिट किया, तो इन्हें रिमोट पर धकेल दिया, जब आपने 'git चेकआउट' निष्पादित किया, तो Git आपको सूचित करता है:

$ git checkout <branch>
Warning: you are leaving 1 commit behind, not connected to any of your branches:
If you want to keep it by creating a new branch, this may be a good time to do so with:

एक अस्थायी शाखा बनाने के लिए अनुशंसित विकल्प अच्छा हो सकता है, और फिर आप इन शाखाओं आदि को मर्ज कर सकते हैं, हालांकि मैं व्यक्तिगत रूप से सिर्फ git cherry-pick <hash>इस मामले में उपयोग करूंगा ।

$ git cherry-pick <hash> # hash which git showed you related to DETACHED HEAD
# if you get 'error: could not apply...' run mergetool and fix conflicts
$ git mergetool
$ git status # since your modifications are staged just remove untracked junk files
$ rm -rf <untracked junk file(s)>
$ git commit # without arguments
# which should open for you commit message from DETACHED HEAD
# just save it or modify the message.
$ git push <origin> <branch>
$ cd <parent-repo-path>
$ git add -A # or just the unstaged submodule
$ git commit -m"Updated <submodule>"
$ git push <origin> <branch>

हालाँकि कुछ और मामले हैं जो आप अपने सबमॉडल्स को डीटेल्ड हैड स्टेट में प्राप्त कर सकते हैं, मुझे उम्मीद है कि अब आप समझ गए होंगे कि अपने विशेष केस को कैसे डीबग करें।


2
HEAD अलग किया गया डिफ़ॉल्ट व्यवहार है git submodule update --remote। कृपया सिम्बा के उत्तर पर एक नज़र डालें, मुझे लगता है कि सही उत्तर होना चाहिए।
मैगोमर

78

एक जोड़ा जा रहा है branchविकल्प में .gitmoduleहै संबंधित नहीं सब पर submodules के अलग व्यवहार करने के लिए। @Mkungla से पुराना उत्तर गलत है, या अप्रचलित है।

से git submodule --help, HEAD अलग किया गया डिफ़ॉल्ट व्यवहार है git submodule update --remote

सबसे पहले, ट्रैक की जाने वाली शाखा को निर्दिष्ट करने की कोई आवश्यकता नहीं हैorigin/masterट्रैक करने के लिए डिफ़ॉल्ट शाखा है।

--remote

सबमॉड्यूल को अपडेट करने के लिए सुपरप्रोजेक्ट के रिकॉर्डेड SHA-1 का उपयोग करने के बजाय, सबमॉड्यूल की रिमोट-ट्रैकिंग शाखा की स्थिति का उपयोग करें। उपयोग किया गया रिमोट शाखा का रिमोट है ( branch.<name>.remote), डिफ़ॉल्ट करने के लिएorigin । दूरस्थ शाखा ने चूक काmaster इस्तेमाल किया ।

क्यों

तो HEAD को अलग क्यों किया जाता है update? यह डिफ़ॉल्ट मॉड्यूल अपडेट व्यवहार केcheckout कारण होता है :।

--चेक आउट

सबमॉड्यूल में एक अलग HEAD पर सुपरप्रोजेक्ट में दर्ज की गई कमेटी को चेकआउट करें । यह डिफ़ॉल्ट व्यवहार है , इस विकल्प का मुख्य उपयोग इसके submodule.$name.updateअलावा किसी मान के लिए ओवरराइड करने के लिए है checkout

इस अजीब अद्यतन व्यवहार की व्याख्या करने के लिए, हमें यह समझने की आवश्यकता है कि सबमॉड्यूल्स कैसे काम करते हैं?

पुस्तक प्रो Git में सबमॉडुल्स से शुरू होने वाला उद्धरण

हालाँकि sbmodule DbConnectorआपकी वर्किंग डायरेक्टरी में एक उपनिर्देशिका है, Git इसे सबमॉड्यूल के रूप में देखता है और जब आप उस डायरेक्टरी में नहीं होते हैं तो इसकी सामग्री को ट्रैक नहीं करते हैं। इसके बजाय, Git इसे उस भंडार से एक विशेष प्रतिबद्ध के रूप में देखता है

मुख्य रेपो एक विशिष्ट बिंदु पर अपने राज्य के साथ सबमॉड्यूल को ट्रैक करता है , कमिट आईडी । इसलिए जब आप मॉड्यूल अपडेट करते हैं, तो आप कमिट आईडी को नए सिरे से अपडेट कर रहे हैं।

किस तरह

यदि आप चाहते हैं कि सबमॉडल रिमोट शाखा के साथ स्वचालित रूप से विलय हो जाए, तो उपयोग करें --mergeया --rebase

--merge

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

--rebase

सुपरप्रोजेक्ट में दर्ज की गई वचनबद्धता पर वर्तमान शाखा को पुनः भेजें। यदि यह विकल्प दिया जाता है, तो सबमॉड्यूल के HEAD को अलग नहीं किया जाएगा

आपको बस इतना करना है,

git submodule update --remote --merge
# or
git submodule update --remote --rebase

अनुशंसित उर्फ:

git config alias.supdate 'submodule update --remote --merge'

# do submodule update with
git supdate

वहाँ भी बनाने के लिए एक विकल्प है --mergeया --rebaseके डिफ़ॉल्ट व्यवहार के रूप में git submodule update, की स्थापना द्वारा submodule.$name.updateकरने के लिए mergeया rebase

यहां एक उदाहरण है कि सबमॉड्यूल अपडेट के डिफ़ॉल्ट अपडेट व्यवहार को कैसे कॉन्फ़िगर किया जाए .gitmodule

[submodule "bash/plugins/dircolors-solarized"]
    path = bash/plugins/dircolors-solarized
    url = https://github.com/seebi/dircolors-solarized.git
    update = merge # <-- this is what you need to add

या इसे कमांड लाइन में कॉन्फ़िगर करें,

# replace $name with a real submodule name
git config -f .gitmodules submodule.$name.update merge

संदर्भ


6
मैं उपयोग करता हूं git submodule update --remote --merge, और यह एक अलग राज्य में सबमॉड्यूल को नीचे खींचता है। --rebaseसाथ ही उसी परिणाम के साथ प्रयास किया।
जो स्ट्राउट

8
@JoeStrout यदि आपका सबमॉडल पहले ही अलग हो चुका है, तो उपरोक्त आदेशों के साथ अपडेट करने से पहले अलग किए गए राज्य को ठीक करें। cdसबमॉड्यूल में, एक विशिष्ट शाखा के साथ सबमॉड्यूल की जांच करें git checkout master
सिम्बा

2
या - यदि यह कई (रिकर्सिव) सबमॉड्यूल के लिए बहुत अधिक परेशानी है - तो बस करें git submodule foreach --recursive git checkout master
स्टीफनक्ट

1
मैं केवल "कैसे काम करता है" विवरणों को आंशिक रूप से समझते हैं। टीबीएच मुझे वास्तव में यह समझने में दिलचस्पी नहीं है कि गिट कैसे काम करता है, मैं बस इसका उपयोग करना चाहता हूं। अब मुझे समझ में आया कि मैं अलग-थलग पड़े सबमॉड्यूल को ठीक कर सकता हूं git submodule foreach --recursive git checkout master। लेकिन मैं हमेशा उन्हें कैसे रोक सकता है? प्रत्येक सबमॉड्यूल के लिए विन्यास विकल्प सेट करना एक विकल्प नहीं है!
निकोलस

मेरे लिए, दौड़ना git submodule update --remote --mergeएक अलग राज्य में उपमोद को नहीं छोड़ता है, लेकिन git submodule updateमेरी .gitmoduleफाइल को संपादित करने के बाद चल रहा है क्योंकि आपने डीआईडी ​​को एक अलग राज्य में उपमोद छोड़ने का संकेत दिया था।
19

41

मैं इसे हमेशा के लिए थक गया तो मैं सिर्फ अपने सभी मॉड्यूल के लिए इसे बनाने के लिए एक शेल स्क्रिप्ट का उपयोग करें। मुझे लगता है कि सभी सबमॉड्यूल मास्टर पर हैं: यहाँ स्क्रिप्ट है:

#!/bin/bash
echo "Good Day Friend, building all submodules while checking out from MASTER branch."

git submodule update 
git submodule foreach git checkout master 
git submodule foreach git pull origin master 

अपने मूल मॉड्यूल से इसे निष्पादित करें


2
git सबमॉड्यूल foreach git पुल
ओरिजनल

सरल और संक्षिप्त! धन्यवाद!
zhekaus

12

यहाँ मेरे जवाब की जाँच करें: गिट सबमॉडल्स: एक शाखा / टैग निर्दिष्ट करें

यदि आप चाहते हैं, तो आप अपने .gitmodules फ़ाइल में "शाखा = मास्टर" पंक्ति को मैन्युअल रूप से जोड़ सकते हैं। मेरा मतलब देखने के लिए लिंक पढ़ें।

संपादित करें: किसी शाखा में किसी मौजूदा सबमॉड्यूल परियोजना को ट्रैक करने के लिए, इसके बजाय यहाँ VonC के निर्देशों का पालन करें:

गिट सबमॉडल्स: एक शाखा / टैग निर्दिष्ट करें


14
उत्तर माना जाता है कि इनलाइन है; IIRC को उत्तरों से जोड़ना एक स्टैक ओवरफ्लो फॉक्स पेस है।
टोनी टॉपर

1
@TonyTopper तब भी जब किसी अन्य SO उत्तर से लिंक हो रहा हो? IIRC केवल बाहरी लिंक के बारे में बताया जाता है क्योंकि ये दूर जा सकते हैं और फिर लिंक मृत हो जाता है और जवाब अच्छा है, बेकार है। फिर भी एसओ के जवाब के साथ ऐसा कोई खतरा नहीं है, वे कभी भी दूर नहीं जाएंगे, जब तक कि एसओ चले न जाएं (और जो कुछ भी हो सकता है उसे बहाल किया जा सकता है)। इसके अलावा, वह इस सवाल का जवाब दे चुका हैbranch = master" line into your .gitmodule कि वास्तव में पूर्ण उत्तर है, मेरे लिए यह समस्या हल हो गई है।
Mecki

9

शाखा को चेक करने के लिए अपना सबमॉड्यूल बनाने का दूसरा तरीका .gitmodulesरूट फ़ोल्डर में फ़ाइल को जाना और branchमॉड्यूल कॉन्फ़िगरेशन में फ़ील्ड को निम्नानुसार जोड़ना है :

branch = <branch-name-you-want-module-to-checkout>


15
मेरे लिए यह काम नहीं करता है। मैंने सही तरीके से सेट किया है branch = my_wanted_branch। लेकिन git submodule update --remoteइसे चलाने के लिए अभी भी अलग सिर के रूप में जाँच करता है।
एंड्रियस

ऐसा करें, फिर cd sudmodule & git co thebranche & cd .., फिर git सबमॉड्यूल अपडेट करें -आराम करें और यह काम करता है!
pdem

क्या ऐसा नहीं है कि '.itmodules' सक्रिय उपयोग के तहत है (पढ़ा जा रहा है) केवल जबकि सुपरप्रोजेक्ट को सबमॉड्यूल-पुनरावर्ती तरीके से क्लोन किया जा रहा है या सबमॉड्यूल को इनिशियलाइज़ किया जा रहा है? दूसरे शब्दों में आपके स्वयं के रिपॉजिटरी में आप उस फाइल को अपडेट करते हैं जिसमें हमेशा सबमॉड्यूल कॉन्फिग अपडेट से from .गितमोड्यूल्स ’को डाला नहीं जाता है। मेरी समझ में '.गितमोड्यूल्स' विन्यास के लिए एक खाका है, जबकि रेपो को क्लोन किया जा रहा है।
Na13-c

3

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

हालांकि, विशेष रूप से यदि आप मूल रूप से रेपो और सबमॉडल दोनों में सक्रिय रूप से विकसित हो रहे हैं, तो detached HEADराज्य भ्रामक और संभावित रूप से खतरनाक हो सकता है। यदि आप detached HEADराज्य में रहते हुए सबमॉडल बनाते हैं , तो ये खतरे में पड़ जाते हैं और आप आसानी से अपना काम खो सकते हैं। (आम तौर पर खतरे का उपयोग करके बचाया जा सकता है git reflog, लेकिन पहली जगह में उनसे बचना बहुत बेहतर है।)

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

[alias]
    submodule-checkout-branch = "!f() { git submodule -q foreach 'branch=$(git branch --no-column --format=\"%(refname:short)\" --points-at `git rev-parse HEAD` | grep -v \"HEAD detached\" | head -1); if [[ ! -z $branch && -z `git symbolic-ref --short -q HEAD` ]]; then git checkout -q \"$branch\"; fi'; }; f"

अब, करने के बाद git submodule updateआपको केवल कॉल करने की आवश्यकता है git submodule-checkout-branch, और किसी भी सबमॉड्यूल की जांच एक कमेटी द्वारा की जाती है, जिसकी शाखा की ओर इशारा करते हुए उस शाखा की जाँच की जाएगी। यदि आपके पास अक्सर कई स्थानीय शाखाएं नहीं हैं, जो सभी एक ही प्रतिबद्ध होने की ओर इशारा करती हैं, तो यह आमतौर पर वही होगा जो आप चाहते हैं; यदि नहीं, तो कम से कम यह सुनिश्चित करेगा कि आपके द्वारा किए जाने वाले कोई भी कार्य झूलने के बजाय वास्तविक शाखा पर जाएं।

इसके अलावा, अगर आपने चेकआउट पर स्वचालित रूप से सबमॉड्यूल्स को अपडेट करने के लिए गिट सेट किया है (उपयोग करके git config --global submodule.recurse true, यह उत्तर देखें ), तो आप पोस्ट-चेकआउट हुक बना सकते हैं जो इस उपनाम को स्वचालित रूप से कॉल करता है:

$ cat .git/hooks/post-checkout 
#!/bin/sh
git submodule-checkout-branch

फिर आपको git submodule updateया तो कॉल करने की आवश्यकता नहीं है या git submodule-checkout-branch, बस कर git checkoutसभी सबमॉड्यूल को उनके संबंधित अपडेट करेंगे और संबंधित शाखाओं की जांच करेंगे (यदि वे मौजूद हैं)।


0

सबसे सरल उपाय है:

git clone --recursive git@github.com:name/repo.git

फिर रेपो डायरेक्टरी में सीडी और:

git submodule update --init
git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
git config --global status.submoduleSummary true

अतिरिक्त पढ़ने: गिट सबमॉडल्स सर्वोत्तम प्रथाओं

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