CVS사용법

last updated 2002-03-14 by 박주형
$Revision: 1.3 $


1. 관련 사이트




2. 관련 문서

한글 문서

영문 문서




3. CVS서버 설치하기

3-1. 리눅스에 설치하기 - cvspserver 를 통해 서비스하기

3-2. NT에 설치하기




4. 저장소 ( Repositery)

CVS의 저장소는 버전관리하는 모든 파일과 디렉토리들의 완벽한 복사본을 저장한다.

보통 저장소안에 있는 파일을 직접 조작하지 않는다. 그대신 CVS명령어를 이용해 작업디렉터리에 카피본을 만들고, 그 카피본으로 작업을 하게된다. 수정이 되면 그것을 저장소로 반영시켜 넣는다. 그러면 저장소는 수정된 내용을 포함할 뿐 아니라, 무엇을 수정했는지에 관한 정확한 기록도 포함한다. 저장소가 작업디렉터리의 서브디렉터리가 아니라는 것에 주의해라. 저장소와 작업디렉터리는 다른 위치에 존재해야 한다.

CVS는 저장소를 다양한 방법으로 접근할 수 있다. 저장소는 로컬컴퓨터일수도 있고, 아니면 방건너에 있거나 다른 나라에 있을수도 있다. 저장소를 접근하는 다양한 방법을 구분하기위하여, 저장소이름은 접근방으로 시작한다. 예를들면 :local:란 것은 저장소 디렉터리를 의미하는 접근방법이다. 따라서 :local:/usr/local/cvsroot는 저장소가 같은 컴퓨터의 `/usr/local/cvs'에 있다는 것을 의미한다. 다른 접근방법에 관해서는 아래에서 설명한다.

저장소는 두분으로 나뉘어진다. `$CVSROOT/CVSROOT' 는 CVS의 관리파일을 담고있다. 다른 디렉터리는 사용자가 정의한 모듈들을 담고 있다. (*주: 모듈은 프로젝트라고 해석하면 된다. 즉 파일의 집합체이다.)

4-1. CVS에 저장소가 어디있는지 알리기

CVS에게 저장소가 어디있는지 알리는 몇가지 방법이 있다. 쉘명령어에서 -d (directory란 의미) 옵션으로 지정할수 있다.


cvs -d /usr/local/cvsroot checkout yoyodyne/tc
그렇지 않으면 환경변수 $CVSROOT에 저장소의 절대위치를 지정할 수 있다. csh이나 tcsh인경우:

setenv CVSROOT /usr/local/cvsroot
sh이나 bash인 경우

CVSROOT=/usr/local/cvsroot
export CVSROOT
옵션 -d가 환경변수 $CVSROOT 보다 우선시된다.




5. 로그인 하기

5-1. 로그인 하기

CVS서버가 설치된후 서버를 이용하려면 일단 로그인이 되어야 한다. 즉 다음장부터 나오는 작업을 하려면 먼저 로그인이 선행되어야 한다. 최초로 로그인이 성공하면 아이디와 패스워드가 저장되므로 두번다시는 암호와 패스워드를 입력하지 않다도 된다.


$ cvs -d :pserver:userid@cvs.hostname.com:/opt/cvsroot login 
          ^^^^^^^ ^^^^^  ^^^^^^^^^^^^^^^  ^^^^^^^^^^^^ ^^^^^
         프로토콜   |    서버주소 혹은IP     |          로그인명령
                    |                        |
                 사용아이디              저장소 디렉터리

중간의 -d옵션은 환경변수로 설정하면 생략가능하다.


$ CVSROOT=:pserver:userid@cvs.hostname.com:/opt/cvsroot
$ export CVSROOT

$ cvs login

로그인이 성공하면 `$HOME/.cvspass' 에 저장되어 다음부터 로그인 절차를 무시해도 된다

5-2. 유닉스 계정유저 - CVS만을 위한 유저

CVS에 사용되는 아이디는 두가지가 있다. 

첫번째 방법은 유닉스의 어카운트를 그대로 cvs에사 사용하는 방법이다. 유닉스에 TELNET으로 들어갈 수있는 아이디가 있다면 CVS에서도 그대로 사용할 수 가 있다. 이 경우 사용자는 CVSROOT디렉토리에 사용권한을 가지고 있어야 한다. 

두번째 방법은 CVS전용의 사용자를 만드는 방법이다. 이 방법은 시스템의 다른 부분의 보안에 영향을 주지 않기때문에 보다 안전하다. 그러나 유저의 생성과 삭제를 해주는 툴이 아직 만들어지지 않아서 번거롭다.




6. 저장소에 프로젝트 등록하기

저장소를 등록하려면 작업디렉토리가 있어야 하고, 저장소의 어느위치에 넣을지를 정해야 한다.


$ cd wdir
$ cvs import -m "Imported source" yoyodyne/rdir yoyo start
      ^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^ ^^^^^
      명령어   로그 옵션           프로젝트의
                                    저장소 위치
wdir CVS에 등록하려고 하는 파일들이 들어있는 폴더
-m "Imported source" -m 옵션을 주지 않으면 CVS가 프롬프트로 물어보게 된다.
yoyoydne/rdir 저장소에서 위치가 $CVSROOT/yoyoydne/rdir 로 설정된다.
yoyo vendor 태그 - 판매구분
start 릴리즈 태그

이렇게 하면 wdir의 내용이 $CVSROOT/yoyodyne/rdir 의 위치에서 관리된다. 

이 작업이 완료되면 저장소의 내용과 원본과 같은지 확인을 하고, 원본 디렉토리를 지워야 한다.

$ cd ..
$ cvs checkout yoyoydne/rdir
$ diff -r wdir yoyoydne/rdir
$ rm -r wdir
처음 import한 직후는 checkout한 상태가 아니다. VSS와는 달리 별도로 checkout을 해야 작업디렉토리안의 파일과 저장소의 파일이 연관성을 갖는다. 원본(wdir)안의 내용은 백업한 후 지우는 것이 좋다. 같은 내용이 두곳에 존재하면 작업에 혼돈을 줄 수 있다. 이후부터 yoyodyne/rdir 에서 작업하고 저장소로 업데이트 하게된다.

checkout하는 과정은 작업파일과 저장소파일이 연관성을 만들어준다. 연관관계가 생긴 파일은 같은 디렉터리에 CVS란 디렉터리가 생성된다. 이 디랙터리안에 저장소와 연관되는 정보가 들어있다. 연관성을 없애려면 release 명령어를 이용한다.


$ cvs release -d yoyoydne/rdir
release명령은 디렉터리와 저장소간의 연관관계를 없애준다. -d 옵션은 추가로 작업디렉토리도 지우라는 의미이다.




7. CVS를 이용해 버전 관리

7-1. 저장소에서 파일 받아오기

이미 저장소에 프로젝트가 등록되었다면 CVS를 통해서 파일들을 받아올 수 있다. 방법은 6장에서 나와있는 방법과 동일하다.


$ cvs checkout yoyodyne/rdir
이렇게 하면 현재의 디렉터리에 yoyodyne/rdir 이란 디렉터리가 생성되고 저장소로부터 파일들이 다운로드 된다.

checkout은 위와같이 디렉터리단위로 할 수도 있지만, 파일단위로도 가능하다.


$ cvs checkout yoyodyne/rdir/somefile.txt

7-2. 수정된 파일을 저장소로 보내기

commit 명령어를 사용하면 된다. 디렉터리를 통체로 업데이트하려면


$ cvs commit yoyodyne/rdir
이렇게 하면, 지정한 디렉터리안의 수정된 파일들만 버전업되고 나머지파일은 업데이트 되지 않고 버전 번호를 그대로 유진한다.

$ cvs commit yoyodyne/rdir/somefile.txt
이렇게 하면 파일 하나만 업데이트 할 수 있다.

7-3. 구 리비젼으로 되돌리기

7-4. 저장소에서 파일 지우기




8. 리비젼 ( Revision )

많은 CVS사용에관해서 리비젼 번호를 너무 걱정할 필요가 없다; CVS가 1.1, 1.2 등등 으로 번호를 부여하고, 그것이 알아야할 모든 것이다. 어쨋거나, 어떤 사람들은 CVS가 리비젼번호를 어떻게 부과하는지에 관한 지식과 제어를 좀더 알고싶어한다.

하나이상의 파일을 포함한 리비젼들을 추적하고 싶다면, 태그(tag)를 사용하라. 태그는 각 파일의 숫자 리비젼을 부과하는 심볼 리비젼이다.<※주: 복잡한 말인데 뒤를 읽어보면 더 자세히 설명이 나온다>

8-1. 리비젼 번호

각각의 버전의 파일은 1.1, 1.2, 1.3.2.2, 혹은 1.3.2.2.4.5와 같이 고유한 리비전번호(revision number)를 갖는다. 리비전번호는 항상 마침표로 구분된 짝수의 숫자로 이루어져 있다. 1.1이 기본 값으로 파일의 첫번째 리비젼 값이 된다. 각각의 연속된 리비젼은 가장 오른쪽 숫자를 하나 증가해서 새로운 값으로 부여된다. 다음의 그림은 오른쪽이 최신 리비젼인 그림이다.

       +-----+    +-----+    +-----+    +-----+    +-----+
       ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
       +-----+    +-----+    +-----+    +-----+    +-----+
1.3.2.2 와 같이 하나이상의 마침표를 포함하는 숫자일 수 있다. 이러한 리비젼은 가지(branch)의 리비젼을 표현한다.

8-2. 버젼(Versions), 리비젼(Revisions), 배포(Releases)

위에서 설명한대로 파일은 여러개의 버전을 가질 수 있다. 게다가 소프트웨어 제품도 종종 4.1.1과 같은 버전번호가 부과된다.

첫번째 예에서 버전은 이 문서에서 리비젼이라고 불리우고, 또 다른 예에서는 배포(release)라고 불리운다. 혼동을 피하기위해서 이 문서에서 버젼이란 말은 사용하지 않는다.

8-2. 리비젼 부과

지정하지 않으면 CVS는 첫번째 숫자는 바꾸지 않고, 두번째 숫자를 증가하는 숫자 리비젼을 부여할 것이다. 예를 들면 1.1, 1.2, 1.3 등등

새로운 파일을 추가할 때, 두번째 숫자는 언제나 1이고 첫번째 숫자는 그 디렉토리에 있는 파일중 가장 높은 첫번째 숫자와 같을 것이다. 예를 들면, 현재의 디렉터리중에 있는 파일중 가장높은 리비젼이 1.7, 3.1, 4.12 라면 추가되는 파일은 4.1 란 리비젼을 가질 것이다.

보통은 리비젼번호에 관심을 가질 이유가 없다. 리비젼들을 CVS가 관리하는 내부적인 것으로 여기는 것이 편하고, 태그(tag)가 배포판1로부터 배포판2와 같은 것들을 구분하는데 더 좋은 방법을 제공한다. 어쨋든, 리비젼번호를 설정하고 싶으면 cvs commit할 때 `-r'옵션을 부과하면 된다. -r 옵션은 -f옵션을 포함하는 것으로 여겨진다. 즉 파일이 수정되지 않았더라도 강제적으로 커밋시켜버린다.

예를 들면, 모든 파일들을 리비젼3.0으로 올리기 위해서는 다음을 호출하면 된다.


$cvs commit -r 3.0
주의할 것은 -r옵션으로 자정하는 숫자가 반드시 존재하는 리비젼보다 커야한다는 점이다. 만약 3.0리비젼이 존재한다면 `cvs commit -r 1.3아로 할 수 없다. 만약 여러개의 배포판을 동시에 관리하길 원한다면 가지치기(branch)를 사용하라.

8-3. 태그 (tag)

리비젼 번호는 독립적으로 진핸된다. 리비젼 번호는 소프트웨어 제품의 배포번호와는 아무런 연관성을 가질 필요가 없다. CVS를 어떻게 사용할지에 따라서 리비젼번호는 두 배포판간에 여러번 바뀔 수 있다. 예를 들면, RCS 5.6으로 작성된 몇몇 소스파일들이 다음과 같은 리비젼 번호를 갖는다고 하자.


ci.c            5.21
co.c            5.9
ident.c         5.3
rcs.c           5.12
rcsbase.h       5.11
rcsdiff.c       5.10
rcsedit.c       5.11
rcsfcmp.c       5.9
rcsgen.c        5.10
rcslex.c        5.11
rcsmap.c        5.2
rcsutil.c       5.10
tag명령어를 이용해서 심볼 이름을 어떤 파일의 리비젼번호에 줄 수 있다. status명령어에 -v옵션을 줘서 파일이 가지고 있는 모든 태그들을 볼 수 있다. 태그명은 반드시 알파벳 대소문자로 시작해야 해야하고, 알파벳 대소문자, 숫자, '-', '_'로 이루어져있다. 두 태그명 BASE와 HEAD는 CVS가 특별한 용도로 정의되어있어서 사용할 수 없다. CVS에서 특별한 용도로 사용될 이름들은 실제의 태그명들과 충돌을 피하기위해서 이름붙여질 것이다.

프로그램의 이름과 배포판의 버젼번호같은 정보를 기본으로 한 규칙에 의해서 태그의 이름을 붙이지를 원할것이다. 예를 들면 프로그램의 이름을 사용하고 뒤에 버전번호를 `.'를 `-'로 바꿔서 붙이면 CVS 1.9는 cvs1-9 라고 태그를 붙일 수 있다. 모순없는 규칙을 정한다면 태그가 cvs-1-9인지 cvs1-9인지 빈번히 추측하지 않을 것이다. 또한 태그정보파일(taginfo file)안의 고딩규칙을 강제화하는 것을 고려할수도 있다.

다음 예는 파일에 태그를 어떻게 붙이는지 보여준다. 명령어는 반드시 작업디렉터리안에서 실행되어야 한다. 다시말하면 `backend.c' 파일이 있는 디렉터리에서 명령을 실행시켜야 한다는 것을 의미한다.


$ cvs tag rel-0-4 backend.c
T backend.c
$ cvs status -v backend.c
===================================================================
File: backend.c         Status: Up-to-date

    Version:            1.4     Tue Dec  1 14:39:01 1992
    RCS Version:        1.4     /u/cvsroot/yoyodyne/tc/backend.c,v
    Sticky Tag:         (none)
    Sticky Date:        (none)
    Sticky Options:     (none)

    Existing Tags:
        rel-0-4                     (revision: 1.4)
(디렉터리를 CVS에게 인수로 준다면, 해당하는 처리를 디렉터리안의 모든 파일과 그 서브디렉터리안의 파일에까지 재귀적으로 적용한다는 것을 의미한다.

checkout명령어는 `-r'명령을 가지고 있는데, 이 옵션은 모듈의 임의의 리비젼을 채크아웃하게 해준다. 이 옵션은 차후에 `tc'란 모듈의 1.0배포판이라고 붙여진 소스들을 얻어오는 것을 수월하게 해준다.


$ cvs checkout -t rel-1-0 tc
이것은 아주 유용하다. 예를 들면, 누군가 그 배포판에 버그가 있다고 요청하고 현재의 작업카피에서는 버그를 찾을수 없다.

주어진 날자의 상태대로 모듈을 채크아웃할 수 있다. `-r'옵션을 이런 명령어에 준다면, 접착성 태그에 관해서 고려할 필요를 느낄것이다. (?)

한개이상의 파일에 동일한 태그를 붙였다면 태그를 "파일명 리비젼번호로 구성된 행열에 그은 곡선"으로 생각될수 있다. 다음과 같은 리비젼을 가진 5개의 파일이 있다고 하자. (*주: 아래그림에서는 곡선으로 안보이지만 곡선으로 생각하자)


          file1   file2   file3   file4   file5

        1.1     1.1     1.1     1.1  /--1.1*      <-*-  TAG
        1.2*-   1.2     1.2    -1.2*-
        1.3  \- 1.3*-   1.3   / 1.3
        1.4          \  1.4  /  1.4
                      \-1.5*-   1.5
                        1.6
과거의 어떤 시점에 *버전에 태그가 붙여졌다. 태그를 태그붙여진 리비젼들을 잇는 곡선의 손잡이라고 여길 수 있다. 이 손잡이를 잡아당기면 모든 태그붙여진 리비젼들을 얻을 수 있다. 이것을 보는 다른 방법은 다음과 같이 태그가 붙여지 리비젼들을 평평하게 놓고 보는 것이다.

          file1   file2   file3   file4   file5

                        1.1
                        1.2
                1.1     1.3                       _
        1.1     1.2     1.4     1.1              /
        1.2*----1.3*----1.5*----1.2*----1.1     (--- <--- Look here
        1.3             1.6     1.3              \_
        1.4                     1.4
                                1.5

8-4. 접착성 태그 (Sticky Tags)

때때로 작업중인 카피본의 리비젼은 리비젼과 관련된 테이터를 가지고 있다. 예를 들면 리비젼은 가지(branch)이거나, `checkout -D'`update -D'에의해서 어떤 날자에 우선해 버젼으로 제한될 수 있다. (뭔말이여?) 왜냐하면, 이 날자는 접착된것(Sticky)으로 여겨진다.

대부분의 경우에, 접착성(stickiness)은 생각할 필요가 없는 CVS의 불투명한 면이다. 어쨋거나, 이 기능을 사용하지 않았으면 하더라도 접착성 태그(sticky tahg)에 관해서 좀 알필요가 있다. (예를 들면 어떻게 이것을 안쓰는지에 관해서)

어떤 접착성 태그들이나 날자가 설정되었는지 보기위해서 status 명령어를 쓸 수 있다.


$ cvs status driver.c
===================================================================
File: driver.c          Status: Up-to-date

    Version:            1.7.2.1 Sat Dec  5 19:35:03 1992
    RCS Version:        1.7.2.1 /u/cvsroot/yoyodyne/tc/driver.c,v
    Sticky Tag:         rel-1-0-patches (branch: 1.7.2)
    Sticky Date:        (none)
    Sticky Options:     (none)


이 접착성 태그들은 `cvs update -A'명령어로 지울때까지 당신의 작업파일들에만 남아있다. `-A'옵션은 본체의 해더로부터 파일의 버젼을 받아오고, 다른 접착성태그들과 날자들과 다른 옵션들은 무시한다.

가장 일반적인 접착성태그의 사용은 어떤 가지(branch)가 작업진행중인지를 구분하는 것이다. 어쨋건, 가지쳐지지 않은 접착성태그들도 또한 사용법을 가지고 있다. 예를 들면, 다른 사람들이 만드는 불안정한 수정내용들로부터 현재 작업중인 디렉터리가 업데이트되는 것을 막고싶다고 가정하자. 물론 `cvs update'를 실행하는 것을 자제할수 있다. 그러나 거대한 트리의 일부분만을 업데이트하는 것을 막고싶다면 접착성 테그가 그것을 도와줄 수 있다. 만약 어떤 리비젼으로 채크아웃한다면 (예를 들어 리비젼 1.4) 이 리비젼은 접착성 태그가 된다. 그 뒤에 이어서cvs update명령어는 당신이 cvs update -A명령어를 해서 리셋하기전까지는 최신 리비젼을 받아오지 않을것이다. 마찬가지로, updatecheckout명령에 `-D'옵션의 사용은 적착성 날자(sticky date) 를 설정한다. 이 방법은 나중에 파일을 받아올때 그 날자가 사용되게 해준다.

사람들은 보통 접착성태그의 사용없이 구버전의 파일을 받아오길 원한다. 이것은 checkout나 update 에 `-p'옵션을 줘서 할 수 있다. 예를 들어서


$ cvs update -p -r 1.1 file1 >file1
===================================================================
Checking out file1
RCS:  /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v
VERS: 1.1
***************
$

어쨌든, 이미 채크인한 것을 되돌릴때 이것이 가장 간단한 방법이다.




9. 가지나누기와 병합 ( Branching and merging )

CVS에서는 가지나누기(branch)라고 알려진 방법을 통해서 독립된 개발선상에서 작업할수 있다. 가지에 있는 파일을 바꿔도 본작업이나 다른 가지의 작업에는 영향을 주지 않는다.

후에 당신은 병합(merging)을 통해서 한쪽 가지에 한 수정을 다른쪽 가지로 옮길 수 있다. 병합은 수정내용을 작업디텍터리에 넣는 `cvs update -j' 를 포함한다. 그런후 그 리비젼을 거밋할 수 있고, 그렇게 해서 작업을 다른 가지에 수정내용을 효과적으로 옮길 수 있다.

9-1. 가지나누기의 잇점

tc란 모듈의 릴리즈 1.0이 만들어졌다고 가정하자. 당신은 tc를 계속 개발하면서 릴리즈 1.1을 두달동안 만들기로 계획을 세웠다. 그러는 중에 고객이 치명적인 버그에 대해서 불평을 하기 시작하였다. 당신은 릴리즈1.0을 채크아웃하고 버그를 찾는다. 어쨋거나 소스의 현재 리비젼은 고쳐지고 있는 상태이고 적어도 한달쯤 지나야 안정화될 것이다. 새로운 소스를 기반으로 버그를 고칠수 있는 방법이 없다.

이런 경우에 하는 것이 리비젼 트리에 가지를 생성하는 것이다. (이 가지에는 모든 파일이 tc의 릴리즈1.0이라고 적혀있다.) 당신은 본체에 방해를 주지않고 수정을 만들 수 있다. 수정이 끝났을 때 수정내용을 본체에 혼합하던가 가지에 그대로 남겨두던가 결정할 수 있다.

9-2. 가지 생성하기

현재 디렉터리가 작업폴더라고 가정하면 tag -b로 가지를 생성할 수 있다.


$ cvs tag -b rel-1-0-patches
이것은 `rel-1-0-patches'란 이름을 부여함으로서 작업본에 있는 현재 리비젼들을 기반으로 가지를 분리한다. 가지가 작업본에 생성되는 것이 아니라 저장소에 생성된다는 것을 이해하는 것이 중요하다. 예와 같이 현재의 리비젼을 기반으로 가지를 생성하는 것은 작업본을 새로운가지로 자동으로 전환하지 않는다.

또한 rtag를 통해 어떠한 작업본의 참조 없이도 가지를 만들 수 있다.


$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
`-r rel-1-0'는 이 가지가, 태그`rel-l-0'에 해당하는 리비젼의 루트가되어야한다는 것을 나타낸다. `rel-1-0'가 가장 최신의 리비젼일 필요는 없다. -- 종종 과거리비젼에서 가지치는 거이 유용하다. (예를들어, 과거 릴리즈에서 버그를 잡는 것이 안정하다고 알려져있다.)

`tag'를 사용하면서 `-b'옵션은 rtag가 (단지 심볼릭 리비젼 명을 만드는 것이 아니라) 가지를 만든다는 것을 나타낸다. `rel-1-0'와 일치하는 파일들의 숫자 리비젼은 파일마다 틀릴것이다.

그렇다면 이 명령어의 전체 결과는 모듈 `tc'안에 (`rel-1-0-patches'라고 이름 붙여진) 새로운 가지를 생성하는 것인데, 이 가지는 `rel-1-0'라고 지정된 리비젼트리의 루트이다. --

9-3. 가지 제어하기


$ cvs status -v driver.c backend.c
===================================================================
File: driver.c          Status: Up-to-date

    Version:            1.7     Sat Dec  5 18:25:54 1992
    RCS Version:        1.7     /u/cvsroot/yoyodyne/tc/driver.c,v
    Sticky Tag:         rel-1-0-patches (branch: 1.7.2)
    Sticky Date:        (none)
    Sticky Options:     (none)

    Existing Tags:
        rel-1-0-patches             (branch: 1.7.2)
        rel-1-0                     (revision: 1.7)

===================================================================
File: backend.c         Status: Up-to-date

    Version:            1.4     Tue Dec  1 14:39:01 1992
    RCS Version:        1.4     /u/cvsroot/yoyodyne/tc/backend.c,v
    Sticky Tag:         rel-1-0-patches (branch: 1.4.2)
    Sticky Date:        (none)
    Sticky Options:     (none)

    Existing Tags:
        rel-1-0-patches             (branch: 1.4.2)
        rel-1-0                     (revision: 1.4)
        rel-0-4                     (revision: 1.4)

9-4. 가지와 리비젼


       +-----+    +-----+    +-----+    +-----+    +-----+
       ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
       +-----+    +-----+    +-----+    +-----+    +-----+



                                                      +-------------+
                           Branch 1.2.2.3.2 ->        ! 1.2.2.3.2.1 !
                                                    / +-------------+
                                                   /
                                                  /
                 +---------+    +---------+    +---------+
Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
               / +---------+    +---------+    +---------+
              /
             /
+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !  <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !
                !
                !   +---------+    +---------+    +---------+
Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
                    +---------+    +---------+    +---------+
 

9-5. 마법 가지 번호 (Magic branch numbers)


$ cvs admin -NR4patches:1.4.2 numbers.c

9-6. 가지 전체를 병합하기


+-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !      <- The main trunk
+-----+    +-----+    +-----+    +-----+
                !
                !
                !   +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                    +---------+    +---------+

$ cvs checkout mod               # Retrieve the latest revision, 1.4

$ cvs update -j R1fix m.c        # Merge all changes made on the branch,
                                 # i.e. the changes between revision 1.2
                                 # and 1.2.2.2, into your working copy
                                 # of the file.

$ cvs commit -m "Included R1fix" # Create revision 1.5.

$ cvs checkout -j R1fix mod
$ cvs commit -m "Included R1fix"

9-7. 하나의 가지에서 여러번 병합하기


9-8. 두 리비젼간의 다른점 병합하기 (Merging difference between any two revisions) --> ?


+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !                           *
                !                          *
                !   +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                    +---------+    +---------+
 

+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !                           *
                !                          *
                !   +---------+    +---------+    +---------+
Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
                    +---------+    +---------+    +---------+


cvs update -j 1.2.2.2 -j R1fix m.c    # Merge changes from 1.2.2.2 to the
                                      # head of the R1fix branch

cvs update -j R1fix:yesterday -j R1fix m.c

cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c

9-9. 병합은 파일을 추가하거나 삭제할 수 있다.


$ cvs update -j 1.5 -j 1.3 backend.c

$ cvs update -j 1.2 -j 1.1 file1
U file1
$ cvs commit -m test
Checking in file1;
/tmp/cvs-sanity/cvsroot/first-dir/file1,v  <--  file1
new revision: 1.3; previous revision: 1.2
done
$

9-10. 병합과 키워드


touch a b c
cvs add a b c ; cvs ci -m "added" a b c
cvs tag -b branchtag
cvs update -r branchtag
touch d ; cvs add d
rm a ; cvs rm a
cvs ci -m "added d, removed a"
cvs update -A
cvs update -jbranchtag
 



10. 공동작업

여러명이 공동으로 작업하는 경우에 두명이상의 사람이 한파일을 동시에 checkout 할 수가 있다. 첫번째 해결책은 파일잠금(file locking)혹은 예약된 채크아웃(Reserved checkout)으로 알려진 방법이다. 이 방법은 한번에 한사람만 파일을 수정할수 있게 하는 방법이다. 이 방법은 RCS나 SCCS등에서 제공하는 유일한 방법이다. CVS에서 예약된 채크아웃을 하는 일반적인 방법은 cvs admin -l 명령이다. 이 방법은 CVS와 훌륭하게 통합되어있지 않다. 필요한 사람만 사용하도록 하자.

CVS에서 기본으로 사용하는 방식은 예약안한 채크아웃 (unreserved checkout) 이다. 이 방식에서 여러개발자가 동시에 한 파일을 자신들의 작업디렉터리에서 작업할 수 있다. 수정내용을 커밋하는 첫번째 개발자는 다른 사람이 그것을 수정하기 시작했다는 것을 자동적으로 알수있는 방법이 없다. 다른 사람들은 그 파일을 커밋하려고 할때 에러메시지를 받는다. 그들은 자신들의 작업용 카피가 업데이트되도록 CVS명령어를 사용해야만 한다. 이 공정은 거의 자동이다.

10-1. 파일 상태

채크아웃된 파일에 어떤 처리를 했느냐에 따라, 그리고 다른이들이 저장소에있는 파일들에 어떤 처리를 했느냐에 따라, 한 파일은 여러 상태로 분류될수 있다. 상태들은 status 명령으로 볼 수 있다.

Up-to-date 파일이 사용되고 있는 가지(branch)의 저장소의 최신 리비전과 동일하다.
Locally Modified 당신이 파일을 수정하였고, 아직 커밋하지 않아 저장소에는 반영되지 않았다..
Locally Added 당신이 add명령으로 파일을 추가하였지만, 아직 커밋하지 않아 저장소에는 반영되지 않았다.
Locally Removed 당신이 remove명령으로 파일을 삭제하였지만 커밋하지 않아 저장소에는 반영되지 않았다.
Needs Checkout 다른 사람이 이미 새로운 리비전으로 커밋해버렸다. 이 이름은 약간 혼란을 준다. 보통 commit가 아니라 update로 새로운 리비전을 받아온다
Needs Patch Need Checkout와 같지만, CVS서버가 전체파일을 보내주기보다 패치를 보내줄것이다. 전체 파일을 보내주거나 패치를 보내주거나 결과물은 같다.
Needs Merge 누군가가 저장소에 새로운 리비전을 커밋했고, 당신도 그 파일을 수정했다.
File had conflicts on merge 선행된 update명령이 충돌(conflict) 되었다는 것을 빼고는 Locally Modified와 같다. 뒤에 설명하는 충돌 해결을 참고하세요.
Unknown CVS가 이 파일에 관해서 아무것도 모른다. 예를 들면 새로운 파일을 만들고 add를 하지 않았다.

status 명령어와 update 명령어를 다소 보충적인 것으로 생각할 수 있다. 파일을 업데이트하기위해 update명령을 사용하고, update가 무었을 했었나를 보기위해 status를 사용할 수 있다. 사실 status 명령보다 간략한 포멧으로 상태를 보고싶다면, 다음을 쓸수도 있다.


$ cvs -n -q update

10-2. 파일 업데이트

파일을 업데이트하거나 병합(merge)하고 싶을때는 update 명령어를 사용하라. 이것은 갱신되지않은 파일인 경우는 commit명령과 대충 동등하다 : 최신 리비젼의 파일이 저장소로부터 추출되어 작업디렉토리에 놓여진다.

파일의 수정내용은 update를 사용할때 없어지지 않는다. 더 새로운 리비젼이 존해하지 않는다면 update는 아무것도 안한다. 파일을 수정했고 새로운 리비젼이 있다면, CVS는 모든 수정내용을 작업디렉터리에 병합한다.

10-3. 충돌의 예

리비젼 1.4인 파일 driver.c가 있다고 가정하자.

#include 

void main()
{
    parse();
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(nerr == 0 ? 0 : 1);
}
리비전 1.6인 driver.c가 다름과 같다고 가정하자.
#include 

int main(int argc,
         char **argv)
{
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(!!nerr);
}
이때 cvs update 를 실행하면 다음과 같은 결과를 얻는다.

$ cvs update driver.c
RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
retrieving revision 1.4
retrieving revision 1.6
Merging differences between 1.4 and 1.6 into driver.c
rcsmerge warning: overlaps during merge
cvs update: conflicts found in driver.c
C driver.c
CVS가 충돌이 났다는 메시지를 보낸다. 당신이 작업하던 원본파일은 수정한된채로 `.#driver.c.1.4'란 이름으로 저장된다. 새로운 버전의 driver.c에는 다음의 내용이 저장된다.
#include 
#include 

int main(int argc,
         char **argv)
{
    init_scanner();
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
<<<<<<< driver.c
    exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
=======
    exit(!!nerr);
>>>>>>> 1.6
}
덮어씌울 수 없는 수정된부분이 작업본에 합체되고, 겹쳐진 부분은 `<<<<<<<', `=======' and `>>>>>>>' 로 구분되는 것에 주목해라.

마커를 지우고 잘못된 라인을 수정하는 것으로 문제를 해결한다. 다음과 같이 수정했다고 가정하자

#include 
#include 

int main(int argc,
         char **argv)
{
    init_scanner();
    parse();
    if (argc != 1)
    {
        fprintf(stderr, "tc: No args expected.\n");
        exit(1);
    }
    if (nerr == 0)
        gencode();
    else
        fprintf(stderr, "No code generated.\n");
    exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
그러면 계속할 수 있고, 이 것을 리비젼1.7로 커밋할 수 있다.

$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
Checking in driver.c;
/usr/local/cvsroot/yoyodyne/tc/driver.c,v  <--  driver.c
new revision: 1.7; previous revision: 1.6
done





+ Recent posts