SVN(Subversion) 사용하기
목차
SVN이란 여러 사람이 협업하는 프로젝트에서 소스 코드를 형상 관리하기 위한 툴이다.
아파치 소프트웨어 재단에서 개발 되었으며 아파치 라이선스를 따른다.
기본 설정 및 세팅
- 서버/클라이언트 구조
- 서버
- Linux 계열은 각 배포판의 패키지 관리자를 이용하여 쉽게 설치 가능(apt, yum 등)
- freeBSD 는 ports 또는 pkg 를 이용하여 설치 가능
- 설치 후 Repository를 관리 할 디렉토리 생성 후 SVN 서비스 시작
- 클라이언트
- Windows 계열
- TortoiseSVN
- RapidSVN
- …
- Windows 계열
- 서버
- TCP/IP 소켓 통신
- SVN 포트 : 3690
- SSH 를 이용하여 통신 가능 : 22
시작하기
- 형상 관리 될 소스 코드(프로젝트)의 Repository 생성하기
# 현재 위치는 SVN 서버의 Repository 디렉토리 ❯ pwd /home/svnsvr/repos # svnadmin 명령어를 통해 "cal-save"라는 저장소 생성 ❯ svnadmin create --fs-type fsfs cal-save ❯ l total 10 drwxrwx--- 3 root svnsvr 3B May 15 20:24 . drwxrwx--- 3 svnsvr svnsvr 3B Mar 22 09:05 .. drwxr-xr-x 6 jongbin svnsvr 8B May 15 20:24 cal-save
- [옵션] SVN 프로토콜을 사용한다면 해당 repository 설정이 필요함 SSH 사용할 경우 SSH 계정을 이용하기 때문에 필요 없음
- 접속 계정
- …
# Repository 설정을 위해 해당하는 저장소 하위 "conf" 디렉토리 이동 ❯ pwd /home/svnsvr/repos/cal-save/conf # passwd 파일을 수정하여 접속 계정을 설정한다. # svnserve.conf 파일을 수정하여 passwd 파일(접속계정)을 사용할 수 있도록 주석 해제 해제한다. ❯ l total 35 drwxr-xr-x 2 jongbin svnsvr 6B May 15 20:24 . drwxr-xr-x 6 jongbin svnsvr 8B May 15 20:24 .. - rw-r--r-- 1 jongbin svnsvr 1.1K May 15 20:24 authz -rw-r--r-- 1 jongbin svnsvr 885B May 15 20:24 hooks-env.tmpl -rw-r--r-- 1 jongbin svnsvr 309B May 15 20:24 passwd -rw-r--r-- 1 jongbin svnsvr 4.3K May 15 20:24 svnserve.conf
- [옵션] Hook 설정
혼자 시작하므로 우선 Skip- 예를 들어 커밋이 될 때 이메일을 송신한다던지 등 스크립트를 통해 훅 설정이 가능하다.
- 클라이언트에서 해당 저장소를 임포트 또는 체크아웃 하기
- 이미 진행한 프로젝트에 대해 형상 관리를 시작할 때
- 기본 구조 생성 후 해당 프로젝트를 trunk에 임포트 시키면 된다.
- 처음부터 저장소에 구조를 잡고 시작할 경우
- 저장소의 trunk 디렉토리 하위로 다시 체크아웃 하기
- 프로젝트 디렉토리를 열었을 때 trunk, branches, tags 등 형상 관리를 사용하기 위한 구조가 보일 필요는 없다. 따라서 임포트했던 프로젝트 또는 체크아웃하여 기본 구조 디렉토리를 만들었던 디렉토리는 지우고 다시 체크 아웃을 한다.
- 이미 진행한 프로젝트에 대해 형상 관리를 시작할 때
형상 관리하기
소스파일 추가
아래와 같은 구조로 소스를 추가했다고 가정한다.
# 현재 디렉토리는 Repository의 trunk C :\Users\jongbin\Desktop\source\cal-save-server C:. ├─doc │ cal-save-server.wsd │ ├─inc │ common.h │ pool.h │ ├─lib │ pool.cc │ └─src main.cc
- 해당 디렉토리를 SVN 컨텍스트 메뉴에서 “추가하기” 버튼을 눌러 추가한다.
- 프로젝트 디렉토리를 우클릭 하여 “커밋”을 누른다.
- 어떤 내용인지 자세히 적고 “확인”을 누른다.

수정 및 삭제
항상 작업 전 프로젝트를 저장소 최신본으로 만들고 작업하는 편이 좋다. 따라서 프로젝트 디렉토리를 우클릭하여 “업데이트”를 먼저 누른다.

우선 아래 최신 리비전의 “main.cc” 파일의 내용이다.
#include "common.h" #include "pool.h" using namespace std; int main(int argc, char **argv) { spdlog::error("test"); // 해당 라인 편집 Pool::init(); return 0; }
여기서 8번째 줄을 편집을 할 것이고 해당 내용을 커밋할 것이이다.
#include "common.h" #include "pool.h" using namespace std; int main(int argc, char **argv) { spdlog::info("start main function <<"); // 변경 Pool::init(); return 0; }
- 프로젝트 디렉토리 우클릭 후 “커밋하기”를 누른다.
- 수정 및 삭제된 내용을 포함하여 상세 내역을 작성한다.

- 삭제가 필요한 경우
- 저장소 및 로컬 모두 삭제
- SVN 메뉴에서 “삭제”를 클릭하여 삭제한다.
- 삭제된 내용을 “커밋”하여 저장소에 반영한다.
- 저장소만 삭제
- SVN 메뉴에서 “버전 관리에서 삭제하고 무시 목록에 추가”
- 해당 내용을 “커밋”하여 저장소에 반영한다.
- 저장소 및 로컬 모두 삭제
충돌 상황
충돌 상황이란 같은 리비전의 소스 파일을 서로 다른 작업자가 서로 다르게 수정했을 때 일어나는 상황으로, 서로 다르게 수정한 부분을 합의하여 하나의 파일로 만들어주는 과정이 필요하다.
충돌 상황을 가정하기 위해 같은 프로젝트의 저장소를 하나 더 체크아웃 한 후 같은 파일을 서로 다르게 수정한다.

작업자 0의 작업 사본 : cal-save-server
작업자 1의 작업 사본 : cal-save-server(conflict test)
작업자 0과 1 모두 “end main function” 이라는 로그를 남기는 소스를 추가하였다고 가정한다. 하지만 작업자 0과 1의 소스 내용이 아래와 같이 사소하게 다른 경우가 발생할 수 있다.
작업자 0의 소스 내용
#include "common.h" #include "pool.h" using namespace std; int main(int argc, char **argv) { spdlog::info("start main function <<"); Pool::init(); spdlog::info("end main function <<"); return 0; }
작업자 1의 소스 내용
#include "common.h" #include "pool.h" using namespace std; int main(int argc, char **argv) { spdlog::info("start main function <<"); Pool::init(); spdlog::error("end main function <<"); return 0; }
작업자 0과 1의 차이점은 해당 로그를 info로 처리하느냐 error로 처리하느냐의 차이
작업자 0은 해당 내용을 커밋하고 저장소에 반영했다. 그 후 작업자 1이 커밋을 하려고 보니까 최신의 리비전이 아니라 아래와 같은 오류가 발생했다.

업데이트를 하니 충돌 상황이 발생했다.

또한 파일들이 생성 되었다.
C:. │ CMakeLists.txt │ ├─doc ├─inc │ common.h │ pool.h │ ├─lib │ pool.cc │ └─src main.cc main.cc.mine main.cc.r3 main.cc.r4
main.cc
#include "common.h" #include "pool.h" using namespace std; int main(int argc, char **argv) { spdlog::info("start main function <<"); Pool::init(); <<<<<<< .mine spdlog::error("end main function <<"); ||||||| .r3 ======= spdlog::info("end main function <<"); >>>>>>> .r4 return 0; }
<<<<<<< .mine
내가 수정한 내용 (작업자 1의 내용 : error로 로그처리)
||||||| .r3
리비전 3의 내용 (해당 리비전에 아무 내용이 없었음)
=======
리비전 4의 내용 (작업자 0의 내용 : info로 처리 후 커밋한 내용)
>>>>>>> .r4
작업자 0과 작업자 1이 상의하여 충돌 상황을 편집하여 다시 main.cc 파일을 만들면 된다. SVN 메뉴에서 “충돌상황 편집”을 누르면 TortoiseMerge 에디터가 실행된다. 여기서 위쪽의 두 개의 서로 다른 소스파일을 갖고 아래 하나의 main.cc 파일을 만들면 된다.

상의 결과 main 함수가 종료되는 것은 error로 판단한다고 결론이 났으며 작업자 1의 내용으로 수정 및 커밋하기로 한다.
작업자 1의 소스 파일의 내용을 사용하기 위해 아래 물음표(?)로 된 두 줄을 선택한 후 아래 아이콘을 선택하여 하나의 파일로 병합 후 저장버튼을 누른다.


충돌 부분이 없다면 아래와 같은 팝업이 뜨고, 해결 완료 표시를 눌러주면 완료된다.

확장자가 .mine, .r3, r4가 없어진 것을 확인할 수 있고 해결된 내용을 커밋해주면 완료된다.
branch & tag
branch를 사용하는 목적은 아래와 같을 것이다.
- trunk 디렉토리에 공통된 모듈 및 레이아웃을 구성 후 사이트별로 프로젝트를 관리할 때
- 운영중인 trunk 소스에 기능을 추가할 때