Git2015. 10. 7. 02:25
반응형

 개발을 진행하다 보면 크게 의식하지는 않지만 신경써야 하는 것이 바로 개행문자입니다. 본 아티클에서는 버전관리시스템(VCS : Version Control System)중 하나인 Git를 이용해서 개행문자를 핸들링하고 관리하는 방법에 대해서 알아보도록 하겠습니다.


 먼저 개행문자가 문제를 일으키는 원인은 개행문자로 사용되는 대표적인 문자 두가지 CR(carriage-return), LF(linefeed)가 플랫폼 별로 다른 조합으로 사용되기 때문입니다. 일반적으로 개발을 진행하는 Windows플랫폼에서는 CRLF, 비 Windows플랫폼은 LF를 개행문자로 많이 사용합니다. 이런 개행문자의 차이는 사용하는 어플리케이션에서 자동적으로 인식해 주기도 하지만 별도의 처리가 없거나 해당 문자가 다른 의미로 사용되는 경우에는 문제를 발생시킬 수도 있습니다.


!#/bin/bash

##Something todo...


 개발하면서 한번씩 접해보았을만한 상황이 위의 예와 같은 Shell Script선언부 입니다. 이 선언부에서 사용되는 문자열(!#/bin/bash)을 Windows플랫폼에서 작성할 경우 라인 말미에 해당 플랫폼의 개행문자인 CRLF가 삽입되게 됩니다. 이 상태로 작성된 Shell Script파일을 Linux플랫폼등에서 실행할 경우 Command not found, bad interpreter: No such file or directory등과 같은 에러 메시지를 만나게 됩니다. 즉 bash shell을 사용하는 shell script라고 선언하는 부분이 !#/bin/bash(개행문자 LF)로 완성되는데 사이에 개행문자 CR이 끼어들어 의도하지 않은 선언부로 해석되어 문제가 발생합니다. 예로 들은 bash이외에도 Perl이나 Phyton 등등 해시뱅(#!)을 이용한 선언부를 사용하는 Script파일에도 문제가 생길듯 합니다.


 이런 문제를 피하는 방법은 개발 및 운용을 동일한 플랫폼에서 진행하거나 개발자 레벨에서 문제가 생기지 않도록 올바른 개행문자를 삽입하는 등의 방법이 있습니다. 하지만 이러한 방법은 단말을 별도로 맞추어서 준비한다거나 개발자의 생산성 저하 등의 문제가 발생할 수 있습니다. 특히 개발자 개인에게 맡기는 방법은 휴먼 에러(실수)에 의한 문제 발생의 가능성을 배제할 수 없습니다.


 이런 경우 Git를 이용해서 소스코드를 관리하고 있는 프로젝트라면 좀더 우아한 방법으로 개행문자에 의한 문제를 회피할 수 있습니다.



core.autocrlf 설정

 

 첫번째로 살펴볼 방법은 core.autocrlf 설정입니다. 이 설정은 Commit혹은 Checkout을 실행할 때 알려진 텍스트 타입의 파일의 개행문자를 자동으로 변환해 주는 설정입니다. 이 설정은 아래와 같은 세가지 값을 가질 수 있습니다.


  • true : Commit시점에 CRLF를 LF로 변환, 체크아웃 시점에 LF를 CRLF로 변환
  • input : Commit시점에 CRLF를 LF로 변환, 체크아웃 시점에는 변환하지 않음(Windows플랫폼의 경우는 true와 동일)
  • false : 변환하지 않음 

 

$git config <--global> core.autocrlf [true | input | false] //설정하기

$git config <--global> --unset core.autocrlf //설정 해제하기


 위와 같은 명령을 실행함으로서 core.autocrlf설정을 할 수 있습니다. --global 옵션 설정에 따라서 명령을 실행하는 리포지터리에만 설정을 하거나전체 리포지터리에 영향을 주도록 설정할 수 있습니다. 기본적으로는 --global옵션 설정을 추가하여 전체적으로 적용하고 필요한 프로젝트에서만 해제하는 식의 전략이 좋을 듯 합니다. 또 개발부터 운영까지 Windows 단일 플랫폼인 경우는 false설정이 효과적입니다.



※ 변환설정이 되어있는 경우 위와 같이 변환이 수행된다는 경고 메시지가 출력된다.



※ IntelliJ와 같이 인텔리한 IDE에서는 core.autocrlf 설정이 되있지 않은 경우 You are about to commit CRLF line separators to the Git repository 경고 메시지를 출력하고 설정을 수행하도록 유도하니 좋은 툴의 도움을 받는 것도 한가지 방법 중 하나인 듯



core.safecrlf 설정


 다음으로 살펴볼 설정은 위에서 소개한 설정의 안전을 위한 설정으로 해당 파일 내부에 여러종류의 개행문자가 혼재해 있을경우 의도적인 것으로 판단해서 core.autocrlf설정에 의해서 변환을 수행하지 않도록 하는 설정입니다.


  • true  : 개행문자가 혼재할 경우 안전을 위해 이후의 처리를 중단함
  • warn : 개행문자가 혼재할 경우 경고를 출력하고 처리는 계속 진행함
  • false : core.autocrlf설정에 의해 변환 수행, 결과적으로 개행문자가 한쪽으로 통일되므로 의도한 경우라면 데이타 손실 가능성이 있음


$git config <--global> core.safecrlf [true | warn | false] //설정하기

$git config <--global> --unset core.safecrlf //해제하기


※ 실제 동작은 개행문자가 혼재해 있는지 확인하는 것이 아니라 CRLF -> LF, LF -> CRLF 변환을 모두 수행하여 변환 후의 데이터가 변환 전과 비교하여 차이가 있을 경우 손실이 발생한 것으로 판단하는 방식입니다.



core.eol 설정


 eol(end of line)문자를 직접 지정하는 설정입니다. Commit과 Checkout을 실행할 때 지정한 개행문자로 변환을 수행합니다.


$git config <--global> core.eol [개행문자] //설정하기

$git config <--global> --unset core.eol //해제하기


 개행문자를 직접 지정하는 방식이기 때문에 Checkout되는 플랫폼에서 코드를 편집하는 IDE혹은 편집기 어플리케이션이 다른 플랫폼의 개행문자를 제대로 인식하지 못할 경우 문제가 될 가능성도 있습니다. 또한 core.autocrlf 설정과 맞지 않도록 설정하면 경고가 발생합니다. 예를 들어 core.autocrlf=input의 경우 Commit시점에 CRLF -> LF변환이 일어나지만 core.eol 설정에 의하면 변환을 수행할 수 없기 때문입니다.



※ core.autocrlf 설정과 맞지 않도록 설정 후 git add 명령을 수행하면 bad config variable 'core.eol' 경고 메시지가 출력된다.



.gitattributes


 앞서 언급한 방식은 개발자 각각의 단말에 설정하는 방법이므로 직접 핸들링 하는 것 보다는 위험성이 적겠지만 여전히 설정을 빼먹거나 실수할 가능성이 남아있습니다. 이 경우 리포지터리 별로 속성을 지정하여 접속 단말의 설정에 상관없이 일관성 있는 동작을 보장할 수 있습니다. 이 방식은 '.gitattributes' 파일을 해당 속성을 적용할 Git저장소의 디렉토리(일반적으로는 프로젝트 루트 디렉토리)에 위치 시킨후 해당 파일에 적용시킬 속성을 기술하는 방식으로 동작합니다.


* text=auto //전체 파일 개행문자 변환적용


 .gitattributes파일 내부에 위와 같이 설정하면 core.autocrlf 설정을 적용한 것과 동일한 효과를 해당 리포지터리를 사용하는 모든 개발자에게 강제할 수 있습니다.


*.txt binary //txt파일 바이너리 타입 파일로 지정

*.bak text //bak파일 텍스트 타입 파일 지정

*.java eol=crlf //eol을 crlf로 지정

*.c eol=lf //eol을 lf로 지정


 패턴 매칭을 통해 별도로 지정하는 방식도 가능하며 위의 전체 설정과 동시에 적용하면 각각 지정한 쪽이 적용됩니다. 아마 먼저 패턴에 일치하는 쪽이 적용되는 듯 합니다.


프로젝트 파일과 같이 위치시키는 것이 싫은 경우에는 '.git/info/attributes'에 위치시킬 수  있습니다.



 본 아티클에서 기술한 내용과 같이 설정을 통해 개발자 개인이 의식하지 않아도 되도록 하는 것이 개개인의 문제해결능력을 떨어뜨릴 수도 있겠지만 시스템적인 것들은 자동화하고 좀더 서비스에 집중하는 것이 좀 더 생산적이지 않을까요?



※ 참조

Customizing Git - Git Configuration

gitattributes - defining attributes per path


Posted by Reiphiel