การรีเซ็ตรีโมตเป็นการกระทำที่แน่นอน


709

ฉันต้องการยกเลิกการเปลี่ยนแปลงทั้งหมดที่ทำหลังจากส่งมอบ<commit-hash>แล้ว ดังนั้นฉันจึง:

git reset --hard <commit-hash>

ตอนนี้ฉันต้องการทำเช่นเดียวกันกับรีโมทของฉัน ฉันจะทำสิ่งนี้ได้อย่างไร ฉันได้ทำบางอย่าง (และดัน) หลังจากนั้น<commit-hash>และฉันต้องการที่จะทิ้งพวกเขาทั้งหมด เป็นเพียงบางสิ่งที่ผิดอย่างมากในทางและฉันไม่ต้องการทำให้มันแย่กว่าที่มีอยู่แล้ว (

โดยทั่วไปฉันต้องการย้อนกลับorigin/masterไปเป็น<commit-hash>


3
คุณแน่ใจorigin/masterหรือไม่ว่าผู้ใช้รายอื่นไม่ได้ถูกดึงและผลักดัน? การเปลี่ยนประวัติของพื้นที่เก็บข้อมูลสาธารณะ (เช่นไม่ใช่ท้องถิ่น) เป็นสิ่งที่คุณต้องการหลีกเลี่ยงตลอดเวลา
vindia

คำตอบ:


1251

สมมติว่าสาขาของคุณถูกเรียกmasterทั้งที่นี่และจากระยะไกลและระยะไกลของคุณถูกเรียกว่าoriginคุณสามารถทำได้:

 git reset --hard <commit-hash>
 git push -f origin master

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

อัปเดต:คุณได้อธิบายไว้ด้านล่างว่าคนอื่น ๆ ได้ดึงการเปลี่ยนแปลงที่คุณผลักไว้ดังนั้นจึงเป็นการดีกว่าที่จะสร้างความมุ่งมั่นใหม่ที่จะยกเลิกการเปลี่ยนแปลงเหล่านั้นทั้งหมด มีคำอธิบายที่ดีของตัวเลือกของคุณสำหรับการทำเช่นนี้ในเป็นคำตอบนี้จาก Jakub Narębski วิธีใดสะดวกที่สุดขึ้นอยู่กับจำนวนที่คุณต้องการส่งคืนและวิธีการที่เหมาะสมที่สุดสำหรับคุณ

เนื่องจากคำถามของคุณเป็นที่ชัดเจนว่าคุณเคยใช้git reset --hardในการรีเซ็ตmasterสาขาของคุณแล้วคุณอาจต้องเริ่มต้นโดยใช้git reset --hard ORIG_HEADเพื่อย้ายสาขาของคุณกลับไปที่เดิม (เช่นเคยgit reset --hardตรวจสอบให้แน่ใจว่าgit statusสะอาดอยู่เสมอว่าคุณอยู่ในสาขาที่ถูกต้องและคุณทราบgit reflogว่าเป็นเครื่องมือในการกู้คืนคอมมิชชันที่หายไปอย่างเห็นได้ชัด) คุณควรตรวจสอบORIG_HEADจุดที่ถูกต้องด้วยgit show ORIG_HEADเช่นกัน

การแก้ไขปัญหา:

หากคุณได้รับข้อความเช่น " ! [การปฏิเสธจากระยะไกล] a60f7d85 -> master (การขอ hook ล่วงหน้าถูกปฏิเสธ) "

จากนั้นคุณต้องอนุญาตให้เขียนประวัติสาขาสำหรับสาขาที่ระบุ ใน BitBucket มีข้อความกล่าวว่า "ไม่อนุญาตให้เขียนประวัติสาขาใหม่" มีช่องทำเครื่องหมายชื่อAllow rewriting branch historyที่คุณต้องตรวจสอบ


21
อันตรายที่เป็นอันตราย: การรีเซ็ตนี้จะถือว่าสาขา( การติดตาม ) ที่เกี่ยวข้องนั้นได้ชำระเงินแล้วและไม่มีการเปลี่ยนแปลงที่คุณต้องการเก็บไว้ ใช้git update-refแทนreset --hard ; มันจะช่วยให้คุณสามารถทำเช่นเดียวกันโดยไม่ต้องมีต้นไม้ทำงาน / สาขาที่เช็คเอาท์
sehe

3
ฉันเห็น. มันถูกผลักดันและเปลี่ยนแปลงโดยผู้อื่น ดังนั้นฉันควรใช้revert แต่ให้บอกว่าฉันต้องการย้อนกลับ 4 คอมมิทที่ผ่านมาดังนั้นฉันควรทำgit revert comit1; git push; git revert comit2; git push; ...หรือgit revert commit4; git pushไม่?
nacho4d

1
@ nacho4d: คุณไม่จำเป็นที่จะต้องผลักดันหลังจากที่แต่ละย้อนกลับ - มีคำอธิบายที่ดีของสิ่งที่ต้องทำในคำตอบนี้จาก Jakub Narębski คุณจำเป็นต้องยกเลิกการคอมมิชชันแต่ละรายการย้อนหลัง - เพียงแค่git revert commit4สร้างการคอมมิทใหม่ที่ยกเลิกการเปลี่ยนแปลงที่นำมาใช้commit4เท่านั้น ในขณะที่คำตอบที่ฉันเชื่อมโยงกับคะแนนออกมาคุณสามารถหมุนสิ่งเหล่านี้เป็นความมุ่งมั่นเดียว
Mark Longair

1
@ มาร์คฉันได้วิ่งไปแล้วgit reset --hardแต่ฉันได้ลบท้องถิ่นของฉันและดึงออกจากแหล่งกำเนิดอีกครั้งดังนั้นฉันจึงสามารถที่จะทำgit revert ...ข้อสงสัยของฉันตอนนี้คือ: ฉันจะต้องย้อนกลับแต่ละกระทำและผลักดัน (หนึ่งโดยหนึ่ง) หรือเพียงแค่ย้อนกลับ กระทำที่ถูกต้องเท่านั้น?
nacho4d

1
@sehe: มันยากที่จะใช้เพราะคุณจำเป็นต้องใช้ชื่ออ้างอิงแบบเต็มและดังนั้นจึงเป็นเรื่องง่ายสำหรับคนที่จะทิ้งขยะ.gitไดเรกทอรีของพวกเขาด้วย refs ที่พวกเขาไม่ได้ตั้งใจจะสร้าง ฉันผิดที่จะบอกว่าไม่มีการตรวจสอบความปลอดภัยแม้ว่า คุณสามารถค้นหาจำแนกเข้า "ประปา" และ "พอร์ซเลน" คำสั่งในส่วนหน้าคนคอมไพล์
Mark Longair

123

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

หากคุณเพียงแค่ต้องการให้การจับคู่ระยะไกลเป็นการกระทำที่ทุกที่ใน repo ท้องถิ่นของคุณ:

  1. อย่าได้ทำตั้งค่าใด ๆ
  2. ใช้git logเพื่อค้นหาการกระทำที่คุณต้องการให้รีโมทอยู่ที่ git log -pเพื่อดูการเปลี่ยนแปลงหรือgit log --graph --all --oneline --decorateเพื่อดูทรีกระชับ
  3. คัดลอกแฮชการกระทำหรือแท็กหรือชื่อของสาขาถ้าเป็นเคล็ดลับ
  4. เรียกใช้คำสั่งเช่น:

    git push --force <remote> <commit-ish>:<the remote branch>
    

    เช่น

    git push --force origin 606fdfaa33af1844c86f4267a136d4666e576cdc:master
    

    หรือ

    git push --force staging v2.4.0b2:releases
    

ฉันใช้นามแฝงที่สะดวก ( git go) เพื่อดูประวัติการเข้าชมในขั้นตอนที่ 2 ซึ่งสามารถเพิ่มดังนี้:

    git config --global alias.go 'log --graph --all --decorate --oneline'`

3
กราฟเป็นเคล็ดลับที่ดีมากฉันเพิ่งเพิ่ม -5 เพื่อให้ได้ค่า n สุดท้ายเท่านั้นมันเป็นต้นไม้ขนาดใหญ่ การหลีกเลี่ยงการรีเซ็ตเป็นสิ่งที่ฉันกำลังมองหา ยอดเยี่ยม
AlexanderD

@AlexanderD คุณยังสามารถเพิ่มนามแฝงใน Git แทนที่จะเป็นเชลล์ของคุณเพื่อให้ทำงานได้ทุกที่ Git เข้าใจนามแฝงและแท็บครบถ้วนจากคำสั่งเต็มเพื่อให้คุณสามารถเพิ่มอาร์กิวเมนต์ git config --global alias.graph 'log --graph --all --decorate --oneline'ยุ่งน้อยลงและคุณยังสามารถ จำกัด ได้เช่น:git graph -5
Walf

มันสมบูรณ์แบบ ฉันมักจะเลอะท้องถิ่นของฉัน นี่คือสิ่งที่ฉันต้องการหลังจากที่ตั้งใจผลักดันการแสดงสดของฉัน :( ขอบคุณ!
Jake

1
บน Windows ให้ป้อนqเพื่อออกจากบันทึก git 2 นาทีฉันจะไม่กลับมา
dst3p

1
@ dst3p นั่นคือในทุกแพลตฟอร์มเพื่อน โปรแกรมวิทยุติดตามตัวมักจะเป็นlessและqเป็นวิธีปกติในการออกจากโปรแกรม Git Bash เปรียบเสมือนเทอร์มินัล * nix
Walf

63

ฉันแก้ไขปัญหาเช่นเดียวกับคุณด้วยคำสั่งนี้:

git reset --hard <commit-hash> 
git push -f <remote> <local branch>:<remote branch> 

13

ใน GitLab คุณอาจต้องตั้งสาขาของคุณให้ไม่มีการป้องกันก่อนทำเช่นนี้ คุณสามารถทำได้ใน [repo]> การตั้งค่า> พื้นที่เก็บข้อมูล> สาขาที่ได้รับการป้องกัน จากนั้นวิธีการจากคำตอบของมาร์คก็ใช้ได้

git reset --hard <commit-hash>
git push -f origin master

10

หากคุณต้องการไฟล์เวอร์ชันก่อนหน้าฉันขอแนะนำให้ใช้ git checkout

git checkout <commit-hash>

การทำเช่นนี้จะส่งคุณย้อนเวลาไม่ส่งผลกระทบต่อสถานะปัจจุบันของโครงการของคุณคุณสามารถมาฉีดฉีดชำระเงิน

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

git checkout <commit-hash> -- file_name
git add .
git commit -m 'file brought from previous time'
git push

ข้อดีของการทำเช่นนี้คือมันไม่ได้ลบประวัติและไม่เปลี่ยนการเปลี่ยนแปลงรหัสเฉพาะ (git revert)

ตรวจสอบเพิ่มเติมได้ที่นี่https://www.atlassian.com/git/tutorials/undoing-changes#git-checkout


นี่คือคำตอบที่ยอดเยี่ยม: มันใช้งานได้ระยะเวลาและปลอดภัยมาก ถ้าคุณทำมันยุ่ง ๆ มันก็ง่ายที่จะย้อนกลับไป
บ๊อบ

8

สองเซ็นต์ของฉันต่อคำตอบก่อนหน้า: ถ้า

git push --force <remote> <the-hash>:<the remote branch>

ยังคงใช้งานไม่ได้คุณอาจต้องการแก้ไข<your-remote-repo>.git/configส่วนรับไฟล์:

[receive]
  #denyNonFastforwards = true
  denyNonFastforwards = false

การรู้วิธีกำหนดค่ารีโมตเพื่อช่วยให้สามารถทำการส่งต่อแบบเร็วได้เนื่องจากคำตอบส่วนใหญ่ดูเหมือนจะรับบริการระยะไกลเช่น Github หรือ Bitbucket
strongbutgood

2

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

git checkout 000000

(โดยที่ 000000 เป็นรหัสการมอบหมายที่คุณต้องการไป) ในสาขาที่มีปัญหาของคุณจากนั้นเพียงสร้างสาขาใหม่:

git remote เพิ่ม [name_of_your_remote]

จากนั้นคุณสามารถสร้าง PR ใหม่และทั้งหมดจะทำงานได้ดี!


1

ทำสิ่งใดสิ่งหนึ่งให้ได้รับความมุ่งมั่นหมายเลข SHA เช่น 87c9808 และจากนั้น

  1. ย้ายตัวเองนั่นคือหัวของคุณไปยังการกระทำที่ระบุ (โดยทำการรีเซ็ต git - ฮาร์ด 89cef43 // พูดถึงหมายเลขของคุณที่นี่)
  2. ถัดไปทำการเปลี่ยนแปลงบางอย่างในไฟล์สุ่มเพื่อให้คอมไพล์จะขอให้คุณกระทำการนั้นจากภายในเครื่องและจากระยะไกลดังนั้นสิ่งที่คุณต้องทำคือตอนนี้ หลังจากใช้การเปลี่ยนแปลงคอมไพล์ commit -a -m "Trial commit"
  3. ตอนนี้ให้กดคอมมิชชันต่อไปนี้ (ถ้ามีการคอมมิทภายในเครื่อง) โดย git push master origin
  4. ตอนนี้สิ่งที่คอมไพล์ขอจากคุณคือ

ข้อผิดพลาด: ล้มเหลวในการผลักดันการอ้างอิงถึง ' https://github.com/YOURREPOSITORY/AndroidExperiments.git ' คำแนะนำ: การอัปเดตถูกปฏิเสธเนื่องจากส่วนปลายของสาขาปัจจุบันของคุณอยู่เบื้องหลังคำใบ้: สำเนาระยะไกล รวมการเปลี่ยนแปลงระยะไกล (เช่นคำใบ้: 'git pull ... ') ก่อนกดอีกครั้ง **

  1. ดังนั้นตอนนี้สิ่งที่คุณสามารถทำได้คือ

git push --force origin master

  1. ดังนั้นฉันหวังว่าจะได้ผล :)

1

Sourcetree: การรีเซ็ตรีโมตเป็นการกระทำที่แน่นอน

  1. หากคุณส่งความมุ่งมั่นที่ไม่ดีไปยังรีโมทของคุณ (ที่มา / คุณสมบัติ / 1337_MyAwesomeFeature) ดังรูป

ไปที่รีโมท

  1. ไปที่รีโมท> แหล่งกำเนิด> คุณสมบัติ> 1337_MyAwesomeFeature
  2. คลิกขวาแล้วเลือก "Delete origin / feature / 1337_MyAwesomeFeature" (หรือเปลี่ยนชื่อถ้าคุณต้องการสำรองข้อมูลและข้ามขั้นตอนที่ 4)
  3. คลิก "บังคับลบ" และ "ตกลง"

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

  1. เลือกการกระทำที่เก่ากว่าของคุณและเลือก "รีเซ็ตสาขาปัจจุบันเป็นการกระทำนี้"
  2. เลือกโหมดที่คุณต้องการ (ยากหากคุณไม่ต้องการเปลี่ยนแปลงล่าสุด) และ "ตกลง"

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

  1. ส่งการกระทำนี้ไปที่ต้นกำเนิด / คุณสมบัติใหม่ / 1337_MyAwesomeFeature ป้อนคำอธิบายรูปภาพที่นี่

  2. สาขาฟีเจอร์ในพื้นที่ของคุณและสาขาฟีเจอร์รีโมตของคุณอยู่ที่การกระทำก่อนหน้า (ที่คุณเลือก) ป้อนคำอธิบายรูปภาพที่นี่

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