git cherry-pick nói rằng Gian Bài 38c74d là một sự hợp nhất nhưng không có tùy chọn nào được đưa ra


519

Tôi đã thực hiện một số thay đổi trong nhánh chính của mình và muốn đưa những thứ đó ngược dòng. Khi tôi chọn các cam kết sau đây, tuy nhiên tôi bị kẹt trên fd9f578 trong đó git nói:

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

Git đang cố nói gì với tôi và anh đào có chọn đúng thứ đang sử dụng ở đây không? Nhánh chính bao gồm các thay đổi đối với các tệp đã được sửa đổi trong nhánh ngược dòng, vì vậy tôi chắc chắn sẽ có một số xung đột hợp nhất nhưng những điều đó không quá tệ để giải quyết. Tôi biết những thay đổi cần thiết ở đâu.

Đây là những cam kết tôi muốn đưa lên thượng nguồn.

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...

Câu trả lời:


607

Cách thức hoạt động của cherry-pick bằng cách lấy diff thay đổi đại diện (sự khác biệt giữa cây làm việc tại thời điểm đó và cây làm việc của cha mẹ của nó) và áp dụng nó vào nhánh hiện tại của bạn.

Vì vậy, nếu một cam kết có hai hoặc nhiều cha mẹ, nó cũng đại diện cho hai hoặc nhiều khác biệt - cái nào nên được áp dụng?

Bạn đang cố gắng hái anh đào fd9f578, đó là sự hợp nhất với hai cha mẹ. Vì vậy, bạn cần nói với lệnh cherry-pick, cái nào sẽ được tính toán với độ lệch khác, bằng cách sử dụng -mtùy chọn. Ví dụ, git cherry-pick -m 1 fd9f578để sử dụng cha mẹ 1 làm cơ sở.

Tôi không thể nói chắc chắn cho tình huống cụ thể của bạn, nhưng sử dụng git mergethay vì git cherry-pickthường được khuyến khích. Khi bạn cherry-chọn một hợp nhất cam kết, nó sụp đổ tất cả những thay đổi được thực hiện trong cha mẹ bạn không chỉ định để -mvào đó một cam kết . Bạn mất tất cả lịch sử của họ, và cùng nhau tìm hiểu tất cả các khác biệt của họ. Cuộc gọi của bạn.


3
@wufoo Có lẽ bạn cũng nên tìm hiểu về git rebase- nó giống như một sự hợp nhất, nhưng thay vì tích hợp hai nhánh, nó ghép một nhánh để ngồi trên đỉnh kia.
Borealid

91
Làm thế nào để bạn biết số phụ huynh?
Anentropic

66
@Anentropic 1 là "cha mẹ đầu tiên", 2 là "cha mẹ thứ hai", v.v. Thứ tự là thứ tự được liệt kê trong cam kết (như được xem bởi git showvà tương tự).
Borealid

2
@lkraav Bạn cũng có thể vừa thực hiện git reset --hard HEAD@{1}để lấy lại cam kết còn thiếu của mình. git resetkhông bị hạn chế di chuyển "ngược" trong lịch sử. git checkout -b mybranch HEAD@{1}cũng sẽ làm việc
Borealid

4
CẢNH BÁO: git mergecó thể có hậu quả không lường trước. Lệnh đó sẽ thêm tất cả các xác nhận (cũ) khác tồn tại trên nhánh cha. Thông thường mọi người chọn hái cherry vì họ không muốn các cam kết khác. Hãy chắc chắn rằng bạn kiểm tra lại rằng bạn chỉ thực hiện những thay đổi bạn muốn!
Kay V

52

-m có nghĩa là số cha mẹ.

Từ tài liệu git:

Thông thường, bạn không thể chọn hợp nhất vì bạn không biết phía nào của hợp nhất nên được coi là đường chính. Tùy chọn này chỉ định số cha (bắt đầu từ 1) của dòng chính và cho phép cherry-pick phát lại thay đổi liên quan đến cha mẹ được chỉ định.

Ví dụ: nếu cây cam kết của bạn giống như dưới đây:

- A - D - E - F -   master
   \     /
    B - C           branch one

sau đó git cherry-pick Esẽ tạo ra vấn đề bạn gặp phải

git cherry-pick E -m 1có nghĩa là sử dụng D-E, trong khi git cherry-pick E -m 2có nghĩa là sử dụng B-C-E.


32

Câu trả lời của @ Borealid là chính xác, nhưng giả sử rằng bạn không quan tâm đến việc lưu giữ lịch sử hợp nhất chính xác của một chi nhánh và chỉ muốn chọn một phiên bản tuyến tính của nó. Đây là một cách dễ dàng và an toàn để làm điều đó:

Trạng thái bắt đầu: bạn đang ở chi nhánh Xvà bạn muốn chọn những cam kết Y..Z.

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (không bắt buộc) git branch -D tempZ

Điều này làm là tạo ra một nhánh tempZdựa trên Z, nhưng với lịch sử từ Ytuyến tính trở đi, và sau đó chọn anh đào trên một bản sao của lệnh Xgọi newX. (An toàn hơn khi thực hiện việc này trên một nhánh mới thay vì đột biến X.) Tất nhiên có thể có xung đột ở bước 4, điều này bạn sẽ phải giải quyết theo cách thông thường ( cherry-pickhoạt động rất giống rebasevới khía cạnh đó). Cuối cùng nó xóa tempZnhánh tạm thời .

Nếu bước 2 đưa ra thông báo "tempZ chi nhánh hiện tại đã cập nhật", thì đó Y..Zđã là tuyến tính, vì vậy chỉ cần bỏ qua thông báo đó và tiếp tục với bước 3 trở đi.

Sau đó xem xét newXvà xem liệu điều đó đã làm những gì bạn muốn.

(Lưu ý: điều này không giống như đơn giản git rebase Xkhi ở trên nhánh Z, vì nó không phụ thuộc vào bất kỳ cách nào vào mối quan hệ giữa XY; có thể có những cam kết giữa tổ tiên chung và Ybạn không muốn.)


1
git rebase YnóiCurrent branch tempZ is up to date
Basilevs

Tôi nghĩ điều đó có nghĩa Y..Zlà đã tuyến tính. Vì vậy, bạn có thể bỏ qua tin nhắn đó và tiến hành các bước 3 và 4.
Daira Hopwood

1
Ý tưởng thú vị, tôi đã phải vẽ nó ra giấy để đánh giá đầy đủ những gì đang diễn ra = D
Chris

2
Xuất sắc. git cherry-pick cho toàn bộ phạm vi phàn nàn rằng tùy chọn -m bị thiếu hoặc nó được cung cấp. Giải pháp của bạn là vàng. (Một đề xuất: xóa chi nhánh tempZ sau)
Otheus

1
Thật đáng kinh ngạc! Tôi đã vật lộn với hái cherry và chỉ điều này có ý nghĩa. Tôi đã gặp một chút rắc rối với các chữ cái được chọn (một số nhánh và cam kết là chữ in hoa và một số nhánh là chữ thường)
pcarvalho

19

Đơn giản hóa. Cherry-chọn các cam kết. Đừng chọn anh đào hợp nhất.

Dưới đây là một bản viết lại của câu trả lời được chấp nhận, lý tưởng làm rõ những lợi thế / rủi ro của các phương pháp có thể:

Bạn đang cố gắng chọn cherry fd9f578, đó là sự hợp nhất với hai cha mẹ.

Thay vì chọn cherry hợp nhất, điều đơn giản nhất là cherry chọn (các) cam kết bạn thực sự muốn từ mỗi nhánh trong hợp nhất.

Vì bạn đã hợp nhất, có thể tất cả các cam kết mong muốn của bạn đều nằm trong danh sách của bạn. Cherry-pick chúng trực tiếp và bạn không cần phải làm phiền với cam kết hợp nhất.

giải trình

Cách thức hoạt động của cherry-pick bằng cách lấy khác biệt mà một bộ thay đổi thể hiện (sự khác biệt giữa cây làm việc tại thời điểm đó và cây làm việc của cha mẹ của nó) và áp dụng bộ thay đổi cho nhánh hiện tại của bạn.

Nếu một cam kết có hai hoặc nhiều cha mẹ, như trường hợp hợp nhất, thì cam kết đó cũng đại diện cho hai hoặc nhiều khác biệt. Lỗi xảy ra do không chắc chắn nên áp dụng khác biệt.

lựa chọn thay thế

Nếu bạn xác định bạn cần bao gồm hợp nhất và chọn anh đào các cam kết liên quan, bạn có hai tùy chọn:

  1. (Phức tạp và tối nghĩa hơn; cũng loại bỏ lịch sử) bạn có thể chỉ ra cha mẹ nào nên áp dụng.

    • Sử dụng -mtùy chọn để làm như vậy. Ví dụ: git cherry-pick -m 1 fd9f578sẽ sử dụng cha mẹ đầu tiên được liệt kê trong hợp nhất làm cơ sở.

    • Cũng xem xét rằng khi bạn cherry-chọn một hợp nhất cam kết, nó sụp đổ tất cả những thay đổi được thực hiện trong cha mẹ bạn không chỉ định để -mvào đó một cam kết . Bạn mất tất cả lịch sử của họ, và cùng nhau tìm hiểu tất cả các khác biệt của họ. Cuộc gọi của bạn.

  2. (Đơn giản hơn và quen thuộc hơn; lưu giữ lịch sử) bạn có thể sử dụng git mergethay vì git cherry-pick.

    • Như thường lệ git merge, nó sẽ cố gắng áp dụng tất cả các xác nhận tồn tại trên nhánh bạn đang hợp nhất và liệt kê chúng riêng lẻ trong nhật ký git của bạn.

2

Đơn giản hóa phương pháp @Daira Hopwood tốt để chọn một cam kết duy nhất. Không cần chi nhánh tạm thời.

Trong trường hợp của tác giả:

  • Z là muốn cam kết (fd9f578)
  • Y cam kết trước nó
  • Chi nhánh làm việc hiện tại

sau đó làm:

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

2
Điều này tất nhiên làm mất siêu dữ liệu liên quan đến cam kết ban đầu. Tôi đoán đó là vấn đề quan điểm cho dù nó đơn giản hơn. Đôi khi tôi sử dụng nó khi tôi muốn mất siêu dữ liệu và chỉ giữ các thay đổi mã tổng thể. Lưu ý rằng nó hoạt động ngay cả khi Y không phải là cha mẹ ngay lập tức của Z (trong trường hợp đó, các thay đổi sẽ bị xóa sạch).
Daira Hopwood
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.