System upgrade notice: java.net projects area will be unavailable while undergoing upgrade Tuesday 2/28 10:00 - 16:00 pacific. Please plan your usage accordingly.
java.net과 이클립스를 이용한 오픈 소스 자바 어플리케이션 개발
2부 : 이클립스와 CVS를 이용한 팀 작업
Martin Pllu
martinpllu-AT-dev.java.net
소개
이 튜토리얼 시리즈는 java.net에 호스팅 되는 오픈 소스 자바 어플리케이션을 개발하기 위해 이클립스가 어떻게 사용될 수 있는지에 대해 설명하고 있다. 이 글은 자바에 대한 지식은 있지만 이클립스는 다뤄보지 않는 개발자들을 대상으로 한다.
문의 사항 또는 피드백이 있다면 튜토리얼의 포럼을 이용해보길 바란다.
튜토리얼의 1부에서는 이클립스에서 프로젝트를 생성하는 방법에 관해 살펴 보았다. 이번 글에서는 팀 개발을 위해서 CVS와 함께 이클립스를 사용하는 방법에 대하여 알아보도록 하자.
CVS의 소개
CVS (Concurrent Versioning System)는 80년대부터 개발되어 오고 있으며, 오픈 소스 개발을 위한 사실 상의 표준이 되어 버린 버전 제어 도구이다.
CVS는 클라이언트/서버 방식의 시스템이다. 온라인상의 대부분의 CVS 문서는, Unix/Linux 시스템에 설치된 cvs 명령어나 윈도우용 cvsnt 포트와 같은 명령 행 클라이언트에 대한 것들이다. 이클립스는 훌륭한 CVS GUI를 제공하는데다가 Java IDE와 밀접하게 통합되어 있어서 명령행 클라이언트를 이용하는 것보다 편리하다.
먼저 몇 가지 CVS 개념을 살펴보자. 이미 이러한 개념들을 잘 알고 있다면, 다음 절로 이동해도 좋다. CVS 저장소
CVS 서버는 다수의 모듈(modules)을 포함하고 있는 저장소(repository)를 관리한다. java.net의 저장소의 경우 개별 프로젝트는 자신만의 모듈을 가지고 있다.
모듈은 디렉토리와 함께 버전이 부여된 파일을 포함하고 있다. 버전이 부여된 파일은 하나의 파일에 대한 이력을 나타내며, 다수의 개정 이력(revisions)을 포함한다. 파일에 변경이 가해질 때마다, 새로운 개정본(revision)이 생성된다. .java, .xml, .properties 등의 텍스트 기반 파일의 경우, 각각의 개정본은 이전 개정본에서 개정된 내역만을 포함하며, .exe, .jar, .pdf 등의 이진 파일의 경우, 각각의 개정본은 완전한 파일 내용을 포함하게 된다.
CVS는 또한 개정본 생성자와 개정본에 대한 주석, 그리고 개정본 번호도 함께 기록한다. 개정본 번호들은 자동으로 갱신되는데, 대부분의 경우, 파일의 첫번째 개정본 번호는 1.1이고 이후에는 1.2 등의 순서로 갱신된다.
repository
moduleA/
versionedFile1
(revision number="1.1" user="dave" comment="Created")
(revision number="1.2" user="mike" comment="New cache implementation")
(revision number="1.3" user="lucy" comment="Fixed defect D113")
versionedFile2
(revision number="1.1" user="dave" comment="Created")
(revision number="1.2" user="dave" comment="Updated after feedback from Lucy")
directory1/
versionedFile3
(revision number="1.1" user="lucy" comment="Initial version")
...
moduleB/
...
저장소 접속과 권한
CVS 클라이언트는 다양한 프로토콜을 사용하여 서버에 접속할 수 있다. 가장 일반적으로 사용되는 프로토콜은 다음과 같다:
- pserver, CVS를 위한 간단한 프로토콜로 java.net을 이용하여 일반적인 작업을 하는 정도에 적합하다.
- ssh, 추가적인 보안을 위해 SSL을 사용하지만, 보통은 인증서 생성과 같이, 대개 약간의 추가적인 설정 작업이 요구된다.
접근 권한은 모듈 단위로 설정된다. java.net 저장소의 경우, java.net에 로그인한 모든 사용자는 누구라도 모든 프로젝트 모듈들에 대해서 읽기 권한을 갖게 된다. 프로젝트 모듈에 대한 쓰기 권한은 모듈을 등록한 소유주나 프로젝트 개발자들에만 부여된다.
작업을 수행하기 위한 파일 사본 가져오기
저장소에 접속한 이후에는 하나 이상의 모듈을 가져올 수 있다. (역자 주:이를 check out 이라고 한다. 앞으로 보다 분명하게 행위 자체를 명시할 필요가 있는 경우 체크아웃이라고 표현하도록 하겠다.) 체크아웃을 하면 CVS에서 여러분의 컴퓨터로 모듈의 최신 내용이 복사되어, 여러분은 모듈 복사본을 가지고 원하는 작업을 수행할 수 있게 된다.
(저장소의 파일을)동시 수정 가능 잠금 방식(Optimistic locking)
버전 관리 도구에 따라 저장소에 위치한 파일을 한 사람이 가져가는 경우 해당 파일에 대해 잠금(locking)을 적용한다. 잠금 상태에서는 체크아웃 한 사람이 파일을 다시 저장소로 보내기 전까지는 아무도 파일에 대한 수정 작업을 할 수 없게 된다. (역자 주: 저장소로 파일을 복사하는 과정을 체크인이라고 한다.)이렇게 엄격하게 잠금을 하는 방식의 버전 관리의 단점은, 종종 다른 개발자들의 수정 작업이 끝날 때까지 대기해야 한다는 점이다. 또한 체크아웃하고 나서 체크인하지 않을 경우, 자신도 모르게 수정도 하지 않는 파일을 잠궈 버리게 된다.
CVS는 잠금을 필요로 하지 않는 동시 수정 가능 방식을 사용한다. 개발자들은 CVS의 상충 사항을 발견하는 기능을 통해, CVS에서 가져온 파일을 동시에 수정할 수 있다. 상충되는 사항이 발견될 경우, CVS에서는 이를 해결해주는 도구를 제공한다. 이러한 방식은 위험해 보일 수 있지만, 실제 개발 환경에서는 매우 유용한 방식이다.
아예 상충이 나는 일 자체를 피하고 싶다면 CVS가 제공하는 파일에 대한 작업자 추적 정보를 이용할 수 있다.
동기화(synchronize), 갱신(update), 작업 공간의 수정 사항 반영(commit)
CVS 클라이언트를 사용하여 로컬 파일과 저장소 파일 사이의 동기화를 할 수 있다. 동기화 과정에서 로컬 파일과 CVS의 최신 모듈 사이의 차이점을 볼 수 있다. 이러한 차이들은 다음과 같이 분류 할 수 있다:
- Incoming changes - 저장소에 변경이 생겼지만 로컬 파일에는 반영이 안된 경우.
- Outgoing changes - 여러분의 로컬 파일에 변경이 생겼지만 저장소에는 반영이 안된 경우.
CVS 클라이언트에서 저장소의 변경 사항(incoming changes)의 일부 혹은 전부를 반영하여 로컬 파일을 갱신(update)할 수 있다. 모듈에 대한 쓰기 권한을 가지고 있는 경우, 로컬 파일의 변경 사항(outgoing changes) 중 필요한 만큼을 저장소에 반영(commit)하는 것도 가능하다.
상충
CVS는 자동적으로 저장소의 변경 사항과 작업 공간의 변경 사항 가운데서 상충하는 내용을 감지한다. 개발자 A와 B가 동시에 같은 파일을 수정하고, A가 먼저 이를 저장소에 반영하고 난 후에 곧바로 B가 자신이 변경한 내용을 저장소에 반영하려고 할 때 이러한 상충이 발생한다.
아래 다이어그램을 보자. 숫자로 된 화살표는 일의 발생 순서를 나타낸다. Alice가 Bob보다 먼저 변경사항을 저장소에 반영하고 Bob이 동기화를 하게 되면 Bob은 상충이 발생했다는 것을 알게 된다
상충되는 변경 사항 해결하기
파일에서 상충되는 변경 사항이 발견 될 경우, 파일을 저장소에 반영하기 전에 상충되는 변경 사항에 대해 병합(merge)을 수행해야 한다. CVS는 한 파일의 서로 다른 행의 변경 사항들에 대한 병합은 자동으로 수행한다. 다만 같은 행에서 변경이 발생할 경우, 개발자가 직접 병합 을 실행해야 한다. 나중에 보겠지만 이크립스는 개발자의 병합을 돕는 매우 훌륭한 GUI를 제공한다.
수정 작업자 추적
CVS에서는 동시 수정 가능 잠금 방식(optimistic locking)을 사용하여 누구라도 CVS 저장소에 접근에 동시에 파일을 수정 가능하지만, 누가 어떤 것을 수정하고 있는지 알아낼 수 있도 있다. 파일 수정 작업을 시작할 경우, 클라이언트가 이 사실을 서버로 알리도록 설정될 수 있다. 만약 누군가 파일을 수정하려고 하면 이미 그 파일이 수정 중이라는 경고를 받을 수 있다. 이것은 수정 사항의 상충을 피하는 유용한 방법이다.
태그
개발할 때 여러분은 종종 다음과 같은 이정표(milestones)들에 도달하게 된다:
- "기본 시스템은 작동중이고 모든 테스트는 통과 했음"
- "account 작업 전의 리팩토링"
- "account 작업 후의 리팩토링"
- "릴리즈 1.4"
- "발견된 D113에 대한 수정 완료"
이러한 이정표를 표시해두는 것(marking)은, 변경 사항을 추적하고, 필요한 경우, 이전 상태로 파일들을 되돌릴 수 있도록 보장해주는데 있어 필수적이다.
CVS에서는 모듈에 태그를 붙임으로써 이정표를 표시하게 된다. 태그는 모듈 안에 있는 각각의 파일들에 대한 단일 개정본(single revision)을 취합한다.
태그의 이름은 이정표와 관련있다. ALL_TESTS_PASS와 같은 것은 직관적인 예다.
사용자는 모듈의 태그가 부여된 개정본을 저장소에서 가져올 수 있다. 설령 태그가 삭제되거나 변경되었다 하더라도 태그가 붙었던 버전의 모듈 내용물은 항상 같을 것이다.
분기(branches)와 HEAD
분기(branch)는 일련의 독립적인 개발 흐름을 유지하기 위해 쓰인다. 기본적으로 저장소의 내용과 작업 공간의 내용의 동기화를 위해 update나 commit 명령을 사용하면, HEAD라고 불리는 기본 분기(trunk 라고도 불리운다) 상에서 작업이 이루어진다.
사용자는 필요에 따라 새로운 분기를 생성할 수 있다. 분기는 항상 루트 태그(root tag)라 불리는 태그부터 반드시 시작되어야 하며, 루트 태그의 이름에는 특별한 규칙이 없다.
분기를 사용하는 목적인 대개 공식 배포(release)의 병렬적인 개발을 관리하기 위함이다. 예를 들어 어플리케이션의 1.4 버전을 공식 배포(Release) 했고 계속해서 HEAD 분기에서 2.0 버전을 개발하기 시작했다고 해보자. 만약 치명적인 버그가 1.4 에서 발견되었다는 사용자의 보고가 있다면 RELEASE1-4-0을 루트 태그로 사용하여 분기를 만들 수 있다.
분기 상에서 작업을 시작했을 때, 모듈 내용은 1.4 정식 배포 버전과 완전 동일할 것이다. 이후부터 저장소와의 동기화는 해당 분기에만 적용될 것이다.
태그는 HEAD에서 정의되는 것과 마찬가지로 다른 분기에서도 정의 될 수 있다. 가능하다면 한 수준 정도(one level)의 분기를 고수하는 것이 가장 좋지만, HEAD 이외의 분기에서도 또 다른 분기를 만들 수 있다.
태그가 부여된 버전은 변하지 않는다.
모듈의 태그가 부여된 버전에 대해서는 변경 사항을 저장소에 반영할 수 없고, 수정을 하려면 루트 태그를 사용하여 분기를 생성해야 한다. CVS에서는 분기에 속한 변경 사항들만 저장소에 반영 할 수 있다. HEAD는 기본 분기로 특수한 형태의 분기이다.
분기의 병합
필요한 경우에 변경 사항을 특정 분기에서 다른 분기로 병합 할 수 있다. 예를 들어 위 그림에서, 버그를 수정한 1.4.1의 변경 사항을 2.0.0 정식 배포판에 포함시키기 위해서 HEAD 분기로 병합을 할 수 있다. 두 개의 분기 사이의 병합은 저장소와 작업공간의 변경 사항 동기화와 유사하며, 마찬가지로 상충이 발생하는 경우는 이클립스 GUI를 활용하면 좀 더 수월하게 해결할 수 있다.
이력 및 차이점 보기
CVS는 개별 파일이나 파일 조합의 변경 이력을 볼 수 있는 다양한 방법을 제공한다. 또한, CVS를 이용하면 각각의 수정본, 태그 그리고 분기들 사이의 차이를 볼 수 있다.
참고 자료
- 이클립스 3.0 도움말의 CVS를 이용한 팀 프로그래밍은 개념 수준의 개요를 제공한다.
- java.net의 간단한 CVS소개에서는 기존의 프로젝트에 수정 가능한 접근을 원하는 개발자들을 위해 몇가지 좋은 조언을 제공하고 있다.
- CVS를 이용한 오픈 소스 개발이라는 책은 매우 좋은 내용을 담고 있지만 명령 행을 통해 CVS를 사용하는 것을 전제하고 있다. 기본적인 개념을 설명하는 장에서 CVS에 관련된 거의 대부분의 사항을 다루고 있다.
- 이클립스가 설치 되어 있어야 한다. 1부의 선행 사항을 참조하라.
- java.net의 CVS 저장소에 연결하기 위해서는 최소한 읽기 권한을 갖는 사용자 계정이 필요하다. 쓰기 권한은 프로젝트 소유주나 개발자들만이 갖는다.
- 방화벽때문에 원격으로 CVS 저장소에 접근하지 못할 수도 있다 (CVS는 2401 포트를 사용한다).
- 여러분이 프로젝트의 소유주이며 CVS를 이용하여 프로젝트의 홈페이지를 관리하기 원한다면 프로젝트 preference의 설정을 다음과 같이 바꾼다.
- 이클립스의 preferences를 열고(Window->Preferences), 아래와 같이 CVS 통신 해제 시간을 600초로 설정한다:
여러분이 프로젝트의 소유주이고 아직 CVS에 프로젝트를 공유하지 않았다면 다음 절의 설명을 참조하라. 이미 특정 프로젝트의 개발자이거나 아직 참여하지 않은 프로젝트 내용을 조회할 수 있는 권한만을 갖고자 한다면 CVS 저장소의 프로젝트를 로컬 작업공간에 복사하기를 설명하는 절로 바로 이동해도 된다.
처음으로 프로젝트를 CVS에 등록하기(프로젝트 소유주만 가능)
지난 튜토리얼의 마지막 부분에서 만든 프로젝트의 이름은 javatools-demo였다. 그리고 약간의 코드와 JUnit 테스트 코드를 작성하였다.
java.net의 CVS 저장소에 접속하여 이 프로젝트를 공유해보자. 먼저 프로젝트를 선택하고, 마우스 오른쪽 버튼을 클릭하고 Team->Share Project...를 선택한다.
Share Project 대화 창에서 저장소의 상세 정보를 입력한다 (아래 표를 보라).
설정 항목 | 값 |
Host | cvs.dev.java.net |
Repository path | /cvs |
User | java.net의 사용자이름(역자 주:java.net 가입이 필요함) |
Password | java.net의 사용자 비밀 번호 |
Connection type | pserver (추가적인 보안을 위하여ssh 를 선택하는 것도 좋다. 추가적인 설명을 요하는 경우 이 글 을 참고하여라). |
Port | 그대로 사용한다. |
Save Password | 비밀번호를 이클립스가 기억하게 할 것인지 결정하라. |
"Next"를 클릭한다.
"Next"를 클릭한다.
"HEAD"를 선택하고 "Next"를 클릭한다. 마법사의 다음 페이지는 로컬 프로젝트 내용과 저장소에 있는 프로젝트 내용 사이의 차이점을 모두 보여준다.
프로젝트에서 마우스 오른쪽 버튼을 클릭하고 "Commit"을 선택한다. 이 명령은 이클립스의 모든 로컬 파일을 CVS에 저장한다.
다음 대화창은 CVS에 로컬 파일이 처음으로 추가된다는 것을 알려준다. "Yes"를 선택한다.이제 첫 수정본들에 대한 주석을 작성할 수 있다. 주석에 대한 작성이 끝나면 "OK"를 클릭한다.
이클립스가 모든 파일을 CVS로 저장 할 것이다.
"Use your project's www/index.html file as the project's description" 박스를 체크했다고 가정하면(선행 사항을 확인할 것.) 저장소의 변경 사항이 나열된 www/index.html 파일을 볼 수 있다. 프로젝트에서 마우스 오른쪽 버튼을 클릭하고 "Update"를 선택하여 CVS로 부터 이 파일을 작업 공간에 복사한다.
모든 것이 끝났다. 이제 여러분의 프로젝트는 이제 CVS와 연결되었다.
프로젝트와 프로젝트 내부의 모든 내용들에 이제 오렌지색 실린더가 표시되어 있다. 이는 CVS와 "연결되었음"을 나타내고 있는 것이다.
CVS 저장소의 프로젝트를 로컬 작업 공간에 복사하기 (프로젝트 개발자나 읽기 권한만을 가진 경우)
여러분이 프로젝트의 소유주이고 앞 절의 설명을 따라했었다면 이 절은 지나쳐도 무방하다.
Java perspective에서, Package Explorer 상에서 마우스 오른쪽 버튼을 클릭하고 "Import..."를 선택한다.
"Checkout Projects from CVS"를 선택하고 "Next"를 누른다.
다음 페이지에서 표 1을 참고하여 CVS 저장소와 사용자 상세 설정을 채워 넣는다.
"Next"를 누른다. 다음 페이지에서, 저장소로부터 복사해 오려는 프로젝트의 이름을 입력한다. 이 목록을 가져오는데 몇 분이 소요 될 수 있으며
프로젝트의 이름을 모른다면 아래와 같이 "Use an existing module"을 선택한다.
"Next"를 누른다. 다음 대화창에서 "Check out as a project in the workspace"를 선택하고 "Finish"를 누른다.
이제 이클립스가 여러분의 작업공간으로 프로젝트를 복사해올 것이다.
이 작업이 끝나면 작업 공간에서 프로젝트를 확인할 수 있다. 파일과 디렉토리 옆에 오렌지색 실린더가 붙어 있다면 이는 CVS와 연결되어 있다는 것을 나타낸다.
CVS 저장소 서버의 호스트 이름은 프로젝트 옆에 표시된다. 프로젝트의 각 파일은 그 파일이 이진 파일(binary)인지 텍스트 파일(ASCII)인지 표시한다. 대부분의 경우 기본 설정을 그대로 두어도 무방하지만, CVS preferences(Window->Preferences)를 통해 파일 형태에 따른 분류를 조정할 수 있다.
이클립스 프로젝트가 아닌 프로젝트를 작업 영역에 복사해오기
java.net의 모든 프로젝트가 이클립스 프로젝트인 것은 아닌다. 이클립스 프로젝트인지 알아보는 가장 빠른 방법은 Package Explorer에 있는 프로젝트 아이콘을 보는 것이다. 만약 파란색 "J" 심볼(javatools-demo처럼)이 있다면 이는 이클립스 프로젝트이다. 그러므로, 이클립스가 제공하는 자바 개발 기능을 바로 사용할 수 있다.
만약 "J" 심볼(아래의 javacc와 같이)이 없다면 불행하게도 이클립스의 자바 개발 기능을 사용하기 위해 몇가지 선행 작업을 해야 한다.
먼저 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼을 클릭한 다음 "Delete"를 선택하여 프로젝트를 삭제한다. 대화 상자가 떴을 때, "Also delete contents under..."를 선택한다.
프로젝트를 로컬 작업 공간으로 가져오기 위해 CVS 저장소의 프로젝트를 로컬 작업 공간에 복사하기절의 내용을 다시 수행한다. 이 때 Check Out As 페이지에서 "Check out as a project configured using the New Project Wizard"를 선택한다.
이제 "Finish"를 클릭하면 새로운 프로젝트 마법사가 나타날 것이다 .
"Java Project"를 선택하고 "Next"를 누른다.
다음 페이지에서 프로젝트의 이름을 적고 "Finish"를 클릭한다.
이제 Package Explorer에서 프로젝트 내용을 볼 수 있지만 아마도 많은 수의 빨간색 X표시를 볼 게 될 것이다.
만약 이러한 상황이 발생한다면, Problems 뷰를 살펴보아라. 아마도 프로젝트의 자바 컴파일 에러를 볼 수 있을 것이다.
![Eclipse By CVS #2 이클립스와 CVS를 이용한 팀 작업 (32) Eclipse By CVS #2 이클립스와 CVS를 이용한 팀 작업 (32)](https://i0.wp.com/dthumb-phinf.pstatic.net/?src=%22https%3A%2F%2Feclipse-tutorial.dev.java.net%2Feclipse-tutorial%2Fpart2_images%2Fpic030.gif%22&type=w2)
새로운 소스 폴더와 새로운 JAR 추가를 위해 프로젝트 클래스 패스를 설정해야 할 것이다. 이 경우, 1부에서 했던 클래스 패스 설정 부분을 수행하면 된다. 이 부분에 대하여는 자세히 다루진 않겠다.
자바 1.5(혹은 5.0) 프로젝트는 Eclipse 3.1을 필요로 한다. 이클립스 다운로드 페이지에서 이를 구할 수 있을 것이다.
복잡한 프로젝트에 있어서는 클래스패스 설정이 상당히 번거로운 일이 될 수 있다. 만약 이것들이 분명하지 않은 경우, 프로젝트 소유주와 클래스패스에 대해서 논의를 해볼 필요가 있다.이클립스는 .project와 .classpath 라는 이름을 가진 파일에 프로젝트와 프로젝트의 클래스 패스에 관한 정보를 저장한다. 이 두 파일은 프로젝트의 최상위 폴더에 있다. 만약 여러분이 프로젝트 개발자인 경우, 여러분이 프로젝트의 클래스 패스를 설정하고, 모든 것들을 제대로 컴파일 한 후, 이 두 파일을 CVS에 반영 할 수 있다. 여러분이 개발자가 아니라 하더라도, 소유주에게 이 파일들을 보내어 이들을 CVS 저장소에 반영하거나 다른 방법으로 이들을 사용할 수 있도록 만들어 달라고 부탁할 수도 있다. 다양한 종류의 IDE가 활용되는 프로젝트라면 이들에 대한 고려도 수반되어야 한다.
필자가 보았던 몇몇 프로젝트들에서 CVS가 .project와 .classpath파일을 무시하도록 설정해두고 있다. 필자는 그 이유를 잘 모르겠다. 만약 누군가 그 이유를 잘알고 있다면 포럼에 의견을 올려 공유해주길 바란다.
저장소와 작업 공간의 동기화 - 변경 내역에 상충되는 것이 없는 경우
이클립스의 리팩토링 도구를 이용하여 org.jtdemo.disply.CurrencyFomatter 클래스의 이름을 org.jtdemo.display.CurrencyForma으로 변경한다고 가정해보자. 이클립스는 자동적으로 연관된 클래스 파일에 바뀐 이름을 적용한다.
Package Explorer에서, Account.java와 TextDisplay.java 파일에 '크다' 기호(>)가 붙게 된다. 이것은 로컬 작업 영역에서 변경이 일어났다는 것을 가리킨다. CurrnecyFormat.java는 물음표(?) 표시가 붙는데, 이는 CVS가 전혀 알지 못하는 새로운 파일이라는 것을 나타낸다.
파일의 이름을 변경한 경우, CVS는 새로운 이름의 파일이 만들어지고, 기존 파일은 삭제된 것으로 간주한다.
프로젝트에서 마우스 오른쪽 버튼을 클릭하여 Team->Synchronise with Repository를 선택한다.
대화창이 열린다.
필자는 보통 "Remember my decision"과 "No"를 선택한다.(역자 주:각자의 기호에 따라 무엇을 선택하더라도 큰 문제는 없다.)
Synchronise 뷰가 나타나게 될 것이다. 이 화면은 저장소에 있는 프로젝트와 작업 영역의 복사본 파일 사이의 차이점을 모두 보여준다.
CVS에 추가할 변경 사항은 다음과 같다.
- Account.java가 변경되었다.
- CurrencyFormat.java가 생성되었다.
- CurrencyFormatter.java가 삭제되었다.
또한 로컬 작업 영역에 반영해야 할 변경 사항들은 다음과 같다.
- TransactionManager.java가 변경되었다.
- TransactionTest.java가 생성되었다.
로컬 작업 영역에 반영해야 하는 변경 사항은 누가 수정했는지 살펴보려면, 변경된 파일을 선택하고, 마우스 오른쪽 버튼을 클릭한 후, "Show in Resource History"를 선택한다.
다음의 CVS Resource History 뷰는 spiffy라는 프로젝트의 다른 개발자가 이를 변경했다는 사실을 보여주고 있다.
Synchronise 뷰에서 아무 파일이나 더블 클릭 해보면 로컬 파일과 저장소 파일 사이의 차이점을 볼 수 있다. TransactionManager.java 파일의 차이점을 확인해 보자.
"Java Source Compare"와 "Java Structure Compare" 모두 차이점을 보여준다. 멋지지 않은가!
로컬 작업 공간에 저장소의 변경 사항을 반영해보자. Synchronise 뷰에서, 프로젝트를 선택하고 마우스 오른쪽 버튼을 클릭하여 "Update"를 선택한다. 이렇게 하면 저장소의 모든 변경 사항이 작업 공간에 반영된다.
파일을 전부 받으면 동기화 뷰에서 변경 사항이 사라지게 된다.
변경된 파일들은 이제 작업 공간에 존재한다. TransactionManager.java 파일의 수정본 버전이 1.2가 된 것을 확인할 수 있다.
항상 저장소에 변경 사항을 반영하기 전에 로컬 작업 영역의 파일을 먼저 갱신하라.
항상 저장소에 변경 사항을 반영하기 전에 작업 공간의 파일을 저장소의 최근 변경 사항을 반영하도록 갱신하고, 다시 테스트를 수행 해야 한다. 이러한 절차가 저장소의 최근 변경 사항에 본인의 수정 사항을 정확하게 반영했음을 보장해준다.
이제 작업 영역의 변경 사항을 저장소에 반영한다. Synchronise 뷰에서 프로젝트를 선택하고, 마우스 오른쪽 버튼을 클릭한 후 "Commit"을 선택한다.
CurrencyFormat.java가 아직 CVS에 추가되지 않았다는 경고가 발생한다. "Yes"를 클릭한다.
변경 사항에 대한 주석을 적는다. java.net 저장소는 몇 가지 템플릿과 함께 자주 사용되는 주석들이 설정되어 있다. 이 템플릿은 프로젝트의 온라인 이슈 관리기 안에 있는 관련된 이슈 사항들에 변화가 있을때 사용된다. https://javatools-demo.dev.java.net/servlets/ProjectIssues가 그 예이다.
그러나 프로젝트들은 아직 이슈 추적 단계에 들어가지 않았기 때문에 전부 선택(Ctrl-A) 하고 자유로운 형태로 주석을 덮어쓴다.
Synchronise 뷰는 이제 우리의 작업 영역과 저장소 간에 어떠한 차이점도 존재하지 않는다는 것을 보여주고 있다.
저장소와 작업 공간의 동기화 - 변경 내역에 상충되는 것이 있는 경우
javatools-demo 예제 어플리케이션에는, martinpllu와 spiffy라는 두 명의 개발자가 참여하고 있다.
martinpllu는 방금 막 Transaction 객체가 문자열 형태로 표현되도록 로직을 리팩토링했다. 즉, 이 로직을TextDisplay.update() 메소드로부터 Transaction.toString() 메소드로 옮겼다. 그런 후, 그는 변경된 파일을 저장소에 반영했다.
반면, spiffy는 CurrencyFormat 파일을 삭제하였고, CurrencyFormat.format() 라는 메소드 호출 코드를 java.text.NumberFormat.getCurrencyInstance().format() 메소드 호출 코드로 바꾸어 버렸다.
spiffy가 작업 영역과 저장소의 동기화를 시도하자, 그는 저장소와 본인의 작업 영역의 파일 사이에서 상충되는 변경 사항이 있음을 발견하였다.
Account.java 파일을 더블 클릭을 하자, toString() 메소드가 로컬의 작업 영역에서 변경되었고, getName() 메소드가 다른 곳에서 추가되어서 CVS 저장소에 반영되었다는 사실을 보여주고 있다.
상충되는 부분이 있는데, 그 변경 사항이 서로 다른 행에 위치할 경우, CVS는 자동으로 변경 사항에 대한 병합을 수행한다.
TextDisplay.java 파일을 더블 클릭하면 update() 메소드가 작업 영역에서도 변경되었고, 저장소에서도 변경되었다는 사실을 보여주고 있다.
상충되는 부분이 있는데, 그 변경 사항이 동일한 행에 위치할 경우, 개발자가 직접 수정 사항에 대한 병합을 수행해야 한다.
spiffy는 프로젝트를 선택하고 마우스 우측 버튼을 클릭하여 "Update"를 선택했다. 그러자, 다음과 같은 경고 상자가 나타났다.
spiffy는 "OK"를 선택했다. 그러자, Account.java에 자동으로 병합이 적용되는 변경 사항뿐만 아니라, CVS 저장소의 모든 변경 사항들이 나타났다.
Account.java 파일의 변경 사항 중에서 저장소에 반영되지 않은 것은 하나(toString() 메소드를 추가한 것)뿐이다. 저장소의 변경 사항은 자동으로 병합되었다.
이제 spiffy는 TextDisplay.java 파일에서 상충되는 변경 사항만 직접 해결해 주면 된다. Java Source Compare 뷰어에서 Show Ancestor Pane 버튼 을 클릭하면, 변경된 두 개의 파일의 공통적인 원본을 볼 수 있다.
spiffy는 Transaction.toString() 메소드에 NumberFormat.getCurrencyInstance().format() 을 추가할 필요가 있다는 것을 알게 되어 Transaction.java 파일에 이를 반영하고, "Copy current change from right to left" 버튼 을 클릭하여, TextDisplay.java 파일의 변경 내용을 갱신하였다.
이 작업을 마친 후, spiffy는 TextDisplay.java 파일을 선택하고 "Mark as merged" 메뉴를 선택하였다.
TextDisplay.java 파일은 이제 작업 공간에만 변경이 가해진 다른 파일과 동일하게 보인다.
spiffy는 상충을 해결하고 나서 문제가 없음을 확인하기 위해서 관련된 모든 테스트를 수행하였다. 그리고 나서 저장소에 변경사항을 반영하였다.
주기적인 갱신
주기적인 갱신을 통해 상충되는 부분을 최소화하고 작업영역의 코드를 최신으로 유지하는 것이 좋다.
이클립스는 주기적으로 저장소와 작업 공간을 동기화 하는 자동화 기능을 제공한다. 이 때, 저장소의 변경 사항이 자동으로 갱신되지는 않는다 (이는 다소 위험을 초래할 수 있기 때문이다). 이클립스는 단순히 동기화를 실행하고 그 결과를 Synchronise 뷰에 보여준다.
일정에 따른 동기화를 수행하려면, Synchronise 뷰의 메뉴에서 "Schedule..."을 선택한다.
원하는 주기를 선택하고 OK를 클릭한다.
태그
프로젝트에서 오른쪽 마우스 버튼을 클릭하고, Team->Tag as Version 메뉴를 선택하면 프로젝트에 태그를 붙일 수 있다.
태그 이름을 입력한다.
"Move tag if it already exists" 옵션을 선택하면 기존의 태그를 이동시킬 수 있다.
이제 태그를 다양한 방법으로 사용할 수 있다. 예를 들면, 프로젝트에서 오른쪽 마우스 버튼을 클릭하고 Compare With->Another Branch or Version을 선택하면 "Versions" 아래에 태그가 나타난다.
또한 Replace With->Another Branch or Version을 선택하는 방법도 있다. 이렇게 하면 태그가 부여된 버전의 프로젝트 산출물을 작업 공간으로 가져온다:
비어있는 작업 공간으로 태그가 부여된 버전의 프로젝트를 불러오려면, 보통 체크아웃 마법사( checkout wizard)를 이용한다 (Checking out an existing project를 참조하여라). 그러나, 이 경우, 아래에 보여지는 것처럼 태그가 부여된 버전을 선택한다.
태그가 부여된 버전은 변하지 않는다.
만약 태그가 부여된 프로젝트를 작업 공간으로 가져올 경우, 이 프로젝트에 변경을 가할 수 없다는 사실을 명심하여라. 만약 변경 사항을 저장소로 반영하려 하게 되면, 다음과 같은 에러가 발생하는 것을 보게 될 것이다:
만약 태그 버전에 따라 변경을 가하고 싶다면, 태그를 루트로 사용하여 분기를 생성할 필요가 있다.
항상 프로젝트 수준에서 태그를 부여하는 것이 좋다.
비록 개별적인 파일, 패키지, 소스 폴더 등에 태그를 붙이는 것도 가능하지만, 항상 프로젝트 수준에서 태그를 부여하여라. 동일한 한 프로젝트 안에서 서로 다른 태그가 부여된 파일들과 폴더들을 섞어서 가져올 경우 혼란을 가져다 줄 수 있다. CVS는 이를 제대로 처리해주지 않는다.
CVS Repository Exploring perspective
"Window->Open Perspective->Other" 메뉴에서 CVS Repository Exploring perspective를 선택한다:
CVS Repositories 뷰는 사용 가능한 CVS 연결들을 보여준다.
저장소 내용들을 살펴보는 방법으로는 네 가지가 있다:
- HEAD는 각 모듈의 가장 최신 내용을 보여준다.
- Branches는 각 모듈에 위해 생성되었던 분기들을 보여준다.
- Versions는 각 모듈의 태그 버전을 보여준다.
- Dates는 사용자가 설정한 날짜에 지정한 모듈들의 내용을 보여준다.
"HEAD"를 펼친다 (프로젝트 목록을 가져오는데 다소 시간이 걸릴 수 있다).
아래로 스크롤 해가면서 자신의 프로젝트를 찾는다. 여기에서 가장 최근의 내용들을 볼 수 있을 것이다.
Branches, Versions 및 Dates 목록에 관한 부분은 여러분의 몫으로 남겨놓도록 하겠다.
분기
javatools-demo 개발자들은 공식 배포판(release) 0.1 빌드를 하나 작성하였고, 이 프로젝트에 V0-1-1이라는 태그를 부여하였다. 이것은 베타 테스트를 위해 배포되었으며, HEAD 상에서는 공식 배포판 0.2를 위한 개발이 진행되고 있다.
베타 테스터들은 급하게 변경을 요청하였다. 이 변경 사항에 대해서는 spiffy에게 맡겨졌다. spiffy는 우선 작업 공간으로 V0-1-1을 불러왔다:
그런 후, spiffy는 Team->Branch를 선택하였다:
새로운 분기에 대한 이름은 branchR0-1이 될 것이다.
spiffy가 OK를 클릭하게 되면, 이 분기는 작업 공간으로 불려지며, spiffy는 이에 대해 작업을 시작할 수 있게 된다.
spiffy가 변경 사항을 저장소에 반영하면, 이 변경 사항은 해당 분기에만 반영된다. 이 분기 상에서의 개발은 HEAD 상에서 진행되는 개발돠는 완전히 분리되어 있다.
변경 사항에 대한 작업 수행, 테스트 및 분기로의 반영이 이루어진 후, 이 어플리케이션은 빌드되고 테스터에게로 넘겨진다. 이 분기에는 V0-1-2이라는 태그를 부여하였는데, 이는 "공식 배포판 1.0의 빌드 2"라는 의미이다.
변경 사항들을 공식 배포판 0.2에 포함시키기 위해서는, 이 분기를 HEAD에 병합해야 할 것이다. spiffy는 먼저 Replace with->Another branch or version에서 HEAD를 선택하고 이를 자신의 작업 공간으로 불러왔다. 그런 후, Team->Merge를 선택하였다:
분기 루트 태그는 V0-1-1이었다.
"from" 분기는 branchR0-1이다:
이 분기는 이제 Synchronise 뷰를 사용하여 HEAD에 병합될 수 있다. 보면 알 수 있겠지만, 분기로부터의 저장소 변경 사항은 두 가지이다:
update를 선택하여 변경 사항들을 가져온다.
이제 변경 사항들은 작업 공간에 존재한다...
... 그런 후, 평소와 같이 변경 사항들이 저장소에 반영될 수 있다.
Watch/Edit를 통해 이력 정보(누가 무엇을 수정하고 있는지에 관한 정보) 추적하기
Introduction to CVS에서 언급했듯이, 누가 무엇을 수정하고 있는지 추적하도록 CVS를 설정할 수 있다.
Window->Preferences를 통한 preferences에서, "Configure projects to use Watch/Edit on checkout"을 선택한다.
프로젝트에 있는 어떠한 파일이라도 변경하게 되면, 변경한 사람은 해당 파일의 수정자(editor)로 등록된다. 이 파일 타인에 의해 변경되어 반영되거나, 해당 파일을 "unedit" (파일을 마우스 우측 버튼을 클릭한 후, Team->Unedit를 선택한다) 하지 않는 한, 해당 파일의 수정자 등록 정보는 그대로 남아있게 된다.
마우스 우측 버튼을 클릭해 Team->Show Editors를 선택하면, 누가 어떠한 파일을 수정하고 있는지 알아볼 수 있다:
만약 다른 누군가가 해당 파일을 수정하려 한다면, 이들은 다음과 같은 메시지를 보게 될 것이다:
이러한 방식 모든 프로젝트의 개발자가 "Configure projects to use Watch/Edit on checkout"을 사용할 경우에만 제대로 적용되어 동작한다.
CVS 웹 인터페이스
java.net에서는 CVS 저장소에 대해 읽기 전용 권한으로 접근할 수 있도록 해주는 웹 인터페이스를 제공하고 있다. 프로젝트 홈페이지에서 Version control - CVS 링크를 통해 이에 접근할 수 있다.
디렉토리들의 안에 들어 있는 내용들을 쭉 살펴볼 수 있다:
한 파일을 클릭하게 되면, 이 파일의 개정본 이력을 볼 수 있다:
HEAD로의 링크 구성
CVS에서 파일의 최신 버전을 항상 가리키도록 링크를 작성할 수 있다. 파이어폭스 브라우저의 경우, "Direct link to HEAD" 링크 상에서 마우스 우측 버튼을 클릭하고 "Copy Link Location"을 선택한다. 인터넷 익스플로러 브라우저의 경우, "Copy Shortcut"을 선택한다. 이는 해당 URL을 클립 보드록 복사한다.
예를 들면, 다음은 Account.java의 가장 최신 버전에 대한 링크이다: https://javatools-demo.dev.java.net/source/browse/javatools-demo/src/org/jtdemo/Account.java?view=markup
프로젝트의 웹 페이지 수정하기
여러분이나 프로젝트 소유주가 "Use your project's www/index.html file as the project's description" 박스(see 선행 사항을 살펴보아라)를 선택했다면, 프로젝트는 www/index.html 파일을 포함하게 된다.
다음은 예제 프로젝트인 https://javatools-demo.dev.java.net의 메인 프로젝트 페이지이다. 만약 이를 수정하고 CVS 저장소로 반영하게 되면, 해당 변경 사항은 즉시 온라인 상에 반영된다.
만약 더 많은 페이지가 필요하다면, www 폴더 아래에 필요한 페이지들을 두고 이들에 대한 링크를 포함시키면 된다:
만약 홈페이지가 복잡하다면, HTML 편집기를 사용하고 싶을 수도 있을 것이다. 이클립스를 위한 몇몇 HTML 편집기 플러그 인 들을 사용하거나 외부 편집기를 사용할 수도 있다 (Mozilla Composer는 매우 훌륭한 WYSIWYG 편집기이다).
외부 편집기 사용하기
만약 외부 편집기를 사용해 프로젝트 파일들을 편집하고 있다면, 이클립스에서 변경된 내용을 감지하기 위해 File->Refresh를 통해 프로젝트를 새로 고침(refresh)해야 한다.
CVS 키워드
키워드들을 사용해 CVS가 파일들에 동적으로 유용한 정보를 추가하도록 만들 수 있다. 이러한 정보의 예로는 마지막 가져온 날짜/시간에 관한 것을 들 수 있다. 자세한 내용은 도구 조언 부분을 참조하여라.
요약
여러분이 이클립스와 CVS 사용법에 대해서 충분히 이해했기를 바란다. 튜토리얼에 대한 질문이나 의견이 있다면 포럼을 이용하길 바란다.
다음 글에서는, 자동 빌드와 테스트 수행을 위해 이클립스에서 Ant와 JUnit을 사용하는 방법에 대해 살펴볼 것이다.
저자와 역자
Martin Pllu: 스코틀랜드 에든버러에 있는 Standard Life Assurance사의 Messaging & Java Infrastructure 팀 멤버이다. java.net에 호스트 되어있는 leafcutter와 tracetest같은 오픈 소스 어플리케이션의 개발자이기도 하다.