ฉันจะกู้คืนจาก git push -f origin master ที่ผิดพลาดได้อย่างไร


93

ฉันเพิ่งระบุแหล่งที่มาที่ไม่ถูกต้องในโครงการของฉันโดยใช้--forceตัวเลือก

สามารถเปลี่ยนกลับได้หรือไม่? ฉันเข้าใจว่าสาขาก่อนหน้านี้ทั้งหมดถูกเขียนทับโดยใช้-fตัวเลือกดังนั้นฉันอาจทำให้การแก้ไขครั้งก่อนของฉันเสียหาย


เป็นไปได้ที่จะซ้ำกันของการยกเลิก git push -f หรือไม่
cmbuckley

คำตอบ:


55

โดยทั่วไป Git ไม่ได้ทิ้งอะไรไป แต่การกู้คืนจากสิ่งนี้อาจเป็นเรื่องยุ่งยาก

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

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

เหนือสิ่งอื่นใดอย่าใช้--forceตัวเลือกนี้เว้นแต่คุณจะตั้งใจจริง


65
คุณเป็นไปได้มากเพียงแค่ดูที่ reflogs เพื่อพิจารณาว่าเดิมทีสาขาระยะไกลอยู่ที่ใด ตัวอย่างเช่นgit reflog show remotes/origin/master. คุณควรจะเห็นการผลักดันของคุณที่นั่น การกระทำในบรรทัดก่อนหน้าคือจุดที่อยู่ก่อนที่คุณจะทำให้มันยุ่งเหยิง จากนั้นคุณสามารถผลักดันการแก้ไขนั้น (พร้อม--force) ไปยังจุดเริ่มต้นและกลับมาที่เดิม!
Cascabel

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

1
@ เดวิด: ใช่ ควรมีไดเร็กทอรีปัจจุบันของคุณเป็นส่วนหนึ่งของพรอมต์เสมอเพื่อหลีกเลี่ยงสิ่งนั้น
Cascabel

1
@Jefromi ฉันคิดว่าสิ่งที่คุณพูดมี anwer จริง: แม้จะเป็นเวอร์ชันเก่า (ไม่มีgit fetched มานานแล้ว) คุณสามารถแสดง reflog ด้านข้างของ GitHub และกู้คืนได้!
nh2

1
คำตอบนี้โดย @Jefromi อยู่ที่ไหน? ฉันไม่เห็นผู้ใช้คนนั้นพูดถึงในหน้านี้นอกชุดความคิดเห็นนี้
Don McCurdy

47

หากคุณรู้จักคอมมิตแฮชก็ทำได้ง่ายๆเพียงสร้างสาขาของคุณขึ้นมาใหม่

5794458...b459f069 master -> master (forced update)

ลบสาขาระยะไกล:

git push origin :master

จากนั้นสร้างสาขาของคุณใหม่ด้วยคำสั่งต่อไปนี้:

git checkout 5794458
git branch master
git push origin master

28

วิธีแก้ปัญหาได้กล่าวไว้แล้วที่นี่

# work on local master
git checkout master

# reset to the previous state of origin/master, as recorded by reflog
git reset --hard origin/master@{1}

# at this point verify that this is indeed the desired commit.
# (if necessary, use git reflog to find the right one, and
# git reset --hard to that one)

# finally, push the master branch (and only the master branch) to the server
git push -f origin master

ขอบคุณสิ่งนี้ได้ผลสำหรับฉัน ฉันไม่มีสิทธิ์เข้าถึงการลบต้นแบบดังนั้นความคิดเห็นที่อนุมัติจึงล้มเหลว
Andi

ใช่และgit reflog show remotes/origin/masterถ้าจำเป็นต้องมีการอ้างอิงคอมไพล์ (ตามที่กล่าวไว้โดย @Cascabel ด้านบน)
Josiah Yoder

2
นี่คือคำตอบที่ถูกต้องขอบคุณสำหรับการเชื่อมโยงไปยังคำตอบที่ถูกต้อง
Noitidart

6

หากคุณไม่ได้อยู่ใน repo ท้องถิ่นที่ซึ่งการผลักดันบังคับมาจากระดับต้นทาง / ระดับมาสเตอร์จะไม่มีทางกู้คืนได้ แต่ถ้าคุณโชคดีพอที่จะใช้GitHubหรือGitHub for EnterpriseคุณสามารถดูREST API และเรียกข้อมูลการกระทำที่สูญหายไปเป็นโปรแกรมแก้ไขได้เช่น

  1. แสดงรายการเหตุการณ์และค้นหารูปแบบยาวของการคอมมิต sha1

https://api.github.com/repos/apache/logging-log4j2/events

  1. ดาวน์โหลดการคอมมิตที่สูญหายและดึงข้อมูลแพตช์ที่เกี่ยวข้องในพา ธ json .files [] / patch

https://api.github.com/repos/apache/logging-log4j2/commits/889232e28f3863d2a17392c06c1dd8cac68485de

  1. สมัครในเครื่องแล้วดันอีกครั้ง

git ใช้ patch.patch && git คอมมิต -m "restore comm" && git push origin master


4

อีกวิธีหนึ่งในการกู้คืนคอมมิตที่หายไปหรือแม้กระทั่งการค้นหาว่าการกระทำใดสูญหายไปหากการผลักดันครั้งก่อนไม่ได้มาจาก repo ในพื้นที่ของคุณคือการดูที่เครื่อง CI ของคุณ

หากคุณมีงานที่ทดสอบสาขาหลักหลังจากทุกครั้งที่มีการคอมมิต (หรือชุดของการคอมมิตต่อเนื่องกัน) ซึ่งคุณควรจะมีคุณสามารถดูได้ว่ามีการทดสอบอะไรล่าสุดบ้าง นั่นคือการกระทำที่คุณต้องกู้คืน

เครื่อง CI อาจเก็บโคลนในเครื่องของ repo ซึ่งคุณอาจสามารถทำการกู้คืนนี้ได้

ที่มา: อาจมีการจัดส่งแบบต่อเนื่อง: ซอฟต์แวร์ที่เชื่อถือได้เผยแพร่ผ่านระบบสร้างทดสอบและปรับใช้งานอัตโนมัติ (ซีรี่ส์ลายเซ็นแอดดิสัน - เวสลีย์ (ฟาวเลอร์))


3

ใช่คุณสามารถกู้คืนคอมมิตได้หลังจากนั้น git push -f your_branch

ข้อความจาก Doc :

รายการพรุนที่เก่ากว่าเวลาที่กำหนด หากไม่ได้ระบุตัวเลือกนี้เวลาหมดอายุจะถูกนำมาจากการตั้งค่าคอนฟิกูเรชัน gc.reflogExpire ซึ่งจะมีค่าเริ่มต้นเป็น 90 วัน --expire = รายการพรุนทั้งหมดโดยไม่คำนึงถึงอายุ --expire = ไม่เคยปิดการตัดรายการที่เข้าถึงได้ (แต่ดู --expire-ไม่สามารถเข้าถึงได้)

คุณสามารถทำได้:

1- git reflog

ป้อนคำอธิบายภาพที่นี่

2- คุณเลือก Head_Number ที่คุณต้องการกู้คืนด้วย git reset –hard HEAD@{HEAD-NUMBER}

ป้อนคำอธิบายภาพที่นี่

3- คุณสามารถเห็นการกระทำทั้งหมดบนหัวนี้โดย git cherry -v branch_name

4- ในที่สุดคุณควรบังคับผลักดัน git push -f branch_name

หรือ

1- รับจำนวน SHA จากไคลเอนต์ GIT ของคุณ (อินเทอร์เฟซ)

git reset --hard commit_SHA

2- แรงผลัก

git push -f your_branch

หวังว่านี่จะช่วยได้


2

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

สิ่งที่ฉันทำคือ (หลังจากทำสำเนา repo ในพื้นที่อีกสองสามชุดอย่างเมามัน):

git add .
git status

(มันบอกว่าต้นกำเนิด / มาสเตอร์อยู่ข้างหน้า 68 คอมมิตดี ... นั่นคือคอมมิตทั้งหมดที่ฉันลบไป)

git remote set-url origin <GIT_SSH_URL>
git push

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


1

สำหรับคนที่อยู่ในสถานการณ์เลวร้ายอย่างฉัน (ตัวอย่างเช่นหากคุณได้รับbad objectข้อผิดพลาดขณะทำงานgit reset --hard ):

ฉันเขียนสคริปต์ชื่อ treesaverที่ดึงไฟล์ทั้งหมดของคุณจาก GitHub API เป็นทางเลือกสุดท้าย วิธีการใช้งานมีดังนี้

  1. โคลนtreesaverสคริปต์และcdไปที่มัน
  2. ค้นหาไฟล์ SHAสตริงของต้นไม้ที่คุณต้องการกู้คืนโดยการเข้าถึง https://api.github.com/repos/<your_username_or_org>/<repo>/eventsสตริงของต้นไม้ที่คุณต้องการที่จะเรียกคืนโดยการเข้าถึง
  3. ในพpayloadร็อพเพอร์ตี้ที่ตรงกับเหตุการณ์พุชของคุณค้นหาสิ่งที่commitคุณต้องการเปลี่ยนกลับและคลิกที่เหตุการณ์นั้นurlเหตุการณ์นั้น
  4. ภายใต้commit.treeคัดลอกtree'surl 's
  5. python3 main.py <tree_url> <path_to_save_to>วิ่ง

ตัวอย่างเช่นในกรณีของฉันฉันจะเรียกใช้:

python3 main.py https://api.github.com/repos/anthonykrivonos/my-repo/git/trees/1234567 .

แน่นอน PRs ยินดีต้อนรับ


0

คุณสามารถอ่านการตัดสินใจได้ที่นี่ https://evilmartians.com/chronicles/git-push---force-and-how-to-deal-with-it

คนที่สองช่วยฉันด้วย ฉันทำผิดคำสั่งเหล่านี้

1) (some-branch) git pull -> correct command was git pull origin some-branch

2) (some-branch) git push -f origin some-branch

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

60223bf ... 0b258eb บางสาขา -> ต้นทาง / บางสาขา

แฮชที่สอง 0b258eb คือสิ่งที่ฉันต้องการ ดังนั้นฉันจึงใช้แฮชนี้และสร้างคำสั่ง

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