2012-03-01 25 views
7

Sử dụng git v1.7.1 Tôi đang cố thực hiện rebase với cả hai tính năng --preserve-merges--onto cùng một lúc. Kết quả cuối cùng dường như không có các cam kết hợp nhất, và do đó xuất hiện tuyến tính. Tôi muốn giữ lại các cam kết hợp nhất, vì lý do tương tự mà mọi người thường sử dụng --preserve-merges (dễ dàng hơn để xem nhóm các cam kết đã được một cách hợp lý một tính năng riêng biệt và phát triển trong chi nhánh riêng của nó).git rebase "--preserve-merges --onto" không bảo toàn việc hợp nhất

ngành thạc sĩ của tôi (điểm đến cho rebase) là nhàm chán:

A-B-C

Nhánh tính năng tôi muốn đi từ có một chi nhánh phụ tính năng đã được sáp nhập vào nó. Giống như:

 X - Y 
/ \ 
V-W ------ Z 

Trường hợp Z là cam kết hợp nhất là người đứng đầu nhánh tính năng cần lấy, và X và Y ở trên nhánh phụ.

Tôi đang sử dụng: git rebase --preserve-merges --onto C V Z

Tôi muốn kết thúc với:

  X - Y 
     / \ 
A-B-C-W ------ Z 

Nhưng thay vào đó tôi nhận được:

A-B-C-W-X-Y 

Từ Z là một conflict- hợp nhất miễn phí, trạng thái cuối cùng của mã là chính xác, nhưng lịch sử không phải là biểu cảm như tôi muốn.

Có cách nào để có được những gì tôi muốn không?

chỉnh sửa địa chỉ @Bombe: Tôi đã viết một tập lệnh bash để xây dựng ví dụ của tôi. Trên hệ thống của tôi (RHEL 6.2 với git 1.7.1) điều này chứng tỏ vấn đề của tôi.

#! /bin/bash 
# start a new empty repo 
git init 
# make some commits on the master branch 
git checkout master 
touch A.txt; git add A.txt; git commit -m "add A.txt"; git tag Atag 
touch B.txt; git add B.txt; git commit -m "add B.txt"; git tag Btag 
touch C.txt; git add C.txt; git commit -m "add C.txt"; git tag Ctag 
# now build the feature branch 
# start at Btag (more or less arbitrary; point is it's before C) 
git checkout Btag 
git checkout -b feature 
touch V.txt; git add V.txt; git commit -m "add V.txt"; git tag Vtag 
touch W.txt; git add W.txt; git commit -m "add W.txt"; git tag Wtag 
# now a subfeature 
git checkout -b subfeature 
touch X.txt; git add X.txt; git commit -m "add X.txt"; git tag Xtag 
touch Y.txt; git add Y.txt; git commit -m "add Y.txt"; git tag Ytag 
# merge the subfeature into the feature 
# preserves branch history with --no-ff 
git checkout feature 
git merge --no-ff subfeature 
# the merge commit is our Z 
git tag Ztag 
# one more commit so that merge isn't the tip (for better illustration of Z missing later) 
touch postZ.txt; git add postZ.txt; git commit -m "add postZ.txt"; git tag postZtag 
# now do the rebase 
git rebase --preserve-merges --onto Ctag Vtag 
# optionally move the master branch forward to the top of feature branch 
git checkout master 
git merge feature 

Trước rebase tôi nhận được:

 X-Y 
    / \ 
    V-W-----Z-postZ 
/
A-B-C 

Sau rebase tôi nhận được:

 X-Y 
    / \ 
    V-W-----Z-postZ 
/
A-B-C-W'-X'-Y'-postZ' 

Note thiếu Z 'giữa Y' và postZ'.

Trả lời

10

Rất cám ơn Bombe và một người bạn ngoại tuyến đã chỉ ra rằng nó không hoạt động đối với một số người. Với nguồn cảm hứng đó, bây giờ tôi có thể trả lời câu hỏi của riêng tôi.

Câu trả lời ngắn: các phiên bản git trước 1.7.5.2 sẽ hiển thị hành vi xấu này.

Câu trả lời dài: trong repo nguồn riêng của git, cam kết c192f9c865dbdae48c0400d717581d34cd315fb8 vào ngày 28 tháng 4 năm 2011 rõ ràng là bản sửa lỗi cho vấn đề này.

Để trích dẫn thông điệp cam kết (do Andrew Wong):

git-rebase--interactive.sh: preserve-merges fails on merges created with no-ff 

'git rebase' uses 'git merge' to preserve merges (-p). This preserves 
the original merge commit correctly, except when the original merge 
commit was created by 'git merge --no-ff'. In this case, 'git rebase' 
will fail to preserve the merge, because during 'git rebase', 'git 
merge' will simply fast-forward and skip the commit. For example: 

       B 
      /\ 
      A---M 
      /
    ---o---O---P---Q 

If we try to rebase M onto P, we lose the merge commit and this happens: 

       A---B 
       /
    ---o---O---P---Q 

To correct this, we simply do a "no fast-forward" on all merge commits 
when rebasing. Since by the time we decided to do a 'git merge' inside 
'git rebase', it means there was a merge originally, so 'git merge' 
should always create a merge commit regardless of what the merge 
branches look like. This way, when rebase M onto P from the above 
example, we get: 

        B 
       /\ 
       A---M 
       /
    ---o---O---P---Q 

Giải pháp: có được một phiên bản mới của git, xây dựng từ nguồn nếu cần thiết.

Btw, tôi đã sử dụng git bisect để tìm hiểu điều này. Công cụ tuyệt vời.

0

Tôi vừa cố gắng tạo lại tình huống của bạn và tôi có thể báo cáo rằng --preserve-merges dường như đang hoạt động như được quảng cáo. Khi bạn ở cam kết Z, chỉ cần phát hành:

git rebase --preserve-merges --onto C V 

Đó là những gì tôi đã làm và bảo quản cam kết hợp nhất.

+0

Tôi đã chỉnh sửa bài đăng gốc để cung cấp các bước để tái tạo sự cố của mình. Tôi chắc chắn bạn đã đúng, nhưng tôi không thấy những gì tôi đang làm sai. – RaveTheTadpole

+2

Và tôi thực sự có một phiên bản lớn hơn 1.7.5.2. :) – Bombe

1

Tôi đã gặp phải vấn đề này. Lưu ý phiên bản git của tôi, nó là 1.7.10.2.

Tôi đang thực hiện việc rebase phạm vi cam kết (được xác định bằng băm SHA1) vào một nhánh và cũng thiếu cam kết hợp nhất cuối cùng.

Giải pháp của tôi là để rebase W thành X (không có --preserve-merges) và sau đó rebase (with --preserve-merges) Y, Z và postZ lên X '.

Hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan