Lý do là git merge
sử dụng chiến lược được gọi là "đệ quy" hợp nhất theo mặc định. Nó có thể thực hiện hợp nhất 3 chiều: lấy miếng vá từ một phía, và áp dụng miếng vá đó sang phía bên kia, để tạo ra một tập tin mới. Nó cũng thực hiện điều này một cách đệ quy, trong các tình huống phức tạp hơn, nơi có nhiều phân nhánh và hợp nhất đã xảy ra và có nhiều cơ sở hợp nhất cho hai cam kết được sáp nhập.
Gần đây tôi đã gặp phải tình trạng tương tự này:
$ git merge-base --all 90d64557 05b3dd8f
711d1ad9772e42d64e5ecd592bee95fd63590b86
f303c59666877696feef62844cfbb7960d464fc1
$
Với 2 cơ sở hợp nhất, một 3-way merge là không thể. Do đó, chiến lược 'đệ quy' giải quyết điều này bằng cách recursing đầu tiên vào một hợp nhất của hai cam kết:
$ git merge-base 711d1ad9 f303c596
3f5db59435ffa4a453e5e82348f478547440e7eb
$
OK, chỉ có một cơ sở hợp nhất, vì vậy 3-way việc sáp nhập có thể bắt đầu. những thay đổi ở hai bên là gì?
$ git diff --stat 3f5db594 711d1ad9
normalize/coll.py | 116 ++++++++++++++++++++++++++++++++++++++-----------
normalize/visitor.py | 49 ++++++++++-----------
tests/test_property.py | 10 +++--
3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 f303c596
normalize/identity.py | 38 +++++++++++++++++++++++++++++++-------
tests/test_property.py | 2 ++
2 files changed, 33 insertions(+), 7 deletions(-)
$
Hai diffs cả đã thay đổi đối với cùng một tập tin, vì vậy họ không thể được giải quyết bằng một chiến lược đơn giản chỉ dùng phiên bản mới hơn của mỗi tập tin từ mỗi bên (một chỉ số merge). Thay vào đó, git lấy tập tin mới từ một phía, và cố gắng áp dụng các miếng vá từ phía bên kia cho nó.Kết quả là một kết hợp cam kết, mà có thể được mô phỏng như thế này:
$ git checkout -b tmp
Switched to a new branch 'tmp'
$ git reset --hard f303c59666877696feef62844cfbb7960d464fc1
HEAD is now at f303c59 record_id: throw a more helpful error if record identity is not hashable
$ git merge 711d1ad9772e42d64e5ecd592bee95fd63590b86
Auto-merging tests/test_property.py
Merge made by the 'recursive' strategy.
normalize/coll.py | 116 ++++++++++++++++++++++++++++++++++++++-----------
normalize/visitor.py | 49 ++++++++++-----------
tests/test_property.py | 10 +++--
3 files changed, 120 insertions(+), 55 deletions(-)
$ git diff --stat 3f5db594 HEAD tests/test_property.py
tests/test_property.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
$
Sau đó nó trở về bản gốc 3-way merge, sử dụng kết quả hợp nhất này là điểm khởi đầu của nó; và điều này cũng liên quan đến các thay đổi đối với cùng một tệp:
$ git diff --stat HEAD 90d64557| grep selector
normalize/selector.py | 17 +--
tests/test_selector.py | 19 ++--
$ git diff --stat HEAD 05b3dd8f| grep selector
normalize/selector.py | 29 +++++++++++++++++------------
tests/test_selector.py | 9 +++++++++
$
Tuy nhiên, một lần nữa các thay đổi là các phần khác nhau của tệp và do đó việc sử dụng khác và áp dụng cho phía bên kia thành công. Vì vậy, C git đã có thể giải quyết sự hợp nhất này bằng cách đầu tiên thực hiện hợp nhất 3 chiều trên hai cơ sở hợp nhất của hai điểm bắt đầu, và sau đó thực hiện một phép nối 3 chiều khác trên hai commit ban đầu được sáp nhập và kết quả trung gian của lần hợp nhất đầu tiên.
Độ phân giải tự động của Github không làm điều này. Nó không nhất thiết phải mất khả năng, và tôi không chắc chắn bao nhiêu chiến lược đệ quy nó thực hiện, nhưng nó là sai lầm về mặt thận trọng, đó là chính xác những gì bạn mong đợi một nút màu xanh lá cây lớn như thế để làm :-).
Ngoài ra tốt đẹp về chiến lược hợp nhất đệ quy. +1 Bổ sung tốt cho câu trả lời của riêng tôi. – VonC