Khởi động lại một cam kết hợp nhất Git


183

Lấy trường hợp sau:

Tôi có một số công việc trong một nhánh chủ đề và bây giờ tôi đã sẵn sàng để hợp nhất trở lại thành chủ:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

Tôi thực hiện hợp nhất từ ​​chủ, giải quyết các xung đột và bây giờ tôi có:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1

Bây giờ, việc hợp nhất đã làm tôi mất một thời gian, vì vậy tôi thực hiện một lần tìm nạp khác và nhận thấy rằng nhánh chủ từ xa có những thay đổi mới:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Nếu tôi thử 'git rebase origin / master' từ chủ, tôi buộc phải giải quyết lại tất cả các xung đột và tôi cũng mất cam kết hợp nhất:

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1

Có cách nào rõ ràng để từ chối cam kết hợp nhất để tôi kết thúc với một lịch sử như lịch sử tôi hiển thị bên dưới không?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1

74
TL; DR:git rebase --preserve-merges origin/master
Ilia K.

6
Liên quan đến việc phải giải quyết lại các xung đột, bạn có thể muốn xem qua git rerere .
Parker Coates

git config --global pull.rebase preserve để luôn duy trì các cam kết hợp nhất trong một cuộc
nổi loạn

4
Cảnh báo: bắt đầu với Git 2.18 (quý 2 năm 2018, 5 năm sau), git --rebase-mergescuối cùng sẽ thay thế cái cũ git --preserve-merges. Xem chính xác những gì Gạc của Gợi rebase --preserve-mergeslàm (và tại sao?)
VonC

1
--preserve-mergesbị phản đối Sử dụnggit rebase --rebase-merges origin/master
Arjun Sreedharan

Câu trả lời:


126

Có hai lựa chọn ở đây.

Một là thực hiện một rebase tương tác và chỉnh sửa cam kết hợp nhất, làm lại hợp nhất thủ công và tiếp tục rebase.

Một cách khác là sử dụng --rebase-mergestùy chọn trên git rebase, được mô tả như sau trong hướng dẫn sử dụng: "Theo mặc định, một rebase sẽ chỉ đơn giản là bỏ các xác nhận hợp nhất từ ​​danh sách việc cần làm và đặt các cam kết bị phản hồi vào một nhánh tuyến tính duy nhất. Với --rebase- hợp nhất, thay vào đó, rebase sẽ cố gắng duy trì cấu trúc phân nhánh trong các cam kết sẽ được khởi động lại, bằng cách tạo lại các cam kết hợp nhất. Mọi xung đột hợp nhất được giải quyết hoặc sửa đổi thủ công trong các cam kết hợp nhất này sẽ phải được giải quyết / áp dụng lại theo cách thủ công. "


16
Tôi đã thử tùy chọn -p và nó thực sự để lại lịch sử cam kết như tôi muốn, nhưng nó buộc tôi phải giải quyết các xung đột một lần nữa, ngay cả trong các tệp không được chỉnh sửa trong bản gốc / master. Theo đề nghị đầu tiên của bạn, đó sẽ là chuỗi lệnh chính xác?
jipumarino

2
@jipumarino: git rebase -i (bảo nó chỉnh sửa cam kết hợp nhất), khi nó đến cam kết hợp nhất, git reset --hard HEAD ^, git merge, sửa xung đột, git commit, git rebase --continue. Bạn cũng có thể muốn xem xét git rerere được cho là sẽ giúp với loại điều này (nhưng tôi chưa bao giờ sử dụng, vì vậy tôi không thể đưa ra bất kỳ lời khuyên hoặc trợ giúp nào).
siride

2
Cảm ơn. Tôi đã kích hoạt lại và thử với rebase -p và nó hoạt động như bình thường.
jipumarino

3
Đây là một bài đăng blog tuyệt vời mô tả tình huống chính xác này:
Rebasing Commge Commits

1
rere không phải là giải pháp, vì bạn vẫn phải giải quyết hợp nhất thủ công lần đầu tiên.
Flimm

29

Ok, đó là một câu hỏi cũ và nó đã chấp nhận câu trả lời @siride, nhưng câu trả lời đó không đủ trong trường hợp của tôi, vì --preserve-mergesbuộc bạn phải giải quyết tất cả các xung đột lần thứ hai. Giải pháp của tôi dựa trên ý tưởng bằng @Tobi Bnhưng với các lệnh chính xác từng bước

Vì vậy, chúng ta sẽ bắt đầu ở trạng thái như vậy dựa trên ví dụ trong câu hỏi:

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Lưu ý rằng chúng tôi có 2 cam kết trước chủ, vì vậy cherry-pick sẽ không hoạt động.

  1. Trước hết, hãy tạo lịch sử chính xác mà chúng tôi muốn:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    Chúng tôi sử dụng --preserve-mergesđể lưu cam kết hợp nhất của chúng tôi trong lịch sử. Chúng tôi sử dụng --strategy=oursđể bỏ qua tất cả các xung đột hợp nhất vì chúng tôi không quan tâm đến nội dung nào sẽ có trong cam kết hợp nhất đó, chúng tôi chỉ cần lịch sử tốt đẹp ngay bây giờ.

    Lịch sử sẽ trông như thế (bỏ qua chủ):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. Bây giờ hãy lấy chỉ số chính xác.

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    Chúng tôi có thể nhận được một số xung đột hợp nhất bổ sung tại đây, nhưng đó chỉ là xung đột từ các tệp được thay đổi giữa 8101fe3f5a7ca8, nhưng không bao gồm các xung đột đã được giải quyết từtopic

    Lịch sử sẽ trông như thế này (bỏ qua lịch sử chính xác):

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. Giai đoạn cuối cùng là kết hợp chi nhánh của chúng tôi với lịch sử và chi nhánh chính xác với chỉ mục chính xác

    git reset --soft correct-history
    git commit --amend
    

    Chúng tôi sử dụng reset --softđể đặt lại chi nhánh (và lịch sử) của mình thành lịch sử chính xác, nhưng để lại chỉ mục và cây làm việc như hiện tại. Sau đó, chúng tôi sử dụng commit --amendđể viết lại cam kết hợp nhất của chúng tôi, được sử dụng để có chỉ mục không chính xác, với chỉ mục tốt của chúng tôi từ chủ.

    Cuối cùng, chúng ta sẽ có trạng thái như vậy (lưu ý một id khác của cam kết hàng đầu):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    

Điều này thật tuyệt vời và giúp ích rất nhiều! Nhưng tôi đã không nhận được mánh khóe với cam kết --amend: bạn có thể thêm thông tin về điều đó không? Chính xác thì chuyện gì sẽ xảy ra sau khi bạn chạy nó - tôi nhận thấy SHA của cam kết đã thay đổi - nhưng tại sao? Hoặc điều gì xảy ra nếu bạn không chạy nó?
ZenJ 27/07/18

1
@ZenJ git commit --amendthêm các thay đổi vào lần xác nhận cuối cùng (CHÍNH, trong trường hợp này là cam kết hợp nhất). Bởi vì nội dung cam kết thay đổi, hàm băm được cập nhật.
Dries Staelens

1
Đối với những người không kích hoạt 'trước khi sửa lỗi xung đột, giải pháp này rất tốt vì nó giúp bạn không phải sửa xung đột một lần nữa. Cảm ơn!
Shackleford

6

Cho rằng tôi vừa mất một ngày cố gắng tìm ra điều này và thực sự tìm ra giải pháp với sự giúp đỡ của đồng nghiệp, tôi nghĩ tôi nên hô vang.

Chúng tôi có một cơ sở mã lớn và chúng tôi phải đối phó với 2 chi nhánh bị sửa đổi nhiều cùng một lúc. Có một nhánh chính và một nhánh phụ nếu bạn.

Trong khi tôi hợp nhất nhánh phụ vào nhánh chính, công việc vẫn tiếp tục ở nhánh chính và đến khi tôi hoàn thành, tôi không thể thúc đẩy các thay đổi của mình vì chúng không tương thích.

Do đó, tôi cần phải "rebase" "hợp nhất" của mình.

Đây là cách cuối cùng chúng tôi đã làm nó:

1) ghi chú của SHA. ví dụ: c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1

2) Tạo lịch sử thích hợp nhưng điều này sẽ phá vỡ sự hợp nhất.

git rebase -s ours --preserve-merges origin/master

3) ghi chú của SHA. ví dụ: 29dd8101d78

git log -1

4) Bây giờ đặt lại về nơi bạn đã ở trước đây

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard

5) Bây giờ hợp nhất chủ hiện tại vào nhánh làm việc của bạn

git merge origin/master
git mergetool
git commit -m"correct files

6) Bây giờ bạn có các tệp đúng, nhưng lịch sử sai, hãy lấy đúng lịch sử trên thay đổi của bạn với:

git reset 29dd8101d78 --soft

7) Và sau đó - gửi kết quả trong cam kết hợp nhất ban đầu của bạn

git commit --amend

Voila!


1

Có vẻ như những gì bạn muốn làm là loại bỏ hợp nhất đầu tiên của bạn. Bạn có thể làm theo quy trình sau:

git checkout master      # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull                 # or git merge remote/master
git merge topic

Điều đó sẽ cung cấp cho bạn những gì bạn muốn.


4
Khi được kích hoạt lại, điều này dường như mang lại kết quả tương tự như giải pháp rebase -p được đưa ra ở trên bởi siride.
jipumarino

0
  • Từ cam kết hợp nhất của bạn
  • Cherry-pick thay đổi mới sẽ dễ dàng
  • sao chép nội dung của bạn
  • làm lại việc hợp nhất và giải quyết các xung đột bằng cách chỉ sao chép các tệp từ bản sao cục bộ của bạn;)

1
Câu trả lời này có vẻ tốt nhưng sẽ hữu ích hơn nếu bạn đưa ra các lệnh git thực tế, trong trường hợp người dùng chưa quen với git
Louise Davies
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.