Cố gắng sửa lỗi kết thúc dòng bằng nhánh lọc git, nhưng không gặp may


270

Tôi đã bị cắn bởi vấn đề kết thúc dòng Windows / Linux với git. Dường như, thông qua GitHub, MSysGit và các nguồn khác, giải pháp tốt nhất là đặt các repos cục bộ của bạn để sử dụng các kết thúc dòng kiểu linux, nhưng được đặt core.autocrlfthành true. Thật không may, tôi đã không làm điều này đủ sớm, vì vậy bây giờ mỗi lần tôi thay đổi kết thúc dòng đều bị hỏng.

Tôi nghĩ rằng tôi đã tìm thấy một câu trả lời ở đây nhưng tôi không thể làm cho nó hoạt động được. Kiến thức về dòng lệnh Linux của tôi bị hạn chế tối đa, vì vậy tôi thậm chí không chắc dòng "xargs fromdos" làm gì trong kịch bản của mình. Tôi liên tục nhận được thông báo về việc không có tệp hoặc thư mục như vậy tồn tại và khi tôi quản lý để trỏ nó đến một thư mục hiện có, nó cho tôi biết tôi không có quyền.

Tôi đã thử điều này với MSysGit trên Windows và thông qua thiết bị đầu cuối Mac OS X.


Tôi không thể nâng cấp chủ đề này thậm chí gần như đủ. +1 ++ cho nó cung cấp câu trả lời tốt nhất về vấn đề này.
sjas

Đồng ý với Charles. Tuy nhiên, trong trường hợp của tôi (sử dụng Mac OS X 10.8)> git config core.autocrlf đã hoạt động sai, không> git config core.autocrlf đầu vào
user1045085

Câu trả lời:


187

Tài liệu git cho gitattote hiện tài liệu một cách tiếp cận khác để "sửa chữa" hoặc bình thường hóa tất cả các kết thúc dòng trong dự án của bạn. Đây là ý chính của nó:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

Nếu bất kỳ tệp nào không được chuẩn hóa sẽ hiển thị ở trạng thái git, hãy bỏ đặt thuộc tính văn bản của chúng trước khi chạy git add -u.

manual.pdf -text

Ngược lại, các tệp văn bản mà git không phát hiện được có thể kích hoạt chuẩn hóa thủ công.

weirdchars.txt text

Điều này tận dụng một --renormalizecờ mới được thêm vào trong git v2.16.0, được phát hành vào tháng 1 năm 2018. Đối với các phiên bản cũ hơn của git, có một vài bước nữa:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

1
Bạn có thể cho tôi biết mục đích của git resetnó là gì không?
crdx

1
buộc git xây dựng lại chỉ mục, trong đó nó quét từng tệp để đoán xem liệu nhị phân của nó. Rm xóa chỉ mục cũ, thiết lập lại xây dựng chỉ mục mới.
Russ Egan

16
Cảm ơn, điều này đã làm việc cho tôi. Một lệnh hữu ích sau khi chạy git statuslà chạy git diff --ignore-space-at-eolchỉ để đảm bảo rằng những thay đổi duy nhất bạn đang cam kết là kết thúc dòng.
zelanix

1
Lưu ý: Sự khác biệt "thực" duy nhất giữa giải pháp này và giải pháp "cũ" là sự hiện diện của .gitattribut (với nội dung phù hợp). Không có điều này, git resetsẽ phát hiện không có sửa đổi, và do đó là vô ích.
Cướp

3
Các hướng dẫn trên trang gitattribut đã được cập nhật để tận dụng --renormalizecờ được thêm vào trong git v2.16.0 được phát hành vào tháng 1 năm 2018. --renormalizeCờ hợp nhất quy trình xử lý lại các kết thúc dòng cho mỗi tệp được theo dõi thành một lệnh : git add --renormalize ..
Mike Hill

389

Cách dễ nhất để khắc phục điều này là thực hiện một cam kết sửa tất cả các kết thúc dòng. Giả sử rằng bạn không có bất kỳ tệp sửa đổi nào, thì bạn có thể làm điều này như sau.

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .


31
Cảm ơn ... đây là một sửa chữa tuyệt vời. Tìm thấy nó trên GitHub.
PHLAK

4
Bạn cũng có thể muốn kiểm tra config.safecrlf để đảm bảo rằng bạn không thay đổi crlfs trong các tệp không phải là văn bản (chẳng hạn như nhị phân). Kiểm tra nó trong tài liệu kernel.org/pub/software/scm/git/docs/git-config.html .
vrish88

4
@ vrish88: Tuy nhiên, nếu bạn ở trong tình huống này, có khả năng bạn đang phải chịu đựng những kết thúc lót hỗn hợp và core.safecrlf thực sự có thể ngăn bạn làm những việc bạn cần làm. Có lẽ dễ dàng hơn để không sử dụng safecrlf. git không thường xuyên phát hiện tệp nhị phân sai và nếu có, bạn có thể tự đánh dấu nó là nhị phân với .gitattribution và khôi phục phiên bản chính xác từ cam kết trước đó.
CB Bailey

26
Giải pháp mới hơn được đề xuất trong câu trả lời của Russ Egan dưới đây đơn giản hơn và không liên quan đến những điều đáng sợ như xóa tất cả mã nguồn của bạn , vì vậy tôi thực sự khuyên mọi người nên sử dụng nó, mặc dù giải pháp cũ này có số phiếu nhiều gấp 10 lần!
Porculus

11

Quy trình của tôi để xử lý các kết thúc dòng như sau (trận chiến được thử nghiệm trên nhiều repos):

Khi tạo một repo mới:

  • đưa .gitattributesvào cam kết đầu tiên cùng với các tệp điển hình khác như .gitignoreREADME.md

Khi giao dịch với một repo hiện có:

  • Tạo / sửa đổi cho .gitattributesphù hợp
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n( --no-verifylà bỏ qua các hook pre-commit)
    • Tôi phải làm điều đó thường xuyên đủ để tôi xác định nó là bí danh alias fixCRLF="..."
  • lặp lại lệnh trước
    • vâng, đó là voodoo, nhưng nói chung tôi phải chạy lệnh hai lần, lần đầu tiên nó bình thường hóa một số tệp, lần thứ hai thậm chí nhiều tệp hơn. Nói chung, có lẽ tốt nhất để lặp lại cho đến khi không có cam kết mới được tạo :)
  • đi qua lại giữa cái cũ (ngay trước khi bình thường hóa) và nhánh mới một vài lần. Sau khi chuyển nhánh, đôi khi git sẽ tìm thấy nhiều tệp hơn nữa cần được chuẩn hóa lại!

Trong .gitattributestôi tuyên bố tất cả các tệp văn bản rõ ràng là có LF EOL vì nhìn chung công cụ Windows tương thích với LF trong khi công cụ không phải Windows không tương thích với CRLF (thậm chí nhiều công cụ dòng lệnh của nodejs giả định là do đó có thể thay đổi EOL trong các tệp của bạn).

Nội dung của .gitattributes

Tôi .gitattributesthường trông như:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

Để tìm ra những phần mở rộng khác biệt được theo dõi bởi git trong repo hiện tại, xem tại đây

Các vấn đề sau khi bình thường hóa

Một khi điều này được thực hiện, có một cảnh báo phổ biến hơn mặc dù.

Giả sử bạn masterđã cập nhật và bình thường hóa, sau đó bạn thanh toán outdated-branch. Khá thường xuyên ngay sau khi kiểm tra chi nhánh đó, git đánh dấu nhiều tệp như đã sửa đổi.

Giải pháp là thực hiện một cam kết giả ( git add -A . && git commit -m 'fake commit') và sau đó git rebase master. Sau khi nổi loạn, các cam kết giả sẽ biến mất.


1
Tôi nghĩ rằng tôi đang phát điên, cho đến khi tôi đọc bài viết của bạn, bởi vì tôi cũng phải chạy chuỗi lệnh được chỉ định nhiều lần. Thư! ;)
Sean Fausett

Với phiên bản git 2.7.0.windows.1, tôi đã sử dụng như sau: git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
Sean Fausett

4
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Giải trình:

  • git status --short

    Điều này hiển thị từng dòng mà git đang và không biết. Các tệp không thuộc quyền kiểm soát git được đánh dấu ở đầu dòng bằng dấu '?'. Các tệp được sửa đổi được đánh dấu bằng chữ M.

  • grep "^ *M"

    Điều này chỉ lọc ra những tập tin đã được sửa đổi.

  • awk '{print $2}'

    Điều này chỉ hiển thị tên tệp mà không có bất kỳ đánh dấu.

  • xargs fromdos

    Thao tác này lấy tên tệp từ lệnh trước đó và chạy chúng thông qua tiện ích 'fromdos' để chuyển đổi các kết thúc dòng.


Điều này thật tuyệt. Cảm ơn bạn. Đối với bất cứ ai tìm kiếm giải pháp sử dụng Homebrew sử dụng dos2unixthay vì fromdos.
Almir Sarajčić

4

Đây là cách tôi sửa tất cả các kết thúc dòng trong toàn bộ lịch sử bằng cách sử dụng git filter-branch. Nhân ^Mvật cần được nhập bằng CTRL-V+ CTRL-M. Tôi đã sử dụng dos2unixđể chuyển đổi các tập tin vì điều này tự động bỏ qua các tập tin nhị phân.

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'


3

"| Xargs fromdos" đọc từ đầu vào tiêu chuẩn (các tệp findtìm thấy) và sử dụng nó làm đối số cho lệnh fromdos, chuyển đổi các kết thúc dòng. (Là tiêu chuẩn fromdos trong các môi trường đó? Tôi đã quen với dos2unix). Lưu ý rằng bạn có thể tránh sử dụng xargs (đặc biệt hữu ích nếu bạn có đủ tệp mà danh sách đối số quá dài cho xargs):

find <path, tests...> -exec fromdos '{}' \;

hoặc là

find <path, tests...> | while read file; do fromdos $file; done

Tôi không hoàn toàn chắc chắn về thông báo lỗi của bạn. Tôi đã thử nghiệm thành công phương pháp này. Chương trình nào đang sản xuất mỗi? Những tập tin / thư mục nào bạn không có quyền cho? Tuy nhiên, đây là một cú đâm để đoán xem nó có thể là gì:

Một cách dễ dàng để nhận được lỗi 'không tìm thấy tệp' cho tập lệnh là sử dụng đường dẫn tương đối - sử dụng một đường dẫn tuyệt đối. Tương tự như vậy, bạn có thể gặp lỗi quyền nếu bạn chưa thực hiện tập lệnh của mình (chmod + x).

Thêm ý kiến ​​và tôi sẽ cố gắng giúp bạn giải quyết nó!


Tôi đã thấy một ví dụ khác với dos2unix và tôi nghĩ rằng bằng cách nào đó, sao chép các tệp vào một thư mục có tên đó, nhưng bây giờ tôi đã nhận được nó. Wow, dường như rõ ràng bây giờ. Cảm ơn bạn đã giúp đỡ!
Brian Donahue

1

được rồi ... dưới cygwin, chúng tôi không có sẵn từ trên mạng và điều đó sẽ khiến bạn nổi giận nếu bạn có bất kỳ khoảng trống nào trong đường dẫn đến các tệp đã sửa đổi (vì vậy chúng tôi phải làm điều đó một cách khác:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

kudos đến @lloyd cho phần lớn giải pháp này


-2

Thực hiện theo các bước sau nếu không có câu trả lời nào khác phù hợp với bạn:

  1. Nếu bạn đang ở trên Windows, hãy làm git config --global core.autocrlf true; nếu bạn đang dùng Unix, hãy làmgit config core.autocrlf input
  2. Chạy git rm --cached -r .
  3. Xóa tập tin .gitattributes
  4. Chạy git add -A
  5. Chạy git reset --hard

Sau đó, địa phương của bạn nên được sạch sẽ ngay bây giờ.


4
Có thật không? Xóa .gitattributestập tin là giải pháp cho vấn đề kết thúc dòng?
Alexanderr M

Có, vui lòng giải quyết nhận xét của @AleksandrM
Mr_and_Mrs_D
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.