ย้ายตัวชี้สาขาไปยังการส่งที่แตกต่าง


760

หากต้องการย้ายตัวชี้แบรนช์ของสาขาที่เช็คเอาต์คุณสามารถใช้git reset --hardคำสั่งได้ แต่จะย้ายตัวชี้แบรนช์ของสาขาที่ไม่ได้ชำระเงินไปยังจุดอื่นได้อย่างไร


11
เสียงเหมือนสิ่งที่คุณต้องการจะทำคือสาขาจากความมุ่งมั่นที่แตกต่างกว่าที่มันถูกสร้างขึ้นจากตอนนี้ หากความเข้าใจของฉันถูกต้องแล้วทำไมคุณไม่สร้างสาขาใหม่จากคำสั่งที่คุณต้องการสร้างจากการใช้git branch <branch-name> <SHA-1-of-the-commit>และทิ้งสาขาเก่า
yasouser

6
@yasouser - ฉันไม่แน่ใจว่าสิ่งที่ทิ้งสาขา "ต้นแบบ" เป็นความคิดที่ดี
Bulwersator

คำตอบ:


578

คุณสามารถทำได้เพื่ออ้างอิงโดยพลการ นี่คือวิธีย้ายตัวชี้สาขา:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

รูปแบบทั่วไป:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

คุณสามารถเลือก nits เกี่ยวกับข้อความ reflog หากคุณต้องการ - ฉันเชื่อว่าข้อความbranch -fนั้นแตกต่างจากข้อความreset --hardหนึ่งและนี่ไม่ใช่สิ่งใดสิ่งหนึ่ง


39
ข้อความไหนดี? เก็บไว้ที่ไหนและจะอ่านในภายหลังได้อย่างไร
Mot

4
หมายเหตุ:วิธีนี้ใช้ไม่ได้กับที่เก็บข้อมูลเปลือย ในที่เก็บเปลือยคุณต้องใช้ 'git branch -f master <commit>' เพื่ออัปเดตสาขา (ดูคำตอบด้านล่าง)
มิถุนายนโรดส์

37
หากเช่นฉันคุณใช้ <branch> โดยไม่ตั้งใจแทนที่จะเป็น refs / heads / <branch> คุณจะพบไฟล์ใหม่ในไดเรกทอรี. git ของคุณที่. git / <branch> และคุณจะได้รับข้อความเช่น "refname 'master' คลุมเครือ" เมื่อคุณพยายามใช้งาน คุณสามารถลบไฟล์จากไดเรกทอรี. git ของคุณเพื่อแก้ไข
David Minor

34
ยังไม่ได้รับการอธิบายถึงความพึงพอใจว่าทำไมมันถึงดีกว่าgit branch -fนี้ วิธีนี้ดูเหมือนจะเป็น: (A) ใช้ยากขึ้น (B) จดจำได้ยากขึ้นและ (C) อันตรายมากขึ้น
Steven Lu

10
"ความหมายที่แท้จริงของการอ้างอิงโดยพลการ" - สาขาไม่ใช่การอ้างอิงชนิดเดียวที่ชี้ไปที่การส่ง มีแท็กและคุณยังสามารถสร้างสไตล์การอ้างอิง / whatevs / myref โดยพลการเองที่ไม่ใช่สาขาหรือแท็ก ฉันเชื่อว่ายังตอบคำถามของ Steven Lu เกี่ยวกับสิ่งที่อาจเป็น "ดีกว่า" ฉันเห็นด้วยกับสาขา -f นั้นง่ายที่สุดถ้าคุณทำงานกับสาขา
อดัม A

964
git branch -f <branch-name> <new-tip-commit>

24
หรือสำหรับ refs git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>โดยพลการ (คุณสามารถเลือก nits เกี่ยวกับข้อความ reflog หากคุณต้องการ - ฉันเชื่อว่าข้อความbranch -fนั้นแตกต่างจากข้อความreset --hardหนึ่งและนี่ไม่ใช่อย่างใดอย่างหนึ่ง)
Cascabel

4
Jefromi โปรดเขียนคำตอบแยกต่างหากเพื่อให้คุณได้รับคะแนนโหวต :)
Mot

16
นี่เป็นคำตอบที่ดีกว่าเนื่องจากสามารถจัดการกับเคสได้ 99% และสอดคล้องกับเอกสารจริง git help branchแจ้งว่า "-f, - บังคับให้รีเซ็ต <branchname> เป็น <startpoint> หากมี <branchname> อยู่แล้วโดยที่ไม่มี -f git branch ปฏิเสธที่จะเปลี่ยนสาขาที่มีอยู่"
AlexChaffee

12
ฉันกำลังทำอยู่git branch -f master <hash>และกำลังบอกฉันว่าfatal: Cannot force update the current branch.ฉันต้องทำอะไรตอนนี้ตรวจสอบสาขาสุ่มอื่นก่อนที่ฉันจะอนุญาตให้ใช้คำสั่งนี้
Qwertie

20
สิ่งนี้จะไม่ทำงานหากสาขาที่คุณต้องการย้ายเป็นสาขาปัจจุบันของคุณ ( HEADชี้ไปที่)
Vladimir Panteleev

135

นอกจากนี้คุณยังสามารถส่งgit reset --hardการอ้างอิงการมอบหมาย

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

git checkout branch-name
git reset --hard new-tip-commit

ฉันพบว่าฉันทำอะไรแบบกึ่งบ่อย:

สมมติว่าประวัตินี้

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

วิธีนี้เหมาะสมที่สุดที่โดยทั่วไปเราใช้ HEAD หรือ HEAD ^ เพื่อย้ายส่วนปลายของสาขาย้อนหลัง ดังนั้นนี่คือความสอดคล้องเพื่อระบุการกระทำข้างหน้า
justingordon

11
นี่เป็นเรื่องปกติถ้าต้นไม้ทำงานของคุณสะอาด หากคุณมีการเปลี่ยนแปลงทั้งแบบ staged และ unstaged จำนวนมากก็น่าจะดีกว่าที่จะทำgit update-refตามที่กล่าวไว้
เงินที่จ่าย nerd

16
คุณสังเกตเห็นว่า“ คำตอบ” ของคุณไม่ได้เพิ่มอะไรที่ไม่ได้เป็นส่วนหนึ่งของคำถามแล้วใช่หรือไม่? - OP กล่าวว่า: ถ้ามีการชำระเงิน ... คุณสามารถใช้git reset --hard ...ไม่จำเป็นต้องทำซ้ำที่นี่! :-(
Robert Siemer

6
@ Robert: ฉันไม่เห็นด้วย คำถามไม่ได้บอกว่าจะใช้มันอย่างไร มันเป็นเรื่องดีที่ไม่ต้องไปมองหามัน
วิลสัน F

7
@ Wilsonson อาจเป็นเรื่องดีสำหรับคุณที่จะพบสิ่งนี้ที่นี่ แต่มันไม่ตอบคำถามเลย บางทีมันอาจจะเป็นคำตอบของคำถามอื่น ๆ บางอย่าง แต่นี่มันเป็นที่ไม่ถูกต้อง
Robert Siemer

52

เพียงเพื่อเพิ่มการอภิปรายหากคุณต้องการย้ายmyBranchสาขาไปสู่การคอมมิชชันปัจจุบันของคุณให้ข้ามอาร์กิวเมนต์ที่สองหลังจากนั้น-f

ตัวอย่าง:

git branch -f myBranch


ฉันมักจะทำสิ่งนี้เมื่อฉันrebaseอยู่ในสถานะ Detached HEAD :)


13

ในgitk --all:

  • คลิกขวาที่การกระทำที่คุณต้องการ
  • -> สร้างสาขาใหม่
  • ป้อนชื่อสาขาที่มีอยู่
  • กด Return บนกล่องโต้ตอบที่ยืนยันการเปลี่ยนสาขาเก่าของชื่อนั้น

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

มันจะเจ๋งถ้าgitkมีคุณสมบัติที่กล่องโต้ตอบมี 3 ตัวเลือก: เขียนทับแก้ไขที่มีอยู่หรือยกเลิก


แม้ว่าโดยปกติคุณจะเป็นคนขี้ยาบรรทัดคำสั่งเหมือนตัวเองgit guiและgitkค่อนข้างได้รับการออกแบบมาอย่างดีสำหรับชุดย่อยของการใช้งานคอมไพล์ที่พวกเขาอนุญาต ฉันขอแนะนำให้ใช้พวกเขาในสิ่งที่พวกเขาทำได้ดี (เช่นการคัดเลือกนักล่าเข้า / ออกดัชนีใน git gui และเพียงแค่ยอมรับ (ctrl-s เพื่อเพิ่มการลงชื่อออก: line, ctrl-enter เพื่อคอมมิท .)

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

ฉันไม่ได้เปิดไฟล์กราฟิกเบราว์เซอร์ แต่ฉันรัก gitk / git gui


1
ง่ายมาก! ฉันอาจเพิ่งเปลี่ยนจาก gitg เป็น gitk
Michael Cole

อย่างไรก็ตามวิธีนี้ข้อมูลสาขาการติดตามจะหายไป
mbdevpl

@mbdevpl: ฉันไม่ใช่ผู้เชี่ยวชาญคอมไพล์ ฉันคิดว่าฉันเข้าใจสิ่งที่คุณหมายถึง แต่ไม่ใช่ความหมาย ฉันใช้มันค่อนข้างบ่อยและยังสามารถผลักกิ่งเหล่านั้นไปยังกิ่งที่มีชื่อเดียวกันบนรีโมทได้ การเชื่อมโยงระหว่างสาขาและสาขาติดตามระยะไกลมีประโยชน์อย่างไรสำหรับคุณ
Peter Cordes


1
@PeterCordes Ineed เมื่อชื่อสาขาไม่ตรงกัน นอกจากนี้เมื่อมีรีโมตมากกว่าหนึ่งตัว เมื่อคุณใช้พรอมต์ git เพื่อแสดงสถานะสาขามันจะแสดงระยะทางส่งไปยังสาขาติดตามของคุณ (ถ้าตั้งค่าไว้) นอกจากนี้git statusเอาต์พุตยังได้รับผลกระทบด้วย นอกจากนี้ในบางกรณีgit fetchและgit pushจะไม่ทำงานโดยไม่ระบุระยะไกลอย่างชัดเจนหากคุณไม่ได้ตั้งสาขาการติดตาม ฉันไม่รู้เกี่ยวกับทุกกรณี แต่สำหรับฉันกฎทั่วไปคือเพื่อความสะดวกและรวดเร็วในการทำงานมันจะดีกว่าถ้ามีการติดตามสาขาตามลำดับ
mbdevpl

7

วิธีการแก้ปัญหาที่แนะนำgit branch -f branch-pointer-to-move new-pointerในTortoiseGit :

  • "บันทึกการแสดง Git"
  • ทำเครื่องหมายที่ "สาขาทั้งหมด"
  • ในบรรทัดที่คุณต้องการให้ตัวชี้สาขาย้ายไปที่ (ตัวชี้ใหม่):
    • คลิกขวา "สร้างสาขาที่เวอร์ชันนี้"
    • ข้าง "Branch" ป้อนชื่อของสาขาที่ต้องการย้าย (Branch-pointer-to-move)
    • ใต้ "ฐานเปิด" ให้ตรวจสอบว่าตัวชี้ใหม่นั้นถูกต้อง
    • ตรวจสอบ "แรง"
    • ตกลง

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

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


4

สุจริตฉันประหลาดใจที่ไม่มีใครคิดเกี่ยวกับgit pushคำสั่ง:

git push -f . <destination>:<branch>

จุด (.) หมายถึงพื้นที่เก็บข้อมูลท้องถิ่นและคุณอาจต้องตัวเลือก -f เพราะปลายทางอาจจะ"หลังคู่ห่างไกล"

แม้ว่าคำสั่งนี้จะใช้ในการบันทึกการเปลี่ยนแปลงของคุณในเซิร์ฟเวอร์ของคุณผลลัพธ์ที่ได้จะเหมือนกับการย้ายสาขาระยะไกล ( <branch>) ไปยังการกระทำเดียวกันกับสาขาท้องถิ่น ( <destination>)


คุณสามารถทำสิ่งนี้ได้โดยไม่ต้อง-fหลีกเลี่ยงการอุดตันในพื้นที่ ตัวอย่างเช่นgit fetch origin && git push . origin/develop:developเป็นรุ่นที่ไม่ต้องชำระเงินซึ่งไม่จำเป็นต้องมีgit checkout develop && git pull --ff-only
btown

1

เปิดไฟล์.git/refs/heads/<your_branch_name>และเปลี่ยนแฮชที่เก็บไว้ในตำแหน่งที่คุณต้องการย้ายส่วนหัวของสาขาของคุณ เพียงแก้ไขและบันทึกไฟล์ด้วยโปรแกรมแก้ไขข้อความใด ๆ เพียงตรวจสอบให้แน่ใจว่าสาขาที่จะแก้ไขไม่ใช่สาขาปัจจุบันที่ใช้งานอยู่

คำเตือน:อาจไม่ใช่วิธีที่แนะนำให้ใช้ แต่อาจทำให้งานเสร็จ


1
ไม่แน่ใจว่านี่เป็นวิธีที่วุ่นวายหรือชั่วร้ายที่จะทำ 🤔😉
Keith Russell

@ KeithRussell อาจเป็นได้ทั้ง: P
Guillermo Gutiérrez

0

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

git merge <commit>

คำถามที่ถามเกี่ยวกับสิ่งที่ต้องทำหากสาขาไม่ได้ชำระเงิน
Keith Russell

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