Git แบบไม่กรอไปข้างหน้าถูกปฏิเสธ


88

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

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

ปัญหาเดียวคือฉันได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

ฉันใช้โมเดล git-flow และกำลังทำงานในสาขาการพัฒนา ฉันจะรวมสิ่งต่างๆกลับเข้ามาเพื่อสร้างความสุขอีกครั้งได้อย่างไร


คำตอบ:


52

บังคับgit push:

git push origin +develop

24
นั่นเป็นวิธีแก้ปัญหา แต่อ่านความคิดเห็นของ Brian Campbell เพื่อให้คุณเข้าใจสิ่งที่คุณทำก่อนที่จะใช้สิ่งนี้
thelem

5
git push origin + master
Aniket Thakur

ดูเพิ่มเติมหมายเหตุเกี่ยวกับreceive.denyNonFastForwardsในคำตอบที่ไบรอันแคมป์เบล : +หรือ--forceไม่อาจจะมีพลังพอที่ขึ้นอยู่กับวิธีที่พวกเขา-ใครก็ตามที่พวกเขาจะมีการกำหนดค่าของพวกเขาที่เก็บ Git
torek

174

ถ้าคุณผลักดันกระทำกับเซิร์ฟเวอร์และจากนั้นเขียนว่ากระทำในประเทศ (มีgit reset, git rebase, git filter-branch, หรือการจัดการประวัติศาสตร์อื่น ๆ ) และผลักดันให้แล้วที่เขียนใหม่กระทำกลับขึ้นไปยังเซิร์ฟเวอร์ที่คุณจะพลาดคนอื่น ๆ ที่ได้ดึง นี่คือตัวอย่าง; กล่าวว่าคุณได้กระทำ A และผลักดันไปยังเซิร์ฟเวอร์

- * - * - A <- มาสเตอร์

- * - * - A <- ที่มา / ต้นแบบ

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

- * - * - ก
    \
     ก '<- master

- * - * - A <- ที่มา / ต้นแบบ

ถ้ามีคนอื่นสมมติว่า Fred ดึงmasterออกจากเซิร์ฟเวอร์ในขณะที่คุณทำสิ่งนี้พวกเขาจะมีการอ้างอิงถึง A ซึ่งอาจเริ่มทำงานจาก:

- * - * - ก '<- โท

- * - * - A <- ที่มา / ต้นแบบ

- * - * - AB <- เฟรด / มาสเตอร์

ตอนนี้ถ้าคุณสามารถผลักดัน A ของคุณไปยังจุดเริ่มต้น / ต้นแบบซึ่งจะสร้างแบบไม่กรอไปข้างหน้าก็จะไม่มี A ในประวัติ ดังนั้นหากเฟร็ดพยายามดึงอีกครั้งเขาก็ต้องรวมเข้าด้วยกันและจะแนะนำการกระทำ A อีกครั้ง:

- * - * - ก '<- โท

- * - * - A <- ที่มา / ต้นแบบ

- * - * - AB- \ 
    \ * <- เฟรด / มาสเตอร์
     ก '- /

หากเฟร็ดสังเกตเห็นสิ่งนี้เขาก็สามารถสร้างฐานใหม่ได้ซึ่งจะป้องกันไม่ให้คอมมิต A ปรากฏขึ้นอีกครั้ง แต่เขาต้องสังเกตสิ่งนี้และอย่าลืมทำสิ่งนี้ และหากคุณมีมากกว่าหนึ่งคนที่ดึง A ลงมาพวกเขาทั้งหมดจะต้องตั้งฐานใหม่เพื่อหลีกเลี่ยงการรับ A พิเศษในทรี

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

git push -f

หรือ

git push origin +master

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

เป็นไปได้ว่าการบังคับผลักถูกปิดใช้งานทั้งหมดด้วยreceive.denyNonFastForwardsตัวเลือกการกำหนดค่า ตัวเลือกนี้เปิดใช้งานโดยค่าเริ่มต้นบนที่เก็บที่ใช้ร่วมกัน ในกรณีที่ว่าถ้าคุณจริงๆ, git push origin :master; git push origin master:masterต้องการบังคับให้กดเลือกที่ดีที่สุดคือการลบสาขาและสร้างใหม่อีกครั้งได้ด้วย อย่างไรก็ตามdenyNonFastForwardsตัวเลือกนี้เปิดใช้งานด้วยเหตุผลซึ่งได้อธิบายไว้ข้างต้น บนที่เก็บที่ใช้ร่วมกันนั่นหมายความว่าตอนนี้ทุกคนที่ใช้มันจำเป็นต้องตรวจสอบให้แน่ใจว่าพวกเขาสร้างฐานข้อมูลใหม่ในประวัติใหม่

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


การศึกษาที่ยอดเยี่ยมและคุณมีคำสั่งที่ถูกต้องในที่สุด แต่สาขาของฉันถูกเรียกว่าพัฒนา (ขึ้นอยู่กับ git-flow) และอีกคนหนึ่งก็+developรับคำสั่งของเขาดังนั้นการตรวจสอบจะไปที่เขา คุณมีคะแนนทางดาราศาสตร์อยู่แล้ว: P
rynmrtn

8
หรือใช้ความลับน้อยลงgit push --force
Bennett McElwee

3
@ Panique คุณกำลังพยายามอนุญาตให้คนหลายคนทำงานบน codebase ขนาดใหญ่ที่ซับซ้อนในเวลาเดียวกันโดยไม่ปิดกั้นซึ่งกันและกัน (อนุญาตให้มีเพียงคนเดียวเท่านั้นที่จะทำงานได้ในแต่ละครั้ง) และไม่มีการเปลี่ยนแปลงเขียนทับกัน คุณต้องให้แต่ละคนสามารถทำการเปลี่ยนแปลงได้อย่างอิสระและรวมการเปลี่ยนแปลงเหล่านั้นเข้าด้วยกัน การผสาน (ไม่ว่าจะด้วยตนเองหรือโดยอัตโนมัติ) สามารถทำให้เกิดปัญหาที่ไม่คาดคิดได้ ดังนั้นคุณจึงต้องการเก็บข้อมูลไว้ให้มากที่สุดเพื่อที่จะได้ทราบว่าเกิดอะไรขึ้นหากผิดพลาด สิ่งนี้มีความซับซ้อนภายใน ไม่สกปรกเป็นปัญหาหนัก
Brian Campbell

ฉันลองทั้งตัวเลือก -f และ + เพื่อเขียนประวัติ repo ระยะไกลอีกครั้ง ในทั้งสองตัวเลือกฉันพบปัญหาที่ไม่ใช่การกรอไปข้างหน้า [17:05 น.] $ git push -f origin local_A: remote_A การนับวัตถุ: 35 เสร็จสิ้น การบีบอัดเดลต้าโดยใช้เธรดสูงสุด 2 เธรด การบีบอัดวัตถุ: 100% (18/18) เสร็จสิ้น การเขียนวัตถุ: 100% (21/21), 7.41 KiB เสร็จสิ้น รวม 21 (เดลต้า 9) ใช้ซ้ำ 0 (เดลต้า 0) ระยะไกล: เพื่อป้องกันไม่ให้คุณเสียประวัติการอัปเดตแบบไม่กรอไปข้างหน้าจึงถูกปฏิเสธ รวมการเปลี่ยนแปลงระยะไกล (เช่น 'git pull') ก่อนที่จะผลักดันอีกครั้ง ดูรายละเอียดในส่วน "หมายเหตุเกี่ยวกับการส่งต่ออย่างรวดเร็ว" ของ "git push --help"
Srikanth

4
@Srikanth เป็นไปได้ที่จะปิดใช้งานการผลักดันที่บังคับทั้งหมดด้วยreceive.denyNonFastForwardsตัวเลือกการกำหนดค่า ตัวเลือกนี้เปิดใช้งานโดยค่าเริ่มต้นบนที่เก็บที่ใช้ร่วมกัน ในกรณีที่ว่าถ้าคุณจริงๆ, git push origin :remote_A; git push origin local_A:remote_Aต้องการบังคับให้กดเลือกที่ดีที่สุดคือการลบสาขาและสร้างใหม่อีกครั้งได้ด้วย แต่อ่านสิ่งที่ฉันเขียนไว้ข้างต้นเกี่ยวกับสาเหตุที่ควรทำเวิร์กโฟลว์ประเภทนี้บนที่เก็บที่ใช้ร่วมกันจึงเป็นความคิดที่ดี คุณควรพยายามทำสิ่งนี้ก็ต่อเมื่อคุณมีบางสิ่งที่ทำให้เกิดปัญหาร้ายแรงในการกระทำที่คุณพยายามกำจัดหรือเขียนใหม่
Brian Campbell

14

คุณอาจต้องทำgit pullซึ่งอาจรวมข้อมูลให้คุณโดยอัตโนมัติ จากนั้นคุณสามารถกระทำอีกครั้ง หากคุณมีความขัดแย้งระบบจะแจ้งให้คุณแก้ไข

โปรดทราบว่าคุณต้องระบุว่าจะดึงสาขาใดหากคุณยังไม่ได้อัปเดต gitconfig เพื่อระบุ ...

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

git pull origin develop:develop

ยังคงคลั่งไคล้การไม่กรอไปข้างหน้า มีความคิดเกี่ยวกับวิธีบังคับให้ผสานหรือไม่? ! [rejected] develop -> develop (non-fast-forward)
rynmrtn

ฉันคิดว่าสวิตช์เป็น -f แต่ฉันคิดผิด kernel.org/pub/software/scm/git/docs/git-pull.html
Tony

ใช้งานได้บางส่วน ฉันไม่เห็นการอัปเดตบน github แม้ว่า (จะแสดงการกระทำก่อนหน้านี้เป็นล่าสุดแม้จะมี a git push origin develop)
rynmrtn

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