ฉันจะย้าย HEAD กลับไปยังตำแหน่งก่อนหน้าได้อย่างไร (หัวเดี่ยว) & เลิกทำ


179

ใน Git ฉันพยายามทำsquash commitโดยรวมสาขาอื่นแล้วรีเซ็ตHEADเป็นสถานที่ก่อนหน้าผ่าน:

git reset origin/master

แต่ฉันต้องก้าวออกจากนี้ ฉันจะย้าย HEAD กลับไปยังตำแหน่งก่อนหน้าได้อย่างไร

ฉันมี SHA-1 fragment ( 23b6772) ของการกระทำที่ฉันต้องการย้ายไป ฉันจะกลับไปที่การกระทำนี้ได้อย่างไร?


12
HEAD เป็นเพียงตัวชี้ตำแหน่งปัจจุบันของคุณ (หรือการแก้ไขเพื่อความแม่นยำ) git checkout 23b6772ควรทำ.
ดูแล Yaroslav


1
@YaroslavAdmin ไม่มันควรไม่ การตรวจสอบการกระทำโดยตรงคือสาเหตุที่สถานะ HEAD ที่แยกออกเกิดขึ้น (เนื่องจากสาขาการติดตามระยะไกลไม่สามารถตรวจสอบได้ด้วยตนเองและเลื่อนการกระทำโดยอัตโนมัติไปที่การกระทำที่พวกเขาชี้ไปที่เมื่อคุณพยายามทำเช่นเดียวกับ OP) ความคิดเห็น :-) ฉันเรียงลำดับของความหวังว่าปัญหาเริ่มต้นจะได้รับการแก้ไขแล้ว ...
244

คำตอบ:


398

ก่อนที่จะตอบลองเพิ่มพื้นหลังอธิบายว่านี่HEADคืออะไร

First of all what is HEAD?

HEADเป็นเพียงการอ้างอิงถึงการกระทำปัจจุบัน (ล่าสุด) ในสาขาปัจจุบัน
สามารถมีได้เพียงครั้งเดียวHEADในเวลาที่กำหนด (ไม่รวมgit worktree)

เนื้อหาของHEADจะถูกเก็บไว้ภายใน.git/HEADและประกอบด้วย 40 ไบต์ SHA-1 ของการกระทำปัจจุบัน


detached HEAD

หากคุณไม่ได้อยู่บนล่าสุดกระทำ - ความหมายที่จะชี้ไปก่อนกระทำในประวัติศาสตร์ก็เรียกว่าHEADdetached HEAD

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

บนบรรทัดคำสั่งจะมีลักษณะเช่นนี้ - SHA-1 แทนชื่อสาขาเนื่องจากHEADไม่ได้ชี้ไปที่ปลายของสาขาปัจจุบัน:

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

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


ตัวเลือกบางอย่างเกี่ยวกับวิธีการกู้คืนจาก HEAD เดี่ยว:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

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

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

คุณสามารถใช้reflogเช่นกัน
git reflog จะแสดงการเปลี่ยนแปลงใด ๆ ที่มีการปรับปรุงHEADและการตรวจสอบรายการ reflog ที่ต้องการจะตั้งค่าHEADกลับไปที่การกระทำนี้

ทุกครั้งที่มีการแก้ไข HEAD จะมีรายการใหม่ใน reflog

git reflog
git checkout HEAD@{...}

สิ่งนี้จะนำคุณกลับสู่ความมุ่งมั่นที่คุณต้องการ

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


git reset --hard <commit_id>

"ย้าย" HEAD ของคุณกลับไปยังการกระทำที่ต้องการ

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • หมายเหตุ: ( ตั้งแต่ Git 2.7 ) คุณสามารถใช้งานได้git rebase --no-autostashเช่นกัน

git revert <sha-1>

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

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

คีมานี้แสดงให้เห็นว่าคำสั่งใดทำอะไร
ที่คุณสามารถดูมีการปรับเปลี่ยนreset && checkoutHEAD

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


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

คุณสามารถอยู่ใน HEAD HEAD และในเวลาเดียวกันก็มีสาขาที่มีความมุ่งมั่นเช่นเดียวกับ HEAD ของสาขานี้ ฉันไม่เข้าใจความคิดเห็นของคุณ
CodeWizard

3
ผมมีปัญหาเกี่ยวกับการใช้งานของอินไลน์รหัสสำหรับมาร์กอัปหัว :)
jub0bs

ไม่สามารถหาวิธีที่ดีกว่าที่จะเน้นมัน อย่าลังเลที่จะแก้ไข คุณเป็นมากกว่าการต้อนรับ
CodeWizard

22

ทำ

git reset 23b6772

เพื่อดูว่าคุณอยู่ในตำแหน่งที่ถูกต้องหรือไม่:

git status

คุณจะเห็นบางสิ่ง

ในสาขาหลักสาขาของคุณอยู่หลัง 'ต้นกำเนิด / หลัก' โดย 17 คอมมิทและสามารถส่งต่อได้อย่างรวดเร็ว

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

git push --force-with-lease // a useful command @oktober mentions in comments

1
เป็นที่น่าทึ่งgit push --forceอย่างมากด้วย ในหลาย ๆ สถานการณ์มันจะทำให้คุณเป็นคนที่ได้รับความนิยมน้อยที่สุดในทีมชั่วขณะหนึ่ง ....
Kay V

เพื่อเพิ่มในบันทึกย่อด้านบนฉันเพิ่งเจอข้อความนี้ที่about.gitlab.com/blog/2014/11/26/keeping-your-code-protectedและต้องเพิ่ม: "คำสั่ง git push --force เดียว สามารถทำลายวันของคนจำนวนมากได้อย่างง่ายดาย: [186 เจนกินส์] ที่เก็บของมีหัวสาขาของพวกเขาย้อนกลับไปชี้ไปที่ความมุ่งมั่นที่มีอายุมากกว่า
Kay V

2
@KayV ดูที่git push --force-with-lease(บทความ Thoughtbot: thoughtbot.com/blog/git-push-force-with-lease )
ตุลาคม

1
ธงที่มีประโยชน์ @oktober และบทความที่ดี ขอขอบคุณที่เพิ่มที่นี่และส่งเรื่องนี้ให้ฉัน
Kay V

1
ขอบคุณ! สิ่งนี้ช่วยฉันในการยกเลิกการรวมที่ไม่ดี เนื่องจากการรวมกันไม่ตอบสนองในลักษณะเดียวกับrevertที่กระทำฉันพบว่าตัวเองอยู่ในสถานการณ์ที่ยากลำบากอย่างไม่น่าเชื่อ force-with-leaseให้ความมั่นใจแก่ฉันในการเขียนประวัติศาสตร์คอมไพล์ของสาขาโดยไม่กระทบต่องานของคนอื่น ไชโย!
anon58192932

11

ทางออกที่เร็วที่สุดที่เป็นไปได้ (เพียง 1 ขั้นตอน)

ใช้ git checkout -

Switched to branch <branch_name>คุณจะเห็น ยืนยันว่าเป็นสาขาที่คุณต้องการ


คำอธิบายสั้น ๆ : คำสั่งนี้จะย้าย HEAD กลับไปที่ตำแหน่งสุดท้าย ดูบันทึกเกี่ยวกับผลลัพธ์ในตอนท้ายของคำตอบนี้


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


วิธีแก้ปัญหาที่เป็นระเบียบมากขึ้น (2 ขั้นตอน แต่น่าจดจำ)

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

1. เลือกสาขาที่คุณต้องการ

ใช้ git branch -v

คุณเห็นรายการสาขาท้องถิ่นที่มีอยู่ คว้าชื่อสาขาที่คุณต้องการ

2. ย้าย HEAD ไปที่

ใช้ git checkout <branch_name>

Switched to branch <branch_name>คุณจะเห็น ที่ประสบความสำเร็จ!


ผลลัพธ์

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

โปรดทราบว่าทั้งสองgit checkout -และgit checkout <branch_name>จะให้คำแนะนำเพิ่มเติมหากคุณยอมรับการเปลี่ยนแปลงในขณะที่ถอด HEAD ออก


สิ่งนี้ไม่ทำงานเพราะถ้าฉันทำ (สมมติว่า 8acc968 เป็น HEAD ~ 2) git checkout 8acc968ก็git branch -vมีMyBranchอยู่ในรายการด้านล่าง ... แต่แล้วก็git checkout MyBranchลบความคิดเห็นของฉัน
amuliar

สวัสดี @amuliar - git checkout 8acc968จะตรวจสอบการกระทำไม่ใช่สาขา หากมีการกระทำที่คุณต้องการลองMyBranch git checkout MyBranchหากไม่มีการเปลี่ยนแปลงในการส่ง 8acc968 คุณจะต้องรวมการเปลี่ยนแปลงเหล่านั้นหลังจากตรวจสอบสาขา
Kay V

ขอบคุณสำหรับคำตอบ! ฉันได้git checkoutเห็นคอมมิชชันก่อนหน้าและต้องการกลับไปใช้คอมมิชชันล่าสุด แต่ถ้าไม่มีแฮชการล่าสุดฉันก็หายไปมาก วิธีนี้เหมาะสำหรับสถานการณ์ของฉัน!
zyy

4

คำถามที่สามารถอ่านได้เป็น:

ฉันอยู่ในสถานะเดี่ยวกับHEADที่23b6772และพิมพ์git reset origin/master(เพราะฉันต้องการสควอช) ตอนนี้ฉันเปลี่ยนใจแล้วฉันจะกลับไปHEADเป็นยัง23b6772ไงได้อีก?

คำตอบที่ตรงไปตรงมาคือ: git reset 23b6772

แต่ฉันตีคำถามนี้เพราะฉันพิมพ์ (คัดลอก & วาง) กระทำการแฮชหรือตัวย่อของมันทุกครั้งที่ฉันต้องการอ้างอิงก่อนหน้านี้HEADและ Googling เพื่อดูว่ามีชวเลขชนิดใด

ปรากฎว่ามี!

git reset -(หรือในกรณีของฉันgit cherry-pick -)

ซึ่งบังเอิญเป็นเช่นเดียวกับcd -การกลับไปยังไดเรกทอรีปัจจุบันก่อนหน้าใน * ระวัง! ดังนั้นฉันจึงเรียนรู้สองสิ่งด้วยหินก้อนเดียว


0

เมื่อคุณเรียกใช้คำสั่งgit checkout commit_idHEAD 13ca5593d(say commit-id)จะถูกแยกจากและสาขาจะพร้อมใช้งานอีกต่อไป

ย้ายกลับไปที่ตำแหน่งก่อนหน้าเรียกใช้ขั้นตอนคำสั่งที่ชาญฉลาด -

  1. git pull origin branch_name (พูดว่าเจ้านาย)
  2. git checkout branch_name
  3. git pull origin branch_name

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


0

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

git push origin HEAD: <My-remote-branch>

แล้วก็

git checkout <My-remote-branch>

แล้วก็

git pull

ในที่สุดฉันก็มีการเปลี่ยนแปลงทั้งหมดในสาขาของฉันที่ฉันทำไว้ในการถอด HEAD


0

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

สมมติว่าชื่อสาขาของคุณเป็นสาขา xxx

ขั้นตอนในการแก้ไข:

  • อย่าอัพเดทหรือดึง - ไม่ทำอะไรเลย
  • เพียงแค่สร้างสาขาใหม่ ( branch-yyy ) จากbranch-xxxบนเครื่องของเขา
  • นั่นคือทั้งหมดการเปลี่ยนแปลงที่มีอยู่ทั้งหมดของคุณจะอยู่ในสาขาใหม่นี้ ( branch-yyy ) คุณสามารถทำงานกับสาขานี้ต่อไป

หมายเหตุ: นี่ไม่ใช่โซลูชันทางเทคนิค แต่จะช่วยได้อย่างแน่นอน

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