จำเป็นต้องรีเซ็ตสาขา git เป็นเวอร์ชั่นเริ่มต้น


439

ฉันตั้งใจทำงานในสาขาที่ฉันไม่ควรจะอยู่พักหนึ่งดังนั้นฉันจึงแยกชื่อมันออกมาเป็นชื่อที่เหมาะสม ตอนนี้ฉันต้องการที่จะเขียนทับสาขาที่ฉันไม่ควรได้รับในรุ่นจากแหล่งกำเนิด (github) มีวิธีง่าย ๆ ในการทำเช่นนี้? ฉันพยายามลบสาขาแล้วทำการรีเซ็ตสาขาการติดตาม แต่มันให้รุ่นที่ฉันทำงานอีกครั้ง



ด้วย Git 2.23 (สิงหาคม git switch -C mybranch origin/mybranch2019): ดูคำตอบที่แก้ไขของฉันด้านล่าง
VonC

คำตอบ:


814

หากคุณยังไม่ได้เริ่มต้นคุณสามารถรีเซ็ตสาขาของคุณเป็นสาขาต้นน้ำด้วย:

git checkout mybranch
git reset --hard origin/mybranch

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

โปรดทราบว่าหลังจากรีเซ็ตแล้วmybranch@{1}หมายถึงการคอมมิชชันเก่าก่อนรีเซ็ต

แต่ถ้าคุณผลักไปแล้วโปรดดู " สร้างสาขา git และเปลี่ยนกลับเป็นสถานะต้นน้ำ " สำหรับตัวเลือกอื่น ๆ


ด้วยGit 2.23 (สิงหาคม 2019)git switchที่จะเป็นหนึ่งในคำสั่ง:
กล่าวคือ:git switch -C mybranch origin/mybranch

ตัวอย่าง

C:\Users\vonc\git\git>git switch -C master origin/master
Reset branch 'master'
Branch 'master' set up to track remote branch 'master' from 'origin'.
Your branch is up to date with 'origin/master'.

ที่เรียกคืนดัชนีและการทำงานต้นไม้เหมือนgit reset --hardจะ


ในฐานะที่เป็นความเห็นโดยแบรดเฮอร์แมนที่reset --hardจะลบไฟล์ใหม่หรือรีเซ็ตแฟ้มที่แก้ไขโดยไปที่หัว

ที่จริงให้แน่ใจว่าคุณเริ่มต้นจาก "กระดานชนวนสะอาด" ซึ่งเป็นgit clean -f -dหลังจากรีเซ็ตจะให้ต้นไม้ทำงานตรงเหมือนกันกับสาขาที่คุณเพิ่งรีเซ็ต


โพสต์บล็อกนี้แนะนำนามแฝงเหล่านั้น (สำหรับmasterสาขาเท่านั้น แต่คุณสามารถปรับเปลี่ยน / ขยายได้):

[alias]
   resetorigin = !git fetch origin && git reset --hard origin/master && git clean -f -d
   resetupstream = !git fetch upstream && git reset --hard upstream/master && git clean -f -d

จากนั้นคุณสามารถพิมพ์:

git resetupstream

หรือ

git resetorigin

26
สิ่งนี้จะลบการเปลี่ยนแปลงที่ไม่ได้รับการจัดเก็บ / จัดลำดับ (จาก
Peter Ehrlich

5
ฉันใช้git reset --hard origin/mybranchคำสั่งหลายครั้งเมื่อฉันไม่สนใจเกี่ยวกับการเปลี่ยนแปลงในท้องถิ่นและต้องการสำเนาที่สะอาดซึ่งตรงกับที่มา อย่างไรก็ตามในวันนี้สิ่งนี้ไม่ได้ผล - ฉันยังคงมีไฟล์ใหม่ ๆ ที่ยังไม่มีการจัดการจำนวนหนึ่งและคอมไพล์ก็ให้คำมั่นสัญญากับฉันว่ามันเป็นที่ HEAD หมายเหตุเกี่ยวกับการgit clean -f -dแก้ไขนั้นโดยการลบไฟล์ใหม่ทั้งหมดที่ฉันไม่ต้องการ
Matthew Clark

@MatthewClark ที่คาดไว้: ดูความคิดเห็นในstackoverflow.com/q/4327708/6309
VonC

1
ที่ดี! หลายครั้งที่ฉันคุ้นเคยgit reset --hard HEADกับการย้อนกลับไปใช้การกระทำก่อนหน้าโดยไม่สนใจการเปลี่ยนแปลงใด ๆ
daronwolff

เป็นไปได้ด้วย sourctree ด้วยหรือไม่
Lonzak

20

สมมติว่านี่เป็นสิ่งที่เกิดขึ้น:

# on branch master
vi buggy.py                 # you edit file
git add buggy.py            # stage file
git commit -m "Fix the bug" # commit
vi tests.py                 # edit another file but do not commit yet

จากนั้นคุณตระหนักว่าคุณทำการเปลี่ยนแปลงในสาขาที่ไม่ถูกต้อง

git checkout -b mybranch    # you create the correct branch and switch to it

แต่masterยังคงชี้ไปที่ความมุ่งมั่นของคุณ คุณต้องการให้จุดที่ชี้ไปก่อน

สารละลาย

วิธีที่ง่ายที่สุดคือ:

git branch --force master origin/master

อีกวิธีคือ:

git checkout master
git reset --soft origin/master
git checkout mybranch

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


นั่นดูเหมือนปลอดภัยกว่าคำตอบของฉัน;) +1
VonC

8

ฉันมี repo ส่วนตัวบนเซิร์ฟเวอร์และ rebase / force-push เป็นประจำซึ่งทำให้จำเป็นต้องรีเซ็ตสาขาในเครื่องบนคอมพิวเตอร์เครื่องอื่นของฉันบ่อยๆ ฉันจึงสร้างนามแฝง "catchup" ซึ่งอนุญาตให้ทำสิ่งนี้กับสาขาปัจจุบัน ซึ่งแตกต่างจากคำตอบอื่น ๆ ไม่มีชื่อสาขา hardcoded ในนามแฝงนี้

ยึดมั่นในแน่น.

[alias]
  catchup = "!f(){ echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \"; read -r ans; if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)); else echo \"catchup aborted\"; fi }; f"

รูปแบบที่เหมาะสม (จะไม่ทำงานกับบรรทัดใหม่ใน. gitconfig) ซึ่งมีลักษณะดังนี้:

"
!f(){
  echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \";
  read -r ans;
  if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then
    git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD));
  else
    echo \"catchup aborted\";
  fi
}; f
"
  • \\033[0;33mและ\\033[0mสำหรับการเน้นสาขาในปัจจุบันและต้นน้ำที่มีสี
  • $(git symbolic-ref -q --short HEAD) เป็นชื่อสาขาปัจจุบัน
  • $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)) คือต้นน้ำของสาขาปัจจุบัน

เนื่องจากการรีเซ็ตเป็นการโทรที่อาจเป็นอันตราย (โดยเฉพาะอย่างยิ่งเมื่อใช้ตัวเลือก - ฮาร์ดคุณจะสูญเสียการเปลี่ยนแปลงใด ๆ ที่ไม่ปราศจากข้อผูกมัด) ดังนั้นจึงเป็นการบอกก่อนว่าคุณกำลังจะทำอะไร ตัวอย่างเช่นหากคุณอยู่ในสาขาdev-container ที่มีรีโมทเรียกว่าqcpp / dev-containerและคุณป้อนgit catchupคุณจะได้รับแจ้ง:

รีเซ็ต dev-container เป็น qcpp / dev-container หรือไม่ (Y / N)

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

หากคุณต้องการที่จะปลอดภัยสุดและโปรแกรมป้องกันการสูญเสีย unstaged / เปลี่ยนแปลงปราศจากข้อผูกมัดคุณสามารถแมงดานามแฝงดังกล่าวข้างต้นต่อไปด้วยการตรวจสอบตามสำหรับ diff

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


1

ฉันลองและไม่ได้รีเซ็ตสาขาปัจจุบันของฉันเป็น Github ระยะไกลล่าสุด ฉัน googled และพบ https://itsyndicate.org/blog/how-to-use-git-force-pull-properly/

ซึ่งแนะนำ

git fetch origin master
git reset --hard origin/master

ฉันต้องการที่จะรีเซ็ตสาขา v8 ของฉันดังนั้นฉันได้

git fetch origin v8
git reset --hard origin/v8

และมันก็ใช้งานได้


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