Làm thế nào để di chuyển một số cam kết dựa trên một nhánh khác trong git?


381

Tình huống:

  • chủ đang ở X
  • quickfix1 là tại X + 2 cam kết

Như vậy mà:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Sau đó, tôi bắt đầu làm việc trên quickfix2, nhưng tình cờ lấy quickfix1 làm nhánh nguồn để sao chép chứ không phải master. Bây giờ quickfix2 đang ở X + 2 lần xác nhận + 2 lần xác nhận có liên quan.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Bây giờ tôi muốn có một nhánh với quickfix2, nhưng không có 2 cam kết thuộc về quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Tôi đã cố gắng tạo một bản vá từ một bản sửa đổi nhất định trong quickfix2, nhưng bản vá không lưu giữ lịch sử cam kết. Có cách nào để lưu lịch sử cam kết của tôi, nhưng có một nhánh mà không thay đổi trong quickfix1 không?



8
@Kevin Câu hỏi đó chỉ hỏi về việc di chuyển các cam kết từ chi nhánh này sang chi nhánh khác, câu hỏi này có yêu cầu bổ sung không bao gồm các cam kết trên quickfix1. (Lưu ý sự khác biệt trong câu trả lời.)
Scott Weldon

Câu trả lời:


372

Đây là một trường hợp kinh điển của rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Vì vậy, bạn nên đi từ

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

đến:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Điều này được thực hiện tốt nhất trên một cây làm việc sạch sẽ.
Xemgit config --global rebase.autostash true , đặc biệt là sau Git 2.10 .


24
Lưu ý rằng các bước này sẽ sửa đổi lịch sử của quickfix2, vì vậy nếu bạn đã chia sẻ chi nhánh, thay vào đó hãy sử dụng tính năng chọn cherry (xem câu trả lời sau).
Max Chernyak

Chỉ dành cho các bản ghi: với nhật ký của SmartGit, chỉ cần kéo q2avào Xvà chọn Rebase 2 xác nhận từ các tùy chọn của hộp thoại xảy ra.
Thomas S.

1
@Thomas. Hấp dẫn. Đó là một triển khai GUI đẹp của a git rebase --onto.
VonC

1
Tôi phải thừa nhận, tôi làm những việc ngớ ngẩn như cam kết sai chi nhánh thường xuyên hơn mà tôi thực sự nên, GUI xem nhật ký SmartGit đã cứu tôi rất nhiều lần với tình huống tương tự.
CÔNG TRÌNH 6/08/2015

1
@Cosine Đồng ý. Tôi đã chỉnh sửa câu trả lời của mình để thêm tham chiếu vào rebase.autostashcấu hình: điều đó sẽ tránh mọi mất công trong tiến trình trong cây làm việc khi thực hiện rebase.
VonC

155

Bạn có thể sử dụng git cherry-pickđể chỉ chọn cam kết mà bạn muốn sao chép.

Có lẽ cách tốt nhất là tạo nhánh ra khỏi master, sau đó trong nhánh đó sử dụng git cherry-picktrên 2 lần xác nhận từ quickfix2 mà bạn muốn.


Đây cũng là tùy chọn tốt nhất nếu bạn muốn di chuyển chỉ một cam kết. Cảm ơn.
Alex

142

Điều đơn giản nhất bạn có thể làm là anh đào chọn một phạm vi. Nó làm giống như rebase --ontonhưng dễ hơn cho mắt :)

git cherry-pick quickfix1..quickfix2

6
Ngoài ra, nó không mất các cam kết ban đầu, IIUC, vì vậy có vẻ thích hợp hơn cho "play-it-két" như tôi;) hoặc rebase --ontocũng giữ nguyên các thay đổi ban đầu?
akavel

6
cả hai rebasecherry-pickcung cấp cho bạn các khóa SHA mới. Đó là bởi vì mỗi cam kết là một ảnh chụp nhanh duy nhất của kho lưu trữ.
Christoph

6
Điều @akavel có nghĩa là cherry-pick sẽ giữ các cam kết ban đầu trong chi nhánh của họ là đúng
Mr_and_Mrs_D

4
Đối với bất cứ điều gì nó có giá trị, tôi đã cố gắng cherry-pickmột phạm vi như trong câu trả lời này và nó nhầm lẫn repo của tôi. Tôi đã phải làm từng cherry-picks cho mỗi cam kết. (Và có lẽ nó đi mà không nói, nhưng trong trường hợp bất cứ ai đang gặp khó khăn, bạn phải cherry-picktheo thứ tự thời gian mà cam kết của bạn đã được áp dụng.)
carmenism

3
git checkoutlà rất quan trọng ở đây. ĐẦU của bạn là gì :)?
Sławomir Lenart

28

Tôi tin rằng:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2

3
cherry-pickhoạt động với băm cam kết vì vậy, nếu bạn chỉ muốn lấy một cam kết từ một nơi nào đó và đặt nó ở một nơi khác thì đây là cách để đi. Chỉ cần chắc chắn rằng bạn làm checkout <branch>chi nhánh chính xác đầu tiên.
John Leidegren

-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Các lệnh hữu ích khác ở đây với lời giải thích: Hướng dẫn Git

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.