ฉันจะยกเลิกการคอมมิตสุดท้ายในที่เก็บ git bare ได้อย่างไร


94

โดยคำนึงว่ามีคำสั่ง git หลายคำสั่งที่ไม่สมเหตุสมผลในที่เก็บเปล่า (เนื่องจากที่เก็บเปล่าไม่ใช้ดัชนีและไม่มีไดเร็กทอรีการทำงาน)

git reset --hard HEAD^ 

ไม่ใช่วิธีแก้ปัญหาในการยกเลิกการสั่งการเปลี่ยนแปลงล่าสุดในที่เก็บดังกล่าว

ค้นหาผ่านอินเทอร์เน็ตทั้งหมดที่ฉันสามารถพบที่เกี่ยวข้องกับหัวข้อนี้คือสิ่งนี้ซึ่งฉันนำเสนอสามวิธีในการดำเนินการนี้:
1. "อัปเดตการอ้างอิงด้วยตนเอง
2. " git push -fจากที่เก็บที่ไม่เปลือย";
3. " git branch -f this $that".

วิธีแก้ปัญหาใดที่คุณคิดว่าเหมาะสมกว่าหรือมีวิธีใดอีกบ้างในการดำเนินการนี้ น่าเสียดายที่เอกสารที่ฉันพบเกี่ยวกับ git bare repository นั้นค่อนข้างแย่


8
@ Lavinia-Garbriela Dobrovol อย่าใช้สิ่งที่ซับซ้อนด้านล่าง คุณกำลังพยายามย้าย HEAD ไปยังคอมมิตอื่นและนั่นคือสิ่งที่การรีเซ็ตคอมไพล์มีไว้สำหรับแม้ใน repo แบบเปล่า ตามคำตอบของฉันด้านล่างใช้: git reset --soft <commit> ด้วย --soft คุณอย่าพยายามเปลี่ยนโครงสร้างและดัชนีที่ใช้งานได้ที่ไม่มีอยู่ดังนั้น git ช่วยให้คุณทำการรีเซ็ตได้โดยไม่มีปัญหา
Hazok

คำตอบ:


133

คุณสามารถใช้git update-refคำสั่ง ในการลบคอมมิตสุดท้ายคุณต้องใช้:

$ git update-ref HEAD HEAD^

หรือถ้าคุณไม่ได้อยู่ในสาขาที่คุณไม่สามารถลบคอมมิตสุดท้าย:

$ git update-ref refs/heads/branch-name branch-name^

คุณยังสามารถส่ง sha1 ได้หากต้องการ:

$ git update-ref refs/heads/branch-name a12d48e2

ดูเอกสารของไฟล์ คำสั่งgit-update-ref


@ Lavinia-Gabriela Dobrovolschi: ใช่ฉันไม่คุ้นเคยกับไวยากรณ์ที่แน่นอน
VonC

@VonC คุณสามารถระบุ <ref> ในgit update-ref <ref> <newvalue>เป็นสาขาที่ถูกต้องเช่น "refs / head / master" แทน HEAD เป็นต้น ฉันหวังว่าฉันจะไม่เข้าใจผิดในคำถามของคุณ
Lavinia-Gabriela Dobrovolschi

@Sylvain: +1 การแก้ไขที่ดี @ Lavinia-Gabriela Dobrovolschi ขอบคุณสำหรับข้อตกลง นั่นเป็นประโยชน์กว่ามาก (ถ้าคุณมีการเข้าถึงโดยตรงไปยังเซิร์ฟเวอร์ระยะไกลฉันคิดว่า)
VonC

3
ตัวอย่างทำให้เข้าใจผิดเกี่ยวกับbranch-nameข้อโต้แย้ง เมื่อใช้update-refกับ "สาขา" คุณต้องระบุชื่ออ้างอิงเต็มของสาขา (เช่นrefs/heads/นำหน้าชื่อสาขาแบบสั้นปกติ) หากคุณเพียงแค่ใช้ชื่อสั้น ๆ ที่คุณจะสิ้นสุดการสร้าง / อัปเดตแทน$GIT_DIR/branch-name $GIT_DIR/refs/heads/branch-nameการมีอยู่ของทั้งสองbranch-nameและrefs/heads/branch-nameจะทำให้เกิดคำเตือน“ refname …มีความคลุมเครือ”
Chris Johnsen

คำตอบนี้ซับซ้อนกว่ามากจากสิ่งที่ Zach เสนอ และวิธีแก้ปัญหาของเขาก็ใช้ได้ดี
Krystian

32

หากคุณใช้สิ่งต่อไปนี้ใน repo เปล่า:

git reset --soft <commit>

จากนั้นคุณจะไม่พบปัญหาที่คุณใช้--hardและ--mixedตัวเลือกใน repo เปล่าเนื่องจากคุณไม่ได้พยายามเปลี่ยนแปลงบางสิ่งที่ repo เปล่าไม่มี (เช่นโครงสร้างการทำงานและดัชนี) ในกรณีของคุณโดยเฉพาะคุณต้องการใช้ (จาก repo เปล่า):

git reset --soft HEAD^

ในการสลับสาขาบน repo ระยะไกลให้ทำ:

git symbolic-ref HEAD refs/heads/<branch_name>

หากต้องการดูสาขาที่เลือกปัจจุบันใช้:

git symbolic-ref HEAD

https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html


3
เลือกสาขาที่ต้องการย้ายได้อย่างไร? ตัวอย่างของคุณใช้งานได้ดีกับต้นแบบ แต่git checkout other_branchใช้งานไม่ได้
Gauthier

1
อืม ... ฉันสงสัยว่าใครโหวตให้ฉันเรื่องนี้ คำถามไม่ได้ถามว่าจะเปลี่ยนสาขาใน repo ระยะไกลได้อย่างไร แต่ถามว่าจะรีเซ็ตบน repo เปล่าอย่างไร ในการเปลี่ยนสาขาเริ่มต้นใน repo ระยะไกลให้ใช้ git symbolic-ref HEAD refs / head / <branch_name>
Hazok

7

git push -fควรปรับการทำงาน:
ถ้าคุณโคลนที่ repo เปลือยลบสุดท้ายกระทำ ( git reset --hard HEAD^ตามที่คุณพูดถึง แต่ใน repo ไม่ใช่เปลือยท้องถิ่น) และผลักดันกลับ ( -f):

  • คุณไม่ได้เปลี่ยน SHA1 ใด ๆ สำหรับการกระทำอื่น ๆ ก่อนหน้าที่คุณลบ
  • คุณแน่ใจว่าคุณผลักดันเนื้อหาที่แน่นอนของ repo เปล่าลบการกระทำพิเศษ (เพราะคุณเพิ่งโคลนก่อน)

@ VonC สวัสดีวอนฉันเห็นคุณตอบคำถามมากมายใน Git จึงอยากถามคุณ ... ฉันอยากรู้ว่าทำไมgit reset --soft <sha1>ตามที่แสดงในคำตอบด้านล่างของฉันจึงไม่เป็นแนวทางปฏิบัติที่แนะนำสำหรับการย้าย HEAD บน repo เปล่า?
Hazok

ฉันเดาว่าอีกเหตุผลหนึ่งที่ฉันถามคือการใช้ soft reset สำหรับ bare repos ไม่ใช่ข้อมูลที่พร้อมใช้งานและหลาย ๆ ฟอรัมดูเหมือนจะมีวิธีแก้ปัญหาที่ซับซ้อนโดยไม่จำเป็นเมื่อดูเหมือนว่า soft reset เป็นแนวทางปฏิบัติที่ดีที่สุดเนื่องจากมีการพิมพ์น้อยที่สุดและมีโอกาสน้อยที่สุด สำหรับข้อผิดพลาด
Hazok

2
@ Zach: reset --softควรทำงานเมื่อทำโดยตรงกับ repo เปล่า ฉันสงสัยว่าสิ่งนี้แทบไม่ได้ทำเพราะโดยทั่วไป repo แบบเปลือยจะเป็นrepo ต้นน้ำ (เช่น repo ที่คุณกำลังผลักดันข้อมูล) และโดยส่วนใหญ่แล้วคุณไม่มีสิทธิ์เข้าถึงโดยตรงในพื้นที่ แต่ถ้าคุณทำเช่นนั้นนี่เป็นอีกหนึ่งตัวอย่างที่ดีของreset --softการใช้งาน "" (เช่นเดียวกับในstackoverflow.com/questions/5203535/… ) ดังนั้น +1 สำหรับคำตอบของคุณ
VonC

2

คุณยังสามารถใช้สัญกรณ์ git refspec และทำสิ่งนี้:

git push -f origin +<commit you want to revert to>:<destination_head | branch_name>

สิ่งนี้บังคับให้อัปเดตสาขาปลายทาง (ตามที่แสดงโดยการอ้างอิง) ไปยังการคอมมิตต้นทางตามที่แสดงโดย+<object ref>ส่วน


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