Chọn chiến lược hợp nhất Git cho các tệp cụ thể (Nhận thức của chúng tôi


207

Tôi đang ở giữa cuộc nổi loạn sau khi a git pull --rebase. Tôi có một vài tập tin có xung đột hợp nhất. Làm cách nào tôi có thể chấp nhận thay đổi "của họ" hoặc thay đổi "của tôi" cho các tệp cụ thể?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Thông thường tôi chỉ mở tệp hoặc công cụ hợp nhất và chấp nhận thủ công tất cả các thay đổi "của họ" hoặc "của tôi". Tuy nhiên, tôi nghi ngờ tôi đang thiếu một lệnh git thuận tiện.

Ngoài ra, lưu ý rằng tôi sẽ chỉ có thể chọn chiến lược hợp nhất cho mỗi tệp khi tôi thấy các tệp nào xung đột với xung đột có thể là xung đột.


@AbeVoelker Tôi không nghĩ rằng nó giải quyết vấn đề của tôi. Tôi muốn chọn một chiến lược hợp nhất cho các tệp cụ thể. Ngoài ra, lưu ý rằng tôi sẽ chỉ biết sử dụng stragegy hợp nhất để sử dụng khi tôi trong rebase của mình và xem các tệp nào có xung đột và xung đột là gì.
Steven Wexler

Tôi đã chỉnh sửa câu hỏi này để chung chung hơn: stackoverflow.com/questions/278081/ . Có lẽ chúng ta có thể đóng câu hỏi này như là một bản sao của điều đó? Điều đó có phù hợp không?

@TheShadow Điều đó có vẻ hợp lý với tôi.
Steven Wexler

Tôi không chắc liệu có phù hợp để thay đổi tiêu đề của câu hỏi khác thành những gì tôi đã làm hay không, vì tôi đã rút ra phần giải quyết các tệp nhị phân. Tôi đã khôi phục câu hỏi khác về những gì trước đây, vì vậy câu hỏi hiện tại này vẫn tăng thêm giá trị.

Câu trả lời:


251

Đối với mỗi tệp xung đột bạn nhận được, bạn có thể chỉ định

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

Từ các git checkouttài liệu

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Khi kiểm tra các đường dẫn từ chỉ mục, hãy kiểm tra giai đoạn # 2 ( ours) hoặc # 3 ( theirs) để biết các đường dẫn không được trộn.

Chỉ mục có thể chứa các mục nhập không được hợp nhất do hợp nhất không thành công trước đó. Theo mặc định, nếu bạn cố kiểm tra một mục như vậy từ chỉ mục, thao tác thanh toán sẽ thất bại và sẽ không có gì được kiểm tra. Sử dụng -fsẽ bỏ qua các mục không hợp nhất. Các nội dung từ một mặt cụ thể của hợp nhất có thể được kiểm tra ra khỏi chỉ mục bằng cách sử dụng --ourshoặc --theirs. Với -m, các thay đổi được thực hiện cho tệp cây làm việc có thể được loại bỏ để tạo lại kết quả hợp nhất xung đột ban đầu.


9
Có thể chấp nhận chúng cho tất cả các tệp bị bỏ trống?
aslakjo

41
@aslakjo git rebase -s recursive -X <ours/theirs>hay git merge -s recursive -X <ours/theirs>. Hãy nhớ rằng đối với một cuộc nổi loạn, "của chúng ta" và "của họ" được đảo ngược với những gì họ đang có trong một sự hợp nhất. Bạn có thể chỉ cần sử dụng một tập tin / shell toàn cầu, như thế git checkout --theirs -- *.txt.

2
Rất cám ơn, @Cupdding, sự đảo ngược bất ngờ ours/theirsvới rebase đã khiến tôi phát điên !! (Bây giờ tôi nghĩ về cách một cuộc nổi loạn thực sự hoạt động, nhưng hoàn toàn không trực quan.)
Dan Lenski

2
Nói chung @DanLenski rebase chỉ là một công cụ thực sự khó hiểu để mọi người hiểu, nhưng một khi bạn hiểu cách thức hoạt động của nó, bạn có thể làm tất cả mọi thứ thực sự mạnh mẽ với nó.

1
@VincentSels thực sự, bạn cần che dấu ký tự *, nếu không, shell sẽ cố gắng mở rộng nó. Vì vậy, trong trường hợp của bạn git checkout --outs -- "**/*.csproj"sẽ làm những gì bạn có ý nghĩa. Điều tương tự cũng đúng, ví dụ như đối với git lfs track "*.jpg". Nếu bạn có một số tệp jpg trong CWD của mình, không có dấu ngoặc kép, chỉ những tệp này sẽ được theo dõi.
eFloh

117

Mặc dù câu hỏi này đã được trả lời, việc cung cấp một ví dụ về "cái của họ" và "của chúng ta" nghĩa là gì trong trường hợp git rebase vs merge. Xem liên kết này

Git Rebase
theirs thực sự là nhánh hiện tại trong trường hợp rebase . Vì vậy, bộ lệnh dưới đây thực sự chấp nhận thay đổi nhánh hiện tại của bạn trên nhánh từ xa.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Hợp nhất Git
Để hợp nhất , ý nghĩa của theirsoursđược đảo ngược. Vì vậy, để có được hiệu ứng tương tự trong quá trình hợp nhất , nghĩa là giữ các thay đổi nhánh hiện tại của bạn ( ours) trên nhánh từ xa được hợp nhất ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b

2
tốt, đây là một sự phân biệt khá quan trọng! cảm ơn đã làm rõ
verboze

26

Lưu ý rằng git checkout --ours|--theirssẽ ghi đè lên toàn bộ các tệp , bằng cách chọn một trong hai theirshoặc oursphiên bản, có thể hoặc không phải là điều bạn muốn làm (nếu bạn có bất kỳ thay đổi không xung đột nào đến từ phía bên kia, chúng sẽ bị mất).

Nếu thay vào đó, bạn muốn thực hiện hợp nhất ba chiều trên tệp và chỉ giải quyết các phần tử bị xung đột bằng cách sử dụng --ours|--theirs, trong khi giữ các phần tử không xung đột từ cả hai bên, bạn có thể muốn dùng đến git merge-file; xem chi tiết trong câu trả lời này .


1
Về "các thay đổi không xung đột" sẽ bị mất - điều này chỉ đề cập đến các tệp có các thay đổi không xung đột trong các dòng cụ thể khác trong cùng một tệp hoặc tất cả các thay đổi từ tất cả các tệp trong lịch sử được căn chỉnh?
ktamlyn

2
@ktamlyn bởi "những thay đổi không xung đột" Tôi có nghĩa là những thay đổi trong cùng một tệp. Ví dụ, có hai người keo cú thay đổi (phần) trong example.txttrong oursphiên bản, một là mâu thuẫn (cũng thay đổi trong theirsphiên bản), còn lại là phi mâu thuẫn. Nếu bạn làm như vậy git checkout --theirs example.txt, nó sẽ chỉ đọc một cách mù quáng toàn bộ tệp khi theirssửa đổi, và phần không xung đột của diff sẽ bị mất.
jakub.g

1
Cảm ơn! Đây là một sự làm rõ cần thiết cho tôi, mặc dù "những thay đổi trong cùng một tệp" có ý nghĩa nhất trong bối cảnh này.
ktamlyn

Đây sẽ là câu trả lời được chấp nhận, mặc dù nó không thực sự đưa ra câu trả lời, nhưng chỉ ra một vấn đề quan trọng trong giải pháp đề xuất khác.
tomasyany

1
Nếu bạn muốn quay lại tệp xung đột ban đầu, bạn có thể chạy git checkout --merge <path>.
Andrew Keeton
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.