จะลบรายการบันทึกการกระทำที่เลือกไว้จากที่เก็บ Git ในขณะที่ยังคงการเปลี่ยนแปลงได้อย่างไร


241

ฉันต้องการลบรายการบันทึกการกระทำที่เลือกจากแผนผังการส่งข้อมูลเชิงเส้นเพื่อให้รายการไม่แสดงในบันทึกการส่ง

ต้นไม้ที่ฉันสร้างดูเหมือนว่า:

R--A--B--C--D--E--HEAD

ฉันต้องการลบรายการ B และ C เพื่อไม่ให้แสดงในบันทึกการกระทำ แต่ควรเปลี่ยนจาก A เป็น D อาจจะด้วยการแนะนำการกระทำเพียงครั้งเดียวเพื่อให้ B และ C กลายเป็น BC และต้นไม้ดูเหมือน

R--A--BC--D--E--HEAD

หรือในอุดมคติแล้วหลังจาก A มาถึง D โดยตรง D 'แสดงการเปลี่ยนแปลงจาก A ถึง B, B ถึง C และ C ถึง D

R--A--D'--E--HEAD

เป็นไปได้ไหม ถ้าใช่เป็นอย่างไร

นี่เป็นโครงการใหม่ที่ค่อนข้างไม่มีสาขาในขณะนี้ดังนั้นจึงไม่มีการรวมกัน


@ xk0der: "commits" เป็นคำที่ถูกต้องที่นี่ rebaseอาจลบเก่า / สร้างการกระทำใหม่ ฉันไม่ทราบว่า "ส่งบันทึกรายการ" หมายถึงอะไร
jfs

@JFSebastian ฉันไม่เห็นปัญหากับ "commit log" - บันทึกการกระทำทั้งหมด และฉันต้องการลบบางรายการจากบันทึก - ในขณะที่ยังคงการเปลี่ยนแปลงที่เกิดขึ้นจริง (ความมุ่งมั่น)
xk0der

@ xk0der: คอมไพล์ยอมรับว่าเป็นเนื้อหาที่อยู่เช่นถ้าคุณเปลี่ยนแปลงอะไรในการกระทำเช่นข้อความบันทึกของมัน คุณสร้างความมุ่งมั่นใหม่ คุณสามารถอ่านของคอมไพล์กระทำโดยไม่ต้องคอมไพล์และดูตัวเอง
jfs

@JFSebastian - ขอบคุณสำหรับลิงค์ - ฉันรู้ว่า - แต่เทคนิคนั้นเปลี่ยนปัญหาที่ฉันเผชิญและวิธีการที่ฉันนำมันออกมา? ฉันเดาว่าไม่. ในท้ายที่สุด: ฉันต้องการลบ "ข้อความบันทึกการกระทำ" - โดยไม่ลบ "การเปลี่ยนแปลงการกระทำ" - โปรดอ่านคำถามของฉันอีกครั้ง - โดยเฉพาะย่อหน้าที่สอง จะเพิ่มมากขึ้นgit logแสดงให้เห็นว่า "บันทึกการกระทำ" git-scm.com/docs/git-log และฉันต้องการกำจัดสองรายการจากบันทึกนั้นไม่ใช่การเปลี่ยนแปลง
xk0der

คำตอบ:


273

git-rebase (1)ทำสิ่งนั้นอย่างแน่นอน

$ git rebase -i HEAD~5

git awsome-ness [รีบูต git - โต้ตอบ]มีตัวอย่าง

  1. อย่าใช้git-rebaseกับการส่งข้อมูลแบบสาธารณะ (ระยะไกล)
  2. ตรวจสอบให้แน่ใจว่าไดเรกทอรีทำงานของคุณสะอาด ( commitหรือstashเปลี่ยนแปลงปัจจุบัน)
  3. เรียกใช้คำสั่งด้านบน $EDITORมีการเปิดตัวของคุณ
  4. แทนที่pickก่อนCและโดยD squashมันจะรวม C และ D เป็น B หากคุณต้องการลบการคอมมิท

หากคุณทำหายให้พิมพ์:

$ git rebase --abort  

ขอบคุณสำหรับการตอบกลับอย่างรวดเร็ว ดังนั้นฉันจะชำระเงิน A และทำ rebase เป็นgit rebase -i D [A]อย่างไร
xk0der


3
เราจะทำใน repos ระยะไกลได้อย่างไร
Eray

6
@Eray: เพียงแค่push -fการเปลี่ยนแปลงของคุณ อย่าทำอย่างนั้นถ้าคุณไม่ได้ทำงานคนเดียว
jfs

2
@ ripper234: ฉันได้แก้ไขลิงก์ไปยังจุดgit-rebaseคู่มือและเครื่อง wayback สำหรับโพสต์บล็อก
jfs

75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master

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

41

ต่อไปนี้เป็นวิธีการลบรหัสการส่งผ่านเฉพาะการรับรู้เฉพาะรหัสการกระทำที่คุณต้องการลบ

git rebase --onto commit-id^ commit-id

โปรดทราบว่านี่จะเป็นการลบการเปลี่ยนแปลงที่นำโดยการส่งมอบจริง


7
HEAD พิเศษในคำสั่งนี้จะทำให้ rebase เสร็จสิ้นด้วย 'HEAD แฝด' ซึ่งไม่เป็นที่ต้องการ มันควรจะเป็น ommitted
Frosty

3
สิ่งนี้จะนำการเปลี่ยนแปลงกลับมาใช้กับ commit-id ของฉัน OP ต้องการเก็บการเปลี่ยนแปลงเพียงแค่สควอชคอมมิชชัน
CB Bailey

1
-1 เพราะมันไม่ได้ทำในสิ่งที่ OP ถาม (มันทำลายสิ่งที่เขาต้องการเก็บไว้อย่างชัดเจน)
Emil Styrke

1
แม้ว่ามันจะไม่ได้ทำตามที่ OP ร้องขอ แต่มันก็เป็นสิ่งที่ฉันต้องการดังนั้น +1 จึงเป็นคำตอบที่มีประโยชน์
Edvins

20

หากต้องการขยายคำตอบของ JF Sebastian:

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

หลังจากรัน git rebase - แบบโต้ตอบคุณจะได้รับสิ่งต่อไปนี้ใน $ EDITOR ของคุณ:

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

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

ฉันคิดว่าการเลือกหมายความว่าคุณต้องการทิ้งความมุ่งมั่นไว้คนเดียว

(ตัวอย่างมาจากที่นี่ )


14

คุณสามารถลบ B และ C แบบไม่โต้ตอบในตัวอย่างของคุณด้วย:

git rebase --onto HEAD~5 HEAD~3 HEAD

หรือเป็นสัญลักษณ์

git rebase --onto A C HEAD

โปรดทราบว่าการเปลี่ยนแปลงใน B และ C จะไม่อยู่ใน D; พวกเขาจะหายไป


ดูที่นี่สำหรับข้อมูลเพิ่มเติม: sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
สูงสุด

3

อีกวิธีหนึ่ง

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

เลือกแฮชที่คุณต้องการใช้เป็นฐานและคำสั่งด้านบนควรทำให้เป็นแบบโต้ตอบเพื่อให้คุณสามารถส่งข้อความทั้งหมดที่ด้านบน (คุณต้องปล่อยให้เก่าที่สุด)


2

ฉันพบว่ากระบวนการนี้ปลอดภัยกว่าและเข้าใจง่ายกว่ามากโดยสร้างสาขาใหม่จาก SHA1 ของ A และเก็บการเปลี่ยนแปลงที่ต้องการเพื่อให้แน่ใจว่าฉันพอใจกับลักษณะของสาขาใหม่นี้ หลังจากนั้นมันเป็นเรื่องง่ายที่จะลบสาขาเก่าและเปลี่ยนชื่อสาขาใหม่

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>

ถ้าคุณทำเช่นนี้คุณจะเสีย E ที่ตกลงเช่นกันใช่มั้ย ดังที่ฉันเข้าใจแล้วคุณลบ master และเปลี่ยนชื่อ rework เป็น master (การพิจารณาโฟลว์ ABCDE เป็นสาขาหลัก)
Renan Bandeira

1

เพียงรวบรวมคำตอบของทุกคน: (m ใหม่เพื่อ git plz ใช้เพื่อการอ้างอิงเท่านั้น)

git rebase เพื่อลบการกระทำใด ๆ

บันทึกคอมไพล์

-first check from which commit you want to rebase

git rebase -i HEAD ~ 1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

จากนั้นหน้าจอจะมีลักษณะดังนี้:

เลือก 0c2236d เพิ่มบรรทัดใหม่

รีบูต 2a1cd65..0c2236d ไปยัง 2a1cd65 (คำสั่ง 1 รายการ)

#

คำสั่ง:

p, pick = use ส่งข้อมูล

r, reword = use commit แต่แก้ไขข้อความกระทำ

e, แก้ไข = ใช้กระทำ แต่หยุดเพื่อแก้ไข

s, squash = ใช้การคอมมิต แต่รวมเข้ากับการคอมมิชชันก่อนหน้า

f, fixup = เช่น "squash" แต่ทิ้งข้อความบันทึกการกระทำนี้

x, exec = คำสั่ง run (ส่วนที่เหลือของบรรทัด) โดยใช้เชลล์

d, drop = remove commit

#

บรรทัดเหล่านี้สามารถสั่งซื้อใหม่ได้ พวกเขาจะดำเนินการจากบนลงล่าง

#

หากคุณลบบรรทัดที่นี่ COMMIT จะหายไป

#

อย่างไรก็ตามหากคุณลบทุกอย่างการปฏิเสธจะถูกยกเลิก

#

โปรดทราบว่าความมุ่งมั่นที่ว่างเปล่าจะถูกใส่ความคิดเห็น ~ ~

~
~
~
~
~
~
~
~
~

ที่นี่เปลี่ยนบรรทัดแรกตามความต้องการของคุณ (ใช้คำสั่งข้างต้นคือ 'ปล่อย' เพื่อลบคอมมิชชัน ฯลฯ ) เมื่อแก้ไขเสร็จแล้วกด ': x' เพื่อบันทึกและออกจากตัวแก้ไข (นี่สำหรับ vim editor เท่านั้น)

และจากนั้น

git push

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

git push -f origin


-1

คุณสามารถใช้ git cherry-pick ได้ 'cherry-pick' จะใช้ความมุ่งมั่นไปยังสาขาของคุณในตอนนี้

จากนั้นทำ

git rebase --hard <SHA1 of A>

จากนั้นใช้คอมมิชชัน D และ E

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

สิ่งนี้จะข้าม B และ C ที่กระทำ ต้องบอกว่ามันอาจเป็นไปไม่ได้ที่จะใช้ D กระทำกับสาขาที่ไม่มี B ดังนั้น YMMV


2
OP ต้องการรวม B, C, D ที่ทำไว้ไม่ให้ลบการเปลี่ยนแปลง
jfs

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