แบ่งการคอมมิชชันก่อนหน้าเป็นหลายคอมมิต


1224

โดยไม่ต้องสร้างสาขาและทำงานที่ขี้ขลาดในสาขาใหม่เป็นไปได้ไหมที่จะแบ่งคอมมิชชันเดียวออกเป็นคอมมิชชันที่แตกต่างกันสองสามอย่างหลังจากที่คอมมิชชันไปยังที่เก็บข้อมูลโลคัลหรือไม่?


36
แหล่งที่ดีสำหรับการเรียนรู้วิธีการทำเช่นนี้คือPro Git .46.4 เครื่องมือ Git - ประวัติการเขียนซ้ำในส่วน "การแยกสัญญา"

2
เอกสารที่ลิงก์ที่ความคิดเห็นด้านบนนั้นยอดเยี่ยมอธิบายได้ดีกว่าคำตอบด้านล่าง
Blaisorblade

2
ฉันแนะนำให้ใช้นามแฝงstackoverflow.com/a/19267103/301717นี้ อนุญาตให้แบ่งการกระทำโดยใช้git autorebase split COMMIT_ID
Jérôme Pouiller

สิ่งที่ง่ายที่สุดที่จะทำโดยไม่มีการรีบูตแบบโต้ตอบคือ (อาจ) เพื่อทำให้สาขาใหม่เริ่มต้นที่คอมมิชชันก่อนหน้าการแยกที่คุณต้องการแยก, เชอร์รี่เลือก -n การคอมมิท, รีเซ็ต, ซ่อน, คอมมิทย้ายไฟล์ กระทำการเปลี่ยนแปลงแล้วรวมกับสาขาเดิมหรือเชอร์รี่เลือกกระทำที่ตามมา (จากนั้นเปลี่ยนชื่อสาขาเดิมเป็นชื่อปัจจุบัน) (น่าจะดีกว่าที่จะทำตามคำแนะนำของ MBO และทำการ rebase เชิงโต้ตอบ) (คัดลอกมาจากคำตอบของปี 2010 ด้านล่าง)
William Pursell

1
ฉันพบปัญหานี้หลังจากที่ฉันบีบสองคอมมิทโดยไม่ตั้งใจระหว่างการรีบูตในการคอมมิชชันก่อนหน้านี้ ทางของฉันที่จะแก้ไขได้คือการชำระเงินแบนกระทำgit reset HEAD~, git stashแล้วคนแรกที่กระทำภายในสควอชแล้วgit cherry-pick git stash popกล่องใส่เชอร์รี่ของฉันค่อนข้างเฉพาะที่นี่ แต่git stashและgit stash popค่อนข้างสะดวกสำหรับคนอื่น ๆ
SOFe

คำตอบ:


1799

git rebase -i จะทำมัน

ขั้นแรกให้เริ่มต้นด้วยไดเรกทอรีการทำงานที่สะอาด: git statusไม่ควรแสดงการแก้ไขการลบหรือการเพิ่มเติมที่ค้างอยู่

ตอนนี้คุณต้องตัดสินใจว่าคุณต้องการแบ่งหน้าที่อะไร

A) แบ่งการกระทำล่าสุด

หากต้องการแยกการกระทำล่าสุดของคุณก่อน:

$ git reset HEAD~

ตอนนี้ทำชิ้นส่วนต่าง ๆ ในแบบปกติโดยสร้างจำนวนมากตามที่คุณต้องการ

B) แบ่งการกระทำไกลออกไปกลับ

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

  • ถ้ามันเป็นสามกระทำกลับแล้ว

    $ git rebase -i HEAD~3
    

    ซึ่ง3เป็นวิธีการที่หลายคนกระทำกลับเป็น

  • หากมันอยู่ในต้นไม้ไกลกว่าที่คุณต้องการนับ

    $ git rebase -i 123abcd~
    

    ที่123abcdSHA1 ของการกระทำที่คุณต้องการที่จะแยกออกเป็น

  • หากคุณอยู่ในสาขาอื่น (เช่นสาขาฟีเจอร์) ที่คุณวางแผนที่จะผสานเข้ากับมาสเตอร์:

    $ git rebase -i master
    

เมื่อคุณได้รับหน้าจอแก้ไขการรีบูตให้ค้นหาการมอบหมายที่คุณต้องการแยก ที่จุดเริ่มต้นของบรรทัดนั้นแทนที่pickด้วยedit( eสั้น ๆ ) บันทึกบัฟเฟอร์และออก การรีบูตจะหยุดลงหลังจากที่คุณยืนยันที่จะแก้ไข แล้ว:

$ git reset HEAD~

มอบชิ้นงานด้วยวิธีปกติให้มากที่สุดเท่าที่คุณต้องการ

$ git rebase --continue

2
ขอบคุณสำหรับคำตอบนี้ ฉันต้องการมีไฟล์ที่มุ่งมั่นก่อนหน้านี้ในพื้นที่การจัดเตรียมดังนั้นคำแนะนำสำหรับฉันแตกต่างกันเล็กน้อย ก่อนที่ผมจะสามารถทำได้git rebase --continueจริงผมต้องgit add (files to be added), git commitแล้วgit stash(สำหรับไฟล์ที่เหลือ) หลังจากนั้นgit rebase --continueฉันเคยgit checkout stash .ได้ไฟล์ที่เหลือ
Eric Hu

18
คำตอบของ manojldsมีลิงก์ไปยังเอกสารของgit-scmซึ่งอธิบายกระบวนการแยกอย่างชัดเจน

56
คุณจะต้องการใช้ประโยชน์จากgit add -pการเพิ่มเฉพาะบางส่วนของไฟล์บางส่วนด้วยeตัวเลือกในการแก้ไข diffs เพื่อคอมมิทก้อนใหญ่ git stashยังมีประโยชน์หากคุณต้องการที่จะดำเนินการต่อไป แต่ลบออกจากการกระทำปัจจุบัน
Craig Ringer

2
หากคุณต้องการแยกและจัดลำดับใหม่สิ่งที่ฉันชอบทำคือแยกก่อนแล้วจึงจัดลำดับใหม่แยกกันโดยใช้git rebase -i HEAD^3คำสั่งอื่น ด้วยวิธีนี้หากการแบ่งไม่ดีคุณไม่ต้องเลิกทำการทำงานมากนัก
David M. Lloyd

4
@kralyk ไฟล์ที่เพิ่งถูกคอมมิทใน HEAD จะถูกทิ้งไว้ในดิสก์หลังจากgit reset HEAD~นั้น พวกเขาจะไม่สูญหาย
Wayne Conrad

312

จากคู่มือgit-rebase (ส่วนการแยกคำสั่ง)

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

  • เริ่มต้น rebase แบบโต้ตอบกับgit rebase -i <commit>^ที่<commit>มีการกระทำที่คุณต้องการที่จะแยก ในความเป็นจริงช่วงการยอมรับใด ๆ ที่จะทำตราบใดที่มันมีการกระทำที่

  • ทำเครื่องหมายการมอบหมายที่คุณต้องการแยกด้วยการกระทำ "แก้ไข"

  • เมื่อพูดถึงการแก้ไขที่กระทำgit reset HEAD^แล้ว เอฟเฟกต์คือ HEAD ถูกกรอด์หนึ่งตัวและดัชนีจะตามหลังชุดสูท อย่างไรก็ตามต้นไม้ทำงานยังคงเหมือนเดิม

  • ตอนนี้เพิ่มการเปลี่ยนแปลงในดัชนีที่คุณต้องการในการกระทำครั้งแรก คุณสามารถใช้git add(อาจโต้ตอบ) หรือgit gui(หรือทั้งสองอย่าง) เพื่อทำเช่นนั้น

  • ยอมรับดัชนีตอนนี้ด้วยข้อความการกระทำใด ๆ ที่เหมาะสมในขณะนี้

  • ทำซ้ำสองขั้นตอนสุดท้ายจนกระทั่งต้นไม้ทำงานของคุณสะอาด

  • ดำเนินการต่อ rebase git rebase --continueด้วย


12
ใน Windows คุณมีคุณใช้แทน~ ^
Kevin Kuszyk

13
คำเตือน: ด้วยวิธีนี้ฉันสูญเสียข้อความกระทำ
user420667

11
@ user420667 ใช่แน่นอน เราresetมุ่งมั่นที่จะทำหลังจากทั้งหมด - รวมข้อความ สิ่งที่ควรทำหากคุณรู้ว่าคุณกำลังจะแยกความมุ่งมั่น แต่ต้องการเก็บข้อความทั้งหมด / บางส่วนเอาไว้ให้คัดลอกข้อความนั้น ดังนั้นgit showกระทำก่อนที่ไอเอ็นจีหรือถ้าคุณลืมหรือชอบนี้ได้รับกลับมาได้ในภายหลังผ่านrebase reflogไม่มีของใดที่จะ "หายไป" จนกว่าจะมีการเก็บขยะใน 2 สัปดาห์หรืออะไรก็ตาม
underscore_d

4
~และ^เป็นสิ่งต่าง ๆ แม้แต่ใน Windows คุณยังคงต้องการคาเร็^ตดังนั้นคุณเพียง แต่ต้องหลบหนีตามความเหมาะสมกับกระสุนของคุณ ใน PowerShell HEAD`^ก็ ด้วย cmd.exe คุณสามารถเพิ่มเป็นสองเท่าเพื่อหลบหนีHEAD^^ได้ ในที่สุด (ทั้งหมด?) "HEAD^"หอยคุณสามารถล้อมรอบด้วยคำพูดเช่น
AndrewF

7
git commit --reuse-message=abcd123นอกจากนี้คุณยังสามารถทำ -Cตัวเลือกที่สั้นเพราะมันเป็น
j0057

41

ใช้git rebase --interactiveเพื่อแก้ไขการคอมมิชชันรันgit reset HEAD~และจากนั้นgit add -pเพิ่มคอมมิชชันจากนั้นทำการคอมมิชชันแล้วเพิ่มการเพิ่มเติมและทำการคอมมิตอื่น ๆ หลาย ๆ ครั้งตามที่คุณต้องการ เมื่อเสร็จแล้วให้เรียกใช้git rebase --continueแล้วคุณจะได้รับการแบ่งทั้งหมดก่อนหน้านี้ในสแต็กของคุณ

สำคัญ : โปรดทราบว่าคุณสามารถเล่นและทำการเปลี่ยนแปลงทั้งหมดที่คุณต้องการและไม่ต้องกังวลกับการสูญเสียการเปลี่ยนแปลงเก่า ๆ เพราะคุณสามารถเรียกใช้git reflogเพื่อค้นหาจุดในโครงการของคุณที่มีการเปลี่ยนแปลงที่คุณต้องการ (เรียกมันว่าa8c4ab) git reset a8c4abและจากนั้น

ต่อไปนี้เป็นชุดคำสั่งเพื่อแสดงวิธีการทำงาน:

mkdir git-test; cd git-test; git init

ตอนนี้เพิ่มไฟล์ A

vi A

เพิ่มบรรทัดนี้:

one

git commit -am one

จากนั้นเพิ่มบรรทัดนี้ใน A:

two

git commit -am two

จากนั้นเพิ่มบรรทัดนี้ใน A:

three

git commit -am three

ตอนนี้ไฟล์ A มีลักษณะดังนี้:

one
two
three

และgit logดูเหมือนว่าของเราดังต่อไปนี้ (ดีฉันใช้git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one

สมมติว่าเราต้องการแยกการกระทำที่สอง, two.

git rebase --interactive HEAD~2

นี่จะแสดงข้อความที่มีลักษณะดังนี้:

pick 2b613bc two
pick bfb8e46 three

เปลี่ยนรายการแรกpickเป็น a eเพื่อแก้ไขที่ส่งมอบ

git reset HEAD~

git diff แสดงให้เราเห็นว่าเราแค่ทำตามคำมั่นสัญญาที่เราทำไว้สำหรับการกระทำครั้งที่สอง:

diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two

ขั้นตอน Let 's ว่าการเปลี่ยนแปลงและเพิ่ม "และคนที่สาม" Aเพื่อบรรทัดในแฟ้มที่

git add .

นี่คือจุดระหว่างการรีบูตแบบโต้ตอบที่เราจะเรียกใช้git rebase --continueเนื่องจากเราเพียงต้องการกลับไปที่กองการคอมมิชชันของเราเพื่อแก้ไขคอมมิชชันก่อนหน้า แต่ครั้งนี้เราต้องการสร้างความมุ่งมั่นใหม่ git commit -am 'two and a third'ดังนั้นเราจะใช้ ตอนนี้เราแก้ไขไฟล์และเพิ่มบรรทัดAtwo and two thirds

git add . git commit -am 'two and two thirds' git rebase --continue

เรามีความขัดแย้งกับความมุ่งมั่นของเราthreeดังนั้นให้แก้ไข:

เราจะเปลี่ยน

one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three

ถึง

one
two and a third
two and two thirds
three

git add .; git rebase --continue

ตอนนี้git log -pหน้าตาของเราเป็นแบบนี้:

commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:57:00 2013 -0700

    three

diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
 one
 two and a third
 two and two thirds
+three

commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:07:07 2013 -0700

    two and two thirds

diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
 one
 two and a third
+two and two thirds

commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:06:40 2013 -0700

    two and a third

diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two and a third

commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:56:40 2013 -0700

    one

diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one

38

คำตอบก่อนหน้าครอบคลุมการใช้งานgit rebase -iเพื่อแก้ไขการกระทำที่คุณต้องการแยกและกระทำในส่วนต่างๆ

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

เมื่อมีการกระทำที่คุณต้องการแยกใช้rebase -iและทำเครื่องหมายeditคุณมีสองตัวเลือก

  1. หลังจากใช้git reset HEAD~ไปให้ทำตามแต่ละชุดที่ใช้git add -pเพื่อเลือกสิ่งที่คุณต้องการในแต่ละการกระทำ

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

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

หลังจากใช้rebase -iและeditดำเนินการส่งมอบให้ใช้

git reset --soft HEAD~

เพื่อเลิกคอมมิชชัน แต่ปล่อยไฟล์ที่คอมมิตไว้ในดัชนี นอกจากนี้คุณยังสามารถทำการรีเซ็ตแบบผสมได้โดยไม่ต้องกดปุ่ม - soft ขึ้นอยู่กับว่าผลลัพธ์สุดท้ายของการคอมมิชชันเริ่มต้นของคุณใกล้เคียงกับผลสุดท้ายอย่างไร ข้อแตกต่างเพียงอย่างเดียวคือคุณเริ่มต้นด้วยการเปลี่ยนแปลงทั้งหมดที่จัดเตรียมไว้หรือไม่เปลี่ยนแปลงทั้งหมด

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

เมื่อคุณมีความสุขแล้วให้เวที / unstage ไฟล์ตามที่ต้องการ (ฉันชอบใช้git guiสิ่งนี้) และยอมรับการเปลี่ยนแปลงผ่าน UI หรือบรรทัดคำสั่ง

git commit

นั่นคือการกระทำครั้งแรกที่ทำ ตอนนี้คุณต้องการคืนค่าสำเนาการทำงานของคุณกลับสู่สถานะที่ได้รับหลังจากการส่งคำสั่งที่คุณแบ่งเพื่อให้คุณสามารถรับการเปลี่ยนแปลงมากขึ้นสำหรับการส่งครั้งต่อไป เพื่อหา sha1 git statusของคุณกระทำการแก้ไขกำลังใช้ ในสองสามบรรทัดแรกของสถานะคุณจะเห็นคำสั่ง rebase ที่กำลังดำเนินการอยู่ซึ่งคุณสามารถค้นหา sha1 ของการส่งต้นฉบับของคุณ:

$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
   pick 4847406 US135756: add debugging to the file download code
   e 65dfb6a US135756: write data and download from remote
  (see more in file .git/rebase-merge/done)
...

ในกรณีนี้กระทำฉันมีการแก้ไข 65dfb6asha1 รู้ว่าฉันสามารถตรวจสอบเนื้อหาของการกระทำที่มากกว่าไดเรกทอรีทำงานของฉันโดยใช้รูปแบบgit checkoutที่ใช้ทั้งกระทำและที่ตั้งของไฟล์ ที่นี่ฉันใช้.เป็นที่ตั้งไฟล์เพื่อแทนที่สำเนาการทำงานทั้งหมด:

git checkout 65dfb6a .

อย่าพลาดจุดในตอนท้าย!

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

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

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

git commit --file .git/rebase-merge/message

ในที่สุดเมื่อคุณทำการเปลี่ยนแปลงทั้งหมดแล้ว

git rebase --continue

จะดำเนินการและดำเนินการต่อให้เสร็จสิ้น


3
ขอบคุณ!!! นี่ควรเป็นคำตอบที่ยอมรับได้ คงจะช่วยให้ฉันประหยัดเวลาและความเจ็บปวดในวันนี้ เป็นคำตอบเดียวที่ผลลัพธ์ของการกระทำครั้งสุดท้ายนำคุณไปสู่สถานะเดียวกับการกระทำภายใต้การแก้ไข
Doug Coburn

1
ฉันชอบวิธีที่คุณใช้ข้อความยืนยันดั้งเดิม
Salamandar

ใช้ตัวเลือก 2 เมื่อฉันทำgit checkout *Sha I'm Editing* .มันจะพูดเสมอUpdated 0 paths from *Some Sha That's Not In Git Log*และไม่เปลี่ยนแปลง
Noumenon

18

git rebase --interactiveสามารถใช้เพื่อแบ่งการคอมมิตเป็นคอมมิทที่เล็กลง เอกสาร Git บน rebase มีคำแนะนำแบบสั้นของกระบวนการ - Commits แยก :

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

  • เริ่มต้น rebase แบบโต้ตอบกับgit rebase -i <commit>^ที่<commit>มีการกระทำที่คุณต้องการที่จะแยก ในความเป็นจริงช่วงการยอมรับใด ๆ ที่จะทำตราบใดที่มันมีการกระทำที่

  • ทำเครื่องหมายการมอบหมายที่คุณต้องการแยกด้วยการกระทำ "แก้ไข"

  • เมื่อพูดถึงการแก้ไขที่กระทำgit reset HEAD^แล้ว เอฟเฟกต์คือ HEAD ถูกกรอด์หนึ่งตัวและดัชนีจะตามหลังชุดสูท อย่างไรก็ตามต้นไม้ทำงานยังคงเหมือนเดิม

  • ตอนนี้เพิ่มการเปลี่ยนแปลงในดัชนีที่คุณต้องการในการกระทำครั้งแรก คุณสามารถใช้git add(อาจโต้ตอบ) หรือ git gui (หรือทั้งสองอย่าง) เพื่อทำเช่นนั้น

  • ยอมรับดัชนีตอนนี้ด้วยข้อความการกระทำใด ๆ ที่เหมาะสมในขณะนี้

  • ทำซ้ำสองขั้นตอนสุดท้ายจนกระทั่งต้นไม้ทำงานของคุณสะอาด

  • ดำเนินการต่อ rebase git rebase --continueด้วย

หากคุณไม่แน่ใจว่าการแก้ไขระดับกลางมีความสอดคล้องกัน (พวกเขารวบรวมรวบรวมผ่าน Testuite ฯลฯ ) คุณควรใช้git stashเพื่อซ่อนการเปลี่ยนแปลงที่ยังไม่ได้ทำหลังจากการคอมมิททดสอบและแก้ไขคอมมิชชันหากการแก้ไขจำเป็น .


ใน Windows ให้จำไว้ว่า^เป็นอักขระเลี่ยงสำหรับบรรทัดคำสั่ง: ควรเพิ่มเป็นสองเท่า โดยยกตัวอย่างเช่นการออกแทนgit reset HEAD^^ git reset HEAD^
Frédéric

@ Frédéric: ฉันไม่เคยเจอเรื่องนี้เลย อย่างน้อยใน PowerShell นี่ไม่ใช่กรณี จากนั้นใช้การ^รีเซ็ตสองครั้งสองคอมมิตเหนือศีรษะปัจจุบัน
Farway

@ แฟร์เวย์ลองในบรรทัดคำสั่งคลาสสิก PowerShell เป็นสัตว์ร้ายอีกตัวหนึ่งตัวละครของมันคือ backtilt
Frédéric

ในการสรุป: "HEAD^"ใน cmd.exe หรือ PowerShell HEAD^^ใน cmd.exe HEAD`^ใน PowerShell มีประโยชน์ในการเรียนรู้ว่าเชลล์ - และเชลล์เฉพาะของคุณทำงานอย่างไร (เช่นวิธีที่คำสั่งเปลี่ยนเป็นแต่ละส่วนที่ส่งผ่านไปยังโปรแกรม) เพื่อให้คุณสามารถปรับคำสั่งออนไลน์เป็นอักขระที่เหมาะสมสำหรับเชลล์เฉพาะของคุณ (ไม่เฉพาะกับ Windows)
AndrewF

11

ตอนนี้ใน TortoiseGit ล่าสุดบน Windows คุณสามารถทำได้อย่างง่ายดาย

เปิดไดอะล็อก rebase กำหนดค่าและทำตามขั้นตอนต่อไปนี้

  • คลิกขวาที่การคอมมิทที่คุณต้องการแยกและเลือก " Edit" (จากการเลือก, สควอช, ลบ ... )
  • คลิก " Start" เพื่อเริ่มการรีบูต
  • เมื่อถึงความมุ่งมั่นที่จะแยกให้ทำเครื่องหมายที่Edit/Splitปุ่ม "" แล้วคลิกที่ " Amend" โดยตรง ไดอะล็อกกระทำจะเปิดขึ้น
    แก้ไข / แบ่งการกระทำ
  • ยกเลิกการเลือกไฟล์ที่คุณต้องการแยกการคอมมิท
  • แก้ไขข้อความยืนยันจากนั้นคลิก " commit"
  • จนกว่าจะมีไฟล์ที่จะส่งข้อความโต้ตอบนั้นจะเปิดขึ้นมาซ้ำแล้วซ้ำอีก เมื่อไม่มีไฟล์ที่จะคอมมิทมันจะยังถามคุณว่าคุณต้องการเพิ่มคอมมิท

มีประโยชน์มากขอบคุณ TortoiseGit!


10

คุณสามารถทำการรีบูตแบบโต้ตอบgit rebase -iได้ หน้าคนมีสิ่งที่คุณต้องการ:

http://git-scm.com/docs/git-rebase#_splitting_commits


14
การให้บริบทเพิ่มเติมเล็กน้อยเกี่ยวกับวิธีแก้ไขปัญหาเมื่อเทียบกับการให้ RTFM จะมีประโยชน์มากขึ้น
Jordan Dea-Mattson

8

git reset --soft HEAD^โปรดทราบนอกจากนี้ยังมี มันคล้ายกับgit reset(ซึ่งเป็นค่าเริ่มต้น--mixed) แต่จะรักษาเนื้อหาดัชนี ดังนั้นถ้าคุณได้เพิ่ม / ลบไฟล์คุณมีมันอยู่ในดัชนีแล้ว

กลายเป็นสิ่งที่มีประโยชน์มากในกรณีที่มีการโจมตีครั้งใหญ่


3

นี่คือวิธีแบ่งการคอมมิตในIntelliJ IDEA , PyCharm , PhpStorm และอื่น ๆ

  1. ในหน้าต่างบันทึกการควบคุมเวอร์ชันให้เลือกการคอมมิทที่คุณต้องการแยกคลิกขวาแล้วเลือก Interactively Rebase from Here

  2. ทำเครื่องหมายสิ่งที่คุณต้องการแยกเป็นeditคลิกStart Rebasing

  3. คุณควรเห็นแท็กสีเหลืองถูกวางไว้ซึ่งหมายความว่า HEAD ถูกตั้งค่าเป็นคอมมิชชันนั้น คลิกขวาที่การกระทำที่เลือกUndo Commit

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


2

สิ่งที่ง่ายที่สุดที่จะทำโดยไม่มีการรีบูตแบบโต้ตอบคือ (อาจ) เพื่อทำให้สาขาใหม่เริ่มต้นที่คอมมิชชันก่อนหน้าการแยกที่คุณต้องการแยก, เชอร์รี่เลือก -n การคอมมิท, รีเซ็ต, ซ่อน, คอมมิทย้ายไฟล์ กระทำการเปลี่ยนแปลงแล้วรวมกับสาขาเดิมหรือเชอร์รี่เลือกกระทำที่ตามมา (จากนั้นเปลี่ยนชื่อสาขาเดิมเป็นชื่อปัจจุบัน) (น่าจะดีกว่าถ้าทำตามคำแนะนำของ MBO และทำการ rebase เชิงโต้ตอบ)


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

@ YakovL ดูเหมือนว่าสมเหตุสมผล ในหลักการของการกระทำขั้นต่ำฉันจะไม่ลบคำตอบ แต่ฉันจะไม่คัดค้านถ้ามีคนอื่นทำ
วิลเลียม Pursell

นี่จะง่ายกว่าrebase -iคำแนะนำทั้งหมด ฉันคิดว่านี่ไม่ได้รับความสนใจมากนักเนื่องจากขาดการจัดรูปแบบใด ๆ บางทีคุณอาจตรวจสอบตอนนี้คุณมีคะแนน 126k และอาจรู้วิธีดังกล่าว ;)
erikbwork


1

หากคุณมีสิ่งนี้:

A - B <- mybranch

ที่ซึ่งคุณได้กระทำเนื้อหาบางอย่างในการกระทำ B:

/modules/a/file1
/modules/a/file2
/modules/b/file3
/modules/b/file4

แต่คุณต้องการแยก B เป็น C - D และรับผลลัพธ์นี้:

A - C - D <-mybranch

คุณสามารถแบ่งเนื้อหาเช่นนี้ได้เช่น (เนื้อหาจากไดเรกทอรีต่าง ๆ ในคอมมิทที่ต่างกัน) ...

รีเซ็ตสาขากลับสู่การส่งก่อนที่จะทำการแยก:

git checkout mybranch
git reset --hard A

สร้างการกระทำแรก (C):

git checkout B /modules/a
git add -u
git commit -m "content of /modules/a"

สร้างการกระทำที่สอง (D):

git checkout B /modules/b
git add -u
git commit -m "content of /modules/b"

เกิดอะไรขึ้นถ้ามีข้อผูกพันข้างต้น B?
CoolMind

1

เป็นเวลานานกว่า 8 ปีแล้ว แต่บางคนอาจเห็นว่ามันมีประโยชน์ rebase -iผมสามารถที่จะทำเคล็ดลับโดยไม่ต้อง ความคิดคือการนำคอมไพล์ไปสู่สถานะเดิมเหมือนที่คุณเคยทำgit commit:

# first rewind back (mind the dot,
# though it can be any valid path,
# for instance if you want to apply only a subset of the commit)
git reset --hard <previous-commit> .

# apply the changes
git checkout <commit-you-want-to-split>

# we're almost there, but the changes are in the index at the moment,
# hence one more step (exactly as git gently suggests):
# (use "git reset HEAD <file>..." to unstage)
git reset

หลังจากนี้คุณจะเห็นเงางามนี้Unstaged changes after reset:และ repo ของคุณอยู่ในสถานะเหมือนคุณกำลังจะส่งมอบไฟล์เหล่านี้ทั้งหมด จากนี้ไปคุณสามารถส่งมอบได้อย่างง่ายดายเหมือนที่คุณเคยทำ หวังว่ามันจะช่วย


0

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

git rebase -i <sha1_before_split>
# mark the targeted commit with 'edit'
git reset HEAD^
git add ...
git commit -m "First part"
git add ...
git commit -m "Second part"
git rebase --continue

เครดิตบล็อกโพสต์มานูเอลเบอร์นาร์ด

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