ฉันใช้ Git submodules หลังจากดึงการเปลี่ยนแปลงจากเซิร์ฟเวอร์หลาย ๆ ครั้งหัว submodule ของฉันจะถูกถอดออกจากสาขาหลัก
ทำไมมันเกิดขึ้น
ฉันต้องทำเสมอ:
git branch
git checkout master
ฉันจะแน่ใจได้อย่างไรว่า submodule ของฉันชี้ไปที่สาขาหลักเสมอ
ฉันใช้ Git submodules หลังจากดึงการเปลี่ยนแปลงจากเซิร์ฟเวอร์หลาย ๆ ครั้งหัว submodule ของฉันจะถูกถอดออกจากสาขาหลัก
ทำไมมันเกิดขึ้น
ฉันต้องทำเสมอ:
git branch
git checkout master
ฉันจะแน่ใจได้อย่างไรว่า submodule ของฉันชี้ไปที่สาขาหลักเสมอ
คำตอบ:
แก้ไข:
ดู@Simba Answerสำหรับวิธีการแก้ไขที่ถูกต้อง
submodule.<name>.update
คือสิ่งที่คุณต้องการเปลี่ยนแปลงให้ดูเอกสาร - ค่าเริ่มต้นcheckout
submodule.<name>.branch
ระบุสาขาระยะไกลที่จะติดตาม - ค่าเริ่มต้นmaster
คำตอบเดิม:
โดยส่วนตัวแล้วฉันเกลียดคำตอบที่นี่ซึ่งนำไปยังลิงก์ภายนอกซึ่งอาจหยุดทำงานตลอดเวลาและตรวจสอบคำตอบของฉันที่นี่ (ยกเว้นคำถามซ้ำกัน) - นำไปสู่คำถามที่ครอบคลุมหัวข้อระหว่างบรรทัดของเรื่องอื่น แต่เท่ากับโดยรวม: "ฉัน ไม่ตอบอ่านเอกสาร "
กลับไปที่คำถาม: ทำไมมันเกิดขึ้น
สถานการณ์ที่คุณอธิบาย
หลังจากดึงการเปลี่ยนแปลงจากเซิร์ฟเวอร์หลาย ๆ ครั้งหัว submodule ของฉันจะถูกถอดออกจากสาขาหลัก
นี้เป็นกรณีที่พบเมื่อไม่ได้ใช้submodulesบ่อยเกินไปหรือได้เริ่มต้นเพียงกับsubmodules ฉันเชื่อว่าฉันถูกต้องในการระบุว่าเราทุกคน เคยมาถึงจุดที่หัวของsubmoduleของเราถูกถอดออก
$ 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>
ในกรณีทั่วไปคุณได้ทำการแก้ไขโดยในตอนนี้ DETACHED 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.
แต่ถ้าคุณทำการเปลี่ยนแปลงบางอย่างในเครื่องแล้วสำหรับ submodule และคอมมิชชัน, ผลักมันไปที่รีโมตเมื่อคุณเรียกใช้ 'git checkout' 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>
แม้ว่าจะมีอีกหลายกรณีที่คุณสามารถทำให้ซับโดมิโนของคุณเข้าสู่สถานะถอดออกได้ แต่ฉันหวังว่าคุณจะเข้าใจวิธีแก้ปัญหากรณีของคุณได้อีกเล็กน้อย
git submodule update --remote
แฝดเป็นพฤติกรรมปกติของ โปรดดูคำตอบของซิมบ้าฉันคิดว่านั่นควรเป็นคำตอบที่ถูกต้อง
การเพิ่มbranch
ตัวเลือกในการ.gitmodule
เป็นที่ไม่เกี่ยวข้องกับพฤติกรรมของแฝด submodules ที่ทั้งหมด คำตอบเก่าจาก @mkungla ไม่ถูกต้องหรือล้าสมัย
จากgit submodule --help
, HEAD แฝดเป็นพฤติกรรมปกติgit submodule update --remote
ของ
แรกมีไม่จำเป็นต้องระบุสาขาที่จะได้รับการติดตาม origin/master
เป็นสาขาเริ่มต้นที่จะติดตาม
--remote
แทนที่จะใช้ SHA-1 ที่บันทึกไว้ของ superproject เพื่ออัปเดต submodule ให้ใช้สถานะของสาขาการติดตามระยะไกลของ submodule ที่ใช้ระยะไกลเป็นระยะไกลสาขา (
branch.<name>.remote
) ผิดนัดorigin
สาขาระยะไกลใช้ค่าเริ่มต้นmaster
เหตุใดจึงต้องเป็นหัวหน้าแฝดหลังupdate
? นี้เกิดจากพฤติกรรมการปรับปรุงโมดูลค่าเริ่มต้น:checkout
--เช็คเอาท์
ชำระเงินการกระทำที่บันทึกไว้ในซูเปอร์โปรเจ็กต์บนHEAD ที่ดึงออกมาใน submodule นี่คือการทำงานเริ่มต้นการใช้งานหลักของตัวเลือกนี้คือการแทนที่เมื่อตั้งค่าอื่นที่ไม่ใช่
submodule.$name.update
checkout
เพื่ออธิบายพฤติกรรมการอัพเดทแปลก ๆ นี้เราต้องเข้าใจว่า submodules ทำงานอย่างไร?
อ้างอิงจากเริ่มต้นด้วย Submodules ในหนังสือPro Git
แม้ว่า sbmodule
DbConnector
เป็นไดเรกทอรีย่อยในไดเรกทอรีทำงานของคุณ Git เห็นว่าเป็น submodule และไม่ติดตามเนื้อหาเมื่อคุณไม่ได้อยู่ในไดเรกทอรีนั้น แต่ Git มองว่ามันเป็นการกระทำเฉพาะจากแหล่งเก็บข้อมูลนั้น
ซื้อคืนภาคหลักติดตาม submodule กับรัฐที่จุดที่เฉพาะเจาะจงการกระทำ ID ดังนั้นเมื่อคุณอัปเดตโมดูลคุณกำลังอัปเดตรหัสยืนยันเป็นรหัสใหม่
หากคุณต้องการ submodule รวมกับสาขาที่ห่างไกลโดยอัตโนมัติใช้หรือ--merge
--rebase
--ผสาน
ตัวเลือกนี้ใช้ได้สำหรับคำสั่งupdateเท่านั้น รวมการกระทำที่บันทึกไว้ใน superproject เข้าไปในสาขาปัจจุบันของ submodule ถ้าตัวเลือกนี้จะได้รับ HEAD submodule นั้นจะไม่ถูกถอดออก
--rebase
Rebase สาขาปัจจุบันไปที่การบันทึกที่บันทึกไว้ใน superproject ถ้าตัวเลือกนี้จะได้รับ HEAD submodule นั้นจะไม่ถูกถอดออก
สิ่งที่คุณต้องทำคือ
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
นี่คือตัวอย่างที่เกี่ยวกับวิธีการปรับแต่งพฤติกรรมการปรับปรุงการเริ่มต้นของการปรับปรุง submodule .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
git submodule --help
git submodule update --remote --merge
และมันจะดึงซับโดคูลลงในสถานะเดี่ยว ลอง--rebase
ด้วยผลลัพธ์เดียวกัน
cd
ลงใน submodule, เช็คเอาต์ submodule ไปยังสาขาเฉพาะด้วย, git checkout master
.
git submodule foreach --recursive git checkout master
ง่าย
git submodule foreach --recursive git checkout master
ๆ ได้ แต่ฉันจะป้องกันไม่ให้คอมไพล์ปลดพวกเขาออกได้อย่างไร การตั้งค่าตัวเลือกการกำหนดค่าสำหรับแต่ละ submoduleไม่ใช่ตัวเลือก!
git submodule update --remote --merge
ไม่ได้ออกจาก submodule ในสถานะ HEAD เดี่ยว แต่ทำงานgit submodule update
หลังจากแก้ไข.gitmodule
ไฟล์ของฉันตามที่คุณระบุ DID ปล่อย submodule ในสถานะ HEAD เดี่ยว
ฉันเบื่อที่จะถอดมันออกมาตลอดดังนั้นฉันจึงใช้เชลล์สคริปต์เพื่อสร้างมันขึ้นมาสำหรับโมดูลทั้งหมดของฉัน ฉันคิดว่าทั้งหมด submodules อยู่ใน master: นี่คือสคริปต์:
#!/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
รันจากโมดูลแม่ของคุณ
ตรวจสอบคำตอบของฉันที่นี่: Git submodules: ระบุสาขา / แท็ก
หากคุณต้องการคุณสามารถเพิ่มบรรทัด "branch = master" ลงในไฟล์. gitmodules ของคุณได้ด้วยตนเอง อ่านลิงค์เพื่อดูว่าฉันหมายถึงอะไร
แก้ไข: เพื่อติดตามโครงการ submodule ที่มีอยู่ที่สาขาทำตามคำแนะนำของ VonC ที่นี่แทน:
branch = master" line into your .gitmodule
จริงแล้วคำตอบแบบเต็มก็แก้ปัญหานั้นให้ฉันได้
วิธีอื่นในการทำให้ submodule ของคุณเพื่อตรวจสอบสาขาคือไปที่.gitmodules
ไฟล์ในโฟลเดอร์ root และเพิ่มฟิลด์branch
ในการกำหนดค่าโมดูลดังต่อไปนี้:
branch = <branch-name-you-want-module-to-checkout>
branch = my_wanted_branch
แล้ว แต่การทำงานgit submodule update --remote
มันยังคงตรวจสอบว่าเป็นหัวเดี่ยว
อย่างที่คนอื่น ๆ พูดเหตุผลที่สิ่งนี้เกิดขึ้นก็คือว่าผู้ปกครอง repo มีเพียงการอ้างอิงถึง (SHA1 ของ) ความมุ่งมั่นที่เฉพาะเจาะจงใน submodule - มันไม่รู้อะไรเกี่ยวกับสาขา นี่คือวิธีที่ควรใช้งาน: สาขาที่ได้รับมอบหมายอาจย้ายไปข้างหน้า (หรือข้างหลัง) และถ้า repo แม่ได้อ้างอิงสาขาแล้วมันอาจแตกง่ายเมื่อเกิดขึ้น
อย่างไรก็ตามโดยเฉพาะอย่างยิ่งถ้าคุณกำลังพัฒนาทั้งใน repo หลักและ submodule detached HEAD
สถานะอาจทำให้สับสนและอาจเป็นอันตราย หากคุณทำคอมมิตในขณะที่อยู่ในdetached HEAD
สถานะสิ่งเหล่านี้จะห้อยต่องแต่งและคุณอาจสูญเสียงานของคุณได้อย่างง่ายดาย (โดยทั่วไปการกระทำที่มุ่งมั่นสามารถช่วยได้โดยใช้git reflog
แต่จะดีกว่ามากในการหลีกเลี่ยงในตอนแรก)
หากคุณเป็นเหมือนฉันแล้วส่วนใหญ่หากมีสาขาในซับโดลูตที่ชี้ไปที่การส่งกำลังออกคุณควรจะตรวจสอบสาขานั้นมากกว่าอยู่ในสถานะ HEAD เดี่ยวที่กระทำเดียวกัน คุณสามารถทำได้โดยเพิ่มนามแฝงต่อไปนี้ใน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
และ submodule ใด ๆ ที่มีการตรวจสอบที่กระทำซึ่งมีสาขาที่ชี้ไปที่มันจะตรวจสอบสาขาที่ หากคุณไม่ได้มีสาขาท้องถิ่นหลายสาขาที่ชี้ไปที่การกระทำเดียวกันสิ่งนี้มักจะทำในสิ่งที่คุณต้องการ ถ้าไม่อย่างน้อยก็จะทำให้มั่นใจได้ว่าการกระทำใด ๆ ที่คุณทำไปสู่สาขาที่แท้จริงแทนที่จะถูกทิ้งให้ห้อยต่องแต่ง
นอกจากนี้หากคุณได้ตั้งค่าคอมไพล์เพื่ออัปเดต submodules โดยอัตโนมัติเมื่อใช้ ( git config --global submodule.recurse true
ดูคำตอบนี้ ) คุณสามารถสร้าง hook post-checkout ที่เรียกนามแฝงนี้โดยอัตโนมัติ:
$ cat .git/hooks/post-checkout
#!/bin/sh
git submodule-checkout-branch
จากนั้นคุณไม่จำเป็นต้องโทรgit submodule update
หรือgit submodule-checkout-branch
ทำเพียงแค่git checkout
อัปเดตข้อมูลทั้งหมดเป็นข้อผูกพันและตรวจสอบสาขาที่เกี่ยวข้อง (ถ้ามี)
ทางออกที่ง่ายที่สุดคือ:
git clone --recursive git@github.com:name/repo.git
จากนั้น cd ในไดเรกทอรี repo และ:
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
อ่านเพิ่มเติม: Git submodules ปฏิบัติที่ดีที่สุด