15장 실전에서 발생하는 문제들

이재홍 http://www.pyrasis.com 2007.10.27 ~ 2008.04.20

목차

충돌 해결

프로젝트를 진행하다 보면 여러가지 문제에 직면하게 됩니다. 특히 버전 관리 시스템을 사용하여 여러 사람이 작업 할 때 서로 업데이트를 하지 않아 충돌이 발생하기도 하며, 커밋한 소스를 되돌리고 싶을 때도 있습니다. 이런 상황이 발생 했을 때 어떻게 해결하는지 설명하겠습니다.

충돌(Conflict)은 Subversion으로 여러 사람이 하나의 소스를 공동으로 작업할 때 자주 발생합니다. 즉 A라는 사람이 소스 코드를 수정하여 커밋하였고, B라는 사람은 A가 커밋한 부분을 수정한 채로 업데이트 했을 때 발생합니다. 즉 B의 작업 디렉터리 상의 내용과 저장소 상의 내용이 달라서 충돌이 발생한 것입니다.


그림 15-1 충돌 과정 1

A는 hello.cpp(리비전 6)의 printf("Hello World\n");printf("Hello trac\n");으로 수정한 뒤 커밋하였습니다. 리비전은 6에서 7로 증가하였습니다.

int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello trac\n");
    
    return 0;
}

B는 A가 소스 코드를 수정하여 커밋한 줄 모르고 업데이트를 하지 않은 채 리비전 6의 printf("Hello World\n");printf("Hello Subversion\n");으로 수정하였습니다. B의 작업 디렉터리는 아직 리비전 6입니다.

int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello trac\n");
    
    return 0;
}


그림 15-2 충돌 과정 2

B는 리비전 6을 기준으로 수정된 소스 코드를 커밋하려고 할 것입니다. 하지만, 저장소에 이미 수정된 hello.cpp(리비전 7)가 있기 때문에, 커밋을 실패하게 됩니다. 이런 오류가 발생하면 작업 디렉터리를 업데이트를 해야 합니다.


그림 15-3 커밋 실패, 업데이트가 필요함

B는 업데이트를 합니다. 하지만, B가 수정한 hello.cpp와 저장소의 hello.cpp(리비전 7)는 같은 부분이 수정되었기 때문에 아래와 같이 충돌이 발생하게 됩니다.


그림 15-4 충돌 경고

hello.cpp에는 충돌(삼각형 느낌표)아이콘이 표시되고 hello.cpp.mine, hello.cpp.r6, hello.cpp.r7이 생성됩니다. hello.cpp.mine은 B가 수정한 내용입니다. 즉 printf("Hello Subversion\n");으로 되어있습니다. hello.cpp.r6은 A가 수정하기 전 내용인 printf("Hello World\n"); 입니다. hello.cpp.r7은 A가 수정한 내용인 printf("Hello trac\n"); 입니다.


그림 15-5 충돌한 파일 hello.cpp

충돌한 hello.cpp를 살펴보면 다음과 같이 되어 있습니다.

// hello.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
<<<<<<< .mine
    printf("Hello Subversion\n");
=======
    printf("Hello trac\n");
>>>>>>> .r7
    
    return 0;
}

풀이하자면, B(mine)가 수정한 것은 Hello Subversion, A가 수정하여 커밋한 것(r7)은 Hello trac 이라는 뜻입니다.

hello.cpp를 선택하고 TortoiseSVN → 충돌 상황 편집(E)을 선택합니다.


그림 15-6 TortoiseSVN 충돌 상황 편집 실행 방법

충돌 상황 편집(E)을 선택하면 TortoiseMerge가 실행됩니다. 3부분으로 표시되는데, 왼쪽 위는 A가 printf("Hello World\n");printf("Hello trac\n");으로 수정한뒤 커밋하여 r7이 되었다는 것을 표시해주고 있고, 오른쪽 위는 B가 printf("Hello World\n");printf("Hello Subversion\n");으로 수정하였다는 것을 표시해 줍니다. 아래쪽은 printf("Hello World\n"); 부분이 충돌했다는 것을 표시해 주고 있습니다. 실제 충돌 해결 작업은 아래쪽 창에서 이루어지게 됩니다.


그림 15-7 TortoiseMerge로 충돌 상황 출력

Unresolved Conflict!! 부분을 선택하고 오른쪽 마우스 버튼을 누르면 다음과 같이 4개의 매뉴가 나오게 됩니다.


그림 15-8 TortoiseMerge로 충돌 상황 편집

  • Use text block from “theirs” : 왼쪽 부분을 사용하겠다는 것입니다. 이것을 선택하면 printf("Hello trac\n");을 사용하게 됩니다.
  • Use text block from “mine” : 오른쪽 부분을 사용하겠다는 것입니다. 이것을 선택하면 printf("Hello Subversion\n");을 사용하게 됩니다.
  • Use text block from “mine” before “theirs” : 왼쪽 부분과 오른쪽 부분을 동시에 다 사용하겠다는 것입니다. theirs 앞에 mine을 사용한다고 되어있으므로 이것을 선택하면 printf("Hello Subversion\n"); printf("Hello trac\n");을 사용하게 됩니다.
  • Use text block from “theirs” before “mine” : 왼쪽 부분과 오른쪽 부분을 동시에 다 사용하겠다는 것입니다. mine 앞에 theirs를 사용한다고 되어 있으므로 이것을 선택하면 printf("Hello trac\n"); printf("Hello Subversion\n");을 사용하게 됩니다.

여기서 Use text block from “theirs”을 선택하면 A가 수정한 것(Hello trac)을 받아들이고 B가 수정한 것(Hello Subversion)을 버리게 됩니다. 따라서 파일 내용은 Hello trac이 되고 리비전 7로 업데이트 된 상태가 되고 따로 커밋해야 할 것은 없습니다. Use text block from “mine”을 선택하면 A가 수정한 것(Hello trac)은 무시하고 B가 수정한 것(Hello Subversion)을 사용하게 됩니다. 단 B는 수정 된 내용(Hello Subversion)을 다시 커밋해야 합니다.

이번 예제에서는 B가 수정한 내용(Use text block from “mine”)을 사용하도록 하겠습니다. 이렇게 되면 아래쪽에는 printf("Hello Subversion\n");이 표시됩니다. 이제 저장 버튼을 눌러 내용을 저장합니다. 저장을 하지 않고 TortoiseMerge를 종료하게 되면 저장 여부를 확인하게 됩니다. 당연히 저장을 하지 않으면 아무 변화가 없게 됩니다.


그림 15-9 충돌 상황 편집 완료

TIP
실제 상황에서는 지금 예제와 같이 한 줄만 충돌 한 것이 아니라 여러 줄이 충돌해 있을 것입니다. 여러 줄 중에서 mine(내가 수정한 것)을 사용해야 하는 줄도 있을 것이고 theirs(남이 수정한 것)를 사용해야 하는 줄도 있을 것입니다. 각자 상황에 맞게 수정된 부분을 선택하면 됩니다.

이제 hello.cpp의 내용을 살펴 보면 다음과 같이 printf("Hello Subversion\n");으로 되어 있음을 확인할 수 있습니다.

// hello.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello Subversion\n");
    
    return 0;
}

아직 충돌이 해결된 것이 아닙니다. 충돌 아이콘이 남아 있는 상태에서 커밋을 하게 되면 다음과 같이 커밋이 실패하게 됩니다.


그림 15-10 커밋 실패, 아직 충돌이 해결되지 않음

충돌 아이콘이 남아 있는 hello.cpp를 선택하고 TortoiseSVN → 충돌 해결됨(O)…를 선택합니다.


그림 15-11 TortoiseSVN 충돌 해결됨 실행 방법

충돌을 해결할 파일이 나옵니다. hello.cpp만 선택했으므로 hello.cpp 만 나옵니다. 충돌한 파일이 여러개일 때에는 여러 파일이 표시됩니다.


그림 15-12 충돌을 해결할 파일 선택


그림 15-13 충돌 해결됨

이제 충돌 해결이 끝났습니다. hello.cpp의 충돌 아이콘과 hello.cpp.mine, hello.cpp.r6, hello.cpp.r7 파일이 사라졌습니다. 이제 B는 hello.cpp를 커밋하면 됩니다. TortoiseMerge에서 A가 수정한 printf("Hello trac\n");(Use text block from “theirs”)을 선택했다면 hello.cpp는 아무 변화 없이 초록색 아이콘으로 표시될 것입니다.


그림 15-14 충돌 해결이 끝났을 때의 화면

충돌이 해결 된 후 리비전은 7이 됩니다.

커밋한 것 되돌리기

프로젝트를 진행하다 보면 커밋한 내용을 되돌리고 싶을 때가 있습니다. 하지만, 이미 올라가버린 리비전을 다시 내릴 수는 없습니다. 커밋 한 내용을 되돌릴 때에는 병합(Merge)를 이용하면 됩니다. 이 병합 메뉴를 이용하여 이전 내용을 현재의 작업 디렉터리에 적용 시키고 다시 커밋하는 방식입니다.

hello.cpp라는 파일이 있고, 현재 리비전은 9입니다. printf("Hello trac\n");라는 내용을 가지고 있습니다.

// hello.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello trac\n");
    
    return 0;
}

이 hello.cpp를 printf("Hello Subversion\n");로 수정하여 커밋하였고 리비전은 10이 되었습니다.

// hello.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello Subversion\n");
    
    return 0;
}

다시 리비전 9의 내용으로 돌아가고자 한다면 체크아웃한 프로젝트의 최상위 디렉터리(C:\project\hello)에서 다음과 같이 TortoiseSVN → 병합(M)…을 실행합니다.


그림 15-15 TortoiseSVN 병합 실행 방법

여기서 설정해야 할 부분은 종료 부분에 리비전(R) 부분입니다. 이 부분에 되돌아가고 싶은 리비전을 입력합니다. 이번 예제에서는 리비전 9를 설정했습니다. 시작 부분의 리비전은 설정하지 않아도 됩니다. 주의할 부분은 “병합 결과가 저장되는 작업사본 위치:”가 체크아웃한 프로젝트의 최상위 디렉터리(C:\project\hello)가 맞는지 확인하는 것입니다.


그림 15-16 병합

비교 버튼을 눌러보면 현재 리비전과 리비전 9사이에 어떤 파일들이 바뀌었는지 표시됩니다.


그림 15-17 바뀐 파일들을 표시하는 화면

hello.cpp 파일을 더블클릭하면 어떻게 되돌려질지 표시됩니다. printf("Hello Subversion\n");printf("Hello trac\n");로 다시 되돌린다는 것을 알 수 있습니다.


그림 15-18 TortoiseMerge로 되돌려지는 내용 표시

병합 버튼을 누르면 리비전 9의 내용을 가져와 현재 작업 디렉터리에 적용하게 됩니다. 가상실행 버튼은 병합 버튼을 눌렀을 때와 똑같은 화면이 나오지만, 실제로 소스 코드를 되돌리지는 않습니다.


그림 15-19 병합 완료

이제 hello.cpp가 리비전 9의 내용으로 되돌려졌습니다. 커밋 로그에는 “리비전 9로 되돌림”이라고 기록하고 커밋합니다. 커밋을 하면 리비전 9의 내용을 가진 리비전 11이 됩니다.


그림 15-20 커밋한 것 되돌리기 완료

Trac 프로젝트, 저장소 이름 바꾸기

프로젝트를 진행하다 보면 프로젝트의 이름이 바뀔 때가 있습니다. 이번에는 Trac 프로젝트와 Subversion 저장소의 이름을 바꾸는 방법을 알아보겠습니다. Trac 프로젝트와 Subversion 저장소의 이름을 바꾸는 것은 특별한 명령이 있는 것은 아니고 Trac 프로젝트, Subversion 저장소 디렉터리의 이름을 바꾸어주는 것에 불과합니다. 이름을 바꾸더라도 Trac 프로젝트와 Subversion 저장소의 이름은 일치하는 것이 좋습니다. 이 두 부분의 이름이 다르다면 관리상 어려움을 겪을 수 있으므로 주의해야 합니다.

Trac 프로젝트와 저장소의 이름을 바꾸는 순서는 다음과 같습니다.


그림 15-21 이름 바꾸는 순서

  • 1. Apache를 정지시킵니다. 시작 → 모든 프로그램 → 보조 프로그램 → 명령 프롬프트를 실행하고 net stop apache2.2를 입력합니다.

  • 2. 탐색기를 실행하고 C:\Repos로 이동합니다. 바꾸고 싶은 프로젝트의 디렉터리를 선택하고 이름을 바꿉니다. 아래 예제에서는 hello 디렉터리를 world로 바꾸었습니다.


    그림 15-22 Subversion 저장소 이름 바꾸기

  • 3. C:\Repos 디렉터리의 authz 파일을 열고 hello로 된 부분을 world로 수정합니다.

[world:/]
* =
@developer = rw
  • 4. C:\trac으로 이동합니다. 마찬가지로 바꾸고 싶은 프로젝트의 디렉터리를 선택하고 이름을 바꿉니다. 여기서도 hello 디렉터리를 world로 바꾸었습니다. Trac 프로젝트와 Subversion 저장소의 이름은 일치시키는 것이 좋습니다.


    그림 15-23 Trac 디렉터리 이름 바꾸기

  • 5. C:\trac\world\conf 디렉터리 아래에 trac.ini 파일을 수정합니다. hello로 되어 있는 부분을 모두 world로 바꿉니다.

[project]
admin = 
descr = My world project
footer = Visit the Trac open source project at<br /><a href="http://trac.edgewall.org/">http://trac.edgewall.org/</a>
icon = common/trac.ico
name = world
url =

[trac]
authz_file = C:\Repos\authz
authz_module_name = world
auto_reload = False
base_url = 
check_auth_ip = true
database = sqlite:db/trac.db
default_charset = cp949
htdocs_location = 
ignore_auth_case = false
mainnav = wiki,timeline,roadmap,browser,tickets,newticket,search
metanav = login,logout,prefs,help,about
permission_policies = DefaultPermissionPolicy, LegacyAttachmentPolicy
permission_store = DefaultPermissionStore
repository_dir = c:\repos\world
repository_type = svn
show_email_addresses = false
timeout = 20
  • 6. Trac과 Subversion을 동기화 시킵니다.
    명령 프롬프트에서 C:\Python25\Scripts\trac-admin.exe c:\trac\world resync를 실행합니다.

  • 7. Apache를 다시 시작합니다.
    명령 프롬프트에서 net start apache2.2를 실행합니다.

이제 Trac 프로젝트와 Subversion 저장소의 이름을 바꾸었습니다. 아직 끝난 것이 아니고 각 개발자가 체크아웃한 작업 디렉터리의 저장소 URL을 바꾸어 주어야 합니다.

이제 개발자PC로 이동합니다. hello 프로젝트를 체크아웃한 곳으로 가서 TortoiseSVN → 저장소 URL 변경(C)를 실행합니다.


그림 15-24 저장소 URL 변경 실행 방법

대상 URL(T):에 이름을 바꾼 저장소의 경로를 입력합니다. hello에서 world로 바꾸었으므로 저장소 경로는 http://192.168.1.100/svn/world/trunk가 됩니다.


그림 15-25 저장소 URL 변경

“예”를 눌러 저장소 URL을 변경합니다.


그림 15-26 저장소 URL 변경 경고

개발자가 체크아웃 한 C:\project\hello 디렉터리도 C:\project\world로 바꿉니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.