ฉันจะย้าย submodule Git ที่มีอยู่ภายในที่เก็บ Git ได้อย่างไร


356

ฉันต้องการเปลี่ยนชื่อไดเรกทอรีของ submodule Git ใน superproject Git ของฉัน

สมมติว่าฉันมีรายการต่อไปนี้ใน.gitmodulesไฟล์ของฉัน:

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

ฉันต้องพิมพ์อะไรเพื่อย้าย.emacs.d/vimpulseไดเรกทอรีไป.emacs.d/vendor/vimpulseโดยไม่ต้องลบออกก่อน (อธิบาย ที่นี่และที่นี่ ) แล้วเพิ่มใหม่อีกครั้ง

Git ต้องการเส้นทางทั้งหมดในแท็ก submodule หรือไม่

[submodule ".emacs.d/vimpulse"]

หรือมันเป็นไปได้ที่จะเก็บเพียงแค่ชื่อของโครงการย่อยหรือไม่

[submodule "vimpulse"]

หมายเหตุ: OP จะตอบคำถามของเขา / เธอด้วยgit mvคำสั่งในคำถาม
Dan Rosenstark

อย่างไรก็ตามคุณไม่สามารถใช้git mvสิ่งนี้ได้ ใช้deinitแล้วrm ตามที่ระบุไว้stackoverflow.com/a/18892438/8047
Dan Rosenstark

14
@Yar: อย่างน้อยใน git 2.0.0 git mv เพียงแค่ทำงานกับ submodules ด้วยและไม่จำเป็นต้องมีอะไรอีก
Pedro Romano

9
เริ่มต้นด้วย Git 1.8.5submodules เคลื่อนไหวได้รับการสนับสนุนอย่างเป็นธรรมชาติโดยใช้git mvคำสั่ง ( จากบันทึกประจำรุ่นแรกที่เชื่อมโยงโดย @thisch ตัวเอง) นอกจากนี้ยังตอบที่นี่
dennisschagt

git mvย้าย submodule ในพื้นที่ทำงานและอัปเดตไฟล์ submodule .git อย่างถูกต้อง แต่โฟลเดอร์ย่อยภายในโฟลเดอร์. git / modules ของ repo หลักยังคงเหมือนเดิม - ตกลงไหม (ฉันใช้ git 2.19.0 บน Windows)
yoyo

คำตอบ:


377

หมายเหตุ:ดังที่กล่าวไว้ในความคิดเห็นคำตอบนี้อ้างถึงขั้นตอนที่จำเป็นสำหรับ git รุ่นเก่า ตอนนี้ Git มีการรองรับพื้นเมืองสำหรับการเคลื่อนย้าย submodules:

ตั้งแต่คอมไพล์ 1.8.5 git mv old/submod new/submodทำงานได้ตามที่คาดไว้และทำการประปาทั้งหมดให้คุณ คุณอาจต้องการใช้ git 1.9.3 หรือใหม่กว่าเนื่องจากมีการแก้ไขสำหรับการย้าย submodule


กระบวนการคล้ายกับวิธีที่คุณจะลบ submodule (ดูที่ฉันจะลบ submodule ได้อย่างไร ):

  1. แก้ไข.gitmodulesและเปลี่ยนเส้นทางของ submodule git add .gitmodulesที่เหมาะสมและวางไว้ในดัชนีด้วย
  2. หากจำเป็นให้สร้างไดเรกทอรีหลักของตำแหน่งใหม่ของ submodule ( mkdir -p new/parent)
  3. ย้ายเนื้อหาทั้งหมดจากเก่าไปยังไดเรกทอรีใหม่ ( mv -vi old/parent/submodule new/parent/submodule)
  4. ตรวจสอบให้แน่ใจว่า Git ติดตามไดเรกทอรีนี้ ( git add new/parent)
  5. git rm --cached old/parent/submoduleลบไดเรกทอรีเก่าด้วย
  6. ย้ายไดเรกทอรีกับทุกเนื้อหาที่จะ.git/modules/old/parent/submodule.git/modules/new/parent/submodule
  7. แก้ไข.git/modules/new/parent/configไฟล์ให้แน่ใจว่าจุดรายการ worktree worktree = ../../../../../new/parent/moduleไปยังสถานที่ใหม่ดังนั้นในตัวอย่างนี้มันควรจะเป็น โดยทั่วไปควรมีมากกว่าสอง..ไดเรกทอรีในเส้นทางโดยตรงในสถานที่นั้น
  8. แก้ไขไฟล์new/parent/module/.gitตรวจสอบให้แน่ใจว่าเส้นทางในนั้นชี้ไปยังตำแหน่งใหม่ที่ถูกต้องภายใน.gitโฟลเดอร์โครงการหลักดังนั้นในตัวอย่างgitdir: ../../../.git/modules/new/parent/submoduleนี้

    git status ผลลัพธ์มีลักษณะเช่นนี้สำหรับฉันหลังจากนั้น:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. ในที่สุดยอมรับการเปลี่ยนแปลง


37
เมื่อคุณอัปเดต. gitmodules ตรวจสอบให้แน่ใจว่าคุณอัปเดตทั้งpathการกำหนดค่านั้นและชื่อของ submodule ยกตัวอย่างเช่นในการย้าย foo / โมดูลบาร์ / โมดูลคุณต้องเปลี่ยนใน .gitmodules ส่วน[submodule "foo/module"]ไป[submodule "bar/module"]และตามมาตราเดียวกับที่ไปpath = foo/module path = bar/moduleนอกจากนี้คุณยังจะต้องมีการเปลี่ยนแปลงใน .git / config ส่วนไป[submodule "foo/module"] [submodule "bar/module"]
wilhelmtell

3
มันใช้งานไม่ได้สำหรับฉัน ... วิธีแก้ปัญหาที่ใกล้เคียงที่สุดที่ฉันพบคือการลบซับมิด (เจ็บปวด) แล้วเพิ่มใหม่อีกครั้งในตำแหน่งอื่น
Pablo Olmos de Aguilera C.

33
หมายเหตุสำคัญมาก: หากคุณได้รับfatal: 'git status --porcelain' failed in...เพียงลบไฟล์. git หรือไดเรกทอรีใน submodule
พิษ

19
ดูเหมือนว่าโพสต์นี้จะหายไปเพียงไม่กี่ขั้นตอนเช่นแก้ไข.git/modules/old/parent/submoduleย้ายไปยังตำแหน่งใหม่กำลังอัปเดตgitdirในold/parent/submodule/.git...
szx

38
ตั้งแต่คอมไพล์ 1.8.5 git mv old/submod new/submodทำงานได้ตามที่คาดไว้และทำการประปาทั้งหมดให้คุณ คุณอาจต้องการใช้ git 1.9.3+ เนื่องจากมีการแก้ไขการย้าย submodule
Valloric

232

คำตอบที่ทันสมัยที่สุดนำมาจากความคิดเห็นของ Valloric ด้านบน:

  1. อัปเกรดเป็น Git 1.9.3 (หรือ2.18 ถ้า submodule มี submodules ที่ซ้อนกัน )
  2. git mv old/submod new/submod
  3. หลังจากนั้น. gitmodules และไดเร็กทอรี submodule จะถูกจัดเตรียมไว้สำหรับคอมมิท (คุณสามารถตรวจสอบได้ด้วยgit status)
  4. ยอมรับการเปลี่ยนแปลงด้วยgit commitและคุณก็พร้อมที่จะไป!

ทำ!


3
สิ่งนี้ใช้ได้กับ1.9.3 ยกเว้น submodule ภายใน submodule ที่ถูกย้าย จำเป็นต้องมีการล้างข้อมูลด้วยตนเอง
Pascal

3
สิ่งนี้ควรทำงานในเวอร์ชัน1.8.5ตามที่อธิบายไว้ในบันทึกย่อประจำรุ่นแล้ว
dennisschagt

6
คำตอบนี้ควรจะได้รับ 1,000 upvote ฉันเกือบจะยุ่งกับ repo ของฉันทำตามขั้นตอนที่อธิบายไว้ข้างต้นจริง ๆ StackOverflow ควรมี usecase สำหรับสถานการณ์นี้
MGP

5
ว้าวมันใช้งานได้อย่างมีเสน่ห์ (git 1.9.5) ฉันหวังว่ามันจะเป็นคำตอบที่เลือก
อเล็กซ์ Ilyaev

7
สิ่งหนึ่งที่สิ่งนี้ไม่ได้ทำคือมันไม่เปลี่ยนป้ายกำกับเริ่มต้นสำหรับ submodule หากคุณตรวจสอบ.gitmodulesไฟล์old/submodจะยังคงใช้เป็นป้ายกำกับสำหรับ submodule ในขณะที่เส้นทางมีการเปลี่ยนแปลง ที่จะได้รับฉลากที่มีการเปลี่ยนแปลงเช่นกันก็จะปรากฏขึ้นคุณจะต้องย้ายจริงภายในเส้นทางโมดูลไดเรกทอรีแล้วด้วยตนเองเปลี่ยนป้ายชื่อใน.git .gitmodules
CMCDragonkai

55

ในกรณีของฉันฉันต้องการย้าย submodule จากไดเรกทอรีหนึ่งไปยังไดเรกทอรีย่อยเช่น "AFNetworking" -> "ext / AFNetworking" นี่คือขั้นตอนที่ฉันปฏิบัติตาม:

  1. แก้ไข. gitmodules เปลี่ยนชื่อ submodule และพา ธ เป็น "ext / AFNetworking"
  2. ย้ายไดเรกทอรี git ของ submodule จาก ".git / modules / AFNetworking" เป็น ".git / modules / ext / AFNetworking"
  3. ย้ายไลบรารีจาก "AFNetworking" เป็น "ext / AFNetworking"
  4. แก้ไข ".git / modules / ext / AFNetworking / config" และแก้ไข[core] worktreeบรรทัด ฉันเปลี่ยนจาก../../../AFNetworkingเป็น../../../../ext/AFNetworking
  5. แก้ไข "ต่อ / AFNetworking / .git" gitdirและแก้ไขปัญหา ฉันเปลี่ยนจาก../.git/modules/AFNetworkingเป็น../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

ในที่สุดฉันก็เห็นสถานะ git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

และ voila ตัวอย่างข้างต้นไม่ได้เปลี่ยนความลึกของไดเรกทอรีซึ่งสร้างความแตกต่างอย่างมากต่อความซับซ้อนของงานและไม่เปลี่ยนชื่อของ submodule (ซึ่งอาจไม่จำเป็นจริงๆ แต่ฉันทำเพื่อให้สอดคล้องกับสิ่งที่ จะเกิดขึ้นหากฉันเพิ่มโมดูลใหม่ที่เส้นทางนั้น)


4
ขอบคุณแมตต์ ฉันหลงทางตามคำตอบที่ยอมรับ ขอบคุณที่ครอบคลุมมากกว่ากรณีพื้นฐาน สิ่งนี้ได้ผลเหมือนมนต์เสน่ห์
Andrew Hubbs

คุณไม่จำเป็นต้องสลับเส้นทาง. git / modules หรือเปลี่ยนชื่อของ submodule (ตามที่ arand และ Bob Bell กล่าวถึง) แม้ว่าการทำเช่นนั้นอาจทำให้ทุกอย่างสะอาดขึ้น
gatoatigrado

อย่าลืมทำตามขั้นตอนที่ 2, 3, 4 และ 5 ซ้ำสำหรับ sub-submodules
herzbube

22

[อัปเดต: 2014-11-26] ตามที่Yarสรุปไว้ด้านล่างก่อนที่คุณจะทำอะไรตรวจสอบให้แน่ใจว่าคุณรู้ URL ของ submodule ถ้าไม่รู้จักเปิดและตรวจสอบที่สำคัญ.git/.gitmodulessubmodule.<name>.url

สิ่งที่ทำงานสำหรับฉันคือการเอา submodule เก่าใช้แล้วตามด้วยgit submodule deinit <submodule> git rm <submodule-folder>จากนั้นเพิ่ม submodule อีกครั้งด้วยชื่อโฟลเดอร์ใหม่และกระทำ การตรวจสอบสถานะ git ก่อนที่จะส่งข้อมูลจะแสดง submodule เก่าที่ถูกเปลี่ยนชื่อเป็นชื่อใหม่และ. gitmodule ถูกแก้ไข

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"

1
สิ่งนี้ต้องมีคอมไพล์ 1.8.3 หรือสูงกว่า ดูโพสต์นี้เพื่ออัพเกรด git ของคุณ: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole

1
หรือวิธีที่ดีกว่า: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get git ติดตั้ง
Michael Cole

@MichaelCole ขอบคุณ! ใช่คุณ! ดูGit-1.8.3 บันทึกประจำรุ่น FYI: อูบุนตู 13.10 (Saucy Salamander) มี Git-1.8.3.2 , แต่ที่ดีที่จะรู้ว่ามีppa อีกทั้งกลยุทธ์การรวมทรีย่อยของ IMHO เป็นวิธีที่ดีกว่า ฉันได้ละทิ้ง submodules สำหรับโครงการของตัวเอง ยังดีที่จะเข้าใจสำหรับโครงการที่มีอยู่
Mark Mikofski

ฉันลองใช้วิธีแก้ไขปัญหาต่าง ๆ แต่คุณดีที่สุด ใช้บรรทัดคำสั่งเท่านั้นดังนั้นคุณไม่จำเป็นต้อง (และไม่ควร) แก้ไขไฟล์ git ใด ๆ ขอบคุณ!
nahung89

12

เคล็ดลับที่ดูเหมือนจะเข้าใจว่า.gitไดเรกทอรีสำหรับ submodules ตอนนี้เก็บไว้ในที่เก็บต้นแบบภายใต้.git/modulesและแต่ละ submodule มี.gitไฟล์ที่ชี้ไปที่มัน นี่คือขั้นตอนที่คุณต้องการตอนนี้:

  • ย้าย submodule ไปที่บ้านใหม่
  • แก้ไข.gitไฟล์ใน submodule ของไดเรกทอรีการทำงานและปรับเปลี่ยนเส้นทางที่มีอยู่เพื่อให้ชี้ไปยังไดเรกทอรีที่เหมาะสมในที่เก็บโท.git/modulesไดเรกทอรี
  • ป้อน.git/modulesไดเรกทอรีของที่เก็บหลักและค้นหาไดเรกทอรีที่สอดคล้องกับ submodule ของคุณ
  • แก้ไขconfigไฟล์โดยอัพเดตworktreeพา ธ เพื่อให้ชี้ไปยังตำแหน่งใหม่ของไดเร็กทอรีการทำงานของ submodule
  • แก้ไข.gitmodulesไฟล์ในรูทของที่เก็บข้อมูลหลักอัพเดตพา ธ ไปยังไดเร็กทอรีการทำงานของ submodule
  • git add -u
  • git add <parent-of-new-submodule-directory>(มันเป็นสิ่งสำคัญที่คุณเพิ่มผู้ปกครองและไม่ไดเรกทอรี submodule ตัวเอง.)

หมายเหตุเล็กน้อย:

  • [submodule "submodule-name"]เส้นใน.gitmodulesและ.git/configต้องตรงกับแต่ละอื่น ๆ แต่ไม่ตรงกับสิ่งอื่น
  • ไดเร็กทอรีการทำงาน submodule และ.gitไดเร็กทอรีต้องชี้ไปที่กันและกันอย่างถูกต้อง
  • .gitmodulesและ.git/configไฟล์ที่ควรจะทำข้อมูลให้ตรงกัน

9

สตริงในเครื่องหมายคำพูดหลัง "[submodule" ไม่สำคัญ คุณสามารถเปลี่ยนเป็น "foobar" ได้ถ้าต้องการ มันถูกใช้เพื่อค้นหารายการที่ตรงกันใน ".git / config"

ดังนั้นหากคุณทำการเปลี่ยนแปลงก่อนที่จะเรียกใช้ "git submodule init" มันจะทำงานได้ดี หากคุณทำการเปลี่ยนแปลง (หรือรับการเปลี่ยนแปลงผ่านการรวม) คุณจะต้องแก้ไขด้วยตนเอง. git / config หรือเรียกใช้ "git submodule init" อีกครั้ง หากคุณดำเนินการต่อคุณจะถูกทิ้งให้อยู่ในรายการ "ควั่น" ที่ไม่มีอันตรายซึ่งมีชื่อเก่าใน. git / config


มันน่ารำคาญจริงๆ แต่คุณพูดถูก ส่วนที่แย่ที่สุดคือถ้าคุณเพิ่งเปลี่ยน URL การเรียกใช้ git init ดูเหมือนจะไม่อัปเดตคุณต้องแก้ไข. git / config ด้วยตนเอง
crimson_penguin

1
ในกรณีนี้git submodule syncเผยแพร่การเปลี่ยนแปลง.git/configโดยอัตโนมัติ
CharlesB

9

คุณสามารถเพิ่ม submodule ใหม่และลบ submodule เก่าโดยใช้คำสั่งมาตรฐาน (ควรป้องกันข้อผิดพลาดจากอุบัติเหตุภายใน. git)

ตัวอย่างการตั้งค่า:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

ตรวจสอบการย้าย 'jquery' เป็น 'ผู้ขาย / jquery / jquery':

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

วิธีโบนัสสำหรับ submodules ขนาดใหญ่:

หาก submodule มีขนาดใหญ่และคุณไม่ต้องการรอการโคลนคุณสามารถสร้าง submodule ใหม่โดยใช้เก่าเป็นจุดเริ่มต้นแล้วสลับจุดเริ่มต้น

ตัวอย่าง (ใช้การตั้งค่าตัวอย่างเดียวกัน)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...

newPathหากคุณไม่ได้ใช้หัวคุณอาจจำเป็นต้องตรวจสอบรุ่นที่ถูกต้องของโมดูลที่
paulmelnikow

2

โซลูชันที่ระบุไม่ได้ผลสำหรับฉัน แต่รุ่นที่คล้ายกันใช้ ...

นี่คือที่เก็บโคลนดังนั้น repodit git repos จึงมีอยู่ในที่เก็บบนสุด. git dir ไพเพอร์ทั้งหมดมาจากแหล่งเก็บข้อมูลชั้นนำ:

  1. แก้ไข. gitmodules และเปลี่ยนการตั้งค่า "path =" สำหรับ submodule ที่เป็นปัญหา (ไม่จำเป็นต้องเปลี่ยนป้ายกำกับหรือเพื่อเพิ่มไฟล์นี้ในดัชนี)

  2. แก้ไข. git / modules / name / config และเปลี่ยนการตั้งค่า "worktree =" สำหรับ submodule ที่เป็นปัญหา

  3. วิ่ง:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

ฉันสงสัยว่ามันสร้างความแตกต่างถ้าที่เก็บเป็นอะตอมหรือ submodules ญาติในกรณีของฉันมันเป็นญาติ (submodule / .git เป็นผู้อ้างอิงกลับไปที่ topproject / .git / modules / submodule)


2

เพียงแค่ใช้สคริปต์เชลล์-git submodule ย้าย


เฮ้ฉันค้นหาคำถามนี้อีกครั้งและใช้หนึ่งในคำตอบที่ได้รับการโหวตแล้วและตอนนี้ฉันหวังว่าฉันจะเลื่อนลงและเห็นคำตอบก่อนหน้าซึ่งฉันลืมไปแล้ว
Flimm

2

ฉันเพิ่งผ่านการทดสอบเมื่อวานนี้และคำตอบนี้ทำงานอย่างสมบูรณ์ นี่คือขั้นตอนของฉันเพื่อความชัดเจน:

  1. ตรวจสอบให้แน่ใจว่ามีการเช็คอิน submodule และส่งไปยังเซิร์ฟเวอร์ คุณจำเป็นต้องรู้ว่าสาขาใดอยู่
  2. คุณต้องการ URL ของ submodule ของคุณ! ใช้more .gitmodulesเพราะเมื่อคุณลบ submodule มันจะไม่หายไปไหน
  3. ตอนนี้คุณสามารถใช้deinit, rmและจากนั้นsubmodule add

ตัวอย่าง

คำสั่ง

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

หมายเหตุ: git mv ไม่ได้ทำเช่นนี้ เลย


3
สรุปที่ดี +1 git mvน่าจะดีกว่าใน Git เวอร์ชันล่าสุด
VonC

@VonC ฉันทดสอบ git 1.8.5 แล้วค่อนข้างแน่ใจว่ามันดีพอ ๆ กับที่ได้รับmvมา ขอบคุณ!
Dan Rosenstark
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.