|| [PragmaticVersionControlWithCVS/WhatIsVersionControl] || [PragmaticVersionControlWithCVS/HowTo] || || [[TableOfContents]] || = Getting Started = == Installing CVS == CVS서버 설치는 알아서 잘해라. -_-; 리눅스에서는 패키지로 설치하면 되고, 윈도우에서는 알아서 받아서 설치하면 된다. 이미 서버가 있으면 더 좋다. 내 경우에는 데비안 리눅스를 사용하는 관계로 apt-get install cvs로 간단히 설치를 끝냈다. == Creating a Repository == 현재 우리는 테스트용으로 CVS를 쓰기 때문에 CVS의 저장소를 임시로 만들 필요가 있다. CVS저장소를 만드는 명령은 다음과 같다. {{{~cpp Unix: cvs -d ~/sandbox init // 나의 경우에는 /home/CVSHOME 로 지정하였다. Wind: cvs -d d:sandbox init }}} == CVS Commands == CVS클라이언트는 현재 우리가 쓰는 커맨드 형태의 클라이언트도 있지만, GUI형태의 TortoiseCVS, WinCVS등도 있다. (sourceforge.net에서 확인) 또한 IDE 자체가 CVS 클라이언트의 기능을 하는 것들도 있다. (ex. eclipse, dev-cpp) == Creating a Simple Project == 간단한 프로젝트를 CVS상에 만들자. 예제는 소스로 보이지는 않지만 크게 상관은 없다. '''color.text''' {{{~cpp black brown red orange yellow green }}} '''number.text''' {{{~cpp zero one two three four }}} 이 파일이 저장된 폴더에서 다음의 명령어를 실행시킨다. {{{~cpp tmpdir#cvs -d /home/CVSHOME/ import -m " " sesame sesame initial }}} import는 프로젝트를 저장소에 넣을 것이라는 파라메터이다. -m " " 프로젝트를 임포트할때 기록할 메시지임. (서드파티 코드를 사용하는 경우에 유리하다.) sesame 저장소안에서 프로젝트의 이름 마지막 2개의 파라메터(sesame initial) tag이다. 이런과정을 마치면 CVS 루트 디렉토리에 프로젝트가 정상적으로 생성되었는지 ls 명령으로 확인해보자. == Starting to Work With a Project == 이제 저장소에 저장된 파일을 로컬 작업공간에 체크아웃해보자. 이를위해서 일단 ~/work 라는 디렉토리를 구성하자. {{{~cpp #mkdir ~/work #cd ~/work #cvs -d /home/CVSHOME co sesame cvs checkout: Updating sesame U sesame/color.txt U sesame/number.txt }}} ~/work를 조사해서 ~/work/sesame 디렉토리에 정상적으로 저장소의 파일이 체크아웃되었다면 원본 파일을 삭제한다. == Making Changes == '''color.txt 의 변경''' {{{~cpp black brown red orange yellow blue purple gray white }}} color.txt를 위와 같이 변경한뒤에 프로프트에서 다음의 명령어를 사용해보자. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs status color.txt =================================================================== File: color.txt Status: Locally Modified Working revision: 1.1.1.1 Tue Aug 2 05:50:14 2005 Repository revision: 1.1.1.1 /home/CVSHOME/sesame/color.txt,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) }}} 상기의 '''status''' 옵션으로 확인이 가능하듯이 cvs는 자동으로 현재의 파일이 로컬 작업공간에서 수정되었다는 사실을 판단할 수 있다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs diff color.txt Index: color.txt =================================================================== RCS file: /home/CVSHOME/sesame/color.txt,v retrieving revision 1.1.1.1 diff -r1.1.1.1 color.txt 6a7,10 > blue > purple > gray > white }}} 또한 '''diff''' 옵션을 이용해서 변경된 파일이 어떤 변경이 있었는지를 조사하여 보여주는 옵션도 존재한다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs diff --side-by-side color.txt Index: color.txt =================================================================== RCS file: /home/CVSHOME/sesame/color.txt,v retrieving revision 1.1.1.1 diff --side-by-side -r1.1.1.1 color.txt black black brown brown red red orange orange yellow yellow green green > blue > purple > gray > white }}} '''--side-by-side''' 옵션을 이용하면 지역 버전과 저장소버전을 한화면에 출력하여서 비교를 할 수 있다. == Updating the Repository == 파일을 수정, UnitTest를 거치면 수정한 내용을 저장소에 저장해야할 것이다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs commit -m "고객이 4가지 색을 더 원함" cvs commit: Examining . /home/CVSHOME/sesame/color.txt,v <-- color.txt new revision: 1.2; previous revision: 1.1 }}} 변경된 프로젝트는 '''commit''' 옵션으로 체크인시키는 것이 가능하다. 이때 '''-m''' 옵션으로 변경된 사항에 대한 주석을 다는 것이 가능하며, 만약 주석을 달지 않을 경우에는 vi 에디터가 실행되면서 주석을 저장할 수 있는 파일이 열린다. ''(직접해보면 안다. -_-;)'' {{{~cpp root@eunviho:~/tmpdir/sesame# cvs status color.txt =================================================================== File: color.txt Status: Up-to-date Working revision: 1.2 Tue Aug 2 13:08:47 2005 Repository revision: 1.2 /home/CVSHOME/sesame/color.txt,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) }}} commit 을 통해서 저장소를 체크인하고난뒤 status로 변경된 파일의 정보를 출력하면 그 결과가 반영된 것을 알 수 있다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs log color.txt RCS file: /home/CVSHOME/sesame/color.txt,v Working file: color.txt head: 1.2 branch: locks: strict access list: symbolic names: initial: 1.1.1.1 sesame: 1.1.1 keyword substitution: kv total revisions: 3; selected revisions: 3 description: ---------------------------- revision 1.2 date: 2005-08-02 13:16:58 +0000; author: sapius; state: Exp; lines: +4 -0 고객이 4가지 색을 더 원함 ---------------------------- revision 1.1 date: 2005-08-02 05:50:14 +0000; author: sapius; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2005-08-02 05:50:14 +0000; author: sapius; state: Exp; lines: +0 -0 ============================================================================= }}} '''log'''옵션을 통해서 특정파일이 어떤 식으로 변경이 되었는지를 알 수 있다. == When Worlds Collide == 이제 한개의 파일을 두사람이 동시에 변경할때 생기는 상황에대해서 살펴보자. 이러한 경우를 살피기 위해서 기존의 sesame 이라는 디렉토리이외의 공간에 저장소에 저장된 sesame을 받아야한다. {{{~cpp root@eunviho:~/tmpdir# cvs -d /home/CVSHOME/ co -d aladdin sesame cvs checkout: Updating aladdin U aladdin/color.txt U aladdin/number.txt }}} 이렇게하면 디렉토리에 {{{~cpp root@eunviho:~/tmpdir# ll total 8 drwxr-xr-x 3 root root 4096 2005-08-02 22:23 aladdin drwxr-xr-x 3 root root 4096 2005-08-02 22:08 sesame }}} 과 같이 동일한 저장소의 프로젝트가 서로다른 디렉토리의 로컬 작업공간을 할당받았다는 것을 알 수 있다. '''sesame/number.txt''' {{{~cpp root@eunviho:~/tmpdir# vi sesame/number.txt zero one two three four five six }}} 상기와 같이 변경한 파일을 체크인 시킨다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs commit -m "숫자가 더 필요했다." cvs commit: Examining . /home/CVSHOME/sesame/number.txt,v <-- number.txt new revision: 1.2; previous revision: 1.1 }}} sesame 폴더에 받아진 파일을 변경하여 체크인 시켰기 때문에 이제 aladdin 폴더에 존재하는 파일들은 더이상 최신 버전이 아니다. {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs status number.txt =================================================================== File: number.txt Status: Needs Patch Working revision: 1.1.1.1 Tue Aug 2 05:50:14 2005 Repository revision: 1.2 /home/CVSHOME/sesame/number.txt,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) }}} 상기와 같이 확인을 해보면 aladdin/number.txt 는 체크아웃을 통해서 저장소의 소스와 동기화를 해주어야한다는 상태를 나타내고 있다. '''최신 버전이 아닌 로컬 작업공간의 내용과 저장소의 내용을 비교한다''' {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs diff -rHEAD number.txt Index: number.txt =================================================================== RCS file: /home/CVSHOME/sesame/number.txt,v retrieving revision 1.2 retrieving revision 1.1.1.1 diff -r1.2 -r1.1.1.1 6,7d5 < five < six }}} -rHEAD는 현재의 branches에 존재하는 가장 최신버전의 것과 비교하는 옵션이다. 만약 이 옵션이 없다면 cvs는 현재 받아진 지역 버전과 동일한 저장소상에 기록된 소스와 비교를 한다. {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs diff number.txt }}} 저장소상의 aladdin 과 동일한 버전의 number.txt는 전혀 변화가 없었기 때문에 출력되는 내용이 없다. '''저장소의 최신버전의 내용을 로컬에 반영하기''' {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs update cvs update: Updating . U number.txt }}} 반영되는 파일은 오로지 최신버전의 파일이 저장소에 존재할 경우만이다. 그렇지 않으면 파일은 다시 받을 필요가 없기 때문에 받지 않는다. == Conflict Resolution == 다음과 같이 변경을 해서 동시에 두사람이 파일의 수정작업을 하는 경우를 가정해보자. '''sesame/number.txt''' {{{~cpp root@eunviho:~/tmpdir# vi sesame/number.txt ZERO one two three four five six }}} '''sesame/number.txt''' {{{~cpp root@eunviho:~/tmpdir# vi aladdin/number.txt zero one two three four five SIX }}} 우선 aladdin 의 파일들을 체크인한다. {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs commit -m "make number six to be important" cvs commit: Examining . /home/CVSHOME/sesame/number.txt,v <-- number.txt new revision: 1.3; previous revision: 1.2 }}} 그렇게 만든뒤에 sesame의 파일을 수정한 사람이 체크인을 한다고 생각해보자. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs commit -m"make number zero to be emphasized" cvs commit: Examining . cvs commit: Up-to-date check failed for `number.txt' cvs [commit aborted]: correct above errors first! }}} 상기에서 보듯이 에러를 내면서 체크인하지 못한다. 이 경우는 동시에 수정이 일어나서 저장소의 최신버전이 반영되지 못했기 때문에 발생한 것이다. 우선은 다음처럼 해보자. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs update cvs update: Updating . RCS file: /home/CVSHOME/sesame/number.txt,v retrieving revision 1.2 retrieving revision 1.3 Merging differences between 1.2 and 1.3 into number.txt M number.txt }}} '''sesame/number.txt의 내용을 확인해보자''' {{{~cpp root@eunviho:~/tmpdir/sesame# vi number.txt ZERO one two three four five SIX }}} 상기에서 보듯이 cvs는 너무도 잘 변경된 부분을 판단해서 현재의 로컬 소스에 반영시켜준다. 로컬에 반영이 되었으므로 {{{~cpp root@eunviho:~/tmpdir/sesame# cvs commit -m"make number zero to be emphasized" cvs commit: Examining . /home/CVSHOME/sesame/number.txt,v <-- number.txt new revision: 1.4; previous revision: 1.3 }}} 상기와 같이 정상적인 체크인이 가능하다. 물론 aladdin 폴더의 내용도 다음번 수정시에는 이와 같은 일이 발생할 것이다. === 박치기 - 변경 내용이 충돌하는 경우 === 상기의 경우에는 2가지 프로그램의 바뀐 부분이 동일한 줄에 해당하지 않기 때문에 큰 문제없이 cvs가 알아서 반영을 해주었다. 그렇나 만약 변경부분이 동일한 부분이라면 어떨까? '''sesame/number.txt''' {{{~cpp root@eunviho:~/tmpdir# vi sesame/number.txt ZERO ichi two three four five SIX }}} '''aladdin/number.txt''' {{{~cpp root@eunviho:~/tmpdir# vi aladdin/number.txt ZERO uno two three four five SIX }}} {{{~cpp root@eunviho:~/tmpdir/aladdin# cvs commit -m "users like italian word of one" cvs commit: Examining . /home/CVSHOME/sesame/number.txt,v <-- number.txt new revision: 1.5; previous revision: 1.4 . . root@eunviho:~/tmpdir/sesame# cvs commit -m "must be japanese of word one" cvs commit: Examining . cvs commit: Up-to-date check failed for `number.txt' cvs [commit aborted]: correct above errors first! . . root@eunviho:~/tmpdir/sesame# cvs update cvs update: Updating . RCS file: /home/CVSHOME/sesame/number.txt,v retrieving revision 1.4 retrieving revision 1.5 Merging differences between 1.4 and 1.5 into number.txt rcsmerge: warning: conflicts during merge cvs update: conflicts found in number.txt C number.txt }}} 3번재에서 알 수 있듯, 동일한 줄을 수정한 경우에는 충돌이 일어난다는 것을 알 수 있다. 이런경우에 rcsmerge 는 그 변경을 다음과 같이 표현한다. '''sesame/number.txt''' {{{~cpp ZERO <<<<<<< number.txt ichi ======= uno >>>>>>> 1.5 two three four five SIX }}} 이 경우 변경된 내용은 '''<<<<<<< >>>>>>> '''의 가운데에 존재하는 내용이 충돌을 일으킨 부분이다. 이런일이 발생한 경우에는 어떤 일이 발생했는지 기록을 우선적으로 찾아보아야한다. {{{~cpp root@eunviho:~/tmpdir/sesame# cvs log -r1.5 number.txt RCS file: /home/CVSHOME/sesame/number.txt,v Working file: number.txt head: 1.5 branch: locks: strict access list: symbolic names: initial: 1.1.1.1 sesame: 1.1.1 keyword substitution: kv total revisions: 6; selected revisions: 1 description: ---------------------------- revision 1.5 date: 2005-08-02 13:46:44 +0000; author: sapius; state: Exp; lines: +1 -1 users like italian word of one ============================================================================= }}} 마지막 세개의 줄에는 이전에 먼저체크인 된 소스를 수정한 사람과 그와 관련된 주석, 변경된 라인의 정보가 출력된다. 이런 정보를 종합해서 이전 소스의 수정한 사람과 토의를 통해서 올바른 결과를 얻어낼 수 있다. 이 경우에는 ichi를 쓰기로 했다고 가정하자. ichi이외의 다른 부분의 나용을 모두 삭제한다. 그리고 토의 결과 two를 due로 쓰기로 했다고 하자 {{{~cpp root@eunviho:~/tmpdir/sesame# vi number.txt ZERO ichi due three four five SIX . . root@eunviho:~/tmpdir/sesame# cvs commit -m "one is japanese, two is italian" cvs commit: Examining . /home/CVSHOME/sesame/number.txt,v <-- number.txt new revision: 1.6; previous revision: 1.5 }}} 위와 같은 방식(느슨한 잠금)에 의해서 버전 커트롤이 가능하기 대문에 동기화로 인한 문제는 거의 발생하지 않는다. ---- [PragmaticVersionControlWithCVS]