CVS는 RCS를 기반으로 작성된 버전 관리 시스템입니다. 쉽게 얘기하자면 RCS는 파일 하나하나에 대해 버전 관리를 해주는 것이고, CVS는 RCS 기능을 이용해 소스나 문서를 프로젝트/모듈 단위로 관리할 수 있도록 확장한 프로그램입니다. 이미 RCS를 쓰고 있고 익숙한 분이 아니라면 굳이 CVS를 새로 배울 필요는 없습니다. RCS로 할 수 있는 모든 것은 CVS로 할 수 있지만 그 역은 성립하지 않기 때문입니다.
형상관리(Software Configuration Management)
형상 관리는 하드웨어에서 출발하였지만…소스는 변경될 때마다 새로운 버전이 생성되고, 추가되고, 삭제되고, 소프트웨어 개발 시에 발생하는 모든 작업은 시스템에 영향을 미치게 되므로 시스템에 영향을 주는 모든 사건을 버전화하고 소스를 버전별로 관리하는 일이 형상관리( 버전 관리란 용어를 사용하기도 합니다.)
• Source control system (version control system) – locking system을 이용해 엑세스를 직렬화함으로써 소스코드 액세르를 제어하는 것과, 모든 파일의 변경사항 히스토리를 저장함으로써 이전 버전을 다시 불러와 구성할수 있게 하는 것
• Pessimistic locking – 한번에 한사람만이 수정가능한 파일 사본을 가져올 수 있다, 수정 권한을 확보한 사람이 변경한 코드를 체크인해서 제어권을 넘겨주기 전까지는 어느 누구도 수정가능한 사본을 얻을 수 없으며, 읽기 전용 사본을 가져오는 것은 가능하다.
• Optimistic locking – 사용자는 언제든 파일을 가져와 수정할 수 있다. 파일을 repository에 다시 체크인하면 버전 컨트롤 소프트웨어는 체크인하지 않은 다른 사람의 변경사항과 충돌이 일어나지 않도록 한다. 버전 컨트롤 시스템은 자동으로 변경사항을 병합할 수 있을 경우 병합하고 그렇지 않으면 직접 충돌을 해결해야 한다고 경고한다.
• 수정병합(Copy Modify Merge) - 소스를 복사하여 수정한 후에 병합이 가능한 구조로 동시에 하나의 파일을 가지고 작업하고 나중에 충돌되는 부분은 확인해가며 작업자간의 의견을 조율하여 소스에 반영하는 방식이다.(CVS, Subversion)
• Lock Reservation – 작업을 하는 사용자가 잠금(lock)을 걸어놓고 작업하는 방식으로 잠금이 걸린 문서나 파일은 다른 사람의 열람은 가능하지만 수정하여 반영할 수는 없다. (Vusual SourceSafe, IBM Rational사의 ClearCase)
• Eclipse에 통합된 소스 컨트롤 툴 CVS(Concurrent Versions System)은 낙관적 잠금을 지원하며 수정병합 방식을 채택한 시스템이다.
• CVS(Concurrent Versions System)는 오픈 소스 프로그램으로 WinCVS와 TortoiseCVS등의 클라이언트 프로그램이 존재하고, 이클립스, NetBeans, JBuilder, Idea(inteliJ)등의 개발 툴에 기본으로 통합되어 있다.
• CVS는 혼자하는 개발, 팀을 이루는 개발, 다국적 개발등에 유용하며 클라이언트 서버 구조로 잠금 상태를 예약하지 않는 수정병합 방식으로 같은 소스의 동시 작업이 가능하다
[CVS 기능]
• History 기능 – 소스파일이 추가되고, 수정되고 삭제되었던 모든 History가 CVS 서버에 기록되며 작업 완료 시에 작업 내용을 기록에 남길 수 있다.
• 변경사항 저장 – 파일의 모든 버전을 파일로 저장하는 대신 CVS는 버전간의 변경사항만을 저장하므로 백업 용량을 적게 차지한다.
• 병합 기능 – 각 개발자가 작업을 끝마쳤을 때, 그 작업을 병합시켜줌으로써, 팀원이 하나의 공동 프로젝트를 수행하고자 할 때 도움을 준다.
• branch 기능 – 개발의 주된 흐름인 메인 줄기(trunk)의 특정 진행 시점에서 갈라져 나와 개발을 추가하거나 변경된 가지(branch)에서 소스를 변경해도 메인 줄기에는 영향을 미치지 않는다.
• tag 기능 – 개발의 특정 시점에 버전을 따는 기능으로 개발이 빌드되거나 릴리즈되는 특정 시점에서 태그를 달고, 개발을 진행해 나간다.(특정 태그가 달린 소스를 찾아서 해당 태그의 모듈을 구할 수 있다)
• diff 기능 - 버전과 버전, 태그와 태그간에 소스의 차이점을 비교해준다.
[CVS 작업 사이클]
• 프로젝트 생성
프로젝트를 생성하고, 프로젝트 매니저나 리드 개발자가 CVS 서버에 프로젝트 저장소를 만든다.(init)
초기 버전에 대한 소스나 문서, 파일 등을 서버에 올린다.(CVS 서버에 모듈을 import)
• 프로젝트 진행
팀에 속한 모든 개발자는 import된 프로젝트 모듈을 다운로드하고(Checkout), 모듈의 소스를 추가(add), 삭제(remove), 커밋(commit), 변경(update) 중에 충돌(conflict)된 것은 합병(merge)하는 등 프로젝트를 진행한다.
일정시점이나 릴리즈 시에는 tag나 branch를 정해서 태그를 붙인다.
[CVS 내에서 사용되는 용어]
• repository – CVS를 통해서 작업하는 소스, 문서 등 작업용 파일이 저장되는 서버상의 공간
• revision – 각 파일별로 commit 할 때마다 자동으로 더해지는 버전으로 CVS가 관리하는 번호로 뒤로 돌리거나, 임의로 수정할 수 없다.
• init – 저장소를 초기화하는 명령어로 프로젝트를 시작할 때 한번만 실행
• module – 하나의 저장소에 구분되어 저장되는 단위.(작은 프로젝트의 경우 하나의 모듈, 큰 프로젝트의 경우에는 컴포넌트별로 모듈을 나누거나 버전별로 나누기도 함)
• import – 하나의 모듈을 서버에 저장하늠 명령어
• checkout – 서버에 저장한 모듈 하나를 통째로 로컬에 가져오는 명령어
• update – 파일이나 디렉토리를 지정하여 최신 것이나 특정 리비전, 특정 날짜의 것을 서버에서 로컬로 가져오는 명령어
• add – 새로운 파일을 디렉토리에 추가했음을 서버에 알리는 명령어.(파일은 commit하기 전까지는 서버에 반영되지 않는다.)
• remove – 파일 삭제했음을 서버에 알리는 명령어 (commit하기 전까지는 서버에서 지워지지 않는다.)
• commit – add, remove를 마치고 서버에 반영한다는 의미의 명령어
• tag – 특정 날짜나 릴리즈 시에 태그를 붙임으로써 나중에 해당 릴리즈의 리비전으로만 가져올 수 있게 한다.
• branch – 일부분 혹은 전체에서 소스를 별도로 관리해야 되는 부분이 생길 때 사용 (리비전의 깊이가 달라진다(예:1.1 > 1.1.2.1)
--------------------------------------------------------------------------------------------------------
CVS에서 유용하게 사용되는 변화 추적(Change-tracking)
CVS(Concurrent Versioning System)는 파일의 동시 개발을 관리한다. 파일을 중앙 저장소(repository)에 저장하고, 사용자는 파일 복사본을 받아서 작업하고 변경된 것을 다시 저장소로 보내기 때문이다.
CVS는 각 파일의 변경 기록을 관리하고, 사용자들이 이전 버전으로 복귀, 병합하거나 변경사항을 추적할 수 있게 해준다. 이 변화 추적(Change-tracking) 기능은 아주 유용하기 때문에 자주 사용될 것이다.
본 기사는 CVS 소개와 CVS 관리라는 두 기사를 바탕으로 작성되었다. 두 기사에서 이미 논의한 바 있는 특정 내용에 대한 언급이 있겠지만 이 기사에서 다시 자세히 설명하는 것은 생략하기로 하겠다.
annotate
anontate는 저장소에 저장된 파일의 각 라인에서 가장 마지막으로 변경된 내용을 보여주는 cvs 명령어이다. 각각의 라인에 대해 이 명령어는 라인의 내용, 날짜, 사용자, 가장 마지막으로 변경된 라인에 대한 변경 번호를 보여준다. 따라서 언제, 누가, 무엇을 변경했는지 알 수 있는 빠른 방법이라고 할 수 있다.
annotate는 현재 작업 중인 디렉토리에서가 아니라 저장소에서 파일 데이터를 출력하므로, 아직 커밋(commit)되지 않은 변경 내용은 보이지 않는다.
cvs annotate의 옵션은 다음과 같다.
-f
일치하는 태그나 데이터가 그 파일에서 발견되지 않는다고 하더라도 (최신 변경 정보를 사용하여) 파일을 보여준다.
-l
현재 디렉토리만 확인하고 하위 디렉토리는 확인하지 않는다.
-R
하위 디렉토리를 확인한다(기본값).
-D date
지정된 날짜를 기준으로 가장 최근에 변경된 내용을 보여준다.
-r tag
태그(꼬리표)로 구분할 수 있는 변경된 내용을 출력한다.
Example 1
$ cvs annotate test.html Annotations for test.html *************** 1.1 (jenn 30-Apr-02): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1.1 (jenn 30-Apr-02): "http://www.w3.org/TR/html4/strict.dtd"> 1.1 (jenn 30-Apr-02): <html> 1.1 (jenn 30-Apr-02): <head> 1.4 (jenn 04-May-02): <title>Sample Article</title> 1.1 (jenn 30-Apr-02): </head> 1.1 (jenn 30-Apr-02): <body> 1.4 (jenn 04-May-02): <h1>Sample Article</h1> 1.1 (jenn 30-Apr-02): <p> 1.11 (jenn 07-May-02): Body text for the sample article. 1.1 (jenn 30-Apr-02): </p>
![]() |
참고 도서 |
diff
cvs diff는 한 파일의 두 가지의 다른 변경된 내용을 비교하여 차이점을 보여주는 명령어이다. cvs diff의 출력된 내용(output)은 표준 diff 명령어의 출력 내용과 매우 유사하다. cvs rdiff는 표준 patch 명령어를 사용하여 설치될 수 있는 패치 파일을 만드는데 사용된다.
대개 cvs diff는 적어도 하나 이상의 -r tag 파라미터(parameter)와 함께 사용된다. 만약 단일 태그와 함께 호출된다면 작업중인 디렉토리에 있는 현재 복사본은 저장소에 있는 버전과 비교된다. cvs log 명령어는 cvs diff의 파라미터로 사용될 수 있는 변경 번호를 보여준다.
Example 2
$ cvs diff -r 1.11 cvs_changes.html Index: cvs_changes.html =================================================================== RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v retrieving revision 1.11 diff -r1.11 cvs_changes.html 64a65 > The command <code>cvs diff</code> compares two revisions of a file and displays the differences. 66a68 > <code>cvs diff</code> is usually called with at least one <code>-r <var>tag</var></code> parameter. 71a74
history
대부분의 CVS 기능과는 달리, cvs history 는 디폴트로 셋업되지 않는다. 셋업하려면 저장소의 CVSROOT 디렉토리 안에 history 라는 파일을 생성해야 한다. CVS 사용자는 (또는 서버에서 CVS를 실행할 수 있는 사용자는 모두) 그 파일을 작성할 수 있어야 한다.
Example 3
(on the cvs repository server) $ cd /home/cvs/CVSROOT $ touch history $ chmod g+w history $ ls -la drwxrwsr-x 4 root src 1024 May 16 01:04 . drwxrwsr-x 35 root src 1024 Mar 20 18:01 .. drwxrwsr-x 2 root src 1024 Sep 7 2001 Attic -rw-rw-r-- 1 root src 0 May 16 01:04 history -r--r--r-- 1 root src 403 Sep 26 2001 loginfo
파일을 커밋하고 cvs history -c filename 실행해서 history 파일을 테스트하자(-c 플래그는 CVS 커밋을 표시함). CVS는 history 파일이 생성된 후로 하나의 커밋된 내용을 보여주는 라인을 하나 표시할 것이다.
Example 4
$ cvs history -c test.html M 2002-05-15 15:04 +0000 jenn 1.2 test.html oreilly/articles/cvs ==$
일단 셋업되면 cvs history는 저장소에 있는 파일과 모듈의 히스토리를 보여주는데 사용될 수 있다. 파일과 모듈 선택은 현재 작업 디렉토리 내에 있는 모듈들, 모듈, 특정 파일이나 파일들을 포함한다.
history 파일은 저장소 안에 저장된 파일의 커밋, 병합, 충돌, 태그(꼬리표), (작업 디렉토리에)업데이트, 추가, 삭제, 변경 등을 기록한다. 이들 각각은 cvs history 명령어로 소환되거나 표시될 수 있다.
cvs history는 사용자 요구 정보, 모든 사용자 또는 현재 작업 중인 복사본의 데이터를 표시할 것이다. 넓게 분포되어 작업하는 팀들을 위해 지정된 시간대에 맞게 시간을 표시하는 옵션을 가지고 있다.
Example 5
$ cvs history -e -w -z EST test.html M 2002-05-15 10:04 EST jenn 1.2 test.html oreilly/articles/cvs == <remote> M 2002-05-15 10:41 EST jenn 1.3 test.html oreilly/articles/cvs == <remote>
예제5에서 -e 는 커밋과 업데이트의 모든 타입를 표시하도록 하고, -w 는 현재 작업중인 디렉토리에서 유래하거나 영향을 받은 변경 내용만 표시하도록 한다. 그리고 -z EST는 동부 표준시간대(EST)로 표시하도록 하기 위해 시간대를 설정한다.
log
cvs log 명령어는 인자로 전달되는 파일(들)에 대한 정보를 표시한다. 만약 파일이 전달되지 않는다면 현재 작업 디렉토리와 그 하위 디렉토리의 모든 파일들에 대한 로그 정보를 표시한다.
cvs log를 위한 옵션은 보여주는 정보의 양을 줄인다. 디폴트로 log는 가지고 있는 모든 정보를 보여준다.
Example 6
$ cvs log cvs_changes.html RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v Working file: cvs_changes.html head: 1.3 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 3; selected revisions: 3 description: ---------------------------- revision 1.3 date: 2002/05/15 15:41:54; author: jenn; state: Exp; lines: +53 -0 history mostly done. needs example. ---------------------------- revision 1.2 date: 2002/05/15 15:04:47; author: jenn; state: Exp; lines: +8 -2 Adding a history file ---------------------------- revision 1.1 date: 2002/05/15 14:54:54; author: jenn; state: Exp; Initial entry for both files. Also includes cvs annotate for changes. ====================================================================
예제6은 본 기사에 대한 초기 로그 히스토리를 보여준다.
Revision 1.1은 내가 두 개의 파일을 만들고 그 빈 템플릿을 체크인(check-in)하는 것을 잊어버리고 본 기사의 주석 부분을 커밋하기 위해 노력할 때 발생하였다.
사용자 정의 로깅
CVS는 확실하다고 생각하는 행동이 일어났을 때 호출되는 스크립트를 정의하는 커스터마이즈된 파일들을 가지고 있다. loginfo(로그정보), 모듈들과 taginfo(태그정보) 파일은 로깅 스크립트들을 호출하기 위해 사용될 수 있다.
이런 파일들은 CVS 저장소의 CVSROOT 디렉토리에서 찾을 수 있고, 그곳에서 형성된다. 그 파일들은 호스트 컴퓨터에서 실행하지만 몇몇 모듈 스크립트들은 클라이언트 머신에서 실행된다. 더 자세한 내용은 다음을 참고하기 바란다.
CVSROOT 모듈 내에 있는 파일들을 편집할 때에는 CVS를 이용하라. 모든 파일을 체크아웃(† 역자 주: checkout, 가져오다)하기 위해서는 단순히 cvs -d repository checkout CVSROOT만 실행하면 된다.
loginfo와 taginfo
loginfo 파일은 cvs commit을 위한 로그 정보를 어디로 보내야 할지를 통제한다. 프로젝트 리더가 팀이 만든 변경된 내용을 유지하고 프로젝트의 진행상의 주요한 로그를 유지하는데 사용할 수 있다.
taginfo는 tag와 rtag 명령어를 위한 것이지만 loginfo도 마찬가지로 사용된다. taginfo는 loginfo와 같은 문법을 가지고 있다.
파일의 각 라인은 디렉토리에 적합한 정규 표현식을 포함해야 한다. 이 디렉토리는 스크립트 주소순으로 표준입력(stdin)과 같은 로그 정보를 예상한다.
특수한 라인들은 'ALL'과 'DEFAULT'로 시작한다. ALL은 적용되는 다른 라인들을 누적하여 실행한다. 만약 그렇지 않으면 처음으로 짝지워진 정규 표현식만 실행되고 나머지 짝지워지지 않은 것들은 DEFAULT로 된다.
예제7의 loginfo 파일은 logscript 스크립트를 통해 커밋되는 모든 것을 로그로 남길 것이다. 그리고 $CVSROOT/oreilly 디렉토리 내의 어떠한 파일이 커밋될 않을 경우, cvsscript를 실행하고 cvsadmin으로 다른 커밋을 메일로 보낼 것이다.
Example 7
ALL /usr/local/bin/logscript ^oreilly /home/jenn/scripts/cvsscript DEFAULT Mail -s "CVS commit" cvsadmin
modules
CVSROOT/modules 파일은 각각의 모듈과 이들의 디렉토리, 파일들을 기록한다. 그 파일(CVSROOT/modules)은 또한 옵션들을 사용한다. 몇몇 옵션들은 CVS 동작이 발생할 때 실행되는 스크립트들이다.
-e script
모듈이 익스포트(export)되었을 때 script를 실행한다.
-i script
모듈이 커밋 되었을 때 실행한다.
-o script
모듈이 체크아웃 되었을 때 실행한다.
-u script
모듈이 업데이트(갱신) 되었을 때 실행한다.
-t script
rtag가 모듈에 사용되었을 때 실행한다. 이것은 tag가 사용되었을 때는 실행되지 않는다. taginfo 파일이 태그의 로그를 남기는 더 좋은 방법이다.
만약 이 파일(CVSROOT/modules)을 변경하고 싶다면 CVS 매뉴얼과 정보 파일을 읽어보기 바란다. CVS는 사용자가 모듈과 상호작용을 할 때 항상 이 파일을 사용한다.
커밋이나 업데이트를 할 때 호출되는 스크립트들은 로컬 머신에서 실행되고, 나머지 스크립트들은 서버에서 실행된다.
예제8은 oreilly 모듈이 oreilly 디렉토리에서 체크아웃될 때 /home/jenn/scripts/cvsscript를 실행하려 한다. 이것 또한 특별한 옵션 없이 CVSROOT 모듈을 정의한다.
Example 8
CVSROOT CVSROOT oreilly -o /home/jenn/scripts/cvsscript oreilly
마지막으로
Change-tracking(변화 추적)은 CVS의 유용한 부분임에도 불구하고 현장에서 사용하는 것을 거의 보지 못했다. 처음으로 CVS를 사용하기 시작했을 때 변화 추적의 특징을 발견하고 순간 "내가 왜 전에는 이것을 사용하지 않았을까?"라고 생각하였다.
여러분도 한 번씩 해보기 바란다. 그리고 내가 그랬던 것처럼 이것의 유용한 점을 발견하길 바란다.
'SVN/CVS' 카테고리의 다른 글
버전관리 시스템(#1 SVN 바로알기) (0) | 2010.01.04 |
---|---|
SVN(Subversion) (0) | 2010.01.04 |
CVS-개념 및 리눅스 서버 설치 (0) | 2010.01.04 |