Viết lại lịch sử git để thay thế tất cả CRLF thành LF?


32

Tôi sẽ chuyển một kho Git riêng từ hộp win32 sang Ubuntu. Mặc dù tôi có thể thực hiện cam kết dos2unix cuối cùng, nhưng tôi muốn viết lại toàn bộ lịch sử, vì vậy một số GUI Git sẽ hiển thị log / diff chính xác. Ví dụ, gitg sẽ chèn các dòng trống cho mỗi CR / LF.

Câu trả lời:


25

Bạn có thể sử dụng git filter-branchcho điều đó, với --tree-filtertùy chọn và chỉ định --allcho chi nhánh.

Đây là một ví dụ (bắt đầu trong một thư mục trống với tệp văn bản loại Unix:

Chuẩn bị:

$ hexdump -C testfile 
00000000  61 0d 0a 62 0d 0a 63 0d  0a                       |a..b..c..|
00000009

$ git init
Initialized empty Git repository in /home/seigneur/tmp/a/.git/

$ git add testfile && git commit -m "dos file checked in"
[master (root-commit) df4970f] dos file checked in
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 testfile

Lệnh:

$ git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all

Đầu ra:

Rewrite df4970f63e3196216d5986463f239e51eebb4014 (1/1)dos2unix: converting file testfile to Unix format ...

Ref 'refs/heads/master' was rewritten

$ hexdump -C testfile 
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006

Tôi mạnh mẽ khuyên bạn nên làm một bản sao lưu đầy đủ trước . Chạy nó từ máy Linux của bạn (trừ khi bạn có một trình bao tốt được thiết lập trong môi trường windows) có lẽ dễ dàng hơn.

Chỉnh sửa: đã chuyển đổi đảo ngược lần đầu tiên.


1
Cảm ơn bạn, bài viết này đã giúp tôi rất nhiều. Tôi đã có một vài tệp có khoảng trắng trong tên của chúng, một chút thay đổi so với lệnh ban đầu đã sửa nó : git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. Cờ -z-0nói git ls-filesxargsđể in và giải thích nullnhư là cuối dòng.
Ivan

Một cách khác để thay thế lệnh dos2unix là dựa vào chính git:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas

6

Câu trả lời của Mat đã đóng đinh vấn đề ngay trên đầu. Thật không may trên Ubuntu Linux, bắt đầu với phiên bản 10.04 (Lucid Lynx), các lệnh dos2unix / unix2dos không còn khả dụng và đã được thay thế bằng fromdos / todos. Hơn nữa, cả hai bộ lệnh chuyển đổi đều có mức độ thiếu hiểu biết khác nhau đối với sự tồn tại của tệp nhị phân, do đó, nếu kho lưu trữ của bạn chứa hình ảnh, phông chữ, v.v. chúng sẽ bị hỏng bởi quy trình này.

Tôi đã có thể tìm ra cách giải quyết cho vấn đề tham nhũng tệp nhị phân sử dụng lệnh 'tệp' của Linux để xác định chính xác và chỉ xử lý các tệp văn bản như dưới đây. Lệnh bên dưới sử dụng tùy chọn --tag-name-filter để giữ các thẻ hiện có bằng cách di chuyển chúng đến các xác nhận mới được sửa đổi. Ngoài ra, nó sử dụng cờ --force để đảm bảo rằng lệnh sẽ hoạt động trong trường hợp bạn đã chạy bộ lọc cây trên kho lưu trữ của mình trước đó.

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs fromdos' --tag-name-filter cat -- --all

3

Và không có bất kỳ công cụ bổ sung nào (như 'fromdos', 'dos2unix', v.v.):

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs -0 sed -i"" -e "s/"$(printf "\015")"$//"' --tag-name-filter cat -- --all

Đa nền tảng (OS X, FreeBSD, Linux) tương tự hữu ích 'fromdos', 'dos2unix':

sed -i'' -e 's/'"$(printf '\015')"'$//'

Có lẽ hữu ích 'unix2dos':

sed -i '' -e 's|$|'"`printf '\015'`"'|' file.name

Nếu bạn hoàn toàn chắc chắn những gì bạn đang làm, bạn có thể sử dụng lệnh nội tuyến đơn giản này để xóa "/ r" khỏi tất cả các tệp trong thư mục hiện tại ".":

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;

1
Thay vì thay đổi \ r \ n thành \ n thay vì chỉ xóa \ r
xdevs23

Tôi nghĩ rằng sedlời mời tương ứng có thể được thay thế bằng cách gọi ngắn hơn:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k
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.