เลิกทำส่วนหนึ่งของการเปลี่ยนแปลงที่ไม่คงที่ในคอมไพล์


158

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

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

ใช้งานได้ แต่จะดีถ้ามีบางอย่างที่เหมือนกับgit commit --interactiveการคืนค่าการเปลี่ยนแปลงเท่านั้น มีวิธีไหนที่ดีกว่านี้?

คำตอบ:


264

คุณสามารถใช้git checkout -pซึ่งช่วยให้คุณเลือก hunks แต่ละตัวจากส่วนต่างระหว่างสำเนาการทำงานและดัชนีของคุณเพื่อย้อนกลับ ในทำนองเดียวกันgit add -pช่วยให้คุณเลือก hunks เพื่อเพิ่มไปยังดัชนีและgit reset -pช่วยให้คุณสามารถเลือก hunks แต่ละตัวจากความแตกต่างระหว่างดัชนีและ HEAD เพื่อกลับออกจากดัชนี

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

หากคุณต้องการถ่ายภาพพื้นที่เก็บข้อมูล git ของคุณล่วงหน้าเพื่อเก็บการเปลี่ยนแปลงเหล่านี้ไว้ก่อนที่จะคืนค่าฉันต้องการ:

$ git stash; git stash apply

หากคุณใช้บ่อยคุณอาจต้องการนามแฝง:

[alias]
    checkpoint = !git stash; git stash apply

ย้อนกลับ hunks บุคคลหรือสายอาจจะง่ายยิ่งขึ้นถ้าคุณใช้โหมดการแก้ไขที่ดีหรือปลั๊กอินซึ่งอาจให้การสนับสนุนสำหรับการเลือกสายโดยตรงเพื่อย้อนกลับไปเช่น-pอาจจะเป็นเงอะงะบิตเพื่อใช้ในบางครั้ง ฉันใช้Magitโหมด Emacs ที่มีประโยชน์มากสำหรับการทำงานกับ Git ใน Magit คุณสามารถเรียกใช้magit-statusค้นหาความแตกต่างสำหรับการเปลี่ยนแปลงที่คุณต้องการเปลี่ยนกลับเลือกบรรทัดที่คุณต้องการเปลี่ยนกลับ (หรือเพียงวางเคอร์เซอร์บน hunks ที่คุณต้องการเปลี่ยนกลับหากคุณต้องการเปลี่ยนก้อนใหญ่ในเวลาเดียวแทน บรรทัดต่อครั้ง) และกดkเพื่อเปลี่ยนกลับบรรทัดที่ระบุเหล่านั้น ฉันขอแนะนำ Magit ถ้าคุณใช้ Emacs


ฉันคิดว่าสิ่งนี้มีความซับซ้อนพอ ๆ กับวิธีการแก้ปัญหาที่ฉันเคยคิดขึ้นมา แต่ฉันคิดว่าโซลูชันดั้งเดิมของฉันมีประโยชน์ในการบันทึกบรรทัดที่ลบออกเป็นเวลา 30 วันเพราะพวกเขามุ่งมั่น ฉันคิดว่าคงเป็นการดีถ้ามีเชลล์สคริปต์เขียนอยู่รอบ ๆ
asmeurer

1
ขออภัยฉันเพิ่งรู้ว่าgit checkoutยังมี-pธงซึ่งทำสิ่งที่คุณขอในคำสั่งเดียว ขอโทษสำหรับชุดขั้นตอนก่อนหน้าที่ซับซ้อน git checkout -pคุณก็สามารถใช้ ก่อนที่จะทำสิ่งที่อาจเป็นอันตรายฉันมักจะทำgit stash; git stash apply(หรือสร้างนามแฝงที่ทำอย่างนั้นgit checkpointหรืออย่างใดอย่างหนึ่ง) เพื่อบันทึกต้นไม้ปัจจุบันด้วยการสะสมเพื่อที่ฉันจะได้กลับไปหามันหากมีบางอย่างผิดปกติ
Brian Campbell

ไปแล้วนั่นคือทางออก! เท่าที่นามแฝงฉันคิดว่าบางสิ่งบางอย่าง git commit -a -m "Backup Commit" --edit; git reset HEAD^ จะดีกว่าเพราะมันจะไม่สกปรกสถานะการสะสมของฉันซึ่งฉันอาจจะใช้สำหรับสิ่งอื่น จากนั้นตราบใดที่คุณมี SHA1 คุณสามารถรับมันได้ภายใน 30 วัน --edit ช่วยให้คุณเพิ่มข้อมูลลงในข้อความยืนยันเพื่อช่วยคุณในการค้นหา SHA1 ในภายหลังหากคุณต้องการ ในทางกลับกันสิ่งนี้จะทำให้การอ้างถึงคอมไพล์สกปรกขึ้นดังนั้นฉันคิดว่ามันเป็นการแลกเปลี่ยนสิ่งที่คุณทำ
asmeurer

นามแฝงของจุดตรวจสอบใช้งานไม่ได้สำหรับฉัน: เฉพาะคำสั่งแรกเท่านั้นที่ดำเนินการไม่ใช่คำสั่งที่สอง นั่นเป็นเรื่องน่าเศร้าเพราะฉันจะชอบมัน ฉันใช้ git เวอร์ชั่น 1.7.10.4
Fabien

มีวิธีการที่จะgit checkout -pไม่นำ patch ไปใช้กับดัชนีหรือไม่
Geremia

28
git diff > patchfile

จากนั้นแก้ไขไฟล์ patchfile และลบส่วนที่คุณไม่ต้องการเลิกทำแล้ว:

patch -R < patchfile

6
อย่างไรก็ตามคำตอบนี้น่าชื่นชมเป็นพิเศษในความเรียบง่ายและใช้งานง่าย +1
ธ.ค.

สิ่งที่สร้างขึ้นนั้นpatchfileดูยอดเยี่ยมในกลุ่มและมันช่วยได้จริงๆ!
Bily

สมบูรณ์ สามารถยืนยันได้ว่าใช้งานได้กับ Windows ด้วย Cygwin และ Ubuntu bash สำหรับ windows
Checo R

1
หมายเหตุคุณสามารถใช้git apply -Rแทนpatch(เพื่อให้อยู่ในขอบเขตของ git หรือในเหตุการณ์ที่patchไม่สามารถใช้ได้)
user1556435

patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace

5

คุณสามารถทำได้

git checkout master -- path/to/file

สำหรับแต่ละไฟล์ที่คุณต้องการรีเซ็ต


หรือใช้ HEAD แทนตำแหน่งถ้าทำงานในสาขา ตามที่ระบุไว้ในรายงาน 'สถานะ git' (อย่างน้อยในรุ่นล่าสุด)
Jonathan Leffler

1

เกี่ยวกับ

  1. สำรองไฟล์ที่ได้รับผลกระทบจากการเปลี่ยนแปลงของดัชนี
  2. ใช้git add -pเพื่อเพิ่มการเปลี่ยนแปลงที่คุณต้องการกลับไปที่ดัชนีเท่านั้น

1

เมื่อฉันเรียกใช้ 'สถานะ git' จะมีข้อความว่า:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

ดังนั้นหากต้องการยกเลิกการแก้ไขแบบไม่มีการแจ้งเตือนฉันจะเรียกใช้:

git checkout -- makefile

3
ฉันคิดว่าเขาสงสัยเกี่ยวกับวิธีการย้อนกลับ hunks แต่ละบุคคลไม่ใช่ไฟล์ทั้งหมดในเวลา แน่นอนว่านี่เป็นวิธีแก้ปัญหาหากคุณต้องการยกเลิกการเปลี่ยนแปลงทั้งหมดในไฟล์
Brian Campbell

ใช่ - ฉันสงสัยว่าคุณถูกต้อง ตัวเลือก 'git checkout -p' และ 'git add -p' ดูเหมือนจะเป็นสิ่งที่ต้องการ - ตามที่คุณพูด
Jonathan Leffler

1

คำตอบของ Brian Campbellทำให้คอมไพล์รุ่น 1.9.2.msysgit.0 ของฉันไม่ทราบสาเหตุดังนั้นวิธีการของฉันคือการตามล่าฉากที่ฉันต้องการเก็บไว้ทิ้งการเปลี่ยนแปลงในสำเนาที่ใช้งานได้และไม่สเตจ

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .

1
git stash -pนอกจากนี้ยังมี git stash -p; git reset --hard; git stash popคุณสามารถทำ สิ่งนี้มีประสิทธิภาพเช่นเดียวกับสิ่งที่คุณทำยกเว้นคุณไม่จำเป็นต้องเขียนข้อความยืนยัน
asmeurer

@memeurer ไชโย ฉันไม่จำเป็นต้องมีข้อความยืนยัน แต่มันน่าจะเหมาะสมกว่าที่จะใช้การซ่อนมากกว่าดัชนีสำหรับสิ่งนี้
G-Wiz

0

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

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