เพื่อประโยชน์ของผู้อ่านที่นี่พยายามที่จะสรุปและให้คำแนะนำทีละขั้นตอนเกี่ยวกับวิธีการทำหากสิ่งไม่ทำงานตามที่คาดไว้ ต่อไปนี้เป็นวิธีที่ผ่านการทดสอบและปลอดภัยสำหรับgit
เวอร์ชั่น2.17
ขึ้นไปเพื่อกำจัด submodule :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- หากสิ่งนี้ไม่ได้ผลสำหรับคุณดูด้านล่าง
- ไม่มีตัวเลือก ไม่มีอะไรอันตราย และอย่าแม้แต่จะคิดที่จะทำมากขึ้น!
- ทดสอบกับ Debian Buster
2.20.1
และ Ubuntu 18.042.17.1
18.04
"$submodule"
เป็นเพียงการเน้นที่จะใส่ชื่อและคุณต้องระวังช่องว่างและไม่ชอบ
- หากใน Windows เพิกเฉยบรรทัดแรกและแทนที่
"$submodule"
ด้วยวิธี Windows ของเส้นทางที่ระบุอย่างถูกต้องไปยัง submodule (ฉันไม่ใช่ Windows)
คำเตือน!
อย่าแตะต้องภายใน.git
ไดเรกทอรีด้วยตัวเอง! แก้ไขข้างใน.git
เข้าสู่ด้านมืด อยู่ให้ไกล!
และใช่คุณสามารถตำหนิgit
เรื่องนี้ได้เพราะมีหลายสิ่งที่ขาดหายไปgit
อดีต ชอบวิธีที่เหมาะสมในการลบ submodules อีกครั้ง
git submodule
ผมคิดว่ามีเป็นส่วนหนึ่งที่อันตรายมากในเอกสารประกอบของ แนะนำให้ลบ$GIT_DIR/modules/<name>/
ตัวคุณเอง
ในความเข้าใจของฉันนี้ไม่เพียงผิดธรรมดามันเป็นอันตรายอย่างยิ่งและกระตุ้นให้เกิดอาการปวดหัวที่สำคัญในอนาคต ดูด้านล่าง
สังเกตได้ว่า
git module deinit
เป็นสิ่งที่ตรงกันข้ามโดยตรงกับ
git module init
แต่
git submodule deinit -- module
git rm -- module
ยังค่อนข้างตรงกันข้ามกับ
git submodule add -- URL module
git submodule update --init --recursive -- module
เพราะโดยทั่วไปคำสั่งบางอย่างจำเป็นต้องทำมากกว่าสิ่งเดียว:
git submodule deinit -- module
git rm
- (2) ลบไฟล์ของโมดูล
- (3) ดังนั้นการลบซ้ำ submodules ของ submodule
- (4) อัปเดต
.gitmodules
git submodule add
- ดึงข้อมูลไปที่
.git/modules/NAME/
- (1) ทำ
git submodule init
เช่นนั้นอัปเดต.git/config
- (2) ทำ
git submodule update
เช่นนั้นโดยไม่ตรวจสอบโมดูล
- (4) อัปเดต
.gitmodules
git submodule update --init --recursive -- module
- ดึงข้อมูลเพิ่มเติมหากจำเป็น
- (3) ตรวจสอบ submodules ของ submodule ซ้ำ
สิ่งนี้ไม่สามารถสมมาตรได้อย่างสมบูรณ์เนื่องจากการทำให้สมมาตรอย่างเคร่งครัดนั้นไม่สมเหตุสมผล ไม่จำเป็นต้องมีคำสั่งมากกว่าสองคำสั่ง นอกจากนี้ "การดึงข้อมูล" ก็เป็นนัยเพราะคุณต้องการ แต่การลบข้อมูลแคชไม่ได้ทำเพราะไม่จำเป็นเลยและอาจล้างข้อมูลที่มีค่า
สิ่งนี้ทำให้งงกับผู้มาใหม่ แต่โดยพื้นฐานแล้วเป็นสิ่งที่ดี git
เพียงทำในสิ่งที่เห็นได้ชัดและทำในสิ่งที่ถูกต้องและไม่พยายามทำมากขึ้น git
เป็นเครื่องมือที่ต้องทำงานที่เชื่อถือได้แทนที่จะเป็น "Eierlegende Wollmilchsau" อีกครั้ง ("Eierlegende Wollmilchsau" แปลให้ฉันเป็น "มีดกองทัพสวิสรุ่นชั่วร้าย")
ดังนั้นฉันจึงเข้าใจการร้องเรียนของผู้คนโดยพูดว่า "ทำไมไม่ทำgit
สิ่งที่ชัดเจนให้ฉัน" นี่เป็นเพราะ "ชัดเจน" ที่นี่ขึ้นอยู่กับมุมมอง ความน่าเชื่อถือในแต่ละสถานการณ์มีความสำคัญมากกว่า ดังนั้นสิ่งที่ชัดเจนสำหรับคุณมักจะไม่ใช่สิ่งที่ถูกต้องในสถานการณ์ทางเทคนิคที่เป็นไปได้ทั้งหมด โปรดจำไว้ว่า: AFAICSgit
ติดตามเส้นทางเทคนิคไม่ใช่สังคม (ดังนั้นชื่อที่ฉลาด: git)
หากล้มเหลว
คำสั่งด้านบนอาจล้มเหลวเนื่องจากสาเหตุดังต่อไปนี้:
- คุณ
git
แก่เกินไป git
จากนั้นใช้ใหม่ (ดูวิธีการด้านล่าง)
- คุณมีข้อมูลที่ไม่มีข้อผูกมัดและอาจสูญเสียข้อมูล ถ้าอย่างนั้นดีกว่ากระทำพวกเขาก่อน
- submodule ของคุณไม่สะอาดใน
git clean
ความรู้สึก จากนั้นทำความสะอาด submodule ของคุณก่อนโดยใช้คำสั่งนั้น (ดูด้านล่าง)
- คุณเคยทำบางสิ่งในอดีตซึ่งไม่ได้รับการสนับสนุนจาก
git
คุณได้ทำบางสิ่งบางอย่างในอดีตที่ผ่านมาซึ่งได้รับการสนับสนุนโดยถ้าอย่างนั้นคุณก็อยู่ในด้านมืดและสิ่งต่าง ๆ น่าเกลียดและซับซ้อน (อาจใช้เครื่องอื่นแก้ไข)
- บางทีอาจมีวิธีอื่นที่ล้มเหลวฉันไม่ทราบ (ฉันเป็นแค่
git
ผู้ใช้ที่มีอำนาจ)
การแก้ไขที่เป็นไปได้ดังต่อไปนี้
ใช้ใหม่กว่า git
ถ้าเครื่องของคุณเก่าเกินไปไม่มีในของคุณsubmodule deinit
git
หากคุณไม่ต้องการ (หรือสามารถ) อัปเดตของคุณgit
ให้ใช้เครื่องอื่นที่ใหม่กว่าgit
! git
มีวัตถุประสงค์เพื่อเผยแพร่อย่างเต็มที่ดังนั้นคุณสามารถใช้งานอื่นgit
เพื่อให้งานสำเร็จลุล่วง:
workhorse:~/path/to/worktree$ git status --porcelain
ต้องไม่ส่งออกอะไร! ถ้าเป็นเช่นนั้นให้ล้างข้อมูลก่อน!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- ตอนนี้ทำสิ่ง submodule
othermachine:~/TMPWORK$ git commit . -m . && exit
workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD
. หากไม่สามารถใช้งานได้ให้ใช้git reset --soft FETCH_HEAD
- ทีนี้ล้างข้อมูลจนกว่า
git status
จะสะอาดอีกครั้ง คุณสามารถทำได้เนื่องจากคุณเคยทำความสะอาดมาก่อนต้องขอบคุณขั้นตอนแรก
นี่othermachine
อาจเป็น VM หรือ Ubuntu WSL ภายใต้ Windows ไม่ว่าจะเป็นอะไรก็ตาม แม้แต่ a chroot
(แต่ฉันคิดว่าคุณไม่ใช่คนรูทเพราะถ้าคุณเป็นคนroot
นั้นมันควรจะอัปเดตเป็นรุ่นใหม่ได้ง่ายกว่าgit
)
โปรดทราบว่าหากคุณไม่สามารถเข้าร่วมได้ssh
จะมีวิธีการขนส่งที่git
เก็บข้อมูล คุณสามารถคัดลอก worktree ของคุณใน USB stick (รวมถึง.git
ไดเรกทอรี) และโคลนจากแท่ง คัดลอกโคลนเพียงเพื่อให้ได้สิ่งที่สะอาดอีกครั้ง นี่อาจเป็น PITA ในกรณีที่ submodules ของคุณไม่สามารถเข้าถึงได้จากเครื่องอื่น ๆ โดยตรง แต่มีวิธีแก้ปัญหาสำหรับสิ่งนี้เช่นกัน:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
$HOME/.gitconfig
คุณสามารถใช้คูณนี้และนี้จะถูกบันทึกลง สิ่งที่ต้องการ
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
เขียน URL ใหม่เช่น
https://github.com/XXX/YYY.git
เข้าไป
/mnt/usb/repo/XXX/YYY.git
ง่ายถ้าคุณเริ่มคุ้นเคยกับgit
คุณสมบัติที่ทรงพลังเช่นนี้
ล้างข้อมูลก่อน
การทำความสะอาดด้วยตนเองนั้นดีเพราะบางทีคุณอาจตรวจพบบางสิ่งที่คุณลืม
- หากคอมไพล์บ่นเกี่ยวกับสิ่งที่ไม่ได้บันทึกกระทำและผลักดันมันที่ไหนสักแห่งที่ปลอดภัย
- หากคอมไพล์บ่นเกี่ยวกับสิ่งที่เหลืออยู่
git status
และgit clean -ixfd
เป็นเพื่อนของคุณ
- พยายามที่จะหลีกเลี่ยงตัวเลือกจาก
rm
และdeinit
ตราบเท่าที่คุณสามารถ ตัวเลือก (เช่น-f
) git
เป็นสิ่งที่ดีถ้าคุณเป็นมืออาชีพ แต่เมื่อคุณมาที่นี่คุณอาจไม่มีประสบการณ์ในsubmodule
พื้นที่ ปลอดภัยกว่าดีกว่าขออภัย
ตัวอย่าง:
$ git status --porcelain
M two
$ git submodule deinit two
error: the following file has local modifications:
two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
NEW
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers 4: ask each
5: quit 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'
คุณจะเห็นไม่มีความจำเป็นในการ-f
submodule deinit
หากสิ่งที่สะอาดในgit clean
ความรู้สึก ยังทราบว่าgit clean -x
ไม่จำเป็น ซึ่งหมายความว่าgit submodule deinit
จะลบไฟล์ที่ไม่ได้ติดตามซึ่งจะถูกละเว้นอย่างไม่มีเงื่อนไข นี่คือสิ่งที่คุณต้องการ แต่อย่าลืมมัน บางครั้งไฟล์ที่ถูกเพิกเฉยอาจมีค่าเช่นข้อมูลแคชที่ต้องใช้เวลาในการคำนวณอีกหลายชั่วโมง
ทำไมไม่เอา$GIT_DIR/modules/<name>/
?
คนอาจต้องการลบที่เก็บแคชเพราะพวกเขากลัวที่จะพบปัญหาในภายหลัง นี่เป็นเรื่องจริง แต่การพบปัญหา "" เป็นวิธีที่ถูกต้องในการแก้ไข! เพราะการแก้ไขนั้นง่ายและทำถูกต้องคุณจะสามารถใช้ชีวิตอย่างมีความสุขตลอดไป วิธีนี้จะช่วยหลีกเลี่ยงปัญหาที่ยุ่งยากกว่าเมื่อคุณลบข้อมูลด้วยตัวเอง
ตัวอย่าง:
mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two
บรรทัดสุดท้ายแสดงข้อผิดพลาดต่อไปนี้:
A git directory for 'two' is found locally with remote(s):
origin https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.
ทำไมข้อผิดพลาดนี้? เพราะ.git/modules/two/
ก่อนหน้านี้มีประชากรจากhttps://github.com/hilbix/empty.gitและตอนนี้จะเป็นอีกครั้งที่มีประชากรจากสิ่งอื่นคือhttps://github.com/hilbix/src.git คุณจะไม่เห็นสิ่งนี้หากคุณเติมข้อมูลอีกครั้งจากhttps://github.com/hilbix/empty.git
ต้องทำอะไรตอนนี้ ดีเพียงทำตามที่บอก! ใช้--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
แล้วดูเหมือนว่า
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
จะช่วยให้
someunusedname/
two/
วิธีนี้ในอนาคตคุณสามารถสลับสาขา / ส่งต่อไปข้างหน้าและข้างหลังและจะไม่มีปัญหาใด ๆ อีกต่อไปเนื่องจากtwo/
มีที่เก็บอัปสตรีมสองที่แตกต่างกัน (และอาจเข้ากันไม่ได้) และที่ดีที่สุดคือคุณเก็บแคชไว้ในเครื่องทั้งสองด้วย
- สิ่งนี้ไม่เพียงเป็นความจริงสำหรับคุณ นอกจากนี้ยังเป็นจริงสำหรับผู้อื่นทั้งหมดที่ใช้ที่เก็บของคุณ
- และคุณจะไม่สูญเสียประวัติศาสตร์ ในกรณีที่คุณลืมที่จะผลักดัน submodule เวอร์ชั่นเก่ามากล่าสุดคุณสามารถป้อนสำเนาโลคัลและดำเนินการในภายหลัง โปรดทราบว่ามันเป็นเรื่องธรรมดาที่บางคนลืมที่จะผลักดัน submodules (เพราะนี่คือ PITA สำหรับผู้มาใหม่จนกระทั่งพวกเขาคุ้นเคยกับมัน
git
)
อย่างไรก็ตามหากคุณลบไดเรกทอรีที่เก็บไว้ทั้งเช็คเอาต์ที่แตกต่างกันจะสะดุดซึ่งกันและกันเพราะคุณจะไม่ใช้--name
ตัวเลือกใช่มั้ย ดังนั้นทุกครั้งที่คุณชำระเงินคุณอาจต้องลบ.git/modules/<module>/
ไดเรกทอรีซ้ำแล้วซ้ำอีก มันยุ่งยากมากและทำให้ยากต่อการใช้งานgit bisect
นี้จะยุ่งยากมากและทำให้ยากที่จะใช้สิ่งที่ต้องการ
ดังนั้นจึงมีเหตุผลทางเทคนิคที่จะทำให้ไดเรกทอรีโมดูลนี้เป็นตัวยึดตำแหน่ง คนที่แนะนำให้ลบบางสิ่งด้านล่าง.git/modules/
ไม่ทราบดีกว่าหรือลืมที่จะบอกคุณว่าสิ่งนี้ทำให้คุณสมบัติที่มีประสิทธิภาพเช่นgit bisect
แทบจะเป็นไปไม่ได้ที่จะใช้ถ้ามันข้ามกันไม่ได้ submodule
เหตุผลเพิ่มเติมแสดงไว้ด้านบน ดูที่ls
. คุณเห็นอะไรที่นั่น?
ทีนี้ตัวแปรที่สองของโมดูลtwo/
ไม่ได้อยู่ภายใต้.git/modules/two/
มันอยู่ภายใต้.git/modules/someunusedname/
! ดังนั้นสิ่งต่าง ๆgit rm $module; rm -f .git/module/$module
ที่ผิดอย่างสิ้นเชิง! คุณต้องปรึกษาmodule/.git
หรือ.gitmodules
ค้นหาสิ่งที่ถูกต้องที่จะลบ!
ดังนั้นไม่เพียง แต่คำตอบส่วนใหญ่เท่านั้นที่ตกอยู่ในกับดักอันตรายนี้แม้กระทั่งgit
ส่วนขยายที่ได้รับความนิยมอย่างมากก็มีบั๊กนี้ ( ตอนนี้ได้รับการแก้ไขแล้ว )! ดังนั้นควรรักษา.git/
ไดเรกทอรีไว้ถ้าคุณไม่ทำสิ่งที่คุณกำลังทำ!
และจากมุมมองทางปรัชญาการล้างประวัตินั้นผิดเสมอ!
ยกเว้นกลศาสตร์ควอนตัมตามปกติ แต่นี่เป็นสิ่งที่แตกต่างอย่างสิ้นเชิง
FYI คุณอาจเดาได้: hilbixเป็นบัญชี GitHub ของฉัน
git rm modulename
และrm -rf .git/modules/modulename