svn: Repository moved permanently to 'http://nextreesvn/common/'; please relocate
...
원인
SVN이 WebDAV로 서비스 되고 있고 SVN에서 tagging하기 위해 아파치 웹서버로 "PROPFIND /common HTTP/1.1" 요청을 하면 301을 응답합니다. 브라우저로 확인하거나 이클립스 subversive (subversion 플러그인)으로 별 이상없는데 maven release 플러그인에서 commit은 잘 되는데 svn tag 에서 이런 에러가 발생합니다.
Subversion(이하 SVN)의 log를 분석하여 지금까지 작업했던 파일의 내용을 분석하는 프로그램을 작성하는 중 기존에 있었으나 삭제되었던 파일을 읽다가 404 에러(HTTP를 사용했음)를 만나게 되었다. 이미 삭제된 파일의 내용은 읽을 수 없는 건가 이상하게 여기다 Peg Revision에 대한 이해 부족으로 발생한 결과임을 알게되었다. 다음은 Subversion의 Peg Revision에 대한 설명이다. 참조: http://svnbook.red-bean.com/nightly/en/svn.advanced.pegrevs.html
파일 복사/이동 이름 바꾸기 우리는 내내 컴퓨터의 파일을 복사/이동하거나 파일이름을 바꾸고 또는 파일을 완전 교체하기도 한다. SVN의 버전관리는 이러한 것들의 버전을 기대하는 수준만큼 잘 지원한다. CVS 같은 경우는 디렉토리 관리, 이름 변경, 삭제 후 다시 동일한 이름으로 생성할 경우를 제대로 지원하지 못했다. 이렇게 유연하게 지원하기 위해서는 버전이 붙은 것은 저장소 안에서 많은 버전 경로를 가질 수 있고 특정 경로에서 서로 다른 버전 객체를 가질 수 있어야 한다. 그렇기 때문에 이런 경로와 객체들을 접근하는데 어느 정도의 복잡함이 따른다.
SVN은 파일 복사/이동 이름바꾸기 버전을 지원한다. SVN은 "위치의 변경(changes of address)"을 포함한 객체 버전 내역을 똑똑하게 인지한다. 예를 들어 지난 주에 이름을 변경한 파일의 로그를 물어보면 SVN은 변경한 리비전뿐만 아니라 어떤 이름에서 어떤 이름으로 변경되었는지에 대한 로그를 잘 제공한다. 따라서 대부분의 경우 이러한 것들은 신경쓰지 않아도 변경내역은 잘 관리된다. 그러나 흔치 않지만 모호한 경우을 없애기 위해 당신의 도움이 필요한 경우가 있다.
복잡한 복사/이동 이름바꾸기 history 이러한 경우의 아주 간단한 예를 들자. SVN 저장소에서 디렉토리나 파일을 지우고 같은 이름으로 디렉토리나 파일을 SVN에 추가했다고 하자. 지웠던 것과 다시 추가한 것은 이름이 같더라도 같은 것으로 취급하면 안된다. 이 경로 이름을 /trunk/object 이라고 하자. 그럼 SVN에게 /trunk/object 를 요청하면 무엇을 뜻하는 것일까? 현재의 것인가? 아니면 지웠던 것인가? 그것도 아니면 그 경로에 있었던 모든 객체를 말하는 것인가? SVN은 당신이 진짜 원하는 것이 무엇인지에 대한 힌트가 필요하다.
좀 더 복잡하게 꼬아보자. 처음에 좀 연습해 보기 위한 프로젝트를 concept 이라는 디렉토리 이름으로 만들 수 있을 것이다. 마침내 그 아이디어는 현실화 될 수 있는 시점까지 성숙해서 프로젝트 이름을 결정했다. 이 소프트웨어를 Frabnaggilywort 이라고 하자. 이 시점에서 디렉토리 이름을 프로젝트를 반영하는 이름으로 변경하는 것은 상식이기에 concept 을 Frabnaggilywort 로 변경한다. 시간이 지남에 따라 Frabnaggilywort 는 1.0 버전을 릴리즈되고 많은 사람들이 이것을 다운받아 사용하여 그들의 삶이 윤택해 질 것이다.
멋진 스토리이지만 거기에서 끝나지 않는다. 창조적인 당신은 벌써 아이디어 창고에서 또 다른 것을 얻었다. 따라서 concept 이라는 새로운 디렉토리를 만들고 위의 싸이클은 또 반복된다. 사실 이러한 싸이클은 여러번 반복된다. 시작할 때마다 concept 디렉토리로 하고 어느 시점에서 아이디어를 나타내는 이름으로 변경한다. 어떤 경우는 그냥 삭제하기도 한다. 심하게는 concept 에서 잠시 동안 다른 이름으로 변경했다가 어떤 이유로 다시 concept 으로 바꾸기도 한다.
동일한 이름의 경로 처리방법 이러한 시나리오에서 SVN이 경로를 재사용하는 것을 설명하는 것은 "양재에서 강남역까지 가서 우회전하여 큰길로 쭉 500m 간 후 좌회전하여 큰길로 들어서"라고 가르치는 차 운전법과 비슷하다. 강남대로, 테헤란로, 양재대로 모두 큰길이라고 부르지만 같은 길은 아니다. 즉 강남대로에서 500m 가는 곳과 양재대로에서 500m 가는 곳은 서로 다른 위치이다. SVN에서 운전하는데는 올바른 길을 가기 위해서는 좀더 상세해야 한다.
Peg Revision SVN ver 1.1에서는 정확하게 어떤 큰길을 의미하는지 명시하는 방법을 소개한다. 이것을 peg revision (기준 리비전) 이라고 하고, 이것은 history에서 유일한 라인을 식별하기 위한 목적만을 위해 제공하였다. 버전관리되는 객체는 어느 시점(정확하게는 어느 리비전)이라도 하나의 경로를 가진다. 때문에 history의 특정 라인을 참조하기 위해 필요한 것은 "경로와 pge revision의 조합"으로 충분하다. Peg revision은 SVN 명령행 클라이언트에서 at 문법으로 표시한다. 경로 끝에 at "@" 표시와 그 뒤에 경로가 어떤 리비젼과 관련이 있는가 를 나타내는 peg revision이 붙는다.
svn command -r OPERATIVE-REV item@PEG_REV
Operative Revision 그리고 그 관계 여기서 --revision (-r)로 표시되는 일반적으로 부르는 리비전을 이야기해야 한다. 이 리비전은 operative revision이라 한다. 일단 경로와 peg revision으로 history의 특정 라인을 식별하면 SVN은 operative revision으로 요청을 실행한다. 이것을 위의 차 운전법과 비교하면 테헤란로 큰길의 테헤란로는 pge revision을 말하며 앞으로 500m 가라는 것은 operative revision을 말하는 것이 된다. 이 두개의 정보(경로와 peg revision)로 복잡한 history를 탐색하기 위한 유일한 경로라인을 식별하여 틀린 큰길에서 헤매지 않도록 한다. 이 유일한 경로로 앞으로 500m 가라고 operative revision을 사용할 수 있고 결국 어디로 갈지 정확히 알 수 있다.
Subversion은 가장 빨리 성장하고 앞선 오픈 소스 버전 컨트롤 시스템이다. SVNKit은 Subversion을 접근할 수 있는 순수 Java API이다. 즉 Java 프로그램으로 Subversion 저장소에서 checkout하거나 commit 하는 등의 일을 할 수 있도록 도와준다. (http://svnkit.com)
High Level API Subversion 사용자가 할 수 있는 작업들(checking out, updating, ... diff,...)을 할 수 있다. 비교적 사용하기 쉬운 API로 구성되어 있다. SVNClientManager 클래스를 이용한다.
Low Level API Subversion 저장소 모델을 따르며 이 API를 이용하여 직접 저장소를 다룰 수 있다. 빠르며 저수순의 API로 구성된다. SVNRepository 클래스를 이용한다.
JavaHL API 원래 Subversion은 JNI 바인딩을 제공하며 이는 JavaHL 인터페이스(SVNClientInterface)로 사용할 수 있다. SVNKit은 이를 SVNClientImpl로 구현해서, 코드변경없이 원래의 JavaHL과 SVNKit을 바꿔(switch)하여 사용할 수 있다. Jar 파일만 교체하면 된다.
여기에서는 간단하게 High Level API를 이용하여 checking out, update하는 예제를 보여줄 것이다.
Checking out
아래 코드는 svn checkout 과 동일하다.
public void checkout() { DAVRepositoryFactory.setup();
Subversion은 다양한 종류의 프로토콜을 지원한다. 사용할 프로토콜에 따라 RepositoryFactory를 setup해야 한다. 각 작업에 종류에 따라 획득해야 하는 client 종류가 다르다. checkout, update 종류의 작업을 위해서는 SVNClientManager로 부터 SVNUpdateClient 객체를 얻어야 한다.
API 시그니처 살펴보기
doCheckout은 시그네처는 아래와 같으며 각 파라메터에 대한 설명은 다음과 같다.
public long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException
파라메터
url: 저장소 URL
dstPath: checkout 할 디렉토리. Working Copy라고 한다.
pegRevision: 해당 revision을 체크아웃할 기준 revision이다. Peg Revision 대한 설명은 별도로 할 필요가 있다. Peg Revision에 대해 자세히 아는 사람이 그리 많지 않은 것 같다. 그냥 현재 시점에서 추출하려면 SVNRevision.HEAD나 SVNRevision.UNDEFINED을 사용해도 무방하다.
revision: 체크아웃할 리비젼
recursive: url이 디렉토리인 경우 하위의 모든 파일/디렉토리를 체크아웃할 지 여부