Có thể cho git-merge để bỏ qua sự khác biệt kết thúc dòng?


150

Có thể git mergebỏ qua sự khác biệt kết thúc dòng?

Có lẽ tôi đang hỏi sai câu hỏi ... nhưng:

Tôi đã thử uisng config.crlf inputnhưng mọi thứ hơi lộn xộn và mất kiểm soát, đặc biệt khi tôi áp dụng nó sau khi thực tế .

Đối với một điều, áp dụng cấu hình này sau khi thực tế dường như không ảnh hưởng đến các tệp đã được cam kết với kho lưu trữ trước khi áp dụng tùy chọn này. Một điều nữa là đột nhiên tất cả các cam kết hiện dẫn đến rất nhiều thông báo cảnh báo khó chịu về việc CRLF được chuyển đổi thành LF.

Thành thật mà nói, tôi không thực sự quan tâm đến việc kết thúc dòng nào được sử dụng, cá nhân tôi thích phong cách Unix \n, nhưng bất cứ điều gì. Tất cả những gì tôi quan tâm, là git mergeđể thông minh hơn một chút và bỏ qua những khác biệt trong kết thúc dòng.

Đôi khi tôi có hai tệp giống nhau, nhưng git sẽ đánh dấu chúng là xung đột (và xung đột là toàn bộ tệp) đơn giản vì chúng sử dụng một ký tự kết thúc dòng khác nhau.

Cập nhật:

Tôi phát hiện ra rằng git diffchấp nhận một --ignore-space-at-eoltùy chọn, liệu có thể cho phép git mergesử dụng tùy chọn này không?


28
Ôi tôi ước. Dòng kết thúc này trong git hoàn toàn bị hỏng
1800 THÔNG TIN

Chỉ cần thêm một trường hợp thử nghiệm minh họa các công cụ hợp nhất của bên thứ ba sẽ bỏ qua kiểu eol trong quá trình hợp nhất
VonC

Vì vậy, để làm rõ (từ những gì tôi có thể xác định): không có cách nào để git bỏ qua CR nhưng phàn nàn về tất cả các khoảng trắng khác?
Stephen

Hãy chắc chắn để xem câu trả lời dưới đây vềgit config merge.renormalize true
qneill

Câu trả lời:


115

Cập nhật 2013:

Các phiên bản git gần đây cho phép sử dụng hợp nhất với tùy chọnrecursive chiến lược và chiến lược ( ):-X

git merge -s đệ quy -Xignore-space-at-eol

Nhưng sử dụng " -Xignore-space-change" cũng là một khả năng


jakub.g cũng nhận xét rằng các chiến lược cũng hoạt động với việc hái anh đào :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Điều này hoạt động tốt hơn nhiều ignore-all-space.


Câu trả lời gốc (tháng 5 năm 2009)

Bản vá cho việc bỏ qua phong cách eol đã được đề xuất vào tháng 6 năm 2007 , nhưng nó chỉ quan tâm git diff --ignore-space-at-eolchứ không phải git merge.

Vào thời điểm đó, câu hỏi đã được đưa ra:

Nên --ignore-space-at-eollà một lựa chọn để git-merge?
Sáp nhập là nơi chức năng này quan trọng.
Các ngữ nghĩa của hợp nhất được giải quyết tự động với các tùy chọn đó có hiệu lực - chúng chỉ được sử dụng để đổi tên phát hiện, hoặc chúng ta, ví dụ, không gắn cờ xung đột với chỉ thay đổi khoảng trắng? Và nếu chúng ta không, chúng ta sẽ chấp nhận phiên bản nào?

Julio C Hamano không thực sự nhiệt tình:

Điều này chắc chắn là hấp dẫn, nhưng tôi nghi ngờ rằng nên để lại cho các vòng sau.
Tôi nghi ngờ rằng nó sẽ đưa ra một khái niệm về hai loại khác nhau, một loại được xử lý cơ học (nghĩa là sử dụng kết hợp với "git-merge-recursive" và áp dụng với "git-am") và một loại khác được kiểm tra bởi con người hiểu.
Nó thường có thể hữu ích để chuyển đổi đầu vào cho trường hợp sau, mặc dù đầu ra từ việc so sánh các tệp đầu vào bị trộn có thể không sử dụng được cho ứng dụng cơ học.

Ý tưởng chung, khi nói đến git merge, là dựa vào công cụ hợp nhất của bên thứ ba.

Chẳng hạn, tôi đã thiết lập DiffMerge làm công cụ hợp nhất Git, thiết lập một quy tắc cho phép công cụ hợp nhất đó bỏ qua eol cho một số loại tệp nhất định.


Thiết lập trên Windows, với MSysGit1.6.3, cho phiên bash DOS hoặc Git, với DiffMerge hoặc KDiff3:

  • thiết lập một thư mục vào PATH của bạn (ở đây c:\HOMEWARE\cmd:).
  • thêm vào thư mục đó script merge.sh (trình bao bọc cho công cụ hợp nhất yêu thích của bạn)

hợp nhất.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Khai báo trình bao bọc hợp nhất của bạn cho Git

Các lệnh cấu hình Git:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Kiểm tra xem autoCRLF có sai không

cấu hình git ở cấp hệ thống:

git config ---system core.autoCRLF=false
  • Kiểm tra xem, khi hai dòng giống hệt nhau (nhưng ký tự eol của chúng), cả DiffMerge hoặc KDiff3 sẽ bỏ qua các dòng đó trong quá trình hợp nhất.

Tập lệnh DOS (lưu ý: lệnh dos2unix xuất phát từ đây và được sử dụng để mô phỏng kiểu Unix eol. Lệnh đó đã được sao chép trong thư mục được đề cập ở đầu câu trả lời này.):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

Tại thời điểm này (Đánh dấu "trở lại"), DiffMerge hoặc KDiff3 sẽ mở ra và bạn sẽ tự mình nhìn thấy những dòng nào thực sự được hợp nhất và những dòng nào bị bỏ qua.

Cảnh báo : tệp kết quả sẽ luôn ở chế độ eol của Windows (CRLF) với DiffMerge ...
KDiff3 cung cấp để lưu theo cách này hay cách khác.


Cảm ơn vì tiền boa! Meld và FileMerge trong Mac dường như cũng là những ứng dụng tuyệt vời.
Léo Léopold Hertz

1
Để biết thông tin, các chiến lược cũng hoạt động với việc hái anh đào : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (cách này hiệu quả hơn nhiều so với ignore-all-space)
jakub.g

1
@ jakub.g điểm tốt! Tôi đã đưa nó vào câu trả lời để dễ nhìn hơn.
VonC

98

Tôi đang tìm kiếm câu trả lời tương tự và tôi phát hiện ra điều này

Sáp nhập các nhánh với các thuộc tính checkin / checkout khác nhau

Nếu bạn đã thêm thuộc tính vào tệp khiến định dạng kho lưu trữ chính tắc cho tệp đó thay đổi, chẳng hạn như thêm bộ lọc sạch / smudge hoặc thuộc tính text / eol / nhận dạng, việc hợp nhất bất cứ nơi nào thuộc tính không có trong đó thường gây ra xung đột hợp nhất .

Để ngăn chặn các xung đột hợp nhất không cần thiết này, git có thể được yêu cầu chạy kiểm tra ảo và đăng ký cả ba giai đoạn của tệp khi giải quyết hợp nhất ba chiều bằng cách đặt biến cấu hình merge.ren normalize. Điều này ngăn các thay đổi gây ra bởi chuyển đổi đăng ký gây ra xung đột hợp nhất giả khi tệp được chuyển đổi được hợp nhất với tệp chưa được chuyển đổi.

Miễn là "smudge → clean" dẫn đến kết quả đầu ra giống như "sạch" ngay cả trên các tệp đã bị nhoè, chiến lược này sẽ tự động giải quyết tất cả các xung đột liên quan đến bộ lọc. Các bộ lọc không hoạt động theo cách này có thể gây ra xung đột hợp nhất bổ sung phải được giải quyết thủ công.

Vì vậy, chạy lệnh này trong bất kỳ kho lưu trữ sẽ thực hiện thủ thuật:

git config merge.renormalize true

20
Điều này xứng đáng bây giờ là câu trả lời mặc định. Nhiều điều đã thay đổi kể từ khi câu hỏi được đặt ra lần đầu tiên, việc xử lý vấn đề này của git hiện được tích hợp với merge.ren normalize như bạn nói.
Anton I. Sipos

Điều này thật tuyệt vời .. tiết kiệm trong ngày của tôi
matthaeus



4

Những gì tôi đã làm là để mọi thứ như mặc định (ví dụ: autocrlf = true), chạm vào tất cả các tệp (find. -Exec touch {} \;), để git xem chúng là 'đã sửa đổi' và cam kết lại và thực hiện với nó. Nếu không, bạn sẽ luôn bị quấy rầy bởi các tin nhắn gây phiền nhiễu hoặc sự khác biệt đáng ngạc nhiên, hoặc phải tắt tất cả các tính năng khoảng trắng của git.

Bạn sẽ mất thông tin đổ lỗi, nhưng tốt hơn là làm điều đó sớm hơn là sau đó :)


4

"Git merge -Xren normalize" hoạt động như một bùa mê.




0

Bây giờ đối với tôi, cách tốt nhất là bình thường hóa các kết thúc dòng trên cả hai nhánh (và cam kết) trước khi hợp nhất chúng.

Tôi đã googled "chuyển đổi crlf thành lf" và thấy đây là kết quả đầu tiên:
http://stahlforce.com/dev/index.php?tool=remcrlf

Tôi đã tải về nó và sử dụng, có vẻ như là một công cụ tốt.

>sfk remcr . .py

Mặc dù vậy, hãy chắc chắn để chỉ định một thư mục và một loại tệp (ví dụ .py) nếu không nó có thể cố gắng gây rối với nội dung của .gitthư mục!


0

AFAICT, (tôi chưa thử) bạn có thể sử dụng git diffđể so sánh chi nhánh bạn muốn hợp nhất với tổ tiên chung, sau đó áp dụng kết quả với git apply. Cả hai lệnh đều có --ignore-whitespacecác tùy chọn để bỏ qua lỗi kết thúc dòng và lỗi khoảng trắng.

Thật không may, nếu bản vá không áp dụng sạch, toàn bộ thao tác sẽ bị hủy bỏ. Bạn không thể sửa các xung đột hợp nhất. Có một --rejecttùy chọn để bỏ các khối không thể chỉnh sửa trong .rejcác tệp, điều này giúp, nhưng không giống như có các xung đột hợp nhất được hiển thị trong một tệp.


-1

Sau khi đọc Giải quyết xung đột hợp nhất: Buộc ghi đè tất cả các tệp

Cuối cùng tôi đã giải quyết phiên bản của tôi về vấn đề này. Tôi đã cố gắng cập nhật các bản cập nhật từ repo ngược dòng nhưng hiện tại tôi đang gặp vấn đề liên quan đến CRLF và kết quả là không thể hợp nhất. Cần lưu ý rằng tôi KHÔNG CÓ THAY ĐỔI ĐỊA PHƯƠNG tôi cần phải lo lắng. Các bước sau đã giải quyết vấn đề của tôi:

Theo hướng dẫn của github về đồng bộ hóa dĩa ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Sự hiểu biết hạn hẹp của tôi về git cho tôi biết đây là việc tôi muốn - khởi động lại ngã ba của tôi (không có thay đổi thực sự không được cam kết) để đạt được tất cả các thay đổi được thực hiện đối với nguồn ngược dòng. Theo trang nguồn, bước này thường không được yêu cầu, nhưng vấn đề CRLF đã khiến nó bắt buộc.

  3. git merge upstream/master

  4. git push

1
Bạn nhận ra rằng git reset --hard upstream/masterném đi chi nhánh địa phương của bạn và chỉ nó upstream/master, làm cho git merge upstream/masterkhông-op?
Christoffer Hammarström

-1

tuy nhiên tôi đề nghị sử dụng công cụ như sed để đạt được kết thúc dòng chính xác, và sau đó là các tệp khác. Tôi đã dành vài giờ trên diffing dự án với kết thúc dòng khác nhau.

Cách tốt nhất là:

  1. chỉ sao chép các tệp dự án ( .gitthư mục bỏ qua ) vào thư mục khác tạo kho lưu trữ trong đó, sau đó thêm tệp và cam kết chúng (nên nằm trên nhánh chính trong kho lưu trữ mới).
  2. sao chép các tệp từ dự án thứ hai vào cùng một thư mục, nhưng một nhánh khác chẳng hạn dev( git checkout -b dev), cam kết các tệp trên nhánh này và chạy (nếu dự án đầu tiên là chính): git diff master..dev --names-only để chỉ xem tên của các tệp đã thay đổi
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.