· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
오픈소스 프로젝트에 참여하기위한 diff와 patch 사용법


많은 분들이 오픈 소스 프로젝트에 참여하고 싶어도 이 두 가지 프로그램을 어떻게 쓰는지 몰라 힘들다고 하셔서 여기다 간단히 소개합니다.

우선 diff는 말 그대로 difference, 즉 차이를 만들어 주는 프로그램입니다. 차는 두 디렉토리간일 수도 있고, 두 파일간일 수도 있습니다. 두 가지 모두 지원합니다. 가령 인터넷에서 chikichiki-2.0.tar.gz란 소스 패키지를 받아서 압축을 풀었다고 합시다. 그럼 현재 디렉토리에

chikichiki-2.0/ 

이라는 디렉토리가 생길 겁니다. 유닉스 세계에서는 관례상 대부분의 소스 패키지가 패키지 이름과 같은 디렉토리 밑에 소스 파일들이 전부 들어갑니다.

이제 할 일은 chikichiki-2.0의 버그를 찾아 내어 개발팀에게 보고하는 일입니다. 우선 디렉토리를 복사합니다.

cp -R chikichiki-2.0 chikichiki-2.0.orig 
이러면
 
chikichiki-2.0/ 
chikichiki-2.0.orig/ 

처럼 같은 이름을 가졌으면서 끝에 .orig가 붙은 디렉토리가 하나 생깁니다. 이 디렉토리는 diff를 구할 때 기준(즉, 원본임)이 되는 것이므로 내용을 절대 변경하면 안됩니다. 작업은 반드시 chikichiki-2.0에서만 하도록 합니다.

그래서 며칠 동안 버그를 잡고 기능을 추가한 끝에 컴파일과 실행이 성공적으로 이루어졌습니다. 일이 끝났으니 개발팀에게 결과물을 전송해야겠죠? 그런데 chikichiki-2.0/을 다시 tar.gz로 묶어 보내면 용량도 너무 크고 개발팀쪽에서도 내가 뭘 바꿨는지 알기가 힘듭니다. 이제 드디어 diff를 써야 할 순간입니다.

 
diff -urN chiki-2.0.orig chikichiki-2.0 > chikichiki.diff 

이렇게 하면 diff 프로그램이 두 디렉토리를 탐색하면서 같은 이름의 파일끼리 비교를 한 뒤 차이를 chikichiki.diff 파일에 기록합니다. 물론 앞의 디렉토리가 원래 것이고, 뒤의 것이 고친 것입니다.

옵션을 살펴 보면, 먼저 -u 옵션은 "unified format"을 뜻하는 것으로, diff 포맷을 지정할 때 씁니다. -u 말고 -c라고 해서 "context format"도 있는데, 두 개가 모양이 다릅니다. -u를 주었을 때, -c를 주었을 때, 또는 아무 것도 안주었을 때 결과를 살펴 보면 포맷간의 차이를 쉽게 알 수 있습니다. 어느 것을 선택할지는 순전히 개인 취향의 문제입니다. 나중에 패치를 적용할 때 쓸 patch 프로그램은 세가지 포맷 모두를 자동 인식합니다. 그러나 오픈 소스 개발자중 대부분은 가장 알아보기 쉬운 unified format을 주로 씁니다.

-r은 경로로 지정한 디렉토리 안의 서브디렉토리를 전부 거슬러 들어가면서(recursive) 안에 있는 파일을 전부 비교하란 뜻입니다. 이걸 지정하지 않으면 명령행에서 지정한 디렉토리만 비교합니다.

-N 옵션은 새 파일도 diff에 포함하란 뜻입니다. 내가 고친 디렉토리에 새로 만들어 넣은 파일이 있을 경우 이걸 꼭 써야 합니다.

여기까지만 알아도 diff 사용에는 큰 문제가 없을 것입니다. 한가지 더, 위에서 디렉토리 두 개를 비교했는데, 파일끼리 비교하는 것도 물론 가능합니다. 보통 그때는 먼저 고칠 파일을 ~.orig로 복사해 놓고 고친 다음 둘간을 비교합니다. 그리고 물론 -r이나 -N 옵션은 필요가 없겠지요.

그런데 또 한가지 의문점이 있습니다. 꼭 디렉토리를 .orig로 복사해서 디스크 용량을 두 배로 잡아먹어야 하느냐는 궁금함이 생길 수 있죠(물론 복사 자체가 귀찮기도 하구요). 그럴 때는 소스 패키지 대신 아예 CVS 소스 트리를 받아다 거기서 바로 작업하면 됩니다. 버전 관리 프로그램은 전부 diff 기능을 내장하고 있거든요. 버전 관리 프로그램을 쓰는 게 거의 필수인 이유중 하나도 이것 때문입니다.

그럼 이번에는 patch 프로그램을 써서 사용자들이 보내온 패치를 트리에 어떻게 적용하는지 알아 봅시다. diff로 구한 패치 모양은 대략 다음과 비슷합니다:

Index: config/util/lndir.c
===================================================================
--- config/util/lndir.c     (revision 9) <-- !여기 적힌 경로명에 주목!
+++ config/util/lndir.c     (working copy) <-- !여기도!
@@ -222,6 +222,8 @@ 
                        continue;
                    if (!strcmp (dp->d_name, "CVS.adm"))
                        continue;
+                   if (!strcmp (dp->d_name, ".svn"))
+                       continue;
                }
                ocurdir = rcurdir;
                rcurdir = buf;

이 패치는 XFree86을 빌드할 때 쓰는 lndir이란 프로그램이 서브버전 관리 디렉토리인 .svn을 무시하도록 해줍니다. XFree86의 최상위 디렉토리는 xc이므로 거기로 가서

patch -p0 < /path/to/lndir.diff 

이렇게 하면 화면에 패치 결과가 주루룩 나옵니다. failed... 하면서 같은 이름의 .rej (rejected, 즉 거부된 패치라는 뜻) 파일이 생성되지만 않는다면 성공한 것입니다. 한 파일의 여러 군데를 고치는 패치의 경우 어떤 것은 적용되고 어떤 것은 적용되지 않는 경우가 가끔 있으니 유심히 봐야 합니다.

patch는 항상 표준 입력으로부터 입력을 받습니다. 그래서 패치 파일을 '<'을 써서 입력해 주었습니다. 그리고 아주 중요하고도 유일한(?) 옵션으로 -p 옵션이 있습니다. 이 옵션은 주어진 패치의 경로에서 몇 단계를 벗길 것인가를 지정합니다. -p0이라고 지정하면 하나도 벗기지 말라가 되겠죠? 위 패치를 보면 경로가 config/util/lndir.c로 되어 있습니다(!주목! 부분). 그리고 patch 프로그램을 실행하는 디렉토리가 xc 였으니까 상대 경로가 딱 맞습니다. 즉

$ pwd 
/home/junyoung/xc 
$ ls config/util/lndir.c 
config/util/lndir.c 
$ patch -p0 < ~/lndir.c.diff 
처럼 하게 됩니다.

그럼 -p0 말고 -p1, -p2, ... 등의 옵션은 언제 써야 할까 하는 의문이 생깁니다. 0이외는 숫자는 아래와 같을 때 씁니다.

 
$ pwd 
/home/junyoung/xc 
$ cd config/util 
$ ls lndir.c 
lndir.c 
$ patch -p2 < ~/lndir.c.diff 
즉, 어떤 이유로 config/util 디렉토리 안으로 들어가 패치를 적용할 필요가 있을 때 -p2 옵션을 쓰면 패치 안에 적힌 경로(!주목!)에서 앞의 두 단계를 벗겨내라는 뜻입니다(config와 util).

patch 프로그램 사용법도 이게 전부입니다. 그밖에 옵션이 더 있는 것 같은데 한번도 써본 적이 없어서 모르겠구요, 아마 -p 옵션만 알면 다른 건 몰라도 전혀 문제 없을 겁니다.

아무튼 그렇게 해서 공헌자가 패치를 제출하면 개발자가 패치를 적용하는 식으로 작업이 진행되는 것이 오픈 소스 프로젝트의 전형적인 과정입니다. 가령 위의 패치를 실제로 XFree86 프로젝트에


로 제출했더니 다음 날 바로


처럼 커밋을 해주더군요. 보잘 것 없는 패치지만 XFree86 프로젝트에 이름이 올라가는 걸 보니 기분이 좋더군요. 아직 경험해 보지 않으셨다면 여러분도 같은 기쁨을 얼마든지 느껴볼 수 있습니다! 지금 참여합시다.





sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2005-09-21 14:39:41
Processing time 0.0281 sec