모든 CRLF를 LF로 바꾸려면 git history를 다시 작성 하시겠습니까?


32

개인 Git 저장소를 win32 상자에서 우분투로 옮길 것입니다. 최종 dos2unix 커밋을 수행 할 수는 있지만 전체 기록을 다시 작성하고 싶습니다. 따라서 일부 Git GUI는 log / diff를 올바르게 표시합니다. 예를 들어, gitg 는 각 CR / LF에 빈 줄을 삽입합니다.

답변:


25

당신은 사용할 수 있습니다 git filter-branch과, 그것을 위해 --tree-filter옵션 및 지정 --all지점에 대해.

다음은 Unix 유형의 텍스트 파일이있는 빈 디렉토리에서 시작한 예입니다.

예비:

$ 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

명령 :

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

산출:

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

나는 강력하게 사전에 전체 백업을 수행하는 것이 좋습니다 . Windows 환경에서 좋은 쉘을 설정하지 않은 한 Linux 시스템에서 실행하는 것이 더 쉽습니다.

편집 : 전환이 처음으로 역전되었습니다.


1
고마워요,이 게시물이 많은 도움이되었습니다. 이름에 공백이있는 파일이 몇 개 있었으며 원래 명령을 약간 변경하여 수정했습니다 git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. 플래그 -z-0이야기 git ls-files하고 xargs인쇄하고 해석하는 null라인의 끝으로.
Ivan

dos2unix 명령의 또 다른 대안은 자식 자체에 의존하는 것입니다.git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas

6

매트의 대답 은 머리에 문제를 바로 잡았습니다. 불행히도 Ubuntu Linux에서는 버전 10.04 (Lucid Lynx)부터 ​​dos2unix / unix2dos 명령을 더 이상 사용할 수 없으며 fromdos / todos로 대체되었습니다. 또한 두 변환 명령 세트 모두 이진 파일의 존재에 대해 다양한 무지가 있으므로 저장소에 이미지, 글꼴 등이 포함되어 있으면이 프로세스로 인해 손상 될 수 있습니다.

Linux 'file'명령을 사용하여 아래 표시된 것처럼 텍스트 파일 만 올바르게 식별하고 처리하는 이진 파일 손상 문제에 대한 해결 방법을 찾을 수있었습니다. 아래 명령은 --tag-name-filter 옵션을 사용하여 기존 태그를 새로 수정 된 커밋으로 이동하여 기존 태그를 유지합니다. 또한 --force 플래그를 사용하여 이전에 저장소에서 트리 필터를 실행 한 경우 명령이 작동하는지 확인합니다.

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

추가 도구가없는 경우 (예 : 'fromdos', 'dos2unix'등) :

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

크로스 플랫폼 (OS X, FreeBSD, Linux) 유용한 아날로그 'fromdos', 'dos2unix':

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

아마도 유용한 'unix2dos':

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

당신이하고있는 것을 절대적으로 확실하게한다면, 현재 디렉토리 "."에있는 모든 파일에서 "/ r"을 삭제하기 위해이 간단한 인라인 명령을 사용할 수 있습니다 :

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

1
오히려 \의 R \ n R 만 \ 제거 대신하는 N \
xdevs23

해당 sed호출을 더 짧은 것으로 바꿀 수 있다고 생각합니다 .sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.