การเรียงลำดับใหม่ของการกระทำ


110

ฉันกำลังทำงานในสาขาหนึ่งและต้องการให้คำมั่นที่จะรวมเข้ากับสาขาอื่น:

    a-b-c-d-e-f-g (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)
   \
    x-x-x-x-x (branchB)

(ตัวอักษรแสดงถึงการกระทำและ "x" คือการกระทำที่ไม่เกี่ยวข้อง)

อย่างไรก็ตามฉันสังเกตว่ามันเป็นความคิดที่ดีที่จะรวมการกระทำบางอย่าง ฉันต้องการ "เชื่อมต่อ" คอมมิต a, d, e และ g เป็นแพทช์เดียวและส่งให้เชี่ยวชาญ การกระทำ b และ f ควรเป็นไปตามที่กระทำกับ branch B มีวิธี 'git'-ish ที่ดีในการบรรลุหรือไม่?


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

คำตอบ:


131

คำสั่งที่คุณกำลังมองหาคือตัวเลือกgit rebaseโดยเฉพาะ-i/--interactive

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

git rebase -i <SHA1 of commit a>^ branchA

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

pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f

ตอนนี้ประวัติควรมีลักษณะดังนี้:

    c - [a+d+e+g] - [b+f] (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)

ตอนนี้เรามาจับคอมมิต b + f ใหม่สำหรับ branchB

git checkout branchB
git cherry-pick branchA  # cherry-pick one commit, the tip of branchA

และเช่นเดียวกันสำหรับ a + d + e + g สำหรับ master:

git checkout master
git cherry-pick branchA^

สุดท้ายอัปเดต branchA เพื่อให้ชี้ไปที่ c:

git branch -f branchA branchA^^

ตอนนี้เราควรมี:

    c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
   /
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
   \
    x-x-x-x-x-[b+f] (branchB)

โปรดทราบว่าหากคุณมีการคอมมิตหลายรายการที่ต้องการย้ายระหว่างสาขาคุณสามารถใช้ rebase ได้อีกครั้ง (ไม่โต้ตอบ):

# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB

ในที่สุดข้อจำกัดความรับผิดชอบ: เป็นไปได้ค่อนข้างมากที่จะเรียงลำดับคอมมิตใหม่ในลักษณะที่บางคนไม่สามารถใช้งานได้อย่างหมดจดอีกต่อไป อาจเป็นเพราะคุณเลือกลำดับที่ไม่ถูกต้อง (วางแพตช์ก่อนคอมมิตแนะนำฟีเจอร์ที่ได้รับการแก้ไข) ในกรณีนี้คุณจะต้องยกเลิก rebase ( git rebase --abort) มิฉะนั้นคุณจะต้องแก้ไขข้อขัดแย้งอย่างชาญฉลาด (เช่นเดียวกับการผสานความขัดแย้ง) เพิ่มการแก้ไขจากนั้นเรียกใช้git rebase --continueเพื่อดำเนินการต่อ นอกจากนี้คำแนะนำเหล่านี้ยังมีให้โดยข้อความแสดงข้อผิดพลาดที่พิมพ์ออกมาเมื่อเกิดความขัดแย้ง


แผนภาพgit branch -f branchA branchA^^ไม่ถูกต้องหรือไม่? คือไม่ควร branchA ชี้ไปที่จุดนี้เพื่อให้บรรทัดแรกของแผนภาพคือc (branchA)ไม่ใช่c - [a+d+e+g] - [b+f] (branchA)?
ntc2

@enoksrd: ใช่มีข้อผิดพลาด แต่การแก้ไขของคุณมีข้อผิดพลาด ฉันจะแก้ไขเมื่อมีโอกาสที่นี่
Cascabel

แทนที่จะทำgit branch -f branchA branchA^^ทำไมทำgit reset --hard <sha1 of c>สาขา A ไม่ได้?
Mikhail Vasilyev

21
git rebase -i HEAD~3

ที่ไหน3คือจำนวนของการกระทำว่าต้องสั่งใหม่ (คนที่มา )

การดำเนินการนี้จะเปิดviโดยแสดงรายการจากเก่าที่สุด (บนสุด) ไปยังใหม่ล่าสุด (ล่างสุด)
ตอนนี้เรียงลำดับบรรทัดใหม่บันทึกและออกจากโปรแกรมแก้ไข

ddpจะย้ายบรรทัดปัจจุบันลง
ddkPจะย้ายบรรทัดปัจจุบันขึ้น (ที่มา )


10

git rebase --interactive คือคำสั่งที่คุณต้องการ

ตัวอย่าง:

สถานะปัจจุบันคือ:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git status
On branch master
nothing to commit, working tree clean
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
a6e3c6a (HEAD -> master) Fourth commit
9a24b81 Third commit
7bdfb68 Second commit
186d1e0 First commit

ฉันต้องการเรียงลำดับคอม9a24b81มิตใหม่(คอมมิตที่สาม) และ7bdfb68(คอมมิตที่สอง) การทำเช่นนี้ครั้งแรกที่ผมพบว่ากระทำก่อนที่จะกระทำแรกเราต้องการที่จะเปลี่ยนแปลง นี่คือการกระทำ186d1e0(การกระทำครั้งแรก)

คำสั่งในการดำเนินการคือgit rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGEในกรณีนี้:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git rebase --interactive 186d1e0

สิ่งนี้จะเปิดไฟล์ในโปรแกรมแก้ไขเริ่มต้นที่มีเนื้อหาต่อไปนี้:

pick 7bdfb68 Second commit
pick 9a24b81 Third commit
pick a6e3c6a Fourth commit

# Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
#
# 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
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

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

ตามความคิดเห็นที่ด้านล่างของไฟล์อธิบายว่ามีหลายสิ่งที่ฉันทำได้เช่นการบีบการวางและการเรียงลำดับคอมมิตใหม่ ในการสั่งคอมมิตใหม่ฉันแก้ไขไฟล์ให้มีลักษณะเช่นนี้ (ไม่แสดงความคิดเห็นด้านล่าง):

pick 9a24b81 Third commit
pick 7bdfb68 Second commit
pick a6e3c6a Fourth commit

pickคำสั่งในช่วงเริ่มต้นของแต่ละบรรทัดหมายถึง "การใช้งาน (เช่นรวม) กระทำนี้" และเมื่อฉันบันทึกไฟล์ชั่วคราวที่มีคำสั่ง rebase และออกจากบรรณาธิการคอมไพล์จะรันคำสั่งและการปรับปรุงพื้นที่เก็บข้อมูลและไดเรกทอรีการทำงาน:

$ git rebase --interactive 186d1e0
Successfully rebased and updated refs/heads/master.
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
ba48fc9 (HEAD -> master) Fourth commit
119639c Second commit
9716581 Third commit
186d1e0 First commit

จดบันทึกประวัติการคอมมิตที่เขียนใหม่

ลิงค์:


1
โปรดเพิ่มรายละเอียดที่เกี่ยวข้องจากลิงก์ของคุณเพื่อให้คำตอบที่สมบูรณ์และมีอยู่ในตัว ดังนั้นจึงขมวดคิ้ว "คำตอบแบบลิงก์เท่านั้น" โดยเฉพาะจะใช้อย่างไรgit rebase --interactiveเพื่อให้บรรลุเป้าหมายของ OP?
SherylHohman

ลิงก์ที่สองไม่มีอยู่ในขณะนี้
devsaw

เพิ่มเนื้อหาเพื่อให้คำตอบสมบูรณ์และมีตัวตน ลบลิงค์ที่สอง
codeape


-2

git rebaseคือสิ่งที่คุณต้องการ ลองดูตัวเลือก --interactive


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