Công cụ đơn giản để 'chấp nhận của họ' hoặc 'chấp nhận của tôi' trên toàn bộ tệp bằng git


399

Tôi không muốn có một công cụ hợp nhất trực quan và tôi cũng không muốn phải vi phạm tệp bị xung đột và chọn thủ công giữa ĐẦU (của tôi) và thay đổi đã nhập (của chúng). Hầu hết thời gian tôi muốn tất cả các thay đổi của họ hoặc tất cả của tôi. Thông thường, điều này là do sự thay đổi của tôi đã làm cho nó trở nên mới hơn và đang quay trở lại với tôi thông qua một cú kéo, nhưng có thể được sửa đổi một chút ở nhiều nơi.

Có một công cụ dòng lệnh nào sẽ loại bỏ các dấu xung đột và chọn tất cả cách này hay cách khác dựa trên sự lựa chọn của tôi không? Hoặc một tập hợp các lệnh git mà tôi có thể tự đặt bí danh để thực hiện từng lệnh.

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

Làm điều này là khá khó chịu. Để 'chấp nhận của tôi' tôi đã thử:

randy@sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

randy@sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Làm thế nào tôi có thể thoát khỏi những dấu hiệu thay đổi này?

Tôi có thể làm:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Nhưng điều này có vẻ khá tròn trịa, phải có một cách tốt hơn. Và tại thời điểm này, tôi không chắc liệu git thậm chí có nghĩ rằng sự hợp nhất đã xảy ra hay không, vì vậy tôi không nghĩ rằng điều này nhất thiết phải hoạt động.

Đi theo một cách khác, làm 'chấp nhận họ' cũng lộn xộn không kém. Cách duy nhất tôi có thể tìm ra là làm:

git show test-branch:Makefile > Makefile; git add Makefile;

Điều này cũng mang lại cho tôi một thông điệp cam kết sai lầm, trong đó có Mâu thuẫn: Makefile trong đó hai lần.

Ai đó có thể vui lòng chỉ ra làm thế nào để thực hiện hai hành động trên một cách đơn giản hơn? Cảm ơn


4
Tôi phải đưa nó cho bạn với tư cách là người dùng dòng lệnh git ba năm + tôi thấy điều này thật khó thực hiện từ bộ nhớ. Nó thực sự nên được xây dựng theo mặc định.
Mauvis Ledford

Câu trả lời:


602

Giải pháp này rất đơn giản. git checkout <filename>cố gắng kiểm tra tệp từ chỉ mục và do đó không thể hợp nhất.

Những gì bạn cần làm là (tức là kiểm tra một cam kết ):

Để kiểm tra phiên bản của riêng bạn, bạn có thể sử dụng một trong:

git checkout HEAD -- <filename>

hoặc là

git checkout --ours -- <filename>

hoặc là

git show :2:<filename> > <filename> # (stage 2 is ours)

Để kiểm tra phiên bản khác, bạn có thể sử dụng một trong:

git checkout test-branch -- <filename>

hoặc là

git checkout --theirs -- <filename>

hoặc là

git show :3:<filename> > <filename> # (stage 3 is theirs)

Bạn cũng cần chạy 'thêm' để đánh dấu là đã giải quyết:

git add <filename>

31
Tôi thấy hơi lạ một chút --ours--theirscó nghĩa hoàn toàn trái ngược với những gì tôi nghĩ theo trực giác khi thử lệnh này ...
Joshua Muheim

6
Hãy cẩn thận khi sử dụng git show- điều này bỏ qua chuẩn hóa dòng mới.
Biên niên

2
Điều này tốt cho một vài tệp, nhưng khi bạn có nhiều tệp bị xung đột (vì ngày trong một nhận xét đã bị thay đổi!), Bạn sẽ làm thế nào?
JhovaniC

4
@Santhos: --Git được sử dụng để phân tách các sửa đổi (tên nhánh, v.v.) khỏi tên đường dẫn (tên tệp, thư mục). Điều quan trọng là nếu Git không thể quyết định nếu tên là tên của chi nhánh hoặc tên của tệp. Điều này tuân theo quy ước POSIX (hoặc GNU) về việc sử dụng dấu gạch ngang kép để tách các tùy chọn khỏi các đối số (tên tệp).
Jakub Narębski

3
@Sammaron @Joshua Muheim; các theirs/ ourscó thể xuất hiện hoán đổi nếu bạn đang giải quyết xung đột trong bối cảnh của một hoạt động rebase. Bởi vì rebase hoạt động bằng cách kiểm tra nhánh mục tiêu sau đó chọn anh đào từ nhánh "của bạn" vào mục tiêu, thay đổi đến ("của họ") là từ nhánh "của bạn" và nhánh hiện tại là nhánh đích ("của chúng ta" ).
RJFalconer

93

Thử cái này:

Để chấp nhận thay đổi của họ: git merge --strategy-option theirs

Để chấp nhận của bạn: git merge --strategy-option ours


5
Lưu ý rằng điều này sẽ giữ các thay đổi của bạn cho TẤT CẢ các tệp xung đột, do đó có thể nguy hiểm nếu xảy ra xung đột không mong muốn.
Giăng

3
Và bạn có thể sử dụng điều này cho các lệnh hợp nhất khác như cherry-pick và rebase.
idbrii

50

Dựa trên câu trả lời của Jakub, bạn có thể định cấu hình các bí danh git sau đây để thuận tiện:

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

Họ tùy ý lấy một hoặc một vài đường dẫn của tệp để giải quyết và mặc định để giải quyết mọi thứ trong thư mục hiện tại nếu không có gì được đưa ra.

Thêm chúng vào [alias]phần của bạn ~/.gitconfighoặc chạy

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'

1
Không làm việc cho tôi ... Đây là cho bash hoặc một số vỏ khác?
dùng456584

Đây là các bí danh git, thêm chúng vào [alias]phần trong ~.gitconfighoặc sử dụng của bạn git config --global accept-ours "...". Đã chỉnh sửa câu trả lời của tôi.
kynan

2
Bạn không biết bí danh này đã cứu tôi bao nhiêu thời gian. Đồng ý
Adam Parkin

1
@hakre Hãy chắc chắn rằng bạn trích dẫn bí danh, nếu không vỏ của bạn sẽ cố gắng giải thích nó. Hoặc chỉ cần chỉnh sửa bằng tay của bạn ~/.gitconfig.
kynan

1
Cú pháp Shell cho các giá trị mặc định:!f() { git checkout --ours -- "${@:-.}" git add -u "${@:-.}; }; f
jthill 04/07 '

17

Dựa trên câu trả lời của kynan, đây là các bí danh giống nhau, được sửa đổi để chúng có thể xử lý khoảng trắng và dấu gạch ngang ban đầu trong tên tệp:

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"

0

Tình huống lý tưởng để giải quyết xung đột là khi bạn biết trước cách bạn muốn giải quyết chúng và có thể vượt qua -Xours hoặc -Xtheirstùy chọn chiến lược hợp nhất đệ quy. Bên ngoài này tôi có thể thấy ba khung cảnh:

  1. Bạn muốn chỉ giữ một phiên bản duy nhất của tệp (điều này có lẽ chỉ nên được sử dụng trên các tệp nhị phân không thể trộn được, vì các tệp không xung đột và không xung đột có thể không đồng bộ với nhau).
  2. Bạn muốn đơn giản quyết định tất cả các xung đột theo một hướng cụ thể.
  3. Bạn cần giải quyết một số xung đột bằng tay và sau đó giải quyết tất cả các phần còn lại theo một hướng cụ thể.

Để giải quyết ba tình huống này, bạn có thể thêm các dòng sau vào .gitconfigtệp của mình (hoặc tương đương):

[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -I '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -I '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true

Các get(ours|theirs) cụ này chỉ giữ phiên bản tương ứng của tệp và loại bỏ tất cả các thay đổi so với phiên bản khác (do đó không xảy ra sự hợp nhất).

Công merge(ours|theirs)cụ này thực hiện lại cách hợp nhất ba cách từ các phiên bản cục bộ, cơ sở và từ xa của tệp, chọn giải quyết xung đột theo hướng đã cho. Điều này có một số cảnh báo, cụ thể: nó bỏ qua các tùy chọn khác được truyền cho lệnh hợp nhất (như xử lý thuật toán và khoảng trắng); hợp nhất sạch sẽ từ các tệp gốc (vì vậy mọi thay đổi thủ công đối với tệp sẽ bị loại bỏ, có thể là tốt hoặc xấu); và có lợi thế là nó không thể bị nhầm lẫn bởi các dấu khác biệt được cho là có trong tệp.

Các keep(ours|theirs) cụ chỉ cần chỉnh sửa các điểm khác biệt và các phần kèm theo, phát hiện chúng bằng biểu thức chính quy. Điều này có lợi thế là nó bảo tồn các tùy chọn khác từ lệnh hợp nhất và cho phép bạn giải quyết một số xung đột bằng tay và sau đó tự động giải quyết phần còn lại. Nó có nhược điểm là nếu có các dấu xung đột khác trong tệp thì nó có thể bị nhầm lẫn.

Tất cả đều được sử dụng bằng cách chạy git mergetool -t (get|merge|keep)(ours|theirs) [<filename>]nếu <filename>không được cung cấp, nó xử lý tất cả các tệp bị xung đột.

Nói chung, giả sử bạn biết không có dấu hiệu khác để nhầm lẫn giữa biểu thức chính quy, các keep*biến thể của lệnh là mạnh nhất. Nếu bạn để mergetool.keepBackuptùy chọn không được đặt hoặc đúng thì sau khi hợp nhất, bạn có thể tìm *.origtệp khác với kết quả của phép hợp nhất để kiểm tra xem nó có hợp lý không. Ví dụ, tôi chạy sau đây mergetoolchỉ để kiểm tra các thay đổi trước khi cam kết:

for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done

Lưu ý : Nếu merge.conflictstylekhông phải diff3thì /^|||||||/mẫu trong sedquy tắc cần phải được /^=======/thay thế.

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.