วิธีแก้ไขการผูกสาขา Git ที่ไม่ถูกต้อง


621

ฉันเพิ่งทำดีมุ่งมั่นที่จะผิดสาขา ฉันจะยกเลิกการคอมมิชชันล่าสุดในสาขาหลักของฉันจากนั้นทำการเปลี่ยนแปลงเหล่านั้นและนำพวกเขาไปสู่การอัพเกรดสาขาของฉันได้อย่างไร

คำตอบ:


975

หากคุณยังไม่ได้ทำการเปลี่ยนแปลงคุณสามารถทำการรีเซ็ตแบบซอฟต์:

git reset --soft HEAD^

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

git checkout branch
git commit

ข้อเสียคือคุณต้องป้อนข้อความยืนยันของคุณอีกครั้ง


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

9
การแก้ไขที่สมบูรณ์แบบจริง ๆ แล้วมีสักสองสามอย่างที่ทำดังนั้น HEAD ^^ และแบมทั้งหมดเป็นน้ำเกรวี่
pablo

8
ขอบคุณ สิ่งนี้ช่วยฉันสองครั้ง หากสาขาแตกต่างกันบ้างหลังจากรีเซ็ตและก่อนเช็คเอาต์คุณอาจต้องทำการเปลี่ยนแปลงก่อนที่คุณจะสามารถชำระเงินสาขาอื่น ใช้การสะสมอีกครั้งหลังจากเช็คเอาท์
Kirby

17
ผู้ใช้ zsh: คุณอาจพบว่าคุณต้องหลบหนี ^ like ดังนี้:git reset --soft HEAD\^
Stephen Fuhry

54
ถ้าคุณได้รับเพิ่มเติม ในบรรทัดคำสั่ง Windows ของคุณใช้เครื่องหมายคำพูดเพื่อล้อมรอบ HEAD ^ ดังนี้: git reset - soft "HEAD ^"
Nate Cook

140

4 ปีในหัวข้อ แต่อาจเป็นประโยชน์กับใครบางคน

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

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

ตอนนี้คุณมีสาขาหลักของคุณเท่ากับและใหม่กระทำทั้งหมดที่อยู่บนorigin/master my_featureโปรดทราบว่าmy_featureเป็นสาขาท้องถิ่นไม่ใช่สาขาระยะไกล


ขอบคุณสำหรับคำตอบ. ตอนนี้ฉันใช้ egit และฉันสงสัยว่าฉันสามารถทำสิ่งเดียวกันได้โดยทำสิ่งต่อไปนี้: 1) เปลี่ยนชื่อ 'ต้นแบบ' ปัจจุบันเป็น 'my_feature' 2) สร้าง 'ต้นแบบ' ท้องถิ่นจาก 'ต้นกำเนิด / ต้นแบบ' ฉันไม่แน่ใจว่าสิ่งที่ egit จะทำภายใต้ประทุนสำหรับการดำเนินการเหล่านี้ แต่ดูเหมือนว่าจะเป็นทางออกที่ทำงานได้
mjj1409

ทำไมถึงผสาน? คุณสามารถสร้างสาขาโดยตรงบนmasterแล้วรีเซ็ตไปmaster origin/master
caesarsol

1
นั่นเป็นส่วนที่น่าสนใจที่สุด: คุณไม่จำเป็นต้องมีจำนวนการคอมมิชชันเพราะorigin/masterอยู่ในคอมมิทที่คุณต้องการรีเซ็ตที่! เครดิตสำหรับคำแนะนำอยู่ที่หน้านี้: github.com/blog/…
caesarsol

4
นี่ควรเป็นคำตอบที่ยอมรับได้ ง่ายชัดเจนตรงไปตรงมาทำงานได้โดยไม่คำนึงถึงจำนวนการกระทำและใช้ฟังก์ชัน Git ขั้นพื้นฐานเท่านั้น ฉันทำตามขั้นตอนเหล่านี้กับ TortoiseGit ขอบคุณ! :)
Ian Grainger

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

111

หากคุณมีสำเนาการทำงานที่สะอาด (ไม่ได้แก้ไข)

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

git reset --hard HEAD^

ในการดึงสิ่งนั้นเข้าสู่สาขาอื่น:

git checkout other-branch
git cherry-pick COMMIT-HASH

หากคุณมีการเปลี่ยนแปลงหรือไม่ได้ติดตามการเปลี่ยนแปลง

นอกจากนี้โปรดทราบว่าgit reset --hardจะฆ่าการเปลี่ยนแปลงที่ไม่ได้ติดตามและแก้ไขใด ๆ ที่คุณอาจมีดังนั้นหากคุณมีสิ่งที่คุณต้องการ:

git reset HEAD^
git checkout .

git rev-parse BRANCH_NAMEเพื่อรับ Sha
wilhelmtell

12
หากคุณลืมที่จะสังเกตแฮชก่อนอื่นเพียงใช้git reflog show <branch>!
Cascabel

2
@Jefromi ฉันกลัวที่นั่นหนึ่งนาที
Ian Hunter

13
เพื่อความรู้สึกปลอดภัยเป็นพิเศษให้เลือกเชอร์รี่ก่อนจากสาขาที่ถูกต้องจากนั้นทำการรีเซ็ตสาขาที่ไม่ถูกต้อง
อายุ Mooij

1
นอกจากนี้ในกรณีที่มีการเปลี่ยนแปลงที่ไม่ได้ติดตามใครสามารถgit stashรีเซ็ตและใช้ในgit stash popภายหลังเพื่อกู้คืนดังนั้นจึงไม่ต้องกลัวชิ้น--hardส่วน
Clemens Klein-Robbenhaar

20

หากคุณผลักดันการเปลี่ยนแปลงของคุณแล้วคุณจะต้องบังคับให้กดครั้งต่อไปหลังจากรีเซ็ต HEAD

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

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

ในกรณีบน Windows (ใช้บรรทัดคำสั่งของ Windows ไม่ใช่ Bash) จริงๆแล้วมันคือสี่^^^^แทนหนึ่งดังนั้นจึงเป็น

git reset --hard HEAD^^^^

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

2
หรือถ้าคุณไม่เข้าใจอย่างรวดเร็วพอก่อนที่คนอื่นจะดึงความผิดพลาด
Michael Mior

หากการกระทำมากกว่าหนึ่งรายการคุณสามารถระบุการมอบหมายที่คุณต้องการ: git reset --hard COMMIT_HASH git push --force
David Cramblett

17

เมื่อเร็ว ๆ นี้ฉันได้ทำสิ่งเดียวกันโดยที่ฉันตั้งใจจะเปลี่ยนเป็นนายเมื่อฉันควรผูกมัดกับสาขาอื่น แต่ฉันไม่ได้ผลักดันอะไรเลย

หากคุณเพียงแค่มุ่งมั่นที่จะผิดสาขาและไม่ได้เปลี่ยนแปลงอะไรเลยตั้งแต่และไม่ได้ผลักไปที่ repo คุณสามารถทำสิ่งต่อไปนี้:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

หมายเหตุ: ในตัวอย่างข้างต้นฉันกำลังกรอกซ้ำ 1 คอมมิตด้วย git reset HEAD ~ 1 แต่ถ้าคุณต้องการกรอ n ทำซ้ำคุณสามารถทำการรีเซ็ต HEAD ~ n ได้

นอกจากนี้หากคุณจบลงด้วยการยอมรับผิดสาขาและจบลงด้วยการเขียนรหัสเพิ่มเติมก่อนที่จะตระหนักว่าคุณมุ่งมั่นที่จะผิดสาขาคุณสามารถใช้ git stash เพื่อบันทึกงานที่กำลังดำเนินการอยู่:

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

หมายเหตุ: ฉันใช้เว็บไซต์นี้เป็นข้อมูลอ้างอิง https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/


สิ่งที่คล้ายกันเกิดขึ้นกับฉันฉันยอมรับการเปลี่ยนแปลงบางอย่างในระดับปริญญาโท แต่ฉันควรจะทำในสาขาใหม่และส่ง PR ฉันลงเอยด้วยการทำgit checkout -b new_branchถูกต้องจากที่นั่นมุ่งมั่นเหมือนเดิมผลักดันและสร้าง PR ทำไม่ได้ ' ไม่ต้องทำอีก
Nishchal Gautam

11

ดังนั้นหากสถานการณ์ของคุณคือการที่คุณมุ่งมั่นที่จะmasterแต่มุ่งมั่นที่จะanother-branch(ซึ่งอาจหรือไม่อาจไม่ได้อยู่) แต่คุณยังไม่ได้ผลักมันเป็นเรื่องง่ายที่จะแก้ไข

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

ตอนนี้สิ่งที่กระทำของคุณเพื่อจะอยู่ในmasteranother-branch

แหล่งข่าวด้วยความรักจาก: http://haacked.com/archive/2015/06/29/git-migrate/


น่าจะเป็นวิธีที่ตรงไปตรงมาที่สุด! ไม่แน่ใจว่าทำไมความรักและการอัปเดตน้อยมาก
keligijus

4
ดูเหมือนจะไม่เหมาะกับฉัน another-branchมีอยู่แล้ว another-branchในกรณีนี้มันเป็นเพียงแค่อบกระทำที่ฉันต้องการทำจะโทและไม่ได้นำพวกเขาใน
Giselle Serate

6

หากต้องการคำอธิบายนี้อย่างละเอียดในกรณีที่คุณมีหลายข้อผูกมัดที่จะย้ายจากตัวอย่างเช่นdevelopไปที่new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started

1
ฉันมีความมุ่งมั่นสามอย่างที่จะยกเลิกและคำถามนี้ดูเหมือนจะดึงลาออกจากไฟ ขอบคุณ!
holdenweb

3

หากคุณพบปัญหานี้และคุณมี Visual Studio คุณสามารถทำสิ่งต่อไปนี้:

คลิกขวาที่สาขาของคุณและเลือกView History:

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

คลิกขวาที่คอมมิทที่คุณต้องการกลับไป และย้อนกลับหรือรีเซ็ตตามต้องการ

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


3

สำหรับหลายกระทำในสาขาที่ไม่ถูกต้อง

หากคุณเป็นเพียงแค่ประมาณ 1 กระทำแล้วมีโซลูชั่นการตั้งค่าที่ง่ายขึ้นมากมาย สำหรับฉันฉันมีประมาณ 10 คอมมิทที่ทำขึ้นโดยไม่ตั้งใจmasterแทนที่จะเรียกมันbranch_xyzมาและฉันไม่ต้องการที่จะสูญเสียประวัติการกระทำ

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

  1. สร้างสาขาชั่วคราวใหม่จาก master
  2. ผสานเข้ากับสาขาเดิมที่มีไว้เพื่อกระทำเช่น branch_xyz
  3. เลิกทำ master
  4. ลบสาขาชั่วคราว

นี่คือขั้นตอนข้างต้นในรายละเอียด -

  1. สร้างสาขาใหม่จากmaster(ซึ่งฉันได้กระทำการเปลี่ยนแปลงจำนวนมากโดยไม่ได้ตั้งใจ)

    git checkout -b temp_branch_xyz
    

    หมายเหตุ: การ-bตั้งค่าสถานะใช้เพื่อสร้างสาขาใหม่
    เพียงเพื่อตรวจสอบว่าเรามีสิทธิ์นี้หรือไม่ฉันจะทำอย่างรวดเร็วgit branchเพื่อให้แน่ใจว่าเราอยู่ในtemp_branch_xyzสาขาและ a git logเพื่อตรวจสอบว่าเราได้รับสิทธิ์หรือไม่

  2. branch_xyzผสานสาขาชั่วคราวลงในสาขาเดิมตั้งใจสำหรับการกระทำคือ
    ก่อนอื่นให้เปลี่ยนเป็นสาขาเดิมbranch_xyz(คุณอาจจำเป็นต้องใช้git fetchหากยังไม่ได้)

    git checkout branch_xyz
    

    หมายเหตุ: ไม่ได้ใช้-bแฟล็ก
    ตอนนี้ให้รวมสาขาชั่วคราวเข้ากับสาขาที่เราได้ชำระเงินตอนนี้branch_xyz

    git merge temp_branch_xyz
    

    คุณอาจต้องดูแลความขัดแย้งบางอย่างที่นี่ถ้ามี คุณสามารถผลักดัน (ฉันต้องการ) หรือไปยังขั้นตอนถัดไปหลังจากรวมสำเร็จแล้ว

  3. เลิกทำโดยไม่ตั้งใจmasterโดยใช้คำตอบนี้เป็นข้อมูลอ้างอิงก่อนอื่นให้เปลี่ยนเป็นmaster

    git checkout master
    

    จากนั้นเลิกทำการย้อนกลับเพื่อจับคู่รีโมต (หรือเฉพาะการกระทำหากคุณต้องการ)

    git reset --hard origin/master
    

    อีกครั้งฉันจะทำgit logก่อนและหลังเพียงเพื่อให้แน่ใจว่าการเปลี่ยนแปลงที่ตั้งใจมีผลบังคับใช้

  4. การลบหลักฐานที่เป็นการลบสาขาชั่วคราว สำหรับสิ่งนี้ก่อนอื่นคุณต้องทำการเช็คเอาท์สาขาที่ temp ถูกรวมเข้าไว้นั่นคือbranch_xyz(หากคุณยังคงอยู่masterและดำเนินการคำสั่งด้านล่างคุณอาจได้รับ a error: The branch 'temp_branch_xyz' is not fully merged) ดังนั้นลองมา

    git checkout branch_xyz
    

    แล้วลบหลักฐานของอุบัติเหตุนี้

    git branch -d temp_branch_xyz
    

ไปแล้ว


1

หากสาขาที่คุณต้องการใช้การเปลี่ยนแปลงของคุณมีอยู่แล้ว ( ตัวอย่างเช่นการพัฒนาสาขา) ให้ทำตามคำแนะนำของfotanusด้านล่างจากนั้น:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

และแน่นอนคุณสามารถใช้tempbranchหรือชื่อสาขาอื่นแทนmy_featureหากคุณต้องการ

นอกจากนี้หากทำได้ให้ชะลอการสะสมป๊อป (นำไปใช้) จนกระทั่งหลังจากที่คุณรวมเข้ากับสาขาเป้าหมายของคุณ


ฉันคิดว่าคำสั่งแรก (การพัฒนาการชำระเงิน) นั้นไม่จำเป็น ... การรีบูตเครื่องจะทำการเช็คเอาต์ "my_feature" อย่างแรกเลย
JoelFan

นอกจากนี้คุณยังสามารถออกจากพารามิเตอร์ "my_feature" ของคำสั่ง "rebase" (เนื่องจากคุณได้ตรวจสอบแล้ว "my_feature") คุณยังสามารถละทิ้งพารามิเตอร์ "พัฒนา" ของ "ผสาน" (เนื่องจากคุณชำระเงินแล้ว "พัฒนา")
JoelFan

1

สำหรับฉันนี่คือการแก้ไขโดยการคืนความมุ่งมั่นที่ฉันผลักแล้วเชอร์รี่หยิบที่กระทำกับสาขาอื่น

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

คุณสามารถใช้git logเพื่อค้นหาแฮชที่ถูกต้องและคุณสามารถผลักดันการเปลี่ยนแปลงเหล่านี้ได้ทุกเมื่อที่คุณต้องการ!

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