Git - ความแตกต่างระหว่าง 'สันนิษฐานว่าไม่เปลี่ยนแปลง' และ 'skip-worktree'


450

ฉันมีการเปลี่ยนแปลงในท้องถิ่นเป็นไฟล์ที่ฉันไม่ต้องการส่งไปยังที่เก็บของฉัน เป็นไฟล์การกำหนดค่าสำหรับการสร้างแอปพลิเคชันบนเซิร์ฟเวอร์ แต่ฉันต้องการสร้างในเครื่องด้วยการตั้งค่าที่แตกต่างกัน โดยปกติไฟล์จะปรากฏขึ้นเสมอเมื่อฉัน 'สถานะ git' เป็นสิ่งที่จะจัดฉาก ฉันต้องการซ่อนการเปลี่ยนแปลงนี้โดยเฉพาะและไม่ยอมรับ ฉันจะไม่ทำการเปลี่ยนแปลงอื่น ๆ กับไฟล์

หลังจากขุดไปรอบ ๆ ฉันเห็น 2 ตัวเลือก: 'สันนิษฐานว่าไม่เปลี่ยนแปลง' และ 'skip-worktree' คำถามก่อนหน้านี้พูดถึงพวกเขาที่นี่แต่ไม่ได้อธิบายความแตกต่างของพวกเขา คำถามของฉันคือสิ่งนี้: สองคำสั่งต่างกันอย่างไร ทำไมบางคนจะใช้อย่างใดอย่างหนึ่ง


1
ฉันมักจะใช้.gitignoreเพื่อวัตถุประสงค์ที่คล้ายกัน โซลูชันนี้ใช้งานได้สำหรับคุณหรือไม่
samuil

45
samuil, .gitignore ละเว้นการเพิ่มไม่เปลี่ยนแปลง เมื่อไฟล์มีอยู่แล้วในคอมไพล์มันจะถูกติดตามเหตุการณ์หากมีการระบุไว้ใน. gitignore
Grigory

แต่ไม่มีใครลบทั้งหมดและเพิ่มทั้งหมดเพื่อ "รีเฟรช" อย่างที่อธิบายไว้ที่นี่? stackoverflow.com/questions/7075923/… @Grigory
Daniel Springer

2
ไม่ควรละเว้นไฟล์ถ้าฉันได้รับความตั้งใจของ OP อย่างถูกต้อง ไฟล์จะต้องอยู่ในที่เก็บ แต่การเปลี่ยนแปลงที่เฉพาะเจาะจงอย่างยิ่งเหล่านี้ที่เขาทำไม่ควรกระทำ - อย่างน้อยตอนนี้
Simone

คำตอบ:


666

skip-worktreeคุณต้องการ

assume-unchangedได้รับการออกแบบมาสำหรับกรณีที่มีราคาแพงในการตรวจสอบว่ามีการแก้ไขกลุ่มไฟล์หรือไม่ เมื่อคุณตั้งค่าบิตgit(แน่นอน) ถือว่าไฟล์ที่สอดคล้องกับส่วนของดัชนีนั้นยังไม่ได้รับการแก้ไขในสำเนาการทำงาน ดังนั้นจึงหลีกเลี่ยงการstatโทรยุ่ง บิตนี้จะหายไปเมื่อใดก็ตามที่รายการของไฟล์ในดัชนีมีการเปลี่ยนแปลง (ดังนั้นเมื่อไฟล์มีการเปลี่ยนแปลง upstream)

skip-worktreeเป็นมากกว่านั้น: แม้ในกรณีที่git รู้ว่าไฟล์นั้นได้รับการแก้ไข (หรือจำเป็นต้องได้รับการแก้ไขโดย a reset --hardหรือคล้าย) ก็จะแกล้งทำเป็นว่ามันไม่ได้รับการใช้รุ่นจากดัชนีแทน สิ่งนี้จะคงอยู่จนกระทั่งดัชนีถูกยกเลิก

มีบทสรุปที่ดีของเครือข่ายของความแตกต่างนี้และกรณีการใช้งานโดยทั่วไปอยู่ที่นี่: http://fallengamer.livejournal.com/93321.html

จากบทความนั้น:

  • --assume-unchangedสมมติว่านักพัฒนาไม่ควรเปลี่ยนไฟล์ การตั้งค่าสถานะนี้มีไว้สำหรับปรับปรุงประสิทธิภาพสำหรับโฟลเดอร์ที่ไม่เปลี่ยนแปลงเช่น SDK
  • --skip-worktreeมีประโยชน์เมื่อคุณสั่งให้คอมไพล์ไม่ต้องแตะไฟล์ใดไฟล์หนึ่งเลยทีเดียวเพราะนักพัฒนาควรเปลี่ยนมัน ตัวอย่างเช่นถ้าที่เก็บหลักอัปสตรีมโฮสต์ไฟล์กำหนดค่าที่พร้อมใช้งานบางไฟล์และคุณไม่ต้องการที่จะยอมรับการเปลี่ยนแปลงไฟล์เหล่านั้นโดยบังเอิญ--skip-worktreeเป็นสิ่งที่คุณต้องการ

3
นั่นทำให้รู้สึก skip-worktree ดูเหมือนจะเป็นทางไป ขอบคุณ!
ckb

100
บันทึกย่อขนาดเล็กเพื่อประหยัดเวลาในการค้นหาและอ่าน หากต้องการยกเลิกเอ--skip-worktreeฟเฟกต์และยกเลิกการตั้งค่าสถานะมี--no-skip-worktreeตัวเลือก ทำงานในลักษณะเดียวกัน สิ่งนี้มีประโยชน์ในกรณีที่มือมีการลื่นและไฟล์ผิดมีการตั้งค่าสถานะหรือหากสถานการณ์มีการเปลี่ยนแปลงและไฟล์ที่ข้ามไปก่อนหน้านี้ไม่ควรถูกละเว้นอีกต่อไป
drdaeman

18
เพื่อตอบคำถามของฉันเองความแตกต่างระหว่างการใช้งาน--skip-worktreeและ.git/info/excludeไฟล์คือไฟล์เก่าจะใช้ได้แม้กับไฟล์ที่ถูกติดตามอยู่ .git/info/excludeเช่น.gitignoreจะป้องกันการเพิ่มไฟล์ที่ไม่ได้ติดตามในดัชนีโดยไม่ตั้งใจ แต่จะไม่ทำการเปลี่ยนแปลงไฟล์ที่ถูกติดตามอยู่แล้ว
LinusR

13
สามารถผลักไปที่รีโมทและเก็บรักษาไว้โดยโคลนทั้งหมดหรือไม่
CMCDragonkai

4
เพียงแค่การใช้งานแหม่ม:git update-index --skip-worktree <file_name>
ruffin

108

หมายเหตุ: fallengamerทำการทดสอบบางอย่างในปี 2011 (ดังนั้นอาจล้าสมัย) และนี่คือข้อค้นพบของเขา:

การดำเนินงาน

  • ไฟล์มีการเปลี่ยนแปลงทั้งในที่เก็บในเครื่องและอัป สตรีม
    git pull:
    Git รักษาการเปลี่ยนแปลงในเครื่องไว้
    ดังนั้นคุณจะไม่สูญเสียข้อมูลใด ๆ ที่คุณทำเครื่องหมายด้วยค่าสถานะใด ๆ โดยไม่ตั้งใจ
    • ไฟล์ที่มีassume-unchangedธง: Git จะไม่เขียนทับไฟล์ในเครื่อง แต่จะส่งผลให้เกิดข้อขัดแย้งและให้คำแนะนำวิธีแก้ไข
    • ไฟล์ที่มีskip-worktreeธง: Git จะไม่เขียนทับไฟล์ในเครื่อง แต่จะส่งผลให้เกิดข้อขัดแย้งและให้คำแนะนำวิธีแก้ไข

  • ไฟล์มีการเปลี่ยนแปลงทั้งในที่เก็บในเครื่องและอัปสตรีมพยายามดึงต่อไป การใช้ผลลัพธ์ในการทำงานพิเศษบางอย่าง แต่อย่างน้อยคุณจะไม่สูญเสียข้อมูลใด ๆ หากคุณมีการเปลี่ยนแปลงในเครื่อง
    git stash
    git pull
    skip-worktree
    • ไฟล์ที่มีการassume-unchangedตั้งค่าสถานะ: ยกเลิกการเปลี่ยนแปลงในเครื่องทั้งหมดโดยไม่สามารถเรียกคืนได้ ผลที่ได้คือ ' git reset --hard' การgit pullโทรจะสำเร็จ
    • ไฟล์ที่มีskip-worktreeธง: Stash จะไม่ทำงานกับskip-worktreeไฟล์ ' git pull' จะล้มเหลวโดยมีข้อผิดพลาดเหมือนด้านบน นักพัฒนาถูกบังคับให้ตั้งค่าskip-worktreeสถานะใหม่ด้วยตนเองเพื่อให้สามารถสะสมและทำตามความล้มเหลวpullได้

  • ไม่มีการเปลี่ยนแปลงในเครื่องอัปโหลดไฟล์อัปสตรีม ทั้งสองแฟล็กจะไม่ป้องกันคุณจากการเปลี่ยนแปลงอัปสตรีม Git ตรวจพบว่าคุณผิดสัญญาและเลือกที่จะสะท้อนความเป็นจริงโดยการตั้งค่าสถานะใหม่
    git pull
    assume-unchanged
    • ไฟล์ที่มีการassume-unchangedตั้งค่าสถานะ: เนื้อหาถูกอัปเดตหายไป
      ' git ls-files -v' จะแสดงว่ามีการปรับเปลี่ยนสถานะเป็นH(จากh)
    • ไฟล์ที่มีการskip-worktreeตั้งค่าสถานะ: เนื้อหาได้รับการปรับปรุงการตั้งค่าสถานะจะถูกเก็บไว้
      ' git ls-files -v' จะแสดงเดียวกันธงเป็นก่อนSpull

  • ด้วยการเปลี่ยนแปลงไฟล์ในท้องถิ่น Git ไม่ได้สัมผัสไฟล์และสะท้อนความเป็นจริง (ไฟล์ที่สัญญาว่าจะไม่เปลี่ยนแปลงจริง ๆ แล้วเปลี่ยน) สำหรับไฟล์
    git reset --hard
    skip-worktreeassume-unchanged
    • ไฟล์ที่มีการassume-unchangedตั้งค่าสถานะ: เนื้อหาไฟล์ถูกเปลี่ยนกลับ ตั้งค่าสถานะเป็นH(จากh)
    • ไฟล์ที่มีการskip-worktreeตั้งค่าสถานะ: เนื้อหาไฟล์ยังคงอยู่ ธงยังคงเหมือนเดิม

เขาเพิ่มการวิเคราะห์ต่อไปนี้:

  • ดูเหมือนว่าskip-worktreeจะพยายามอย่างหนักเพื่อรักษาข้อมูลท้องถิ่นของคุณ แต่ก็ไม่ได้ป้องกันไม่ให้คุณทำการเปลี่ยนแปลงต้นน้ำหากปลอดภัย pullพลัสคอมไพล์ไม่รีเซ็ตธงบน
    แต่การเพิกเฉยreset --hardคำสั่ง '' อาจกลายเป็นเรื่องน่าประหลาดใจสำหรับนักพัฒนา

  • Assume-unchangedการตั้งค่าสถานะอาจสูญหายในการpullดำเนินการและการเปลี่ยนแปลงภายในไฟล์ดังกล่าวดูเหมือนจะไม่สำคัญต่อคอมไพล์

ดู:

เขาสรุป:

อันที่จริงค่าของธงจะง่ายพอ

  • assume-unchangedสมมติว่านักพัฒนาไม่ควรเปลี่ยนไฟล์ หากไฟล์มีการเปลี่ยนแปลง - แล้วการเปลี่ยนแปลงนั้นไม่สำคัญ การตั้งค่าสถานะนี้มีไว้สำหรับปรับปรุงประสิทธิภาพสำหรับโฟลเดอร์ที่ไม่เปลี่ยนแปลงเช่น SDK
    แต่ถ้าสัญญาแตกและไฟล์ถูกเปลี่ยนจริง git จะเปลี่ยนสถานะเพื่อสะท้อนความเป็นจริง อาจเป็นเรื่องปกติที่จะมีการตั้งค่าสถานะที่ไม่สอดคล้องกันบางอย่างในโฟลเดอร์ที่ไม่ได้ตั้งใจจะเปลี่ยน

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


ด้วย Git 2.25.1 (ก.พ. 2020) "จริง ๆ แล้วทั้งธงไม่ง่ายพอ" ดังกล่าวข้างต้นมีการชี้แจงเพิ่มเติม:

ดูคอมมิชชัน 7a2dc95 , ยอมรับ 1b13e90 (22 ม.ค. 2020) โดยbrian m คาร์ลสัน (bk2204 )
(ผสานโดยJunio ​​C Hamano - gitster- in 53a8329 , 30 Jan 2020)
( รายชื่อผู้รับจดหมาย Git )

doc: ห้ามผู้ใช้พยายามละเว้นไฟล์ที่ถูกติดตาม

ลงชื่อออกโดย: Jeff King
ลงชื่อออกโดย: brian m คาร์ลสัน

เป็นเรื่องปกติที่ผู้ใช้จะต้องการเพิกเฉยต่อการเปลี่ยนแปลงของไฟล์ที่ Git ติดตาม

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

อย่างไรก็ตามผู้ใช้เรียนรู้เกี่ยวกับบิตที่ไม่เปลี่ยนแปลงและข้ามบิต worktree และพยายามที่จะใช้พวกเขาในการทำเช่นนี้ต่อไป

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

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

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

นอกจากนี้เราขอเสนอวิธีแก้ปัญหาที่แนะนำเพื่อจัดการกับกรณีทั่วไปของไฟล์การกำหนดค่าเนื่องจากมีวิธีการที่รู้จักกันดีที่ใช้ในสภาพแวดล้อมที่ประสบความสำเร็จมากมาย

git update-indexหน้าคนในขณะนี้รวมถึง:

ผู้ใช้มักจะพยายามใช้assume-unchangedและskip-worktreeบิตเพื่อบอก Git ให้ละเว้นการเปลี่ยนแปลงไฟล์ที่ถูกติดตาม สิ่งนี้ไม่ทำงานตามที่คาดไว้เนื่องจาก Git อาจยังตรวจสอบไฟล์แผนผังการทำงานกับดัชนีเมื่อดำเนินการบางอย่าง โดยทั่วไป Git ไม่ได้ให้วิธีในการละเว้นการเปลี่ยนแปลงในไฟล์ที่ถูกติดตามดังนั้นจึงแนะนำให้ใช้วิธีอื่น

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

ที่ส่วนสุดท้ายคือสิ่งที่ผมอธิบายทั่วไปควบคุมตัวกรองเนื้อหาตามรอยเปื้อนสคริปต์ / ทำความสะอาด


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

3
ใช่ฉันสามารถยืนยันได้ว่าคุณทำ หมายความว่ามันยังคงเป็นเรื่องยากมากที่จะมีไฟล์ในตัวเครื่องที่คุณต้องการให้แตกต่างไปจากต้นฉบับ
GreenAsJade

1
@GreenAs อาจจะดูเก่ากว่า โอกาสใดที่คุณสามารถทดสอบด้วย 2.2.x?
VonC

1
@VonC ลิงก์ไปยัง "ความคิดเห็นของ Junio" ไม่ได้อยู่ในประวัติการแก้ไข คือนี้สิ่งที่คุณกำลังหมายถึง?
ไมเคิล - Clay Shirky อยู่ที่ไหน

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