· 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 프로젝트에 이름이 올라가는 걸 보니 기분이 좋더군요. 아직 경험해 보지 않으셨다면 여러분도 같은 기쁨을 얼마든지 느껴볼 수 있습니다! 지금 참여합시다.



ID
Password
Join
True happiness will be found only in true love.


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.0060 sec