· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Rcs Tutorial

RCS 강좌

임대영 <RAXIS@hitel.net> v1.0h, 1997년 8월 28일

윤현호 <hhyoon@kldp.org> HTML문서를 위키문서로 변환. 2005년 2월 23일



강력한 버전 관리 도구인 RCS에 대하여 설명한다.


1. 들어가면서 (버전이란)

프로그램 개발과 유지에 있어서 가장 중요한 문제 중의 하나가 바로 버전 관리(version management)입니다. 여러분은 버전이라는 것을 어떤 의미로 이해하고 계산가요? 한글 3.0 이나 MS windows 3.1, Windows 95 등에서 프로그램 뒤에 이상한 소수점 달린 숫자가 아니냐고 답하시겠지요. 맞습니다.

그러면 버전이라는 것은 이렇게 이미 제품화되어 있는 프로그램에 붙이는 것일까요? 아닙니다.

여러분들이 프로그램을 짤 때도 엄연히 버전은 존재하는 것입니다. 가령 100줄 짜리 프로그램을 하나 짰다고 가정합시다. 그리고 여기서 함수를 하나 추가했습니다. 그리고 며칠 있다가 다시 함수 몇 개를 추가하고, 필요 없는 함수 한 개를 없앴습니다. 보통 일어날 수 있는 경우이겠지요. 이렇게 프로그램을 개발할 때 그 구성 요소가 바뀜에 따라서 프로그램은 전혀 새로운 것이 될 수가 있습니다. 이렇게 프로그램에 영향을 줄 수 있는 각 단계를 버전(version)이라는 말로 표현하게 되죠.

이 강좌는 이런 프로그램에 있어서의 버전이라는 개념을 이해하고, 버전을 전문적으로 관리하는 RCS(Reversion Control System)에 대해서 소개하는 것입니다. 한번 천천히 읽어보시고 한번 따라해 보세요. 재밌어요.

2. RCS 란 무엇인가?

여러분들은 잘 모르겠지만 버전 관리 프로그램은 아주 많습니다. 몇 개만 열거해 보죠. IBM의 CLEAR/CASTER, AT&T의 SCCS, CMU(카네기 멜론 대학)의 SDC, DEC의 CMS, 그리고 오늘 소개할 RCS 가 있습니다. 오늘날의 RCS 는 한 사람이 만든 것이 아닙니다. Linux가 그러하듯이 RCS도 수많은 사람들이 기능 하나 하나를 추가하고 고쳐서 오늘날의 RCS 가 되었습니다.

지금까지 대부분의 사람들이 프로그램을 짤 때 하나 고치고 이것을 temp 파일로 하나 저장해 놓고, 하나 고치고 또 하나 temp 파일 만들고 이런 방식이었을 겁니다. RCS는 자동으로 버전을 저장하고, 꺼내고, 비교하고, 추적하고, 합치는 여러 가지 일을 할 수가 있습니다. UNIX 계열에서만 있는 것이 아니고, 요즘은 도스용도 나와 있더군요, RCS를 이용해서 단순하게 C 프로그램 소스의 버전만을 관리한다고 생각하시면 오산입니다. RCS 는 C, C++, Fotran 등의 일반 프로그램뿐만 아니라 일반 문서, 논문, 그림 등등 생각해 보면 버전이라는 것을 갖다 붙일 수 있는 거의 모든 곳에 이용할 수 있을 겁니다.

3. RCS의 기능과 구성

그럼 RCS에는 어떤 기능들을 제공하고 있으며, 또 어떤 파일로 구성되어 있는지 한번 생각해 보죠.

3.1. RCS 의 기능

RCS 에서 제공하는 기능을 한번 정리해 볼까요.
  • 텍스트 파일의 리버전(reversion)을 저장하고 꺼내 볼 수 있다.
  • 저장된 임의의 버전을 선택해서 꺼내 볼 수가 있다. (이게 좋죠. 이것은 모두 RCS가 바뀐 내용을 다 가지고 있기 때문입니다.)
  • 하나의 완성된 프로그램이 되기 위해서는 버전 트리(Version Tree)가 형성된다. 즉 하나의 원래 버전에서 여러 개의 새끼 버전(child version)이 만들어 질 수가 있다. 이것이 하나의 트리를 형성하게 된다.
  • 각 버전에 대한 특징들을 기록할 수가 있어, 보기에 편하다. 아울러 버전 이름, 생성 날짜, 저자(author)등에 대한 정보도 제공한다.
  • 여러 사용자가 하나의 파일을 접근(access)함으로 인해 빚어질 수 있는 문제를 해결할 수 있습니다. 만약 다른 사용자가 내용을 고치려고 하면 RCS는 경고를 내게 되죠.
  • 결과적으로 디스크를 절약해 준다. 즉 더이상의 temp 파일을 저장할 필요가 없기 때문이다. 극단적인 경우 디렉토리 통째로 temp로 저장하기도 한다. RCS에서는 이런 무식한(?) 작업이 더이상 필요하지 않다.

대충 무슨 말을 하는지 아시겠어요? 곧 나올 예제와 설명을 보시면 잘 아시게 될 겁니다. (한가지 걱정되는 것은 내용이 얼마 안될 줄 알았는데 너무 많아서 끝까지 보기를 포기하시지 않으실 지 모르겠네요.)

3.2. RCS 의 구성

지금까지 RCS의 기능들에 대해서 약간은 중복되게 말씀드렸습니다. 그럼 도대체 RCS가 어느 디렉토리에 있는 프로그램인가, 리눅스에는 이것이 있는가 하고 질문하시겠지요.

RCS 는 아래의 프로그램으로 이루어져 있는 거대한 프로그램 집단입니다.
  • ci - 체크인(check in)한다.
  • co - 체크아웃(check out)한다.
  • rcs - RCS 파일의 속성을 바꾼다.
  • ident - RCS 파일의 인식표(identification marker)를 읽는다.
  • rcsdiff - RCS 파일의 버전들을 비교한다.
  • rcsmerge - 여러 버전을 합친다.
  • rlog - 로그(log) 메시지 등의 정보를 출력한다.

장난이 아니죠. 그러나 너무 걱정 마세요. 이중에 몇 개만 알아도 RCS의 진수를 맛볼 수 있거든요. ci, co, rcs만 기억하고 계세요.

4. RCS를 사용해 봅시다. (초급)

이번 편은 RCS의 구체적인 예제입니다. 초급 과정을 다루기 때문에 약간 복잡한 요소는 제외시켰습니다. 여기서는 ci, co, rcs 명령어의 예를 들어 전개됩니다.

4.1. 기본적인 ci, co의 사용법

이제부터 본격적으로 RCS 명령어를 이용해 보기로 합시다. 그럼 먼저 준비를 해야겠군요. 우선 RCS를 연습할 수 있는 적당한 디렉토리를 하나 만드신 다음에 거기에서 시작합시다. 그리고, RCS 파일을 저장할 디렉토리를 만듭니다. 이름은 'RCS'. RCS가 고정적으로 쓰는 이름입니다.
% mkdir RCS 

그리고 아래와 같은 간단한 파일을 가지고 시작합니다.

exam.c
/* $Log: RcsTutorial,v $
 * Revision 1.1  2005/02/23 01:46:02  kss
 * 203.237.51.80;;윤현호;;
 * */

#include <stdio.h>

main()
{
     printf(' Hello \n' );
}

위에서 `/* $Log: RcsTutorial,v $ 위에서 `/* Revision 1.1 2005/02/23 01:46:02 kss 위에서 `/* 203.237.51.80;;윤현호;; 위에서 /* */ 라는 쓴 부분이 보이십니까? 이 부분은 원래는 없어도 됩니다. 하지만 각 버전의 특징을 소스 파일에 기재함으로써 사용자에게 정보를 제공해 주기 때문에 저는 쓰기로 하겠습니다. 참고로 이 부분이 만약 없다고 가정한다면 RCS 파일은 원래 소스 파일에 아무런 표시도 하지 않기 때문에 사용자가 보기엔 어느 버전인지 좀 이해하기 어렵겠죠. $Log: RcsTutorial,v $ 위에서 /* $Log:$ */ 라는 쓴 부분이 보이십니까? 이 부분은 원래는 없어도 됩니다. 하지만 각 버전의 특징을 소스 파일에 기재함으로써 사용자에게 정보를 제공해 주기 때문에 저는 쓰기로 하겠습니다. 참고로 이 부분이 만약 없다고 가정한다면 RCS 파일은 원래 소스 파일에 아무런 표시도 하지 않기 때문에 사용자가 보기엔 어느 버전인지 좀 이해하기 어렵겠죠. Revision 1.1 2005/02/23 01:46:02 kss 위에서 /* $Log:$ */ 라는 쓴 부분이 보이십니까? 이 부분은 원래는 없어도 됩니다. 하지만 각 버전의 특징을 소스 파일에 기재함으로써 사용자에게 정보를 제공해 주기 때문에 저는 쓰기로 하겠습니다. 참고로 이 부분이 만약 없다고 가정한다면 RCS 파일은 원래 소스 파일에 아무런 표시도 하지 않기 때문에 사용자가 보기엔 어느 버전인지 좀 이해하기 어렵겠죠. 203.237.51.80;;윤현호;; 위에서 /* $Log:$ */ 라는 쓴 부분이 보이십니까? 이 부분은 원래는 없어도 됩니다. 하지만 각 버전의 특징을 소스 파일에 기재함으로써 사용자에게 정보를 제공해 주기 때문에 저는 쓰기로 하겠습니다. 참고로 이 부분이 만약 없다고 가정한다면 RCS 파일은 원래 소스 파일에 아무런 표시도 하지 않기 때문에 사용자가 보기엔 어느 버전인지 좀 이해하기 어렵겠죠. 라는 부분은 제가 나중에 설명할 자동 인식표(Auto Identification)의 하나입니다.

그럼 이제 RCS 파일을 만들어 볼까요. 파일을 RCS에 올리는 명령어가 바로 ci(check in)입니다. 처음 버전은 1.1부터 시작합니다.
% ci exam.c 
RCS/exam.c,v <- exam.c
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> This is our First RCS test file
>> .
initial revision: 1.1
done

RCS 에서는 버전 1.1 의 특징을 기록할 수 있도록 메시지를 출력합니다. 저는 그냥 This is our First RCS test file 이라고 기록하겠습니다. 메시지를 마치려면 '.' 을 입력하면 됩니다. 그러면 RCS/exam.c,v 라는 파일이 만들어지죠. 초기 버전은 이미 말씀드린 것과 같이 1.1 입니다.

이때 ls를 쳐보시고 파일이 없어졌다고 놀라지 마세요. 아니 RCS에 버그가 있는 것 아니냐고 반문하시는 분이 계시겠지요. 아닙니다. 우리는 파일을 RCS 에다가 저장한 것입니다. 저장만 하면 안되겠지요. 그럼 꺼내는 방법을 말씀드리죠. co(check out)이라는 명령어를 사용합니다.
% co exam.c
RCS/exam.c,v -> exam.c
revision 1.1
done

그러면 다시 exam.c라는 파일이 생성이 됩니다. 이것이 RCS 의 대략적인 메카니즘입니다. 간단하죠. exam.c가 어떻게 변했나 볼까요.

`exam.c `
/* $Log: RcsTutorial,v $
 * Revision 1.1  2005/02/23 01:46:02  kss
 * 203.237.51.80;;윤현호;;
 *
* Revision 1.1 1995/10/12 14:22:08 raxis
* Initial revision
* */

#include <stdio.h>

main()
{
     printf(' Hello \n' );
}


원래는 없던 메시지가 잔뜩 생겼네요. 이것은 RCS에서 자동적으로 생성시켜 주는 정보들입니다. 로그 파일(log file) 이름이 보이고요... 버전이 1.1 이고 1995/10/12 오후 2시에 만들었군요. 그리고 RCS 파일을 생성한 사람은 raxis(제 리눅스의 사용자 이름)이네요. 여기서 소수점 앞의 1은 release number이구요, 소수점 첫째 자리의 1은 level number 라고 합니다. 여기에 대한 자세한 설명은 3번째 강좌에서 다루도록 하겠습니다.

한가지 아무런 옵션을 붙이지 않고 그냥 co exam.c만 하면 읽기 전용(read only)모드로 만들어집니다. 흠. 그러면 "파일의 내용을 바꾸려면 exam.c의 퍼미션을 바꾸어야 하나요?" 하고 묻는 분이 계시겠네요. 아닙니다.

co 의 옵션중에 -l(lock을 의미)이 있습니다. 이것은 붙이면 exam.c를 생성시켜 주는데 쓰기(write)가 가능하도록 합니다.
% co -l exam.c
RCS/exam.c,v -> exam.c
revision 1.1 (locked)
done

그런데 아까랑 메시지가 약간 다르지요. (locked)라는 말이 추가 되었습니다. 'lock'의 뜻이 자물쇠라는 것을 아시나요. 쓰기 가능하게 하는 것과 자물쇠를 다는 것이 무슨 관계일까요? (이상하죠?)

제가 RCS의 기능을 설명한 부분에 RCS는 여러 사용자가 하나의 파일을 접근함으로써 생기는 문제를 해결할 수 있다고 했습니다. 다른 사용자가 내용을 고치려고 하면 메시지를 낸다고 했죠. 그러니까 RCS파일을 만든 사람이 아니라면 절대로 그 파일에 lock을 걸 수가 없습니다. 오로지 co exam.c만 가능하다는 것입니다.(읽기만) 그럼 상대적으로 RCS파일을 만든 사람은 그 반대로 쓰기가 가능하여야 된다는 결론이 이르게 되네요. 약간 이상한 결론이지만 현실이 그런걸 어쩌겠습니다. (^^)

다른 사람이 다음과 같이 한다고 가정합니다. 즉 RCS 디렉토리를 자신의 디렉토리로 링크(link)시켜서, exam.c를 check out 합니다.
%co -l exam.c
co error: RCS/exam.c,v: Permission denied

%co exam.c
RCS/exam.c,v -> exam.c
revision 1.1
done

제작 설명 드린 대로 역시 lock를 걸 수가 없군요. 파일의 모드를 한번 살펴봅시다. 읽기 모드로만 되어 있겠죠.
%ls -al exam.c
1 -r--r--r-- 1 guest users 157 Oct 12 23:48 exam.c

다시 한번 말씀드립니다. 이미 lock이 걸려 있는 파일은 다른 사람이 절대로 그 내용을 건드리지 못합니다. 흠. 데이터의 안전성을 보장하네요. 그런데 RCS 목록에 올릴 때마다 ci, co를 일일이 다 쓴다면 좀 귀찮은 작업 같은 기분이 들 겁니다. 그래서 ci 옵션에도 -l (lock) 이 있습니다. 즉, ci -l exam.c 라고 한다면 RCS/exam.c,v 란 파일을 변경하게 되고 원래 exam.c는 고대로 놓아두게 되죠.

그럼 이번엔 exam.c를 일주일 동안 생각해서 버전업을 하기로 결정했습니다. print라는 함수를 추가하기로 한 것이죠. 밤을 새는 디버그 끝에 드디어 다음 버전을 완성시켜서 RCS에 다시 등록시키기로 하겠습니다.
% ci -l exam.c ( -l 이 무슨 의미인지 아시겠죠 )
RCS/exam.c,v <- exam.c
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single '.' or end of file:
>> function print() is added (타이핑하는 부분이죠.)
>> .
done

버전이 1.2로 올라갔군요. 뿌듯합니다. 자신의 프로그램도 이렇게 힘차게 버전업을 할 수가 있습니다. 그럼 그 결과를 한번 봅시다.

exam.c
/* $Log: RcsTutorial,v $
 * Revision 1.1  2005/02/23 01:46:02  kss
 * 203.237.51.80;;윤현호;;
 *
* Revision 1.2 1995/10/12 15:05:58 raxis
* function print() is added
*
* Revision 1.1 1995/10/12 14:22:08 raxis
* Initial revision
* */ 

#include <stdio.h> 

void print( char* pszMsg )
{
     puts( pszMsg);
}

main()
{
     print(' Hello ');
}

버전 1.2가 보이시죠. 1.2가 만들어진 날짜도 보이구요. raxis란 분께서 다시 버전업을 해주셨군요. 그런데 위에서 RCS의 모든 메시지들은 모두 코멘트(comment)처리되어 있다는 것을 눈치채셨는지.. 즉 컴파일할때 RCS부분은 없는 거나 마찬가지겠죠(당연한 소리).

제가 1부에서 RCS로 관리 할 수 있는 파일은 C 프로그램 소스만이 아니라고 했지요. 기억이 나실런지... RCS는 일반적으로 C(.c), 파스칼(.p), C++(.cc, .C), latex(.tex) 등의 프로그램은 확장자에 기초해서 코멘트 마크를 달게 됩니다. 그리고 나머지 파일들에 대해서는 대부분의 UNIX 쉘 스크립트에서 코멘트로 사용되는 '#' 마크를 사용하게 되는데..(좀 멍청한가요... 후후.) 그럼 postscript와 같이 '%'를 코멘트로 처리하는 파일들은 어떻게 할까요.
% rcs -c'%' beauty.ps

rcs라는 명령어는 RCS 파일의 속성을 바꾼다는 것을 기억하고 계시나요. beauty.ps로부터 만들어진 RCS 파일의 코멘트 부분은 '%'마크를 사용하라는 명령어입니다.

참고

RCS 에 대한 입문은 man rcsintro를 하시면 됩니다. RCS 에 대한 설명이 아주 긴 영어로 나옵니다. 해석하시면서 머리를 한번 식혀 보심이... ^^ 그리고, ci, co, rcs 에 대해서 더 잘 알고 싶으신 분은 man을 이용해 보시죠. UNIX에서 전문가가 되기 위해서는 매뉴얼을 열심히 봐야 된다고 하는 전설(?)이 있습니다.

5. RCS를 사용해 봅시다. (고급)

5.1. RCS에서의 버전 (버전트리)

RCS를 사용해서 자꾸 버전업(version up)을 하다 보면 한 줄로 이어서 버전이 만들어질 껍니다. 버전트리의 개념을 설명하기 전에 RCS에서의 버전 체계에 대해서 말씀드리죠. RCS파일이 처음으로 만들어지면 1.1부터 시작합니다. 그리고 다음 버전은 1.2,1.3 이렇게 소수점 이하의 숫자만 계속 늘어나게 됩니다. 결코 2.0의 파일은 만들어지지 않습니다. RCS에서는 강제적으로 버전업을 시킬 수 있는 기능을 제공합니다.
% ci -r2.0 -l exam.c

위와 같이 하면 버전 2.0으로 강제적으로 만들 수가 있습니다. 여기서 -r 은 revision을 뜻하는 옵션입니다. 위의 예제는 exam.c를 버전 2.0으로 올리고 동시에 lock도 걸라는 표시입니다. 버전이 2.0이 되고 부터는 ci를 하면 다시 2.1 -> 2.2 -> 2.3 의 순서로 버전이 증가합니다.

그렇다면 각 버전의 파일을 풀 수도 있겠군요.
% co -r1.2 -l exam.c

위와 같이 하면 exam.c가 어떻게 되어 있더라도 버전 1.2 에 해당하는 RCS 파일이 풀려나옵니다. 그냥 co -l exam.c라고만 한다면 exam.c의 가장 높은 버전이 풀려나옵니다. 만약 필요에 의해 1.2 버전을 몇 가지 고친 다음에 다시 이것을 RCS에 올린다고 가정합니다. 그럼 다음 버전은 무엇일까요? 답은 가장 높은 버전의 다음 버전입니다. 즉 2.1이 되겠군요.

그런데 한가지 논리적으로 이상하지 않나요. 다음의 버전 트리를 한번 봅시다.
+-----+     +-----+     +-----+      +-----+
| 1.1 |---->| 1.2 |---->| 2.0 |      | 2.1 |                                
+-----+     +--+--+     +-----+      +--+--+
               |                        |
               +------------------------+

각 2.0의 다음이 2.1인데 1.2 버전의 다음이 2.1이라니 말입니다. 완전히 할아버지 다음에 아버지 빼고 아들로 바로 내려가는 거랑 같군요. 그럼 2.0을 바꾸면 다음은 2.2가 되겠군요. 이것은 버전의 연속성이 깨어지게 되는 나쁜 결과입니다.

RCS에서는 버전의 연속성을 보장하기 위해서 branch 기능을 제공합니다. 가령 1.2를 수정한 후 이것을 다른 버전으로 다시 관리하고 싶다고 생각이 들 때 버전을 1.2.1로 저장하는 것입니다. 맨 끝의 1은 branch number를 가리킨다고 생각하시면 됩니다. 1.2.1의 첫 번째 branch 는 1.2.1.1로 시작합니다. 그러니까 앞의 1.2를 빼면 다시 버전이 1.1로 시작하는 것과 같다고 할 수가 있군요. 이것을 버전 트리로 표현한다면 아래와 같이 될 수가 있습니다.
+-----+     +-----+     +-----+      +-----+      +-----+
| 1.1 |---->| 1.2 |---->| 2.0 |----->| 2.1 |----->| 2.2 |
+-----+     +--+--+     +-----+      +-----+      +-----+
               |
            +--+----+     +--------+
            |1.2.1.1|---->|1.2.1.2 |
            +-------+     +--------+

버전 트리를 보니까 대충 이해가 되시죠. 그런데 또 한가지 문제가 있습니다. 뭐냐 하면 1.2.1.1 을 고쳐서 ci시키면 에러가 난다는 것입니다. 원래는 1.2.1.2 가 되어야 하는데 말입니다. 즉 아래와 같이
%ci -l exam.c
RCS/exam.c,v <- exam.c
ci error: multiple revisions locked by raxis; please specify one

이게 무슨 날벼락 같은 소리. lock이 여러개가 걸려있다니요. lock을 잘은 모르지만 하나밖에 걸지 않은 것 같은데 말입니다. 그럼 RCS/exam.c,v의 내용(윗부분)만 잠시 보기로 할까요. 문제의 답이 있기 때문이죠.

`RCS/exam.c,v `
head 2.0;
access;
symbols;
locks
raxis:1.2.1.1
raxis:1.2
raxis:2.0; strict;
comment @ * @;

위에 보면 locks 라는 곳이 보이십니까? 흠... 알게 모르게 lock이 3군데나 걸려 있군요. 위에서 strict라고 쓰여진 부분은 저도 아직 잘은 모르지만 짐작컨대 아마도 버전 트리가 형성될 가망성이 있는 부분을 가리키고 있는 것 같습니다. 제가 여러 가지 테스트를 거쳐서 얻은 결론은 strict가 있는 버전을 중심으로 버전 트리가 형성된다는 것입니다. 1.2 에 만약 strict가 있다면 이것은 1.2.2 (두번째 branch)가 형성될 수 있다는 말이 됩니다.

그럼 strict 라는 것이 1.2.1.1에 오게 하면 되겠군요. 맞습니다. 결론은 2.0과 1.2의 lock를 해제해야 한다는 말이 되는군요. 강좌1에서 rcs란 명령어는 RCS파일의 속성을 바꾼다고 했습니다. rcs의 옵션중에 보면 -u가 있습니다. unlock 이란 뜻이 됩니다.
% rcs -u2.0 exam.c
RCS file: RCS/exam.c,v
2.0 unlocked
done

% rcs -u1.2 exam.c
RCS file: RCS/exam.c,v
1.2 unlocked
done

이제는 strict 가 1.2.1.1 에 있는 것을 보게 되실 겁니다. locks라고 불린 곳에는 strict가 있는 버전 하나만 존재해야 합니다. 나머지는 모두 unlock 시켜서 없애야 되겠군요. 이제부터는 1.2.1로부터 버전 트리가 형성됩니다. 만약 버전 2.0에서 버전 트리를 형성하고 싶으시다면 아래와 같이 하세요.
% rcs -u1.2.1 exam.c
% rcs -l2.0 exam.c

참고

사실 버전 트리 부분은 초보자가 보기엔 참 애매모호한 부분입니다. 또 lock이라는 개념 자체도 어렵죠. 죄송합니다. 더 이상 설명을 쉽게 할 수가 없네요. 그러나 버전업이 될 때 버전 트리가 형성된다는 것은 기억하고 계세요. 모든 것을 버전 트리로 이해하면 위의 것도 대충 이해가 될 겁니다.

5.2. Auto Identification 기능

이제 좀 화제를 다른 데로 돌리기로 하죠. 보통 제품을 생산을 한다면 그 제품에는 생산 날짜, 생산지 등등의 정보가 찍혀지게 되죠. RCS에서는 이와 유사한 것을 지원합니다. 즉, 소스와 목적 코드(object code)에 자신의 프로그램임을 확신시켜 주는 특별한 문자열을 삽입하게 되죠.

소스에 아래와 같은 라인을 추가해 봅시다.
static char rcsid[] = '$Id: RcsTutorial,v 1.1 2005/02/23 01:46:02 kss Exp kss $' ;

그럼 RCS의 ci 명령어 이후에는 다음과 같은 형태로 바뀌어져 있습니다.
static char rcsid[] = '$Id: exam.c,v 1.1
1995/10/13 14:54:09
raxis Exp raxis (줄이 길어서 분리)

생성날짜, 시간, 만든이 등등의 정보가 나와 있군요. 프로그램 내부에서 static 변수이므로 당연히 프로그램 컴파일과 함께 프로그램에 영원히(?) 내장이 되겠지요. 누가 자기꺼 훔쳐 가도 금방 알 수가 있겠죠.

우리가 지금까지 아무 생각 없이 써 온 $Log: RcsTutorial,v $ 우리가 지금까지 아무 생각 없이 써 온 Revision 1.1 2005/02/23 01:46:02 kss 우리가 지금까지 아무 생각 없이 써 온 203.237.51.80;;윤현호;; 우리가 지금까지 아무 생각 없이 써 온 라는 것도 자동 인식표의 하나입니다. 예제에서 보다시피 각 버전에 대한 모든 정보가 소스 파일에 표시가 되게 되죠. 대신 이것은 코멘트(comment)안에 있으므로 컴파일할때 없는 거나 마찬가지겠죠. Id와의 차이점입니다.

5.3. rlog, rcsdiff 명렁어

rlog는 log메시지를 출력하는 것입니다. 그리고 rcsdiff 는 RCS 파일에서 각 버전간의 차이를 diff 유틸리티의 출력 결과와 같은 형태로 출력합니다.
% rlog exam.c
(exam.c의 log 메시지를 출력한다.)

% rcsdiff -r1.2 -r2.0 exam.c
(exam.c에서 1.2 버전과 2.0 버전을 비교한다.)

두 명령어 모두 필요해서 있겠지만 제 생각으로는 별로 쓸 필요는 없는 것 같습니다. 우선 모든 메시지가 소스 파일에 있으니까 rlog가 필요없구요, rcsdiff에 의한 출력 결과는 보통시람이 보기엔 참 어지럽기 때문에 또 필요가 없구... 결론은 ci, co, rcs만 잘 알고 있음 된다는 소리지요.

5.4. GNU make와의 연결

GNU make와 RCS는 찰떡궁합이라고 할만큼 서로 인식을 잘합니다. 즉 make가 Makefile의 내부에서 의존성(dependency - 이것이 몬지 아실런지. Make 강좌에서 자세하게 하죠.)을 조사하다가 파일이 발견되지 않으면 자동적으로 RCS 디렉토리를 뒤져서 co 명령어를 알아서 수행시킨다. 따라서 가장 최신 버전의 파일들이 자동적으로 컴파일되는 이점을 누릴 수가 있다. RCS에서 읽혀진 파일들은 컴파일이 성공하면 자동적으로 삭제가 되므로 디스크 공간도 아낄 수가 있다.

여기서 한가지 더. Makefile 자체도 RCS 파일로 만들어 질 수 있다는 것. 즉, make 명령어를 수행시켰는데 Makefile이 발견되지 않을 때 RCS에서 Makefile,v를 찾아서 자동적으로 Makefile 을 푼다는 것. (상당히 똑똑하지요.)

6. 언제 RCS를 사용해야 할까요?

6.1. RCS로 인한 파멸(?)

RCS를 사용함으로써 생길 수 있는 문제점이 무엇인지 알아봅시다.
  • 프로그램을 잔뜩 고쳐서 ci를 하려고 했는데 잘못해서 co를 했더니 파일을 덮어 썼다. 그래서 고친게 말짱 도루묵이 되어 버렸다.
  • branch 가 많아짐으로 인해 구조가 복잡해 졌다. 차라리 옛날처럼 temp1, temp2 하던 때가 더 편했다.
  • 언제 ci를 하는지 모르겠다. 함수 몇 개 추가할 때마다 ci를 수행했더니 나중에 메시지 부분이 너무 많아서 눈에 거슬렸다. 그래서 메시지 몽땅 다 지우고 다시 버전 1.1부터 시작했다.
  • lock 이란 것 때문에 복잡해 죽겠다. 자꾸 에러를 낸다.

대충 이런 것이 있지 않을까요. 버전을 제어한다는 것이 멋있는 것이기는 하지만 잘못하면 거의 망하죠. 일의 속도만 더 느려지고. 하지만 일단 익숙해지기만 하면 RCS의 고마움을 느끼게 될 껍니다.

6.2. RCS 사용의 기본적인 지침(guideline)

그럼 RCS를 사용함에 있어 무엇인가 지침이 없을까. 잘 쓰시는 분들에겐 저의 말이 틀린 것처럼 들릴 수가 있습니다만. 그들 나름대로의 철학을 가지고 하시는 일이라서. 그럼 어떤 지침이 있는지 알아보죠.

RCS 에서 가장 중요한 것은 언제 ci, co를 하느냐 입니다. 여기에는 저의 아주 실력 좋은 선배님의 지침들을 제 나름대로 구성해서 적겠습니다.

6.2.1. ci의 시점

ci(check in)은 일반적으로 하나의 작업 단위로 이루어져야 한다. 작업 단위 라는 것이 완성이 되어야만 체크인을 하여야 한다는 것이다. 만약 작업 단위 별로 체크인을 하지 않고 무작위로 하게 되면 버전이라는 의미가 퇴색하게 되며, 자신도 헷갈릴 뿐 아니라, 이를 체크아웃 해서 사용하는 다른 공동 사용자(같이 프로그램을 개발하는 사람)에게 피해를 줄 수 있다는 것을 명시해야 한다. 여기서 작업 단위라는 것의 정의를 내려보기로 하죠.
  1. 프로그램에서 드러난 논리적/물리적 오류(버그, bug)를 수정하고 정상적인 동작을 확인한 경우가 하나의 작업 단위이다. 따라서 체크인 한다.
  2. 어떤 모듈의 인터페이스가 변경되어 이를 사용하는 다른 모듈에까지 영향을 미칠 경우에 바뀌게 되는 모든 모듈, 아님 이와 관련된 파일이 모두 하나의 작업 단위가 되게 한다. 즉, 인터페이스가 바뀐 부분을 체크인 하려면 이와 관련된 다른 곳도 적절하게 수정한 다음 체크인 하여야 한다. 그래야, 프로그램의 일관성을 유지할 수 있다.
  3. 새로운 기능을 위해서 모듈에 인터페이스를 추가할 경우에 이 모듈의 선언부와 구현부가 하나의 작업 단위가 된다. 즉 새로운 기능이 완전하게 구현되었을 때 체크인을 한다.

6.2.2. co의 시점

co(check out)은 체크인과는 달리 원하는 버전을 가져오기만 하면 되므로 원본에 피해를 주지 않으므로 체크인에 비해서는 대단한 주의는 필요하지 않다. 다만 아래와 같은 경우는 일어나지 않도록 합시다.
  1. 작업 중인 파일을 체크인 하지 않은 상태에서 이전 버전의 내용을 보기 위해 체크아웃 하는 경우가 있다. 이 경우 고친 부분이 다 날아가 버리므로 주의하자. co를 할 때는 항상 (경고)메시지에 주의를 기울여야 한다.
  2. 변경된 모든 파일을 체크아웃 하지 않고 일부만 체크아웃 해서 컴파일할 경우 비정상적인 동작을 보이게 된다. 이럴 경우 자신은 분명히 맞게 프로그램을 짰는데 프로그램의 동작이 이상하기 때문에 컴파일러를 의심하게 되는 경우가 많다. (컴파일러가 잘못할 이유가 없다는 것을 항상 명심합시다.) 논리적인 실수도 아니고, 물리적인 실수도 아니기 때문에 에러를 찾기가 힘들죠.
  3. 공동 작업자가 체크인 했다고 해서 자신이 무조건 체크아웃 해서는 안된다. 분명히 자신의 작업 진도에 맞추어 체크아웃을 해야 한다. 공동 작업자와의 충분한 대화가 필요할 것이다. rlog 나 rcsdiff를 사용해서 버전의 특징을 조사해 보는 것도 좋은 방법이다.

7. 대규모 프로젝트와 RCS

7.1. 대규모 프로젝트란

제가 대규모 프로젝트라고 했습니다. 대규모 프로젝트라니. 프로젝트란 회사에서 많이 쓰던 용어 같은데. 라고 묻는 분이 계실 겁니다. 그럼 저는 먼저 여러분이 지금까지 짜 보신 프로그램 중에 가장 긴 것이 얼마나 되느냐고 묻고 싶네요.

일반적으로 어떤 목적을 달성하기 위해서 꽤 수고를 기울여서 프로그램을 짜야 할 경우 우린 이것을 프로젝트라고 합니다. 학교에서 나온 프로그램 숙제를 프로젝트라고 할 수도 있겠군요. 그럼 대규모 프로젝트라면, 프로그램의 크기가 엄청나서 장난이 아닌 것이라고 정의하면 될까요.

보통 GCC 가 10만 라인이 넘어섭니다. 모티프 라이브러리가 약 15만 라인 인걸로 알고 있구요. 하지만 보통 수천 라인 정도의 프로그램이라면 어느 정도 대규모라고 말할 수가 있습니다. 대규모 프로젝트의 몇 가지 특징을 간단하게 열거해 보겠습니다.
  1. 우선 라인 수가 엄청나다.
  2. 혼자 짜기엔 너무 힘들다. 따라서, 2명 이상의 팀의 단위로 작성된다.
  3. 기간이 오래 걸린다. 며칠? 몇 주일? 몇 달? 몇 년? (프로그램 개발에서 기간은 곧 '돈'을 의미합니다.)

혼자 프로그램 짜는데 익숙하신 분들이 힘드신 점이 바로 다른 사람과 같이 프로그램을 짜야 한다는 것입니다. 그리고 프로그램 개발의 효율성에 따라서 기간에 엄청난 차이를 줄 수가 있습니다. 이런 의미에서 RCS는 개발 주기를 앞당길 수 있다는 의미에서 꽤 중요한 것 같습니다.

7.2. RCS 디렉토리를 공유하자

가령 두사람이 같이 프로그램을 짠다고 가정합시다. 프로그램을 칼로 무우 자르듯 잘라서 A가 어느 부분을 짜고, B가 다른 부분을 짜는 일의 분담이 이루어 졌습니다. 당연히 그리고 서로가 다른 사람이 짠 함수나 데이터를 써야 하는 것은 당연한 일이지요. 여기서 문제가 발생합니다. 만약 한 디렉토리에서 파일을 공유한다고 가정한다면 A가 바꾼 파일을 또 B가 필요에 의해 고치고, 또 A가 고치고.. 이런 과정을 반복하다 보면 서로 헷갈리게 되죠.

이때는 RCS 디렉토리만 공유하게 되면 모든 문제는 해결됩니다. 한 사람의 디렉토리에 RCS를 만들어 놓고 다른 사람은 그곳을 링크 시킵니다. 그러면 두사람은 하나의 RCS 디렉토리를 공유하게 되는 것이죠. 당연히 쓰기가 가능하도록 permission을 열어야 겠죠. 두 사람은 미리 합의된 대로 자신의 모듈을 작성한 다음 어느 정도 기능의 수행이 가능하게 되면 RCS 디렉토리에 올리게 됩니다. 그리고 다른 사람이 필요에 의해 RCS 에 있는 파일을 co를 써서 풀게 되구요.
    +--------------+
    |    R C S     |
    +--+--------+--+
       |        |
+------+-+    +-+------+
|   A    |    |   B    |
+--------+    +--------+ 

그림으로 설명하면 위와 같습니다. 이렇게 되면 서로 파일을 공유함으로써 생기는 문제는 사라지게 되고, 파일을 만든 사람만이 lock 을 걸 수가 있기 때문에 RCS 디렉토리에 있는 원본은 아주 안전하게 보호되죠. 그리고 푸는 사람도 자신이 필요한 버전만 풀 수가 있으므로 매번 다른 사람한테 이것좀 고쳐 달라, 이건 왜 안되느냐 하면서 서로 싸울 필요가 없겠죠. 이것은 RCS 디렉토리에 각 버전별로 제대로 동작하는 프로그램이 올라와 있다고 가정할 때 가능합니다. 또 두 사람 사이의 개발 속도가 달라도 되겠죠. A가 아주 실력이 좋아서 빨리 짜더라도, B는 우선 자신의 프로그램과 궁합이 맞는 A의 옛날 버전을 갖다가 쓰면 되거든요.

흠. 어떠세요. 그럴듯하지 않아요? 여기서 A 와 B가 동일 인물이 되어도 됩니다. 왜냐하면 같은 사람이 여러 군데에서 일을 할 수도 있으니까요. 위와 같은 룰만 제대로 지킨다면 프로그램 개발 중에 서로 안 싸워서 좋고, 서로 자신의 프로그램을 시험해 볼 수 있어서 좋고. 아무튼 다 좋아요.

8. 마치면서

제가 나름대로 정해 본 첫 번째 강의가 여기서 끝이 났군요. 너무 많이 가르쳐 드리려고 하다 보니까 내용이 난해하기도 하고 문장이 엉성한 부분도 많을 것입니다. 제 강의의 목적은 다양한 리눅스 사용자들에게 리눅스로 무엇을 할 수 있는지에 대한 물음에 대한 답이라고 할 수가 있습니다. 리눅스에서 할 수 있는 프로그램은 원하신다면 제가 책임지고 강의를 해드릴수가 있습니다. 대신 너무 하드웨어적인 문제는 제 컴퓨터가 고물이라서(486DX 33Mhz) 보장을 할 수가 없습니다.

여기까지 읽어 주신 분들에게 감사드리면서 한가지 부탁 말씀 드립니다. 제 판단 기준에 의해 강의 소재를 택하다 보면 너무 여러분의 관심과 동떨어 질 수 있다는 것입니다. 제 딴에는 여러 가지 흥미로운 소재를 다루고 싶습니다만, 여러분의 도움이 필요합니다.

여러분의 요청이 있으시다면 RCS 명령어들을 정리해서 간단하게 요약해서 올리겠습니다.





sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2005-02-23 10:46:02
Processing time 0.0147 sec