ฉันจะบังคับให้กด Git ได้อย่างถูกต้องได้อย่างไร?


1273

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

ตอนนี้ฉันต้องเปลี่ยนอะไรบางอย่างใน repo ระยะไกล จากนั้นฉันเปลี่ยนบางสิ่งบางอย่างใน repo ท้องถิ่นของฉัน ฉันรู้ว่าไม่จำเป็นต้องเปลี่ยนรีโมตรีโมต ดังนั้นฉันจึงพยายามgit pushจาก repo ท้องถิ่นของฉันไปยัง repo ระยะไกลของฉัน แต่ฉันได้รับข้อผิดพลาดเช่น:

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

ฉันคิดว่าอาจจะเป็น

git push --force

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

ดังที่ฉันได้กล่าวถึงในความคิดเห็นกับหนึ่งในคำตอบ :

[I] พยายามบังคับใช้ แต่เมื่อกลับไปที่เซิร์ฟเวอร์หลักเพื่อบันทึกการเปลี่ยนแปลงฉันจะเลิกแสดงละครที่ล้าสมัย ดังนั้นเมื่อฉันยอมรับที่เก็บไม่เหมือนกัน และเมื่อฉันพยายามใช้ git push อีกครั้งฉันได้รับข้อผิดพลาดเดียวกัน

ฉันจะแก้ไขปัญหานี้ได้อย่างไร


4
คุณจะเร็ว ๆ นี้ (git1.8.5, Q4 2013) จะสามารถที่จะทำgit push -forceอย่างระมัดระวังมากขึ้น
VonC

1
ที่เกี่ยวข้อง: กองทัพ git เขียนทับไฟล์ระยะไกลในการผลักดัน

6
ขณะที่ผมรายละเอียดในคำตอบของตัวเอง , git push --forceเป็นที่แน่นอนอีกวิธีที่ถูกต้องในการผลักดันแรงและจะผลักดันสาขาเพียงเช่นเดียวกับgit push origin master --forceที่มีการเริ่มต้น Git ของpush.default config settingsแต่ที่สาขาเฉพาะได้รับการผลักดันให้มีความแตกต่างระหว่างรุ่น Git ก่อน 2.0 เมื่อเทียบกับหลัง 2.0

2
git push --forceทำงานได้ดีวันนี้ FWIW ...
rogerdpack

git push --force-with-leaseทำงานได้ดียิ่งขึ้น :) มันจะปฏิเสธที่จะอัปเดตสาขาจนกว่าจะเป็นสถานะที่คุณคาดหวัง (ดูdeveloper.atlassian.com/blog/2015/04/force-with-
Please

คำตอบ:


2307

แค่ทำ:

git push origin <your_branch_name> --force

หรือถ้าคุณมี repo เฉพาะ:

git push https://git.... --force

การดำเนินการนี้จะลบการกระทำก่อนหน้าของคุณและผลักดันรายการปัจจุบันของคุณ

มันอาจไม่เหมาะสม แต่ถ้าใครมาสะดุดหน้านี้คิดว่าพวกเขาอาจต้องการทางออกที่ง่าย ...

ธงสั้น

ยังทราบว่า-fสั้นสำหรับ--forceดังนั้น

git push origin <your_branch_name> -f

ยังจะทำงาน


58
คุณสามารถใช้git push origin +masterแทนซึ่งจะช่วยให้คุณสามารถผลักดันการอ้างอิงหลายรายการโดยไม่บังคับให้พวกเขาทั้งหมด
nickgrim

5
โปรดระวังว่าหากคุณทำโดยไม่ตั้งใจgit push --forceคุณอาจจะยุ่งกับสาขาหลัก (ขึ้นอยู่กับพฤติกรรมการกดเริ่มต้นของคุณ) .. ซึ่งอาจดูด .. .. บิต: D
Jeewes

9
@Jeewes เริ่มต้นด้วย Git รุ่น 2.0 ที่เริ่มต้นการทำงานของนั้นเป็นแรงผลักดันการตรวจสอบออกในขณะนี้สาขาที่ห่างไกลที่เคาน์เตอร์ของดังนั้นหากคุณมีสาขาต้นแบบการตรวจสอบออกมาแล้วมันเหมือนกันกับgit push --force git push origin master --forceมันจะแตกต่างกันหากคุณใช้การmatchingตั้งค่าpush.defaultซึ่งเป็นค่าเริ่มต้นสำหรับเวอร์ชัน Git ก่อนหน้า 2.0 matchingผลักดันให้คนในพื้นที่ทุกสาขาไปยังที่อยู่ไกล ๆ ที่มีชื่อเดียวกันดังนั้นการบังคับให้ทำอย่างนั้นอาจไม่ใช่สิ่งที่คุณต้องการทำ ...

@Jeewes แต่ด้วย Git 2.0 ค่าเริ่มต้นนั้นปลอดภัยกว่าหรืออย่างน้อยก็ไม่เป็นอันตรายมากกว่าที่git push origin master --forceเป็นอยู่

2
พุช -f นั้นดี แต่ไม่ได้เรียกคืนสำหรับต้นแบบเนื่องจากที่เก็บข้อมูลองค์กรส่วนใหญ่ปิดใช้งาน -f สำหรับต้นแบบ merge -s oursทำงานสำหรับฉัน
หมดเวลา

247

และถ้าไม่ได้ทำงานที่คุณสามารถทำได้push --force push --deleteดูที่ 2 ครั้งที่บรรทัดในกรณีนี้:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

แต่ระวัง ...

ไม่เคยย้อนกลับไปในประวัติศาสตร์คอมไพล์สาธารณะ!

ในคำอื่น ๆ :

  • อย่าforceผลักดันที่เก็บข้อมูลสาธารณะ
  • อย่าทำสิ่งนี้หรือสิ่งใดก็ตามที่อาจทำลายความpullรู้สึก
  • ไม่เคยresetหรือrewriteประวัติในrepoใครบางคนอาจได้ดึงแล้ว

แน่นอนว่ามีข้อยกเว้นที่หายากเป็นพิเศษแม้แต่ในกฎนี้ แต่ในกรณีส่วนใหญ่ไม่จำเป็นต้องทำและจะสร้างปัญหาให้กับคนอื่น

ทำการย้อนกลับแทน

และมักจะต้องระมัดระวังกับสิ่งที่คุณผลักดันไปสู่การซื้อคืนภาคประชาชน ย้อนกลับ:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

ในความเป็นจริงทั้งต้นกำเนิด HEADs (จากการย้อนกลับและจากการรีเซ็ตชั่วร้าย ) จะมีไฟล์เดียวกัน


แก้ไขเพื่อเพิ่มข้อมูลที่อัปเดตและข้อโต้แย้งอื่น ๆ push --force

ลองผลักดันด้วยการเช่าแทนที่จะกด แต่ก็ยังชอบการถอยกลับ

ปัญหาอื่นที่push --forceอาจเกิดขึ้นคือเมื่อมีคนผลักสิ่งใดก่อนที่คุณจะทำ แต่หลังจากคุณได้ทำการดึงข้อมูลมาแล้ว ถ้าคุณผลักดันบังคับให้คุณปรับฐานรุ่นนี้คุณจะเปลี่ยนการทำงานจากคนอื่น ๆ

git push --force-with-leaseแนะนำในgit 1.8.5 ( ขอบคุณ @VonCความคิดเห็นเกี่ยวกับคำถาม) พยายามแก้ไขปัญหาเฉพาะนี้ โดยพื้นฐานแล้วจะทำให้เกิดข้อผิดพลาดและไม่ส่งข้อมูลหากรีโมตถูกแก้ไขตั้งแต่การดึงข้อมูลล่าสุดของคุณ

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

และเนื่องจากเรากำลังพูดถึงgit --pushอินสแตนซ์ ...

ทำไมทุกคนต้องการบังคับให้กด?

@linquizeนำตัวอย่างที่ผลักดันแรงที่ดีในการแสดงความคิดเห็น: ข้อมูลที่สำคัญ คุณรั่วไหลของข้อมูลอย่างผิดพลาดซึ่งไม่ควรผลักดัน หากคุณเร็วพอคุณสามารถ"แก้ไข"*ได้โดยบังคับให้กดที่ด้านบน

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


1
ปัญหา @rogerdpack ไม่ใช่ถ้าเป็นไปได้ มันคือ. แต่มันสามารถสรุปได้ถึงภัยพิบัติครั้งใหญ่ ยิ่งมีคนทำอะไรมาก (บังคับให้กด) และยิ่งคุณอัปเดต (ดึง) น้อยลงจาก repo สาธารณะมากเท่าไรภัยพิบัติก็จะยิ่งใหญ่ขึ้นเท่านั้น มันสามารถแยกโลกออกได้อย่างที่คุณรู้ !!! 111 อย่างน้อยโลกนี้ก็ประกอบด้วยที่เก็บอันนั้น
cregox

3
หากคุณมีข้อมูลที่สำคัญแรงผลักดันมัน
linquize

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

3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushสิ่งนี้แก้ไขปัญหาของฉันได้อย่างสมบูรณ์แบบ (บน repo ที่มีเพียงฉันและเพื่อนของฉัน) อาจจะผิดสำหรับ repos สาธารณะ แต่สำหรับส่วนตัวนี้เป็นตัวช่วยชีวิต
สามารถPoyrazoğlu

1
สิ่งนี้เกิดขึ้นโดยอัตโนมัติกับผู้จัดการ repo บางคนอาคาสควอชและอื่น ๆ บังคับให้กดหลังจากเสร็จสิ้นฟีเจอร์สาขาเพื่อลดการคอมมิชชัน
FlavourScape

18

ก่อนอื่นฉันจะไม่ทำการเปลี่ยนแปลงใด ๆ โดยตรงใน repo "main" หากคุณต้องการมี repo "main" จริงๆคุณควรกดไปที่มันเท่านั้นอย่าเปลี่ยนมันโดยตรง

เกี่ยวกับข้อผิดพลาดที่คุณได้รับคุณลองgit pullจาก repo ในพื้นที่ของคุณแล้วgit pushไปยัง repo หลักหรือไม่? สิ่งที่คุณกำลังทำอยู่ (ถ้าฉันเข้าใจดี) กำลังบังคับให้ต้องผลักดันและจากนั้นการสูญเสียการเปลี่ยนแปลงใน repo "main" คุณควรรวมการเปลี่ยนแปลงในเครื่องก่อน


ใช่ฉันพยายามดึง แต่ฉันสูญเสียข้อมูลเนื่องจากการดึงที่ ฉันต้องการให้ repos หลักเป็นท้องถิ่นของฉันโดยไม่ต้องปรับปรุงจากหลัก
Spyros

1
ในกรณีที่ใช้git push -fแต่ถ้าคุณเปลี่ยน repo หลักของคุณอีกครั้งคุณจะต้องกลับไปที่ repo ท้องถิ่นของคุณและgit pullเพื่อให้มันได้รับการซิงค์กับการเปลี่ยนแปลงล่าสุด จากนั้นคุณสามารถทำงานของคุณและผลักดันอีกครั้ง หากคุณทำตามขั้นตอน "push-pull" นี้คุณจะไม่ได้รับข้อผิดพลาดที่คุณบ่น
ubik

ใช่ฉันเข้าใจว่านี่เป็นความผิดของฉัน: / ฉันจะลองและกลับมาอีกหน่อยขอบคุณ thanx
Spyros

1
พยายามบังคับ แต่เมื่อกลับไปที่เซิร์ฟเวอร์หลักเพื่อบันทึกการเปลี่ยนแปลงฉันได้รับการแสดงละครที่ล้าสมัย ดังนั้นเมื่อฉันยอมรับที่เก็บไม่เหมือนกัน และเมื่อฉันพยายามใช้ git push อีกครั้งฉันได้รับข้อผิดพลาดเดียวกัน
Spyros

17

ถ้าฉันอยู่ในสาขาท้องถิ่น A และฉันต้องการบังคับให้สาขาท้องถิ่น B ไปที่สาขาต้นทาง CI สามารถใช้ไวยากรณ์ต่อไปนี้:

git push --force origin B:C

2
ผมพบว่าแม้ฉันในสาขา B git push --force origin B:Cท้องถิ่นของฉันฉันยังคงต้องทำ ในกรณีของฉันดูเหมือนว่าgit push --force origin Cจะผลักดันจากเจ้านายท้องถิ่นไปยังสาขา C ระยะไกลโดยไม่คำนึงถึงสาขาที่ฉันกำลังเปิดอยู่ git version 2.3.8 (Apple Git-58)
Weishi Zeng

12

ใช้คำสั่งต่อไปนี้:

git push -f origin master

1
อาจให้คำอธิบายเพิ่มเติมว่าทำไมคำตอบนี้จึงเป็นคำตอบที่ดีกว่าและสิ่งที่ทำให้แตกต่าง
Adam

โอ้ขอโทษด้วยความไม่สะดวกฉันมีปัญหาเดียวกันและคำสั่งนี้แก้มันฉันคิดว่าฉันควรแบ่งปัน
mustafa Elsayed

12
มันเป็นเพียงเช่นเดียวกับคนอื่น ๆ ที่คุณเพียงแค่เปลี่ยนตำแหน่งของ-fธง ...
svelandiag

11

ฉันอยากจะแนะนำ:

กล่าวอีกนัยหนึ่งให้เก็บ repo เปลือยทั้งจากเซิร์ฟเวอร์หลักและเครื่องคอมพิวเตอร์เพื่อให้มี repo upstream เดียวจาก / ที่จะดึง / ดึง


5

นี่เป็นวิธีการแก้ปัญหาของเราในการเปลี่ยนต้นแบบบนที่เก็บ gitHub ขององค์กรในขณะที่รักษาประวัติ

push -fหลักในคลังเก็บขององค์กรมักจะปิดการใช้งานเพื่อรักษาประวัติสาขา วิธีนี้ใช้ได้ผลกับเรา

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

ผลักดันให้สาขาของคุณdesiredOriginและสร้างการประชาสัมพันธ์


3

ฉันมีคำถามเดียวกัน แต่คิดออกในที่สุด สิ่งที่คุณต้องทำมากที่สุดคือเรียกใช้คำสั่ง git สองคำสั่งต่อไปนี้ (แทนที่แฮชด้วยหมายเลขการแก้ไขที่คอมมิตยอมรับ):

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