ไดเรกทอรีทำงานหลายรายการด้วย Git


242

ฉันไม่แน่ใจว่านี่เป็นสิ่งที่ Git สนับสนุน แต่ในทางทฤษฎีแล้วดูเหมือนว่ามันควรจะทำงานให้ฉัน

เวิร์กโฟลว์ของฉันมักจะเกี่ยวข้องกับการแก้ไขไฟล์ในหลายสาขาพร้อมกัน กล่าวอีกนัยหนึ่งฉันมักจะต้องการเปิดไฟล์ไม่กี่ไฟล์ในสาขาหนึ่งคือในขณะที่ฉันแก้ไขเนื้อหาของไฟล์อื่นในสาขาอื่น

วิธีแก้ปัญหาทั่วไปของฉันคือทำการเช็คเอาต์สองครั้ง แต่มันเป็นความอัปยศที่ฉันไม่สามารถแชร์สาขาและอ้างอิงระหว่างพวกเขาได้ สิ่งที่ฉันต้องการคือมีไดเรกทอรีการทำงานสองแห่งที่จัดการโดยโฟลเดอร์. git เดียวกัน

ฉันรู้ถึงวิธีแก้ไขปัญหา git clone ในพื้นที่ (ค่าเริ่มต้นซึ่งคือการแชร์วัตถุแบบ hardlink และตัวเลือก --shared ซึ่งตั้งค่าที่เก็บวัตถุสำรองด้วย repo ดั้งเดิม) แต่โซลูชันเหล่านี้ลดการใช้พื้นที่ดิสก์เท่านั้น และโดยเฉพาะอย่างยิ่งในกรณีของ --shared ดูเหมือนจะเต็มไปด้วยอันตราย

มีวิธีใช้โฟลเดอร์. git หนึ่งโฟลเดอร์หรือไม่และมีไดเรกทอรีทำงานสองอันที่สำรองข้อมูลไว้หรือไม่ หรือ Git hardcoded มีไดเรกทอรีทำงานเพียงหนึ่งเช็คเอาท์ตลอดเวลา?


1
git-new-workdirจะถูกแทนที่ด้วยgit checkout --to=<path>ใน Git 2.5 ดูคำตอบของฉันด้านล่าง
VonC

3
ที่จริงแล้วคำสั่งจะเป็นgit worktree add <path> [<branch>](Git 2.5 rc2) ดูคำตอบที่แก้ไขของฉันด้านล่าง
VonC

คุณควรเปลี่ยนคำตอบที่ยอมรับได้คำตอบของ VonC เนื่องจากสิ่งต่าง ๆ ได้เปลี่ยนไปตั้งแต่แรกที่คุณถามคำถาม
xaxxon

ขอบคุณสำหรับคำตอบที่อัพเดต!
jtolds

คำตอบ:


293

Git 2.5 เสนอมาตั้งแต่เดือนกรกฎาคม 2558 แทนcontrib/workdir/git-new-workdir: git worktree

ดูกระทำ 68a2e6aโดยJunio C Hamano (gitster )

เอกสารเผยแพร่ระบุว่า :

การแทนที่contrib/workdir/git-new-workdirสิ่งที่ไม่ต้องพึ่งพาลิงก์สัญลักษณ์และทำให้การแบ่งปันวัตถุและการอ้างอิงปลอดภัยยิ่งขึ้นโดยทำให้ผู้ยืมและผู้ยืมได้รับรู้ซึ่งกันและกัน

ดูคอมมิชชัน 799767cc9 (Git 2.5rc2)

นั่นหมายความว่าคุณสามารถทำได้git worktree add <path> [<branch>]

สร้าง<path>และชำระเงิน<branch>เป็นมัน ไดเร็กทอรีการทำงานใหม่เชื่อมโยงกับที่เก็บปัจจุบันแชร์ทุกอย่างยกเว้นไฟล์เฉพาะไดเรกทอรีทำงานเช่น HEAD, index ฯลฯgit worktreeส่วนเพิ่ม:

ที่เก็บ git สามารถรองรับต้นไม้ทำงานได้หลายต้นช่วยให้คุณสามารถตรวจสอบได้มากกว่าหนึ่งสาขาในเวลาเดียวกัน
ด้วยแผนผังgit worktree addการทำงานใหม่จะเชื่อมโยงกับที่เก็บ

ต้นไม้ต้นนี้การทำงานใหม่ที่เรียกว่า "การเชื่อมโยงต้นไม้ทำงาน" เมื่อเทียบกับ "ต้นการทำงานหลัก" จัดทำโดย " git init" หรือ "git clone "
ที่เก็บมีต้นไม้การทำงานหลักหนึ่งต้น (ถ้าไม่ใช่ที่เก็บเปลือย) และมีต้นไม้การทำงานเชื่อมโยงเป็นศูนย์หรือมากกว่า

รายละเอียด:

ต้นไม้แต่ละต้นการทำงานที่เชื่อมโยงมีไดเรกทอรีย่อยในพื้นที่เก็บข้อมูลส่วนตัวของ $GIT_DIR/worktreesไดเรกทอรี
ชื่อของไดเรกทอรีย่อยส่วนตัวมักจะเป็นชื่อพื้นฐานของเส้นทางของแผนผังการทำงานที่เชื่อมโยงซึ่งอาจผนวกเข้ากับตัวเลขเพื่อทำให้เป็นเอกลักษณ์
ตัวอย่างเช่นเมื่อ$GIT_DIR=/path/main/.gitคำสั่งgit worktree add /path/other/test-next nextสร้าง:

  • แผนผังการทำงานที่เชื่อมโยงใน/path/other/test-nextและ
  • สร้าง$GIT_DIR/worktrees/test-nextไดเรกทอรีด้วย (หรือ$GIT_DIR/worktrees/test-next1ถ้าtest-nextถ่ายไปแล้ว)

ภายในแผนผังการทำงานที่เชื่อมโยง:

  • $GIT_DIRถูกตั้งค่าให้ชี้ไปที่ไดเรกทอรีส่วนตัวนี้ (เช่น/path/main/.git/worktrees/test-nextในตัวอย่าง) และ
  • $GIT_COMMON_DIRถูกตั้งค่าให้ชี้กลับไปที่แผนผังการทำงานหลัก$GIT_DIR(เช่น/path/main/.git)

การตั้งค่าเหล่านี้จะทำใน.gitไฟล์ที่อยู่ในไดเรกทอรีด้านบนของแผนผังการทำงานที่เชื่อมโยง

เมื่อคุณทำแผนผังการทำงานที่เชื่อมโยงแล้วคุณสามารถลบมันได้
ไฟล์การดูแลระบบของแผนผังการทำงานในที่เก็บในที่สุดจะถูกลบออกโดยอัตโนมัติ (ดูgc.pruneworktreesexpireในgit config) หรือคุณสามารถเรียกใช้git worktree pruneในแผนผังการทำงานหลักหรือแผนผังที่เชื่อมโยงเพื่อล้างไฟล์การดูแลระบบที่เก่าเกินไป


คำเตือน: ยังมีส่วนgit worktree"BUGS"ที่ต้องระวัง

การสนับสนุนสำหรับsubmodulesไม่สมบูรณ์
ไม่แนะนำให้ทำการเช็คเอาต์หลายรายการของ Superproject


หมายเหตุ: ด้วย git 2.7rc1 (พ.ย. 2558) คุณสามารถแสดงรายการ worktrees ของคุณ
ดูกระทำ bb9c03b , กระทำ 92718b7 , กระทำ 5193490 , กระทำ 1ceb7f9 , กระทำ 1ceb7f9 , กระทำ 5193490 , กระทำ 1ceb7f9 , กระทำ 1ceb7f9 (8 ตุลาคม 2015) กระทำ 92718b7 , กระทำ 5193490 , กระทำ 1ceb7f9 , กระทำ 1ceb7f9 (8 ตุลาคม 2015) กระทำ 5193490 , คอมมิชชัน 1ceb7f9 (08 ต.ค. 2558), คอมมิท 1ceb7f9 (08 ต.ค. 2558), และกระทำ ac6c561(2 ตุลาคม 2015) โดยไมเคิล Rappazzo (rappazzo )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ a46dcfb , 26 ตุลาคม 2015)

worktree: เพิ่มlistคำสั่ง ''

' git worktree list' วนซ้ำผ่านรายการ worktree และแสดงรายละเอียดของ worktree รวมถึงเส้นทางไปยัง worktree การตรวจสอบการแก้ไขและสาขาในปัจจุบันและถ้าต้นไม้ว่างเปล่า

$ git worktree list
/path/to/bare-source            (bare)
/path/to/linked-worktree        abcd1234 [master]
/path/to/other-linked-worktree  1234abc  (detached HEAD)

นอกจากนี้ยังมีตัวเลือกรูปแบบพอร์ซเลน

รูปแบบ Porcelain มีบรรทัดต่อแอตทริบิวต์

  • แอ็ตทริบิวต์ถูกลิสต์ด้วยเลเบลและค่าคั่นด้วยช่องว่างเดียว
  • แอตทริบิวต์บูลีน (เช่น 'bare' และ 'แฝด') จะแสดงรายการเป็นป้ายกำกับเท่านั้นและจะปรากฏต่อเมื่อค่านั้นเป็นจริงเท่านั้น
  • บรรทัดว่างหมายถึงจุดสิ้นสุดของ worktree

ตัวอย่างเช่น

$ git worktree list --porcelain

worktree /path/to/bare-source
bare

worktree /path/to/linked-worktree
HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
branch refs/heads/master

worktree /path/to/other-linked-worktree
HEAD 1234abc1234abc1234abc1234abc1234abc1234a
detached

หมายเหตุ: หากคุณย้ายโฟลเดอร์ worktree คุณต้องอัปเดตไฟล์ด้วยตนเองgitdir

ดูกระทำ 618244e (22 มกราคม 2016) และกระทำ d4cddd6 (18 มกราคม 2016) โดยNguyễnTháiNgọc Duy (pclouds )
ช่วยโดย: เอริคซันไชน์ (sunshineco )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ d0a1cbc , 10 กุมภาพันธ์ 2016)

เอกสารใหม่ใน git 2.8 (มีนาคม 2016) จะรวมถึง:

หากคุณย้ายแผนผังการทำงานที่เชื่อมโยงคุณต้องอัปเดตgitdirไฟล์ '' ในไดเรกทอรีของรายการ
ตัวอย่างเช่นหากย้ายแผนผังการทำงานที่เชื่อมโยงไปยัง/newpath/test-nextและ.gitไฟล์ชี้ไปที่ให้/path/main/.git/worktrees/test-nextอัปเดต /path/main/.git/worktrees/test-next/gitdirเป็นข้อมูลอ้างอิง/newpath/test-nextแทน


ระวังเมื่อทำการลบสาขา: ก่อนที่จะคอมไพล์ 2.9 (มิถุนายน 2559) คุณสามารถลบสาขาที่ใช้งานในแผนผังการทำงานอื่นได้

เมื่อgit worktreeมีการใช้งานฟีเจอร์ " git branch -d" จะอนุญาตให้ลบสาขาที่เช็คเอาท์ใน worktree อื่น

ดูกระทำ f292244 (29 มีนาคม 2016) โดยKazuki ยามากูชิ (rhenium )
ช่วยโดย: เอริคซันไชน์ (sunshineco )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 4fca4e3 , 13 เมษายน 2016)

branch -d: ปฏิเสธการลบสาขาที่ชำระเงินแล้วในปัจจุบัน

เมื่อสาขาถูกเช็คเอาท์โดยแผนผังการทำงานปัจจุบันการลบสาขาจะถูกห้าม
อย่างไรก็ตามเมื่อสาขาถูกเช็กเอาต์ด้วยต้นไม้ทำงานอื่นการลบจะไม่สำเร็จ
ใช้find_shared_symref()เพื่อตรวจสอบว่ามีการใช้งานสาขาหรือไม่ไม่ใช่แค่เปรียบเทียบกับ HEAD ของแผนผังการทำงานปัจจุบัน


ในทำนองเดียวกันก่อนที่จะคอมไพล์ 2.9 (มิถุนายน 2559) การเปลี่ยนชื่อสาขาที่เช็คเอาท์ใน worktree อื่นไม่ได้ปรับ HEAD เป็นสัญลักษณ์ใน worktree อื่นที่กล่าวมา

ดูกระทำ 18eb3a9 (8 เมษายน 2016) และกระทำ 70999e9 , กระทำ 2233066 (27 มีนาคม 2016) โดยKazuki ยามากูชิ (rhenium )
(ผสานโดยJunio ​​C Hamano - gitster-ในการกระทำ 741a694 , 18 เมษายน 2016)

branch -m: อัปเดตหัวต่อ worktree ทั้งหมด

เมื่อเปลี่ยนชื่อสาขาปัจจุบันเฉพาะ HEAD ของแผนผังการทำงานปัจจุบันเท่านั้นที่ได้รับการอัปเดต แต่ต้องอัปเดต HEADs ของแผนผังการทำงานทั้งหมดซึ่งชี้ไปที่สาขาเก่า

นี่คือพฤติกรรมปัจจุบัน / HEAD / path / to / wt ไม่ได้รับการอัพเดต:

  % git worktree list
  /path/to     2c3c5f2 [master]
  /path/to/wt  2c3c5f2 [oldname]
  % git branch -m master master2
  % git worktree list
  /path/to     2c3c5f2 [master2]
  /path/to/wt  2c3c5f2 [oldname]
  % git branch -m oldname newname
  % git worktree list
  /path/to     2c3c5f2 [master2]
  /path/to/wt  0000000 [oldname]

โปรแกรมแก้ไขนี้แก้ไขปัญหานี้ได้โดยการอัปเดต worktree HEADs ที่เกี่ยวข้องทั้งหมดเมื่อเปลี่ยนชื่อสาขา


กลไกการล็อครองรับอย่างเป็นทางการกับ git 2.10 (ไตรมาส 3 ปี 2559)

ดูกระทำ 080739b , กระทำ 6d30862 , กระทำ 58142c0 , กระทำ 346ef53 , กระทำ 346ef53 , กระทำ 58142c0 , กระทำ 346ef53 , กระทำ 346ef53 (13 มิถุนายน 2016) และกระทำ 984ad9e , กระทำ 6835314 (3 มิถุนายน 2016) โดยNguyễnTháiNgọc Duy (pclouds )
แนะนำโดย: เอริคซันไชน์ (sunshineco )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 2c608e0 , 28 กรกฎาคม 2016)

git worktree lock [--reason <string>] <worktree>
git worktree unlock <worktree>

หากแผนผังการทำงานที่เชื่อมโยงถูกจัดเก็บไว้ในอุปกรณ์พกพาหรือเครือข่ายที่ไม่ได้ติดตั้งอยู่ตลอดเวลาคุณสามารถป้องกันไม่ให้ไฟล์การดูแลระบบถูกตัดโดยการออกgit worktree lockคำสั่งหรือระบุทางเลือก--reasonเพื่ออธิบายว่าทำไมแผนผังการทำงานถูกล็อก

<worktree>: หากส่วนประกอบของเส้นทางสุดท้ายในเส้นทางของต้นไม้ทำงานไม่ซ้ำกันในหมู่ต้นไม้ทำงานมันสามารถใช้เพื่อระบุ worktrees
ตัวอย่างเช่นหากคุณต้องทำงานต้นไม้ที่ " /abc/def/ghi" และ " /abc/def/ggg" ดังนั้น " ghi" หรือ " def/ghi" ก็เพียงพอที่จะชี้ไปยังต้นไม้ทำงานเดิมได้


Git 2.13 (Q2 2017) เพิ่มlockตัวเลือกในการกระทำ 507e6e9 (12 เมษายน 2017) โดยNguyễnTháiNgọc Duy (pclouds )
แนะนำโดย: เดวิดเทย์เลอร์ (dt )
ช่วยโดย: เจฟฟ์คิง (peff )
(ผสานโดยJunio ​​C Hamano - gitster- in e311597 , 26 Apr 2017)

อนุญาตให้ล็อค worktree ทันทีหลังจากที่สร้างขึ้น
ซึ่งจะช่วยป้องกันการแข่งขันระหว่าง " git worktree add; git worktree lock" และ " git worktree prune"

ดังนั้นจึงgit worktree add' --lock เทียบเท่ากับgit worktree lockหลังจากgit worktree addแต่ไม่มีเงื่อนไขการแข่งขัน


Git 2.17+ (Q2 2018) เพิ่มgit worktree move/ git worktree remove: ดูคำตอบนี้


Git 2.19 (ไตรมาสที่ 3 ปี 2018) เพิ่ม--quietตัวเลือก "" เพื่อให้git worktree addverbose น้อยลง ""

ดูกระทำ 371979c (15 สิงหาคม 2018) โดยเอเลียปินโต (devzero2000 )
ช่วยโดย: มาร์ติน Agren, Duy เหงียน ( pclouds)และเอริคซันไชน์ (sunshineco )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ a988ce9 , 27 สิงหาคม 2018)

worktree: เพิ่ม--quietตัวเลือก

เพิ่ม--quietตัวเลือก '' ลงgit worktreeในเช่นเดียวกับgitคำสั่งอื่น ๆ
' add' เป็นคำสั่งเดียวที่ได้รับผลกระทบเนื่องจากคำสั่งอื่น ๆ ทั้งหมดยกเว้น ' list' จะเงียบโดยปริยาย


โปรดทราบว่า " git worktree add" เคยทำ "ค้นหาชื่อที่มีสถานะเป็น stat แล้วmkdir" ซึ่งเป็นไปได้ยาก
สิ่งนี้ได้รับการแก้ไขด้วย Git 2.22 (Q2 2019) โดยการใช้mkdirและการตอบสนองEEXISTในการวนซ้ำ

ดูกระทำ 7af01f2 (20 กุมภาพันธ์ 2019) โดยคาล Suchanek (hramrach )
(ผสานโดยJunio ​​C Hamano - gitster-ในการกระทำ 20fe798 , 09 Apr 2019)

worktree: แก้ไขworktree addการแข่งขัน

Git ใช้การวนรอบสถิติเพื่อค้นหาชื่อ worktree ที่พร้อมใช้งานจากนั้นใช้mkdirกับชื่อที่พบ
เปลี่ยนเป็นmkdirวนซ้ำเพื่อหลีกเลี่ยงการเรียกใช้ worktree เพิ่มการค้นหาชื่อฟรีเดียวกันและสร้างไดเรกทอรีก่อน


Git 2.22 (Q2 2019) แก้ไขลอจิกเพื่อบอกว่าที่เก็บ Git มีแผนผังการทำงานปกป้อง " git branch -D" จากการลบสาขาที่เช็คเอาท์โดยไม่ได้ตั้งใจในขณะนี้
การดำเนินการตามตรรกะนี้ใช้งานไม่ได้กับที่เก็บที่มีชื่อผิดปกติ

ดูกระทำ f3534c9 (19 เมษายน 2019) โดยโจนาธานตาล (jhowtan )
(ผสานโดยJunio ​​C Hamano - gitster- in ec2642a , 08 พฤษภาคม 2019)

คำขอให้ดึงรหัส 178 ข้อมูลเชิงลึก

worktree: อัพเดตis_bareฮิวริสติก

เมื่อgit branch -D <name>เรียกใช้" " Git มักจะตรวจสอบก่อนว่าสาขานั้นเช็คเอาท์อยู่หรือไม่
แต่การตรวจสอบนี้จะไม่ดำเนินการหากไดเรกทอรี Git ของที่เก็บนั้นไม่อยู่ที่ " <repo>/.git" ซึ่งเป็นกรณีที่ที่เก็บนั้นเป็น submodule ที่มีไดเรกทอรี Git จัดเก็บเป็น " super/.git/modules/<repo>"
ซึ่งส่งผลให้สาขาถูกลบแม้ว่าจะเช็คเอาท์

นี่เป็นเพราะget_main_worktree()ในworktree.cชุดis_bareบน worktree ใช้ฮิวริสติกเท่านั้นที่ repo จะว่างถ้าเส้นทางของ worktree ไม่ได้ลงท้ายด้วย " /.git" และไม่เปลือยเปล่า รหัส
นี้is_bareถูกนำมาใช้ใน92718b7 (" worktree: เพิ่มรายละเอียดให้กับโครงสร้าง worktree", 2015-10-08, Git v2.7.0-rc0) ตามด้วยการpre-core.bareแก้ปัญหา

แพทช์นี้ทำ 2 สิ่ง:

  • สอนget_main_worktree()ให้ใช้is_bare_repository()แทนแนะนำใน7d1864c ("แนะนำ is_bare_repository () และตัวแปรการตั้งค่า core.bare", 2007-01-07, Git v1.5.0-rc1) และอัพเดทในe90fdc3 ("ทำความสะอาดการจัดการต้นไม้ทำงาน", 2007 -08-01, Git v1.5.3-rc4)
    วิธีนี้จะช่วยแก้git branch -D <name>ปัญหาที่อธิบายไว้ข้างต้น

อย่างไรก็ตาม ... หากที่เก็บมีcore.bare=1แต่gitคำสั่ง "" กำลังถูกเรียกใช้จากหนึ่งใน worktrees รองของมันis_bare_repository()ส่งกลับเท็จ (ซึ่งเป็นเรื่องปกติเนื่องจากมี worktree พร้อมใช้งาน)

และการรักษา worktree หลักเป็น non-bare เมื่อมันเปลือยทำให้เกิดปัญหา:

ตัวอย่างเช่นความล้มเหลวในการลบสาขาจาก worktree รองที่ถูกอ้างถึงโดย HEAD ของ worktree หลักแม้ว่า worktree หลักนั้นจะว่างเปล่า

เพื่อหลีกเลี่ยงปัญหานี้ให้ตรวจสอบcore.bareการตั้งค่าis_bareด้วย
หากcore.bare=1เชื่อถือและใช้is_bare_repository()อย่างอื่น


1
นี่คือสิ่งที่เจ๋งที่สุดที่พวกเขาสร้างขึ้นสิ่งที่ฉันกำลังมองหา ขอบคุณสำหรับสิ่งนั้น!

วิธีลบแผนผังการทำงานเท่านั้นและยังคงรักษาสาขาไว้
Randeep Singh

@DotnetRocks คุณสามารถลบแผนผังการทำงานใด ๆ (โฟลเดอร์ในเครื่องคอมพิวเตอร์ของคุณ): ที่จะไม่มีผลกับสาขา: repo หลัก. git จะยังคงรวมประวัติที่ได้ทำไว้ทั้งหมดกับสาขาทั้งหมดไม่ว่าจะเป็นหรือไม่ แผนผังการทำงานถูกลบไปแล้ว
VonC

ใช่ แต่ถ้าเพียงแค่ลบแผนผังการทำงานโดยไปที่โฟลเดอร์นั้นในระบบของฉันและลบแล้ว git ไม่ให้ฉันเช็คเอาต์ที่สาขานั้นและบอกว่าเช็คเอาต์แล้วที่ <path> (เส้นทางพา ธ worktree) แต่ดูเหมือนว่าถ้าฉันทำต่อไปนี้: rm -rf <path> git worktree พรุนแล้วมันทำงาน นั่นถูกต้องใช่ไหม ?
Randeep Singh เมื่อ

1
@Jayan ขอบคุณ ฉันทำให้ชัดเจนว่าตอนนี้ 2.5 และ 2.7 หมดแล้ว
VonC

113

gitกระจายมาพร้อมกับสคริปต์ที่มีส่วนgit-new-workdirที่เรียกว่า คุณจะใช้มันดังต่อไปนี้:

git-new-workdir project-dir new-workdir branch

โดย project-dir เป็นชื่อของไดเร็กทอรีที่มีที่.gitเก็บของคุณ สคริปต์นี้สร้าง.gitไดเรกทอรีอื่นที่มี symlink มากมายไปยังต้นฉบับยกเว้นไฟล์ที่ไม่สามารถแชร์ได้ (เช่นสาขาปัจจุบัน) ช่วยให้คุณทำงานในสองสาขาที่แตกต่างกัน

ฟังดูเปราะบาง แต่เป็นตัวเลือก


3
+1 ฉันยืนถูกต้องแล้วมันยอดเยี่ยมมาก ดูเหมือนว่าจะแบ่งปันประวัติและสาขาทันทีระหว่างที่เก็บข้อมูลที่เช็คเอาต์สองแห่งที่ต่างกันโดยไม่มีการผลัก / ดึงเพียงการเชื่อมโยงเท่านั้น ฉันไม่รู้เลยว่าคอมไพล์สามารถจัดการสิ่งนี้ได้ อนิจจามันไม่รวมอยู่ในการกระจายของฉัน
meagar

2
สำหรับผู้ที่ใช้ msysgit (Windows) คุณสามารถใช้รุ่นนี้รังเพลิงของสคริปต์: github.com/joero74/git-new-workdir
amos

9
โดยปกติแล้วจะใช้งานได้ดี แต่ถ้าคุณแก้ไขสาขาเดียวกันในสถานที่ต่างกันโดยไม่ตั้งใจคุณไม่จำเป็นต้องแก้ไขสิ่งต่าง ๆ อีก
grep

สำหรับผู้ที่ติด Git <2.5 และผู้ที่มี submodules ลองgit-new-workdir-recursiveใช้ตัวgit-new-workdirเลือก
Walf

13

ฉันเจอคำถามนี้โดยหวังว่าจะหาทางออกฉันไม่พบที่นี่ ดังนั้นตอนนี้ที่ฉันไม่พบสิ่งที่ฉันต้องการฉันตัดสินใจที่จะโพสต์ไว้ที่นี่สำหรับคนอื่น ๆ

Caveat: นี่อาจไม่ใช่วิธีที่ดีถ้าคุณต้องการแก้ไขหลายสาขาพร้อมกันเช่นสถานะ OP มีไว้สำหรับการตรวจสอบหลายสาขาพร้อมกันซึ่งคุณไม่ต้องการแก้ไข (ไดเรกทอรีทำงานหลายรายการสำรองข้อมูลโดยโฟลเดอร์. git เดียว)

มีบางสิ่งที่ฉันเรียนรู้ตั้งแต่ฉันมาที่คำถามนี้ในครั้งแรก:

  1. " คลังเก็บเปลือย " คืออะไร มันเป็นเนื้อหาของ.gitไดเรกทอรีโดยไม่ต้องอยู่ในแผนผังการทำงาน

  2. ความจริงที่ว่าคุณสามารถระบุตำแหน่งของ repo ที่คุณใช้ (ตำแหน่งของ.gitdir ของคุณ) บนบรรทัดคำสั่งพร้อมgitตัวเลือก--git-dir=

  3. ข้อเท็จจริงที่ว่าคุณสามารถระบุตำแหน่งของสำเนาการทำงานของคุณด้วย --work-tree=

  4. "repo กระจก" คืออะไร

สุดท้ายนี้เป็นข้อแตกต่างที่สำคัญทีเดียว จริง ๆ แล้วฉันไม่ต้องการทำงานกับ repo ฉันแค่ต้องมีสำเนาของสาขาที่แตกต่างกันและ / หรือตรวจสอบแท็กพร้อมกัน ในความเป็นจริงแล้วฉันต้องรับประกันว่าสาขาจะไม่แตกต่างจากสาขาของรีโมตของฉัน ดังนั้นกระจกจึงเหมาะสำหรับฉัน

ดังนั้นสำหรับกรณีการใช้งานของฉันฉันได้รับสิ่งที่ฉันต้องการด้วยการทำ:

git clone --mirror <remoteurl> <localgitdir> # Where localgitdir doesn't exist yet
mkdir firstcopy
mkdir secondcopy
git --git-dir=<localgitdir> --work-tree=firstcopy checkout -f branch1
git --git-dir=<localgitdir> --work-tree=secondcopy checkout -f branch2

ข้อแม้ขนาดใหญ่เกี่ยวกับเรื่องนี้ก็คือไม่มี HEAD แยกต่างหากสำหรับทั้งสองชุด ดังนั้นหลังจากข้างต้นการวิ่งgit --git-dir=<localgitdir> --work-tree=firstcopy statusจะแสดงความแตกต่างทั้งหมดจาก branch2 ถึง branch1 เป็นการเปลี่ยนแปลงที่ไม่มีข้อผูกมัด - เนื่องจาก HEAD ชี้ไปที่ branch2 (นั่นเป็นเหตุผลที่ฉันใช้-fตัวเลือกcheckoutเพราะฉันไม่ได้วางแผนที่จะทำการเปลี่ยนแปลงใด ๆ ในพื้นที่เลยฉันสามารถเช็คเอาต์แท็กหรือสาขาสำหรับต้นไม้ทำงานใด ๆ ตราบใดที่ฉันใช้-fตัวเลือก)

สำหรับกรณีการใช้งานของฉันที่มีเช็คเอาต์หลายรายการอยู่ร่วมกันบนคอมพิวเตอร์เครื่องเดียวกันโดยไม่จำเป็นต้องแก้ไขมันสิ่งนี้ได้ผลอย่างสมบูรณ์แบบ ฉันไม่รู้ว่ามีวิธีใดที่จะมี HEAD หลายอันสำหรับต้นไม้ทำงานหลายต้นที่ไม่มีสคริปต์เช่นนั้นจะครอบคลุมในคำตอบอื่น ๆ แต่ฉันหวังว่าสิ่งนี้จะเป็นประโยชน์กับคนอื่นอยู่ดี


นี่คือสิ่งที่ฉันกำลังมองหา แต่ฉันไม่สามารถไปทำงาน ... ฉันได้รับ "ร้ายแรง: ไม่ใช่ที่เก็บ git: '<localgitdir>'" ความคิดใด ๆ
Dan R

ไม่เป็นไรกลับกลายเป็นว่าฉันใช้ "~" ในชื่อไดเรกทอรีของฉันและคอมไพล์ไม่ชอบมัน เมื่อฉันใช้เส้นทางแบบเต็มมันก็ใช้ได้ดี
Dan R

@ DanR ดีใจที่ได้ช่วย :) $HOMEคุณอาจจะยังใช้ มีข้อแม้อื่นเกี่ยวกับวิธีการข้างต้นที่ฉันค้นพบในภายหลังซึ่งจะทำอย่างไรกับไฟล์ที่ไม่มีอยู่ในหนึ่งหรือสาขาอื่น หากคุณชำระเงิน A เป็น dir1 จากนั้นชำระเงิน B เป็น dir2 จากนั้นบังคับชำระเงิน C เป็น dir1 หากมีไฟล์ที่มีอยู่ใน A แต่ไม่ใช่ใน B หรือ C ไฟล์จะไม่ถูกลบออกจาก dir1 แม้โดยการบังคับชำระเงิน . ดังนั้นคุณอาจต้องทำการทดสอบgit cleanในกรณีเช่นนี้ - หรือทำสิ่งที่ฉันทำและใช้วิธีนี้เพื่อเติมไดเรกทอรีที่สร้างขึ้นใหม่เท่านั้น
Wildcard

ขอบคุณสำหรับทิป. ฉันกำลังจะห่อนี่เป็นส่วนหนึ่งของเครื่องมือ CLI เป็นทับทิมอยู่แล้วดังนั้นฉันจะทำให้แน่ใจว่ามันเริ่มต้นจากศูนย์เสมอ
Dan R

@DanR คุณอาจสนใจดูรหัสที่ฉันเขียนในขณะนั้น ส่วนใหญ่โดยทั่วไปจะใช้กับสคริปต์การจัดเตรียม git ใด ๆ ยกเว้นการตรวจสอบไวยากรณ์ CFEngine (บางทีคุณอาจแทนที่ด้วยการตรวจสอบไวยากรณ์ของ Ruby) :)
Wildcard

3

ทางออกเดียวที่ฉันคิดได้คือการโคลนสองไดเรกทอรีและเพิ่มเป็นที่เก็บระยะไกลของกันและกัน จากนั้นคุณสามารถดึงสิ่งต่าง ๆ จากสิ่งที่ถูกเปลี่ยนไปยังสิ่งอื่นได้โดยไม่ต้องผลักสิ่งใดไปยังที่เก็บระยะไกล

ฉันสมมติว่าคุณต้องการมีสองไดเรกทอรีการทำงานและไม่ใช่สองโคลนของรีโมทเพราะคุณไม่ต้องการที่จะผลักดันบางสาขาไปยังระยะไกล มิฉะนั้นโคลนสองอันของรีโมตของคุณจะทำงานได้ดี - คุณเพียงแค่ต้องทำการกดและดึงเพื่อให้ทั้งสามซิงก์


สวัสดี ผู้ชายข้างต้นแบ่งปันวิธีแก้ปัญหาที่ ยอดเยี่ยมคำสั่งgit worktree มันทำงานได้ดีกว่าโคลนหลายเท่าในที่เก็บเดียวกัน ลองคุณจะชอบคุณสมบัติใหม่นี้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.