คืนค่าส่วนหนึ่งของคอมมิชชันด้วย git


144

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

มีวิธีการคล้ายกับgit add --patchที่จะให้ฉันเลือกแก้ไข diffs เพื่อตัดสินใจว่าส่วนใดของการกระทำที่จะย้อนกลับ?


โซลูชันเพิ่มเติมที่นี่แต่มุ่งเน้นไปที่การ จำกัด การย้อนกลับบางส่วนเป็นไฟล์เฉพาะ
ntc2

คำตอบ:


226

ใช้ตัวเลือก--no-commit( -n) เพื่อgit revertแล้วยกเลิกการเปลี่ยนแปลงจากนั้นใช้git add --patch:

$ git revert -n $bad_commit    # Revert the commit, but don't commit the changes
$ git reset HEAD .             # Unstage the changes
$ git add --patch .            # Add whatever changes you want
$ git commit                   # Commit those changes

หมายเหตุ: ไฟล์ที่คุณเพิ่มโดยใช้ git add --patch เป็นไฟล์ที่คุณต้องการเปลี่ยนกลับไม่ใช่ไฟล์ที่คุณต้องการเก็บ


13
อาจคุ้มค่าที่จะเพิ่มคำสั่งสุดท้ายที่จำเป็นสำหรับผู้ที่ไม่คุ้นเคยกับคอมไพล์: หลังจากที่ทำgit reset --hardไปแล้วเพื่อละทิ้งการเปลี่ยนแปลงอื่น ๆ ที่คุณไม่ต้องการเปลี่ยนกลับ
สั่น

15
git reset --hardเป็นสิ่งที่อันตรายสำหรับมือใหม่เนื่องจากอาจแก้ไขได้อย่างอิสระ แทนที่จะทำตัวให้คุ้นเคยกับgit statusสิ่งนี้คำแนะนำนี้git checkout -- FILE..เพื่อเปลี่ยนสิ่งต่าง ๆ ให้ปลอดภัยยิ่งขึ้น
Tino

สิ่งที่ละเว้นการอ้าปากค้างในgit; git revertควร--patchโต้แย้งกัน
Kaz

@Kaz: git revertใช้สำหรับคืนค่าคอมมิททั้งหมด คุณสามารถใช้git checkout -pเพื่อเลือกบิตแบบโต้ตอบเพื่อย้อนกลับ
mipadi

1
ฉันต้องการเพิ่มชัดเจน (อาจ) ซึ่งเป็นบันทึกงานของคุณก่อน ไม่ว่าจะcommitก่อนหรือแล้วลองstash revert
เฟลิเป้อัลวาเรซ

39

ฉันใช้ต่อไปนี้สำเร็จแล้ว

ก่อนอื่นให้คอมมิทเต็ม (วางไว้ในดัชนี) แต่อย่าคอมมิท

git revert -n <sha1>  # -n is short for --no-commit

จากนั้นลบการเปลี่ยนแปลง GOOD ที่เปลี่ยนกลับออกจากดัชนี

git reset -p          # -p is short for --patch  

จากนั้นคอมมิทย้อนกลับของการเปลี่ยนแปลงที่ไม่ดี

git commit -m "Partially revert <sha1>..."

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

git reset --hard

5
นี่ไม่ใช่ทางเลือกที่เหนือกว่าสำหรับคำตอบที่ยอมรับ (ซึ่งใช้reset HEAD .) เพราะไม่ต้องการการล้างข้อมูลขั้นสุดท้ายของการทำงานหรือไม่
Steven Lu

2
คำตอบนี้จะดีกว่าเพราะreset -pจะสั้นกว่าตามมาด้วยreset HEAD add -pแต่มันยังคงต้องการการล้างข้อมูลเนื่องจาก hunks "ดี" ที่ถูกรีเซ็ตยังคงอยู่ในไดเรกทอรีการทำงานหลังจากการส่งมอบ
Chiel ten Brinke

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

5

โดยส่วนตัวแล้วฉันชอบรุ่นนี้มากซึ่งจะนำข้อความการส่งข้อความที่สร้างขึ้นอัตโนมัติมาใช้ใหม่และให้ผู้ใช้มีโอกาสที่จะแก้ไขและติดคำว่า "บางส่วน" ก่อนที่จะยอมรับ

# generate a revert commit
# note the hash printed to console on success
git revert --no-edit <hash to revert>

# undo that commit, but not its changes to the working tree
# (reset index to commit-before-last; that is, one graph entry up from HEAD)
git reset HEAD~1

# interactively add reversions
git add -p

# commit with pre-filled message
git commit -c <hash from revert commit, printed to console after first command>

# reset the rest of the current directory's working tree to match git
# this will reapply the excluded parts of the reversion to the working tree
# you may need to change the paths to be checked out
# be careful not to accidentally overwrite unsaved work
git checkout -- .

4

สารละลาย:

git revert --no-commit <commit hash>
git reset -p        # every time choose 'y' if you want keep the change, otherwise choose 'n'
git commit -m "Revert ..."
git checkout -- .   # Don't forget to use it.

มันจะช่วยให้ผู้คนถ้าคุณบอกว่ามันแตกต่างจากวิธีการแก้ปัญหาที่ยอมรับ
CharlesB

1
@Krzysztof เหตุใดการชำระเงินที่จุดสิ้นสุดจึงมีความสำคัญและเหตุใดโซลูชันนี้จึงแตกต่างจากของผู้ใช้งาน 1338062
martin

3

อีกทางเลือกหนึ่ง (หากไฟล์เวอร์ชันปัจจุบันของคุณอยู่ไม่ไกลจากเวอร์ชั่นที่คุณพยายามจะแปลงกลับ) คือการรับแฮชการคอมมิตทันทีก่อนที่ไฟล์ที่คุณต้องการจะเปลี่ยนกลับบางส่วน (จากgit log) จากนั้นคำสั่งของคุณจะกลายเป็น:

$ git checkout -p <hash_preceding_commit_to_revert> -- file/you/want/to/fix.ext

นี้จะเปลี่ยนไฟล์ในต้นไม้การทำงานของคุณ git reset --hard -- file/you/want/to/fix.extแต่ไม่สร้างกระทำดังนั้นหากคุณจริงๆขึ้นสิ่งที่คุณก็สามารถเริ่มต้นอีกครั้งกับ


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