git push --force-with-lease vs. --force


182

ฉันพยายามเข้าใจความแตกต่างระหว่าง

git push --force

และ

git push --force-with-lease

ฉันเดาว่าดันเพียงหลังระยะไกลถ้าระยะไกลไม่ได้มีการกระทำที่สาขาในประเทศไม่ได้มี ?


" สาขาการติดตามระยะไกลท้องถิ่น" โดยทั่วไปหมายถึงรีโมตจะต้องมีลักษณะเหมือนที่ลูกค้าของคุณคาดหวัง git help pushมีกรณีใช้อธิบายวัตถุประสงค์ (โดยทั่วไปเพื่อป้องกันไม่ให้คุณทิ้งการเปลี่ยนแปลงที่เกิดขึ้นกับใครบางคนที่เพิ่งผลัก) สิ่งที่ชัดเจนสำหรับฉันคือการทำงานของสาขาการติดตามระยะไกล แต่โดยทั่วไปน่าจะเป็นไปได้ที่จะต้องดูว่ามันดูครั้งสุดท้ายที่คุณทำfetchหรือpullไม่มีความมุ่งมั่นใหม่
zzxyz

4
@zzxyz: การใช้งานจริง--force-with-leaseนั้นคล้ายกับคำแนะนำในการเปรียบเทียบและสลับบนซีพียูสมัยใหม่: ผู้ที่ต้องการให้การแลกเปลี่ยนเกิดขึ้นจะให้ค่าที่คาดหวังและค่าใหม่ ระบบที่ทำการแลกเปลี่ยนจะเปรียบเทียบค่าที่คาดหวังกับมูลค่าปัจจุบันที่แท้จริงและทำการแลกเปลี่ยนหากทั้งสองเท่ากัน ด้วยgit pushค่าที่คาดหวังคือสิ่งที่อยู่ในชื่อการติดตามระยะไกลเช่นgit push --force-with-lease origin Xส่งของคุณเองorigin/Xพร้อมกับค่าที่ต้องการใหม่ originGit บอกคุณหรือไม่ว่ามันเป็นการแลกเปลี่ยนหรือไม่
torek

1
หาก Git originทำการแลกเปลี่ยนคุณก็เสร็จเรียบร้อย ถ้าไม่ได้คุณสามารถเรียกใช้git fetch originที่จะรับใหม่ค่าปัจจุบันปรับปรุงเปลี่ยนแปลงของคุณถ้าจำเป็นและเรียกใช้อีกแรงที่มีสัญญาเช่าเปรียบเทียบและแลกเปลี่ยนเพื่อลองอีกครั้ง
torek

คำตอบ:


172

force เขียนทับสาขาระยะไกลด้วยสาขาท้องถิ่นของคุณ

--force-with-leaseเป็นตัวเลือกที่ปลอดภัยกว่าที่จะไม่เขียนทับงานใด ๆ ในสาขาระยะไกลหากมีการเพิ่มการผูกพันในสาขาระยะไกล (โดยสมาชิกในทีมหรือเพื่อนร่วมงานคนอื่นหรือสิ่งที่คุณมี) เป็นการรับรองว่าคุณจะไม่เขียนทับคนอื่นโดยใช้แรงผลักดัน

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

ฉันคิดว่า--force-with-leaseเป็นตัวเลือกที่จะใช้เมื่อฉันต้องการให้แน่ใจว่าฉันไม่ได้เขียนทับรหัสเพื่อนร่วมทีม หลายทีมใน บริษัท ของฉันใช้--force-with-leaseเป็นตัวเลือกเริ่มต้นสำหรับการไม่ปลอดภัย มันไม่จำเป็นในสถานการณ์ส่วนใหญ่ แต่จะช่วยให้คุณปวดหัวมากถ้าคุณเขียนทับสิ่งที่คนอื่นมีส่วนทำให้ระยะไกล

ฉันแน่ใจว่าคุณดูที่เอกสาร แต่อาจมีคำอธิบายเพิ่มเติมที่ชัดเจนอยู่ในที่นี้:

https://git-scm.com/docs/git-push


38

กำลังมองหาคำตอบจากแหล่งข้อมูลที่น่าเชื่อถือและ / หรือเป็นทางการ

"เปรียบเทียบและสลับ" กล่าวโดยtorekในการแสดงความคิดเห็นและคำตอบอื่น ๆ ของเขาจะแสดงต่อไปโดยแหล่งที่มาของ Git ตัวเอง

ส่วนหลังจะส่งสัญญาณไปที่รีโมตเท่านั้นหากรีโมตไม่ยอมรับว่าสาขาโลคัลไม่มี?

คุณลักษณะดังกล่าวได้รับการแนะนำในการกระทำนี้ (ธันวาคม 2013, Git v1.8.5-rc0)

--force-with-lease จะปกป้องการอ้างอิงระยะไกลทั้งหมดที่จะได้รับการอัปเดตโดยกำหนดให้ค่าปัจจุบันของพวกเขาเป็นค่าเริ่มต้นที่เหมาะสมยกเว้นว่าจะระบุไว้เป็นอย่างอื่น

สำหรับตอนนี้ "ค่าเริ่มต้นที่สมเหตุสมผล" ถูกกำหนดอย่างไม่แน่นอนว่าเป็น " ค่าของสาขาการติดตามระยะไกลที่เรามีสำหรับการอ้างอิงของการอัปเดตระยะไกล " และเป็นข้อผิดพลาดหากเราไม่มีสาขาการติดตามระยะไกลดังกล่าว

ดังนั้น "เช่า" หมายถึง:

"force-with-lease ": คุณคิดว่าคุณได้ทำการเช่าซื้อในการอ้างอิงเมื่อคุณได้รับข้อมูลเพื่อตัดสินว่าประวัติที่ถูกปฏิเสธควรเป็นอย่างไรและคุณสามารถผลักดันกลับได้ก็ต่อเมื่อสัญญาเช่านั้นไม่เสียหาย

แหล่งข้อมูลยังกล่าวถึง "cas":

  • ตัวเลือกนี้เดิมเรียกว่า " cas" (สำหรับ "การเปรียบเทียบและการสลับ") ชื่อที่ไม่มีใครชอบเพราะเป็นเทคนิคเกินไป
  • ความพยายามครั้งที่สองเรียกมันว่า "lockref" (เพราะมันเป็นแนวคิดที่ชอบผลักหลังจากล็อคแล้ว) แต่คำว่า "ล็อค" ถูกเกลียดเพราะมันบอกเป็นนัยว่ามันอาจปฏิเสธการผลักจากคนอื่นซึ่งไม่ใช่วิธีที่ตัวเลือกนี้ทำงาน
  • รอบนี้เรียกมันว่า "การบังคับให้เช่า"
    คุณถือว่าคุณเช่าซื้อในการอ้างอิงเมื่อคุณดึงข้อมูลเพื่อตัดสินใจว่าประวัติที่ถูกปฏิเสธควรเป็นอย่างไรและคุณสามารถกดกลับได้ก็ต่อเมื่อสัญญาเช่านั้นไม่ได้ถูกทำลาย

ดังนั้น: " git push --force-with-leasevs. --force"

ในฐานะที่ผมกล่าวถึงใน " push --force-with-leaseไปโดยปริยาย " เช่น Git 2.13 (Q2 2017) กล่าวว่าตัวเลือกที่--force-with-leaseสามารถละเว้นถ้ากระบวนการพื้นหลัง (เช่นคนที่คุณพบใน IDE กับปลั๊กอิน Git) git fetch originวิ่ง
ในกรณีนั้น--forceจะมีชัย


29

git push --forceเป็นสิ่งที่ทำลายล้างเพราะมันจะเขียนทับ repository ระยะไกลโดยไม่มีเงื่อนไข git's push --forceถูกกีดกันอย่างรุนแรงเนื่องจากสามารถทำลายคอมมิชชันอื่นที่ถูกพุชไปยังที่เก็บที่แบ่งใช้แล้ว หนึ่งในสาเหตุที่พบบ่อยที่สุดของแรงผลักคือเมื่อเราถูกบังคับให้รีบูทสาขา

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

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

นี่คือโพสต์ที่ดีเกี่ยวกับการกด git - การบังคับและ git push - การบังคับกับการเช่า


2
สิ่งที่ฉันไม่เข้าใจ - ถ้าคุณ rebase กับอาจารย์แล้วคุณควรจะสามารถผลักดันโดยไม่ต้อง --force-with-lease ? ทำไมจึง--force-with-leaseจำเป็นต้องทำการรีบูตเครื่องกับอาจารย์?
Alexander Mills

3
@AlexanderMills อาจมีความเป็นไปได้ที่ทำให้เกิดปัญหา หากคุณเป็นคนสุดท้ายที่ผลักดันสิ่งนี้ให้เป็นผู้เชี่ยวชาญแล้วไม่มีปัญหา แต่มีอีกคนที่ทำงานกับงานอื่นมันอาจทำให้เกิดปัญหาร้ายแรง พูดในตอนแรก A - B - C เป็นอาจารย์ในตอนแรกอลิซทำให้มันเป็น A - B - C - D - E และในเวลาเดียวกันบ๊อบทำให้มัน A - B - C - F - G ถ้าอลิซเป็นคนสุดท้ายที่ผลัก ในระดับมาสเตอร์หลังจากรีบูต A - B - C - D - E - F - G จะไม่ทำให้เกิดปัญหาใด ๆ แต่คนอื่นทอมพยายามที่จะผลักดัน A - B - C - D - E - R ในเวลาเดียวกันในภัยพิบัติต้นแบบจะเกิดขึ้น !! !
Shakil

3
--forceไม่สูญเสียความมุ่งมั่นมันเป็นเพียงแค่แยกพวกเขา พวกเขาสามารถฟื้นคืนชีพโดยแฮชของพวกเขาในgit checkout <SHA>หรือgit reset --hard <SHA>สมมติว่าผู้ดูแลของ repo ระยะไกลไม่ได้ทำ GC หรือการดำเนินการตัดแต่งกิ่ง
Keith Russell

1
"แรงผลักดันของคอมไพล์ - ลดทอนแรงอย่างมากเนื่องจากมันสามารถทำลายคอมมิชชันอื่น ๆ ที่ถูกผลักไปยังพื้นที่เก็บข้อมูลที่ใช้ร่วมกันแล้ว" ข้อความนี้มีพื้นฐานจากความเห็นอย่างยิ่ง การกดปุ่มบังคับนั้นเป็นส่วนหนึ่งของขั้นตอนการตรวจสอบโค้ดรีคอมไพล์ปกติ เช่นเดียวกับที่กล่าวถึงแล้วคุณสามารถเรียกคืนคอมมิทแม้หลังจากทำเช่นนี้
Étienne

9

สมมติว่า hooks รับล่วงหน้าบนเซิร์ฟเวอร์ยอมรับการพุชนี่จะประสบความสำเร็จเสมอ:

git push --force

โดยที่สิ่งนี้เรียกใช้การตรวจสอบฝั่งไคลเอ็นต์เฉพาะก่อนดำเนินการต่อ:

git push --force-with-lease

คุณสามารถเรียกใช้การตรวจสอบเฉพาะด้วยตนเองได้ นี่คืออัลกอริทึม "การตรวจสอบการเช่าซื้อ":

  1. กำหนดสาขาปัจจุบันของคุณ

  2. git for-each-ref refs/remotesวิ่ง จดบันทึกรหัสคอมมิชชันที่ลูกค้าของคุณคิดว่าสอดคล้องกับสถานะต้นน้ำของสาขาปัจจุบันของคุณ

เช่นหากคุณอยู่ในสาขา "foo" ให้จดบันทึกรหัสประจำตัวที่เชื่อมโยงกับ "refs / remotes / origin / foo"

  1. กำหนด commit-id จริงของ remote branch บนเซิร์ฟเวอร์ upstream git ทันที

  2. ให้ "git push" เท่านั้นดำเนินการต่อหากรหัสการยืนยันที่คุณคลายจากขั้นตอนที่ 2 และขั้นตอนที่ 3 ยอมรับ กล่าวอีกนัยหนึ่งให้ดำเนินการต่อหากแนวคิดของ git clone ของคุณเกี่ยวกับ upstream เห็นด้วยกับ upstream จริง

มีความหมายที่น่าเศร้าที่นี่: เนื่องจากgit fetchอัปเดตการอ้างอิงทั้งหมดภายใต้ "refs / remotes / origin / *" เป็นเวอร์ชันล่าสุดของพวกเขาชุดคำสั่งนี้จึงเหมือนกับgit push --force:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

เพื่อหลีกเลี่ยงความอ่อนแอโดยธรรมชาตินี้ฉันพยายามที่จะไม่ทำงานgit push --force-with-lease git fetchแต่ฉันมักจะเรียกใช้git pull --rebaseทุกครั้งที่ฉันต้องการซิงค์กับอัปสตรีมเนื่องจากgit pullอัปเดตการอ้างอิงเดียวภายใต้การอ้างอิง / รีโมทโดยเก็บ "การเช่า" ที่--force-with-leaseเป็นประโยชน์


1
ถ้าการตรวจสอบเป็นฝั่งไคลเอ็นต์มีความเป็นไปได้สำหรับสภาพการแข่งขันหรือไม่? คือมีคนอื่นผลักดันการเปลี่ยนแปลงหลังจากเช็ค แต่ก่อนที่จะถูกบังคับ
craq

2

การบังคับให้เช่าไม่จำเป็นต้องปลอดภัย มันใช้งานได้ตามที่ Sylvie พูด One note: ในคอมไพล์สาขาเป็นเพียงตัวชี้การกระทำ และกระทำการชี้ไปที่ศูนย์หรือมากกว่าผู้ปกครองกระทำ แม้ว่าคุณจะเปลี่ยนสาขาทั้งหมดด้วยการรีเซ็ต git อย่างหนักและการกดแบบบังคับหรือการกดด้วย - - การบังคับด้วยการเช่าโดยไม่ต้องการมันไม่จำเป็นต้องเป็นปัญหาใหญ่ คุณสามารถใช้ refit คอมไพล์ท้องถิ่นของคุณเพื่อดูว่าเคล็ดลับท้องถิ่นของคุณในสาขา (หัวอยู่ที่ไหนในเวลานั้น?) มีการเปลี่ยนแปลงและรีเซ็ตและผลักดันสาขาอีกครั้ง จากนั้นคุณจะสูญเสียคอมมิชชันใหม่ในสาขาระยะไกล แต่ถึงแม้ว่าสมาชิกในทีมอาจได้รับการกู้คืน

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