Home‎ > ‎

svn 유닉스 노트

이 문서는 SVN Tutorial of Unix문서를 참고하면서 정리해 둔 노트이다.

svn에 관련된 모든 파일을 저장하는 디렉토리 -> 저장소(repository)
저장소는 로컬의 디렉토리일 수도 있고 원격에 있을 수도 있고 HTTP를 통한 원격(웹 서버)일 수도 있다. 그래서 저장소를 지정하기 위해서 URL을 사용한다. (예> 로컬의 경우 file:// 이 된다.)

저장소 만들기:
svnadmin create --fs-type fsfs /home/user/svn

/home/user/svn 에 저장소를 만든다. fsfs는 저장소의 데이터 형식이다 (그 외에 버클리 DB형식 등이 있다)
저장소 내부에 어떻게 파일을 저장하는지는 신경을 안써도 된다. 중요한 것은 저장소를 하나의 평범한(그러나 다기능의) 디렉토리라는 점을 깨닿는 것이다.

저장소에 디렉토리를 만들어 보자.

svn mkdir file:///home/user/svn/foo -m "디렉토리 생성"

저장소의 내용을 보자.

svn ls file:///home/user/svn

삭제는 아래와 같이

svn rm file:///home/user/svn

다시 svn ls 명령으로 확인해 보면 삭제되어 있을 것이다.
여기까지는 그냥 평범한 디렉토리를 조작하는 느낌이다.

svn은 버젼을 유지하고 있다. 다음과 같이 변경 로그를 참고해 보자

svn log file:///home/user/svn

아래가 그 결과이다.

------------------------------------------------------------------------
r2 | user | 2010-03-17 16:47:47 +0900 (Wed, 17 Mar 2010) | 2 lines

디렉토리 삭제

------------------------------------------------------------------------
r1 | user | 2010-03-17 16:46:05 +0900 (Wed, 17 Mar 2010) | 1 line

디렉토리 생성
------------------------------------------------------------------------

프로젝트 import

svn import /path/to/project file:///home/user/svn/project/trunk -m "초기 생성"
Adding         /path/to/project/trunk
Adding         /path/to/project/trunk/doc
Adding         /path/to/project/trunk/doc/index.html
Adding         /path/to/project/trunk/src
Adding         /path/to/project/trunk/src/main.cpp
Adding         /path/to/project/trunk/src/Makefile
Adding         /path/to/project/trunk/bin

실행하면 /path/to/project 에 있는 모든 파일을 저장소의 project/trunk에 저장한다.(왜 trunk의 아래에 넣었는 지는 아래에 설명된다.)
-m 은 로그 메세지를 지정하는 필수 옵션이다. svn에서는 메세지를 생략할 수 없다. -m 을 생략하면 vi같은 에디터가 실행되어서 로그 메세지를 입력하게 된다. SVN_EDITOR 환경변수로 에디터 설정이 가능하다. 아직까지 /path/to/project 내에는 svn에 관련된 정보가 없다.

이제 아래와 같이 /path/to/project의 내용을 다 지우자.

cd /path/to
rm -rf project

프로젝트 checkout

이제 저장소에서 프로젝트를 checkout해보자.

svn checkout file:///home/user/svn/project

위에서 import 했던 파일들을 저장소로부터 복사해 올 것이다. 또한 svn에 관련된 정보도 생성되었다.

cd /path/to/project
ls -a

명령으로 확인해 보면 .svn 디렉토리가 존재하는 것을 확인할 수 있다. (연결된 저장소 정보도 들어 있어서 svn 명령에 더이상 저장소를 일일이 지정하지 않아도 된다)
이제 svn info 명령으로 확인해 보자.

svn info

프로젝트 진행

checkout 후, 파일 2개를 추가하고 원래 있는 파일들에도 수정을 가했다고 하자. 아래와 같이 해서 변경 상태를 확인한다.

cd /path/to/project/trunk
svn status
?      src/class.cpp
?      src/class.h
M      src/main.cpp
M      src/Makefile
?      bin/main

3개의 파일이 추가(? 마크)되어 있고, 2개의 파일이 변경(M 마크)되어 있다는 것을 알 수 있다.
여기서 소스에 해당하는 2개의 파일을 svn 관리하에 추가해야 한다. 

svn add src/class.h src/class.cpp
A         src/class.h
A         src/class.cpp

svn status로 확인하면 ?가 A로 바뀌어 있을 것이다. 이제 저장소로 커밋을 해야한다. (소스 수정 작업 완료했다면 말이다)

svn commit -m 'main에 있던 hello world출력 로직을 class로 이동'

실행 결과는 아래와 같다.

Sending        trunk/src/Makefile
Adding         trunk/src/class.cpp
Adding         trunk/src/class.h
Sending        trunk/src/main.cpp
Transmitting file data ....
Committed revision 4.

Send, Add? svn에서는 저장소에 데이터를 보내거나/받는다라고 용어가 통일되어 있다. copy, create, modify라는 단어 대신에 send, add, receive라고 표현한다. 여기서 주목할 라인은 가장 아래 라인이다.

버젼관리

변경을 commit했을 때 나온 버젼 번호 4, 이 숫자는 어디서 온 것일까? import한 것이 1, 이번에 커밋했으니깐 2나 1.1 이 되는 것이 아니고 4이다. svn은 CVS와는 다른 버젼부여 방식을 체택하고 있다. 어떠한 변경(디렉토리 생성/삭제, import, 커밋)을 가하더라도 모든 파일의 버젼 번호가 증가한다. foo 디렉토리를 생성했고, 삭제했고, import했고, 커밋을 했으니 4가 된 것이다. 무언가 변경을 가하면 저장소 자체가 새롭게 복사되는 형식이 된다. 즉, 버젼1 때의 저장소... 버젼2 때의 저장소... 버젼3 때의... 이렇게 말이다. 물론 실제로 모든 내용이 복사되는 것은 아니고 내부적으로는 변경사항(delta)만 관리된다. 파일 각각의 버젼이 관리 되는 것에 비하면 상당히 편한 방법이다.

버젼 4의 프로젝트를 checkout하는 예를 보자. tmp디렉토리로 가서 아래를 실행한다.
svn checkout -r 4 file:///home/user/svn project
A  project/project
A  project/project/trunk
A  project/project/trunk/doc
A  project/project/trunk/doc/index.html
A  project/project/trunk/src
A  project/project/trunk/src/main.cpp
A  project/project/trunk/src/class.cpp
A  project/project/trunk/src/class.h
A  project/project/trunk/src/Makefile
A  project/project/trunk/bin
Checked out revision 4.

보다 시피 버젼4에 해당하는 모든 파일을 가져오게 된다.
다시 tmp디렉토리에서 버젼 3을 가져와 보자.

svn checkout -r 3 file:///home/user/svn project
U  project/project/trunk/src/main.cpp
U  project/project/trunk/src/Makefile
D  project/project/trunk/src/class.cpp
D  project/project/trunk/src/class.h
Checked out revision 3.

자세히 보면 D(delete: 삭제)라고 표시된 파일 들이 있다. 버젼 4에는 있었지만 버젼 3에는 없는 파일들이다. 마찬가지 이유로 2개의 파일은 변경(U)이라고 나와있다.

버젼에 대해서 좀 더 자세히 조사해 보자. /path/to/project 디렉토리로 되돌아 가서 svn info 명령으로 확인해 보면

cd /path/to/project
svn info trunk/src/main.cpp

Path: trunk/src/main.cpp
Name: main.cpp
URL: file:///home/user/svn/project/trunk/src/main.cpp
Revision: 4

svn info trunk/doc/index.html
Path: trunk/doc/index.html

Name: index.html
URL: file:///home/user/svn/project/trunk/doc/index.html
Revision: 3

main.cpp는 4인데 index.html은 아직 3이다. 좀 전에 모든 파일의 버젼에 올라간다고 했는데 왠 3인가? 3은 그 파일이 가장 마지막으로 변경됬던 버젼 번호이다. 헷갈리기 시작한다. 그럼, 현재 프로젝트의 버젼을 구하려면 모든 파일 중에서 가장 버젼이 높은 것을 찾아야 한다는 말인가? 사실 결론부터 말하자면, svn에서는 이 버젼 번호에 메달릴 필요가 없다. 왜인지 이해하려면 계속해서 읽어 보길 바란다.

tag, trunk(그리고 branch)

앞서 파일들을 trunk라는 디렉토리에 담았던 것을 상기해 보자. 이제 그 이유를 알 수 있을 것이다. 버젼관리 측면에서 보면 프로젝트의 라이프사이클은 개발 - 커밋 - 릴리즈의 반복이다. 릴리즈를 하면 그 때의 상태를 기억시켜 두기 위해서 tag를 붙여두고 다음 릴리즈를 위한 작업을 계속하게 된다. 현재 작업중인 내용을 trunk또는 HEAD라고 한다. 그래서 처음에 trunk에 저장하는 것이다. 즉 svn에서는 버젼 번호가 아니라 주로 tag를 베이스로 버젼을 관리하게 된다. 아래에 tag를 사용하는 예가 있다.

이전까지 Makefile을 사용하고 있었지만 qmake라는 툴로 이전하고 싶다고 하자. 하지만 Makefile을 사용하는 버젼으로 되돌아 갈 수 있도록 현재의 버젼을 남겨 두는 것이 좋을 것이다. 이를 위해서 tag를 붙일 것이다. 앞으로 release와 같이 다른 태그를 붙이게 될 수도 있기 때문에 tag된 버젼을 관리하는 디렉토리를 준비하는 것부터 시작한다.

cd /path/to/project
svn mkdir tags
A    tags

이제 아래의 명령으로 trunk의 내용을 tags로 복사한다.

svn copy trunk/ tags/before-qt
A    tags/before-qt

이제 이 변경 내용을 저장소에 커밋한다.

svn commit -m 'qt화하기 이전 상태' tags/

Adding         tags
Adding         tags/before-qt
Adding         tags/before-qt/src/Makefile
Adding         tags/before-qt/src/class.cpp
Adding         tags/before-qt/src/class.h
Adding         tags/before-qt/src/main.cpp

여기까지 보면 trunk의 내용을 그대로 복사한 듯이 보이지만 svn 저장소 내부에서 일어난 일은 당시의 버젼에 before-qt라는 참조를 생성한 것 뿐이다. 이 before-qt 버젼을 저장소로 부터 checkout하는 방법은 아래와 같다. tmp 디렉토리로 가서 실행해 보자.

svn checkout file:///home/user/svn/project/tags/before-qt
A  before-qt/doc
A  before-qt/doc/index.html
A  before-qt/src
A  before-qt/src/main.cpp
A  before-qt/src/class.cpp
A  before-qt/src/class.h
A  before-qt/src/Makefile
A  before-qt/bin
Checked out revision 5.

이제 그 다음 시나리오를 생각해 보자. 팀을 2개로 나누어야 하는 일이 발생했다. 한 팀은 계속해서 새로운 버젼을 만들어 내는 작업을 진행해야 하고 또 하나의 팀은 릴리즈한 버젼의 버그 수정 등의 보수 작업을 해야 한다. trunk로 부터 2가지의 버젼으로 나누어져서 서로 독립적으로 진행되다가 마지막에는 하나로 병합될 것이다. 이를 branch하기(branching)이라고 한다. branch에 대해서는 다음에 다루기로 하겠다.

삭제&이름 변경

위의 예에서 태그를 붙여 두었기 때문에 이제 qmake작업을 시작해서 커밋 해도 될 듯 하다. .pro 파일에 설정한 내용 대로 자동생성될 Makefile을 삭제할 것이고. 그리고 src.pro를 작성할 것이다. 그리고는 아래의 명령으로 svn에 삭제와 추가를 한다.

svn rm Makefile
D    Makefile
svn add src.pro
A    src.pro

그리고 이제 생각한 것이 doc라는 디렉토리명 보다 html이라는 이름이 어울리는 것 같다. 아래와 같이 이름을 변경한다.

svn rename doc html

A     html
D     doc/index.html
D     doc

이제 커밋한다.

svn commit -m 'Switched to qmake. Renamed doc -> html'
Deleting       trunk/doc
Adding         trunk/html
Deleting       trunk/src/Makefile
Adding         trunk/src/src.pro
Transmitting file data .
Committed revision 6.

그 이외의 유용한 svn 명령어들

revert: 현재 디렉토리의 모든 변경사항을 되돌린다.
update: 다른 사람들이 커밋한 변경한 내용을 현재 디렉토리에 적용한다.
diff: 현재 디렉토리의 내용과 저장소의 내용을 비교한다.

server.com의 원격 저장소를 가리키는 URL예>

svn+ssh://server.com/home/user/svn

2010/03/17 허 련호(airless at funit.net)

Comments