2016-05-15 16 views
5

Tôi đang cố gắng tìm hiểu cách sử dụng git cherry pick, tôi đọc các trang hướng dẫn sử dụng git trả về bằng cách thực hiện git cherry-pick --help nhưng điều đó dường như không giúp ích gì. Tôi sẽ cố gắng giải thích vấn đề dưới đây. Tôi có hai chi nhánh masterother.Git cherry-pick gây ra xung đột hợp nhất trong khi hợp nhất không

Mở chi nhánh master Các cam kết lịch sử là

0x2 Second commit from master branch 
0x1 Initial commit 

Và các tập tin chỉ trong kho mà tôi đang theo dõi readme có các nội dung sau

Some text 

Mở chi nhánh other Lịch sử cam kết là

0x5 CHECKPOINT, going to cherry-pick onto master 
0x4 second commit from branch other 
0x3 first commit from other branch: 
0x2 Second commit from master branch 
0x1 Initial commit 

Và nội dung của file readme

Some text. 

Adding some text from other branch. Adding some more text. 

Going to cherry-pick this commit. 

Các thư mục làm việc sạch sẽ trên cả hai chi nhánh không có thay đổi được theo dõi. Từ thời điểm này, khi tôi chuyển sang nhánh chính và hợp nhất với git merge other quá trình hợp nhất diễn ra một cách duyên dáng mà không có xung đột hợp nhất. Nhưng khi tôi cố gắng git cherry-pick 0x5 có một cuộc xung đột nhập, tôi nhận được kết quả sau từ git

error: could not apply 0x5... CHECKPOINT, going to cherry-pick onto master 
hint: after resolving the conflicts, mark the corrected paths 
hint: with 'git add <paths>' or 'git rm <paths>' 
hint: and commit the result with 'git commit' 

readme tập tin có các nội dung sau

<<<<<<< HEAD 
Some text 
======= 
Some text. 

Adding some text from other branch. Adding some more text. 

Going to cherry-pick this commit. 
>>>>>>> 0x5... CHECKPOINT, going to cherry-pick onto master 

Tại sao lại có cuộc xung đột nhập này? Tôi đang cố gắng hiểu tại sao nó xảy ra. Không nên cherry-pick ing giống như cố gắng thực hiện tất cả các chỉnh sửa được thực hiện trên cam kết sẽ là cherry-pick tự chỉnh sửa và sau đó cam kết thay đổi đó vào chi nhánh (master trong trường hợp này)?

Ngoài ra khi chính xác có xung đột hợp nhất trong git? Tôi dường như nhận được chúng vào những thời điểm kỳ lạ. Việc triển khai này có phụ thuộc không (ví dụ phụ thuộc vào thuật toán được sử dụng để hợp nhất)?

Cảm ơn bạn!

Trả lời

1

Nếu bạn nói merge, tất cả ba (3-5) cam kết sẽ được hợp nhất. Nếu bạn cherry-pick chỉ cái cuối cùng được sử dụng. (Các) tệp mà nó lo ngại có thể có các thay đổi đã có trong 3 và/hoặc 4 do đó giai đoạn ban đầu không khớp với những gì được mong đợi.

Hãy kiểm tra xung đột để xem lý do xảy ra với công cụ hợp nhất.

Ví dụ này sẽ gây ra một cuộc xung đột:

Original 
Original 
Original 
Commit3 
Original 
Commit5 
Original 

đây cơ diff git sẽ chứng minh rằng bạn đã thay đổi một dòng được trước bởi một vài dòng, trong đó có một dòng từ cam 3. Cherry-pick doesn' t thấy rằng dòng trong bản gốc để git sẽ hét lên xung đột và yêu cầu bạn xử lý nó. Không có bản chỉnh sửa xung đột nào (ví dụ như cùng một dòng đã được chỉnh sửa), git không chắc chắn vị trí đặt phần đã chỉnh sửa.

Tất nhiên bạn có thể chỉnh sửa thủ công các tệp theo cách bạn muốn.Chỉ có các chi nhánh hợp nhất mới có vấn đề và xung đột và không phải tất cả xung đột đều có nghĩa là "bạn không thể làm điều này", họ chỉ có nghĩa là "Tôi không biết chính xác phải làm gì, bạn tự xử lý nó".

+1

Nhưng nếu tôi tiếp tục và tự thực hiện các thay đổi sẽ được thực hiện nếu lựa chọn anh đào đi qua thì không có vấn đề như vậy, tại sao lại có vấn đề khi tôi chọn anh đào? Không nên cả hai ngữ nghĩa giống nhau? – Curious

+1

@ Git git rất ngu ngốc khi thực hiện sáp nhập (mà anh đào cũng chọn). Nó sẽ rên rỉ về bất kỳ điều nhỏ và yêu cầu bạn để xử lý nó cho mình. Đó là gây phiền nhiễu nhưng sau đó một lần nữa, nó tốt hơn không cho nó để đoán nếu nó không biết chắc chắn. –

+0

Tôi đã bình chọn câu trả lời của bạn nhưng tôi vẫn gặp khó khăn khi hiểu điều này. Nhưng tại sao không có xung đột hợp nhất khi tôi sáp nhập? Tôi đã chỉnh sửa các tập tin từ cuối trong tất cả các cam kết trong chi nhánh 'khác' vì vậy cần phải có được một hợp nhất đó cũng? – Curious

3

tôi chỉ kiểm tra kịch bản đó, sau khi đọc:

Nếu việc sửa đổi vào dòng đầu tiên (Some text. thay vì Some text) đã được thực hiện ngay lập tức sau 0x2, như trong 0x3, sau đó git cherry-pick 0x3 hoạt động mà không xung đột.

Nhưng nếu thay đổi tương tự được thực hiện sau một vài cam kết, git cherry-pick sẽ không tạo bản vá tương thích với nội dung của 0x2.

Không có khái niệm "tổ tiên chung" ở đây (as incorrectly stated here): chỉ có "bản vá".

A git cherry-pick, ngay cả khi sử dụng chiến lược hợp nhất, là không a git merge.

  • Một git merge sẽ tìm kiếm một tổ tiên chung (sẽ trở lại trong lịch sử của các cam kết của 0x5, để tìm một chung cam kết với 0x2: đây 0x2 chính nó)
  • Một git cherry-pick chỉ tạo ra một bản vá bằng cách thực hiện một thống nhất khác nhau giữa hai cam kết (theo mặc định, cam kết bạn đề cập và cha mẹ trực tiếp của nó là 0x4)

Vấn đề là: bản vá đó sẽ không thể áp dụng trên 0x2.

Hãy thử dùng thử: git cherry-pick 0x5 giống như đang thực hiện git diff -p 0x4..0x5.
Bạn sẽ thấy trong các đường vá đó là không một phần của 0x2 và phản ánh các thay đổi đến từ 0x3 hoặc 0x4.

Không thể áp dụng bản vá này trên 0x2 vì nó dựa trên nội dung không tồn tại cho 0x2.

Tôi đã tạo một repo thử nghiệm mà tôi đã thực hiện từ hai sửa đổi chính.

  • Thêm một số văn bản từ chi nhánh khác (không sửa đổi vào dòng đầu tiên)
  • Sau đó một giây cam kết sửa đổi dòng đầu tiên.

Ở đây những gì bản vá của tôi trông giống như:

C:\Users\vonc\prog\git\tests\cp>git diff -p dev~..dev 
diff --git a/f b/f 
index 2b6dd7b..1c4bb79 100644 
--- a/f 
+++ b/f 
@@ -1,4 +1,4 @@ 
-"Some text" 
+"Some text."^M 

Adding some text from other branch. Adding some more text. 

Tôi không thể áp dụng (cherry-pick) có hành lên 0x2, 0x2 như không có dòng "Adding some text from other branch" được nêu ra. Nó chỉ có một dòng "Some text".

Đó là lý do tại sao git báo cáo xung đột: nội dung đã phân tán và bản vá đó được cho là thay đổi dòng 1 ở đầu tệp bao gồm "Adding some text from other branch", mà 0x2 không có.

Điều này khác với git merge tất nhiên, vì hợp nhất git sẽ tìm kiếm tổ tiên chung (ở đây 0x2) và báo cáo tất cả sửa đổi từ 0x2 lên 0x2 mà không gặp bất kỳ sự cố nào.

+1

Tôi không quen thuộc với khái niệm" tổ tiên chung "hay" miếng vá ", bạn có thể giải thích chúng không? – Curious

+0

@Curious Đây là chìa khóa để hiểu tại sao git cherry-pick là * không git merge (ngay cả khi nó sử dụng chiến lược hợp nhất). Một tổ tiên chung có nghĩa là quay trở lại lịch sử cam kết. Bản vá chỉ là sự khác biệt thống nhất giữa hai lần commit. Không có lịch sử ở đó. – VonC

+0

Vì vậy, lựa chọn anh đào có thể luôn tạo ra xung đột hợp nhất trong các dự án lớn với mỗi tệp đơn lẻ đã được thay đổi? – Curious

1

Hãy tạo một thử nghiệm nhỏ về trường hợp của bạn.

mkdir tmp 
cd tmp 
git init 
echo "root" >> hello 
git add hello 
git commit -m 'root commit' 
git branch exp 
#open the file hello and write 111 in the 2nd line 
git add hello 
git commit -m '111' 
#open the file hello and modify 111 to 112 in the 2nd line 
git add hello 
git commit -m '222' 
#now we have 3 commits in the master branch 
git log --oneline 
6b86a6d 112 
663a36b 111 
28b2e12 root commit 
git checkout exp 
#now we are in the exp branch, which has only 1 root commit. 
git log --oneline 
28b2e12 root commit 
#now we try to cherry pick 6b86a6d 
git cherry-pick 6b86ad6 
error: could not apply 6b86a6d... 112 
hint: after resolving the conflicts, mark the corrected paths 
hint: with 'git add <paths>' or 'git rm <paths>' 
hint: and commit the result with 'git commit' 
#a conflict occurs,why? 

The 2nd cam kết tại các chi nhánh tổng thể là tương đương với modify the 2nd line, from empty to 111 The 3rd cam kết tại các chi nhánh tổng thể là tương đương với modify the 2nd line, from 111 to 112

Chúng ta có thể thấy 3 phụ thuộc vào thứ 2. Nếu không có 111, chúng tôi không thể cập nhật 111 đến 112. Khi chúng tôi chọn được anh đào thứ 3 mà không có 2nd, không có 111 có thể tìm thấy trong tệp hello của nhánh exp, dẫn đến xung đột.

Nếu chúng ta cherry-chọn thứ 2 đầu tiên, xin chào của dòng thứ 2 sẽ được cập nhật từ trống để 111. Và sau đó nếu chúng ta cherry-chọn thứ 3, xin chào của dòng thứ 2 sẽ được cập nhật từ 111 đến 112.

Hãy tiếp tục với thử nghiệm.

#abor the cherry-pick first 
git cherry-pick --abort 
#go back to the master branch 
git checkout master 
> world 
git add world 
git commit -m 'add new file world' 
git log --oneline 
1cf8f90 add new file world 
6b86a6d 112 
663a36b 111 
28b2e12 root commit 
#now we have 4 commits in the master branch 
#cherry pick the 4th commit into the exp branch 
git checkout exp 
git cherry-pick 1cf8f90 
[exp 79a34bb] add new file world 
Date: Sun May 15 20:55:39 2016 +0800 
1 file changed, 0 insertions(+), 0 deletions(-) 
create mode 100644 world 
#no error 

Cam kết thứ 4 bằng add a new file world. Thay đổi này không phụ thuộc vào lần commit thứ 2 hoặc thứ 3. Nó có thể được anh đào chọn vào chi nhánh điểm kinh nghiệm mà không gặp bất kỳ rắc rối nào.

Hãy quay lại kịch bản xung đột.

#cherry pick the 3rd commit again 
git cherry-pick 6b86a6d 
error: could not apply 6b86a6d... 112 
hint: after resolving the conflicts, mark the corrected paths 
hint: with 'git add <paths>' or 'git rm <paths>' 
hint: and commit the result with 'git commit' 
git status 
On branch exp 
You are currently cherry-picking commit 6b86a6d. 
    (fix conflicts and run "git cherry-pick --continue") 
    (use "git cherry-pick --abort" to cancel the cherry-pick operation) 

Unmerged paths: 
    (use "git add <file>..." to mark resolution) 

    both modified: hello 
#we can see conflict ocurrs in the file hello. open hello with text editor 
hello world 
<<<<<<< HEAD 
======= 
112 
>>>>>>> 6b86a6d... 112 

< < < và >>> phần là bối cảnh xung đột. Phần < < < và === là phần hiện tại của nhánh hiện tại, còn gọi là nhánh chi nhánh. Nó trống. === và >>> phần là những gì nó là trong cam kết 6b86a6d. Đó là 112. Quá trình chọn lựa anh đào không thể quyết định phần nào sẽ được áp dụng, vì vậy chúng ta phải tự làm nó. Nếu chúng tôi nhấn mạnh nó phải để trống, sau đó chỉ cần xóa các dòng < < <, ===, >>> và 112. Nếu chúng tôi muốn thay vào đó 112, thì chỉ cần xóa các dòng < < <, ===,> >>. Tất nhiên, chúng tôi có thể giữ tất cả ngoại trừ < < <, === và >>> trong một số trường hợp. Trong một từ, giữ những gì bạn muốn và loại bỏ những gì không cần thiết. Lưu và thoát. git add hello;git cherry-pick --continue Sau đó, tất cả được thực hiện. Để biết thêm thông tin, vui lòng tham khảo 'LÀM THẾ NÀO CONFLICTS ĐƯỢC HIỆN TẠI' trong git merge --help. Trong trường hợp khác, nếu hai cam kết từ hai chi nhánh cập nhật cùng một dòng hoặc dòng với nội dung khác nhau và git cherry-pick một cam kết với chi nhánh khác, nó dẫn đến xung đột quá.

1

Tôi sẽ ít kỹ thuật hơn và có nhiều ý nghĩa hơn so với các câu trả lời khác. (Điều này không phải lúc nào cũng đúng, nhưng tôi nghĩ là trong trường hợp này.)

Bạn đang nghĩ, "Rõ ràng là sự thay đổi mà tôi muốn đơn giản gắn thêm một dòng vào cuối tập tin. có thể git không chỉ làm điều đó? "

Git đang áp dụng bản vá. Áp dụng một miếng vá liên quan đến việc cố gắng tìm ra nơi mà các miếng vá nên đi. Điều này bao gồm việc xem xét số dòng gần đúng và tìm kiếm các dòng n ngữ cảnh giống hệt nhau trước và sau khi thay đổi được thực hiện. Trong trường hợp này, bối cảnh sau là End Of File. Nhưng bối cảnh trước "Thêm một số văn bản từ chi nhánh khác. Thêm một số văn bản." không thể tìm thấy trong tệp đích.Git do đó gắn cờ này là "Tôi không thể so sánh một số trước và sau bối cảnh cho sự thay đổi này, vì vậy tôi sẽ đặt các điểm đánh dấu xung đột ở nơi có thể thay đổi, nhưng hãy để trí thông minh của con người thực hiện giải pháp cuối cùng."

Trong trường hợp này, bạn biết rằng điều này có thể được giải quyết một cách bình thường, có nhiều trường hợp tương tự như các lập trình viên rất vui vì git đã gắn cờ một tình huống như thế này và để chúng tự khắc phục.

Nếu đây là thứ bạn sẽ gặp thường xuyên, git cho phép bạn viết trình xử lý hợp nhất tùy chỉnh cho tệp để biết thêm về các mẫu hợp nhất và cú pháp được phép và cú pháp của tệp của bạn. .

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