Sắp xếp lại các cam kết


103

Tôi hiện đang làm việc trên một chi nhánh và muốn một số cam kết hợp nhất vào các chi nhánh khác:

    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)

(Các chữ cái biểu thị các cam kết và "x" là các cam kết không liên quan.)

Tuy nhiên, tôi nhận thấy rằng sẽ là một ý kiến ​​hay nếu gộp một số cam kết. Tôi muốn "nối" commit a, d, e và g thành một bản vá và commit nó thành master. Các cam kết b và f nên đi như một cam kết với nhánhB. Có cách 'git'-ish tốt để đạt được nó không?


4
Hai câu trả lời đã được đưa ra đề cập đến lệnh chính xác, nhưng tôi nghĩ rằng với một nhiệm vụ cơ bản như câu này, rất đáng để có hướng dẫn thực sự ở đây trên StackOverflow, vì vậy tôi đã đăng một số. (Tôi ngạc nhiên vì không thể tìm thấy một câu hỏi hay nào trước đó để liên kết đến.)
Cascabel

Câu trả lời:


125

Lệnh bạn đang tìm git rebase, cụ thể là -i/--interactivetùy chọn.

Tôi sẽ giả sử bạn muốn để lại cam kết c trên nhánh A, và điều đó thực sự có nghĩa là bạn muốn chuyển các cam kết khác sang các nhánh khác, thay vì hợp nhất, vì việc hợp nhất rất đơn giản. Hãy bắt đầu bằng cách thao tác với nhánh A.

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

^nghĩa là cam kết trước đó, vì vậy lệnh này nói để rebase nhánh A bằng cách sử dụng cam kết trước "a" làm cơ sở. Git sẽ cung cấp cho bạn danh sách các cam kết trong phạm vi này. Sắp xếp lại chúng và yêu cầu git chọn những cái thích hợp:

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

Bây giờ lịch sử sẽ như thế này:

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

Bây giờ, hãy lấy cam kết b + f mới được bóp méo cho nhánhB.

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

Và tương tự cho a + d + e + g cho master:

git checkout master
git cherry-pick branchA^

Cuối cùng, cập nhật branchA để nó trỏ đến c:

git branch -f branchA branchA^^

Bây giờ chúng ta nên có:

    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)

Lưu ý rằng nếu bạn có nhiều commit muốn di chuyển giữa các nhánh, bạn có thể sử dụng lại rebase (không tương tác):

# 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

Cuối cùng, tuyên bố từ chối trách nhiệm: Có thể sắp xếp lại thứ tự các cam kết theo cách mà một số không còn áp dụng rõ ràng nữa. Điều này có thể là do bạn đã chọn một thứ tự không tốt (đặt một bản vá trước khi cam kết giới thiệu tính năng mà nó đã vá); trong trường hợp đó, bạn sẽ muốn hủy bỏ rebase ( git rebase --abort). Nếu không, bạn sẽ phải khắc phục xung đột một cách thông minh (giống như bạn làm với xung đột hợp nhất), thêm các bản sửa lỗi, sau đó chạy git rebase --continueđể tiếp tục. Các hướng dẫn này cũng được cung cấp bởi thông báo lỗi được in khi xung đột xảy ra.


không phải là sơ đồ sau git branch -f branchA branchA^^sai? Cụ thể, nhánhA không nên trỏ đến c tại thời điểm này, vì vậy dòng đầu tiên của sơ đồ là c (branchA)và không c - [a+d+e+g] - [b+f] (branchA)?
ntc2

@enoksrd: Có, có một sai sót, nhưng bản chỉnh sửa của bạn có sai sót trong đó. Tôi sẽ sửa nó khi tôi có cơ hội ở đây.
Cascabel

Thay vì làm git branch -f branchA branchA^^tại sao bạn không thể thực hiện git reset --hard <sha1 of c>ở nhánh A?
Mikhail Vasilyev

17
git rebase -i HEAD~3

Đâu 3là số lượng cam kết cần sắp xếp lại ( nguồn ).

Thao tác này sẽ mở ra vi , liệt kê các cam kết từ cũ nhất (trên cùng) đến mới nhất (dưới).
Bây giờ sắp xếp lại thứ tự các dòng, lưuthoát khỏi trình chỉnh sửa.

ddpsẽ di chuyển dòng hiện tại xuống
ddkP sẽ di chuyển dòng hiện tại lên ( nguồn )


8

git rebase --interactive là lệnh bạn muốn.

Thí dụ:

Tình trạng hiện tại là:

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

Tôi muốn sắp xếp lại 9a24b81thứ tự các cam kết ( Cam kết thứ ba) và 7bdfb68( Cam kết thứ hai). Để làm điều này, đầu tiên tôi tìm cam kết trước khi cam kết đầu tiên mà chúng tôi muốn thay đổi . Đây là cam kết 186d1e0(First commit).

Trong git rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGEtrường hợp này, lệnh để thực thi là :

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

Thao tác này sẽ mở ra một tệp trong trình chỉnh sửa mặc định với nội dung sau:

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.
#

Lưu ý rằng thứ tự của các cam kết trong tệp ngược lại với thứ tự được sử dụng cho git log. Trong nhật ký git, cam kết gần đây nhất nằm ở trên cùng. Trong tệp này, cam kết gần đây nhất nằm ở dưới cùng.

Như nhận xét ở cuối tệp giải thích rằng tôi có thể làm nhiều việc khác nhau, chẳng hạn như thu gọn, bỏ và sắp xếp lại các cam kết. Để sắp xếp lại các cam kết, tôi chỉnh sửa tệp để nó trông như thế này (các nhận xét dưới cùng không được hiển thị):

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

Các picklệnh vào lúc bắt đầu của mỗi phương tiện đường "sử dụng (ví dụ bao gồm) này cam kết" và khi tôi lưu các tập tin tạm thời với các lệnh rebase và thoát trình soạn thảo, git sẽ thực thi các lệnh và cập nhật các kho lưu trữ và thư mục làm việc:

$ 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

Lưu ý lịch sử cam kết được viết lại.

Liên kết:


1
Vui lòng thêm các chi tiết liên quan từ liên kết của bạn, để cung cấp câu trả lời đầy đủ và khép kín. SO cau mày về "câu trả lời chỉ liên kết". Cụ thể, một người sẽ sử dụng như thế nào git rebase --interactiveđể đạt được mục tiêu của OP?
SherylHohman

Liên kết thứ hai hiện không tồn tại.
devsaw

Đã thêm nội dung để làm cho câu trả lời hoàn chỉnh và khép kín. Đã xóa liên kết thứ hai.
codeape


-1

git rebase là những gì bạn muốn. Kiểm tra tùy chọn - tương tác.


4
Vui lòng thêm các chi tiết liên quan từ liên kết của bạn, để cung cấp câu trả lời đầy đủ và khép kín. SO cau mày về "câu trả lời chỉ liên kết".
SherylHohman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.