2011년 12월 1일 목요일

SCM - 소스 변경 충돌 해결


요약

병렬 개발은 Jazz에선 늘상 있습니다. 우리는 여러분이 작성한 변경 사항을, 당신 팀과 공유할지 말지에 관계없이, 추적하고 버전관리할 수 있는 SCM의 기능에서 혜택을 받길 원합니다. 그런 이유로, 사용자는 개인 전용 저장소 작업공간을 갖습니다. 때때론 당신이 작성한 변경사항을 전달하기까지 두어시간만 걸릴 수도 있고, 하루가 될수도 있고, 더 길어질 수도 있습니다. 게다가, 소스제어 멀티 스트림 개발에 나와 있듯이, Jazz에서는 병렬 개발을 위해 스트림을 사용하는 것이 편리합니다. 이 자료는 충돌이 일어나는 일상에서 동료와 가까이 지내기 위한 가이드였음 합니다. 

목차

  1. 충돌 소개
  2. 충돌 인지
  3. 잠재적 충돌
  4. 충돌 제스처
  5. 충돌 유형
  6. 충돌 표현
  7. 충돌 해결
    1. 예 - Bill과 Markus가 같은 파일을 수정할 때
    2. 예 - Markus가 이름 변경한 파일을 Bill이 수정할 때
    3. 예 - Markus가 삭제한 폴더에 Bill이 파일을 추가할 때
    4. 예 - Bill과 Markus가 같은 파일의 특성을 다르게 설정할 때
    5. 예 - Bill이 아직 모르는 컨텐츠 유형의 파일을 자동해결할 때
    6. 예 - Bill과 Markus가 같은 이름의 파일을 생성할 때 ('evil twin')
    7. 예 - Bill과 Markus가 충돌하는 심볼릭링크를 만들 때
  8. 결론

충돌 소개

Jazz SCM은 낙관적 잠금 모델을 사용합니다. 명시적인 체크아웃이나 잠금없이 파일을 변경할 수 있습니다. 다른 사람도 자신의 저장소 작업공간에서 같은 파일을 또한 변경할 수 있습니다. 이런 결과로, 해당 변경 작업들을 같은 스트림이나 저장소 작업공간으로 통합할 때에는, 누군가가 충돌을 해결해야 합니다. 일반적으로 얘기하면, 충돌은 하나의 파일이 분기될 때마다 일어납니다 : 다시말해, 특정 파일의 두가지 상태는 같은 공통 조상을 가지며 두가지 상태는 저장소 작업공간에 허용되길 원합니다. 대개 충돌은 다른 팀 동료와 함께 작업할 때 일어나지만, Jazz에서는 혼자서 작업할 때 분기를 만들기도 합니다 : 변경 세트를 일시중단하고, 또 다른 변경세트에 같은 파일에 대한 변경 작업을 하고, 일시중단된 변경 세트를 재개하는 경우처럼.
(your repository workspace) S1 -> S3 -> S4
                                                                 ^
                                                                  |
(suspended)                                   S1 -> S2 

당신의 저장소 작업공간에 있는 파일의 초기 버전은 S1입니다. 해당 파일을 변경해서 버전 S2를 만듭니다. 그리고 나서 변경 작업을 일시중단합니다. S1->S2 일시중단된 상태입니다. S2 작업을 일시중단했기에, 저장소 작업공간상에는 S1이 재선택됩니다. 해당 파일을 수정해서 버전 S3를 만듭니다. S1->S3로 변경되었습니다. 일시중단된 상태를 재개하면 Jazz는 S2나 S3 중 어떤 것을 선택해야 하는지 알수 없으므로 충돌이 발생합니다. 충돌을 해결하기 위해 S2와 S3를 병합하고 새로운 상태 S4를 만듭니다. 물론, 충돌을 해결하기 위해 버전 S3 ("mine") 이나 버전 S2 ("proposed")를 유지할 수도 있었습니다. 충돌이 해결되면, 병합된 것으로 간주합니다.

이제부터는 JUnit 예제 프로젝트를 이용해서 충돌이 어떻게 발생하고 어떻게 해결하는 지를 보여줄려고 합니다. 이 프로젝트에는 두 사람의 개발자 Markus Kent와 Bill Cassavelli 등이 변경작업을 합니다. Markus는 빨리 작업을 하고 변경 작업을 스트림으로 전달합니다.  Bill이 그 변경작업을 자신의 저장소 작업공간으로 수신할 때는 대개 충돌을 해결해야 합니다. 그림 1은 예제 프로젝트 레이아웃을 나타냅니다.
Package Explorer showing the project layout
그림 1: 예제 프로젝트
 

충돌 인지

충돌을 예방하는 한가지 방법은 충돌을 회피하는 겁니다. Jazz는 당신처럼 같은 스트림으로 전달할려고 하는 다른 팀 멤버들이 작업한 변경 사항을 인지할 수 있도록 해줍니다. 당신이 수정을 하기 전 수신할 변경 사항을 먼저 허용하길 원할 때도 있고, 기다렸다가 나중에 통합하기로 결정할 때도 있습니다. 허용을 바로 할건지 말건지는 변경의 범위나 종류에 따라 달라집니다.

다시 예제로 돌아갑니다. Bill은 자신의 작업공간에서 몇개의 파일을 수정합니다. Markus도 몇개의 파일을 수정했고, 스트림으로 변경세트를 전달했습니다. Bill은 SimpleTest 클래스를 수정하기로 합니다. 그림 2에서 보듯이 해당 클래스 관련 수신할 변경 사항이 있다는 걸 뜻하는 수신 화살표를 봅니다. 

Package Explorer showing incoming and outgoing changes
그림 2: 수신할 변경 사항 표식
 

해당 파일에 대한 변경사항을 더 잘 이해하기 위해, 해당 파일을 선택하고, 팀 > 보류중인 변경사항 보기를 실행해 보류중인 변경사항 보기를 전시합니다(그림 3). 해당 파일과 관련된 모든 수신할 변경사항들이 강조됩니다. 각 변경사항을 더블클릭해서 변경 상세 내역을 확인합니다. Bill은 충돌을 회피하기 위해 진행 전 먼저 Markus의 변경사항을 허용합니다.

Incoming changes for file SimpleTest.java showing in Pending Changes view
그림 3: 수신할 변경 사항 탐색
 

잠재적 충돌

저장소 작업공간 상의 전달되지 않은 모든 변경사항들은, 다른 저장소 작업공간이나 스트림 상에서 같은 파일에 다른 누군가가 수정을 했을 수 있습니다. 만약 다른 스트림이나 저장소 작업공간에 그러한 파일의 분기가 있다면, 우리는 이를 잠재적 충돌이라 부릅니다. 여러분이 작업 중인 모든 파일들을, Jazz에서 모든 분기를 계속 추적할 수 없습니다. 대신에, 여러분이 작업중인 변경사항과 현재 플로우대상에 있는 변경사항을 추적합니다. 잠재적 충돌은 여러분의 저장소 작업공간과 현재 플로우 대상 간의 속성입니다. 플로우대상을 바꾸면, 잠재적 충돌 또한 바뀔수 있습니다. 
Jazz는 잠재적 충돌에 대한 인지해 줍니다. 그림 4에서 보듯이, 보류중인 변경사항 보기를 새로 고치면, 잠재적 충돌을 탐지합니다. 보류주인 변경사항 보기에서 하나의 파일을 선택하면, 같은 파일 관련 다른 변경사항을 강조하여 찾기 쉽도록 강조합니다. 비교편집기를 열어서각 변경 세트의 변경사항을 파악합니다. 
Pending Changes view shows potential conflict with Markus's change on SimpleTest.java
그림 4: 보류중인 변경사항 보기 상의 잠재적 충돌
 
추가로, 그림 5에서 보듯이, 패키지 탐색기 상에 잠재적 충돌이 있는 파일에 표식을 보여줍니다. 비교편집기는 실제 충돌이 없다면 충돌난 변경사항을 보여주지 않습니다. 잠재적 충돌이 있는 변경사항을 탐색할 수 있고 아직 해결할 건 없습니다.
Package Explorer shows potential conflict on SimpleTest.java file
그림 5: 패키지 탐색기 상의 잠재적 충돌
 
잠재적 충돌을 가진채로 전달할 순 없습니다. 당신은 변경 사항이나 변경 세트를 저장소 작업공간에서 제거하거나, 다음에서 보듯이 변경사항을 허용한뒤 충돌을 해결할 수 있습니다. 변경사항을 제거할려면, 아직 완료 안한 (그리고 이전 충돌과 관련이 없었던) 변경 세트에서 실행 취소하거나, 전체 변경 세트를 버리기하거나 일시중단할 수 있습니다. 그림 6은 Markus가 작성한 수신가능 변경세스와 잠재적 충돌하는 Bill의 변경세트를 일시중단한 뒤의 보류중인 변경사항 보기 모습입니다. 보류중인 변경사항 보기에 잠재적 충돌을 나타내는 표식이 더이상 보이지 않습니다.
Bill suspended his change set in the Pending Changes view
그림 6: 일시중단을 통한 잠재적 충돌 정리
 

충돌 제스처

충돌은 변경사항을 저장소 작업공간으로 허용할 때 발생합니다. 잠재적 충돌이 현재 플로우 대상과 관련있으며 지속되지 않는 반면, 충돌은 저장소 작업공간의 속성으로 해결될 때까지 지속됩니다. 저장소 작업공간에 충돌을 추가시키는 두가지 주요 UI 제스처가 있습니다:
  • 변경사항 허용하기
    • 협력 작업하는 스트림으로 부터 허용할 때 보류중인 변경사항 보기에 충돌이 나타날 수 있습니다.
    • 작업항목이나 다른 저장소 작업공간 또는 스트림의 이력보기로 부터 변경세트를 허용할때 충돌이 나타날 수 있습니다.
  • 일시중단된 변경사항을 재개하면 충돌이 발생할 수 있습니다.
잠재적 충돌을 현시한 변경사항을 허용하기로 결정하면, 저장소 작업공간은 해결해야 할 충돌을 포함합니다. 변경사항을 허용할 때 잠재적 충돌을 (플로우대상으로 전달을 해야하는 등) 피할수 없다면, 병합이 필요합니다. 충돌을 도입하기 전에, 충돌을 대하는 두가지 방식이 있습니다 : 선행 병합, 역행 병합. 일종의 작업 방식에 대한 기호입니다.  
  • 선행 병합: 첫번째 방식에서는, 당신이 한 작업 위에 수신할 변경사항을 병합하고자 합니다. 기본적으로 당신은 비교편집기에서 당신 작업에 다른 변경사항을 어떻게 적용할 지 명백히 알고자 합니다. 특별히 할건 없고, 수신할 변경사항을 허용할 뿐입니다. 충돌한다고 모든 걸 적용하진 않습니다. 당신은 충돌을 해결하려 당신 작업 위에 제안된 변경사항을 병합합니다.
  • 역행 병합: 두번째 방식에서는, 당신은 다른 사람의 작업 위에 당신의 변경사항을 병합하고자 합니다. 기본적으로 당신은 스트림을 따라잡은 후 그 위에 당신의 변경사항을 재적용합니다. 이를 위해서, 당신이 송신할 변경세트를 일시중단하고, 수신할 변경세트를 허용하고나서, 일시중단된 변경세트를 재개합니다. 충돌한다고 당신의 모든 변경사항을 적용하지 않습니다. 당신은 이전에 만든 변경사항을 최신 현존 세상 위로 병합합니다. 이 방식은 당신의 변경사항에 충돌이 발생했던 최초시점일때만 사용가능합니다. 일단 병합과 충돌해결 작업을 마친 뒤에서 더 이상 해당 변경세트를 일시중단할 수 없으며 그 이유는 이전에 해결했던 충돌이 재도입될 수 있기 때문입니다. 대신, 선행 병합 방식을 사용할 수 있습니다.
잠재적 충돌은 충돌보다는 덜 급합니다. 잠재적 충돌을 언제 다룰지는 여러분 맘에 달렸습니다. 충돌이 있을때, 언제 어떻게 해결할지도 여러분 맘입니다. 모든 충돌 해결 작업은 보류중인 변경사항 보기에서 진행합니다.

충돌 유형

Jazz에서, 충돌은 두가지 유형으로 나뉩니다: 내용 (파일의 내용이 분기됨) 및 구조.  내용 충돌은 흔합니다. 구조 충돌은 리팩토링시 발생하는 경향이 있습니다.  구조 충돌이 일어나는 경우는:
  • 두사람이 같은 파일/폴더를 추가할때 ("evil twin" 충돌로 알려져 있음)
  • 한사람이 삭제할 폴더에 다른사람이 해당 폴더로 파일/폴더를 추가하거나 옮길때
  • 한사람이 삭제한 파일/폴더를 다른사람이 옮기거나 수정할때
  • 두사람이 같은 파일/폴더를 다른장소로 옮기거나 이름을 바꿀때
  • 한사람이 이미 같은 이름의 파일/폴더를 추가한 폴더에 다른사람이 같은 이름의 파일/폴더를 그 폴더로 옮길때
어떤 충돌은 다른 것보다 해결이 더 쉽습니다.  당신 대신 Jazz에서 변경사항을 병합할 수 있는 자동 병합 가능 충돌이 있습니다. 어떻게 병합할지 결정을 필요로 하는 실제 충돌이 있습니다. 다른 충돌때문에 적용할 수 없는 변경사항을 일컫는 부수 충돌도 있습니다. 실제 충돌을 해결할 때, 어떻게 충돌을 해결했는 지에 따라 부수 충돌이 동시에 자동 해결될 수 있습니다.  

충돌 표현

잠재적 충돌은 오랜지색충돌은 빨간색으로 표시됩니다. 각 충돌에는 충돌과 가능한 조치에 대한 설명을 담은 툴팁을 제공합니다. 아이콘을 통해 구조 충돌인지 내용 충돌인지 알려줍니다. 밝은 회색은 부수 충돌을 나타냅니다. 그림 7, Bill은 AllTests.java를 수정했고. Markus도 같은 파일을 수정했습니다. Bill은 Markus의 변경사항을 자신의 작업공간으로 허용했고, 이제 AllTests.java에 충돌이 있습니다. 툴팁은 충돌과 해결방안을 좀더 자세히 설명합니다.


Bill has a conflict on AllTests.java showing in the Pending Changes view
그림 7: AllTests.java 파일 충돌 해결 방안을 설명하고 있는 툴팁
 

충돌 해결

여러분에게 충돌이 일어난다면, 어떤 옵션이 있을까요? 많습니다! 충돌을 야기한 변경사항을 실행취소하거나, 변경사항을 다시살펴 구조충돌을 막거나, 내용을 병합하거나, 작업공간상의 다른 장소로 수신할 파일/폴더를 옮기거나, 다른사람으로 하여금 그들의 변경세트를 되돌리게 한거나, (당신 거나 또는 허용한) 변경세트를 버리거나, 당신의 변경사항만 적용하거나, 허용한 변경사항만 적용하거나 등등 모두 충돌의 유형과 여러분이 해결하는 방식에 달려 있습니다. 다음 두 예제는 흔히 만나게 되는 충돌 유형을 예시합니다.

예1. Bill과 Markus가 같은 파일을 수정을 한뒤, Bill이 춛돌 비교 편집기를 이용해 변경사항을 병합합니다.

Bill은 AllTests.java, SimpleTest.java, VectorTest.java를 수정했습니다.  Markus도 같은 파일들을 수정했습니다. Bill은 Markus의 변경세트를 저장소 작업공간으로 허용했고, 이로써 AllTests.java, SimpleTest.java, VectorTest.java에 충돌이 있습니다. Markus의 변경사항을 허용한 즉시 그림 8처럼 충돌 자동 해결할 지를 묻는 대화상자가 나타납니다.
Auto Resolve Conflicts dialog
그림 8: 충돌 변경사항 허용 뒤 자동 해결을 제안하는 대화상자


Bill은 대개 그냥 '자동 해결'을 클릭합니다. 이번에는 '나중에 해결'을 클릭해 프롬프트를 무시합니다. 그러면 그림 9처럼 보류중인 변경사항 보기에 해결되지 않은 충돌이 나타납니다. He knows he can also 'Auto Resolve' the conflicts later in the Pending Changes view.

Pending Changes view shows three files in conflict for Bill
그림 9: Bill 작업공간 상의 JUnit 콤포넌트 아래에 나타난 세개의 내용 충돌
 

각 충돌에서 제공하는 툴팁은 '자동 해결'을 제안합니다. Bill이 자동 해결을 실행했을 때, 
두개의 파일 SimpleTest.java 및 VectorTest.java에 대해선 Markus의 변경사항이 성공적으로 Bill의 변경사항과 병합되었습니다. 그림 10은 AllTests.java만이 충돌이 있다고 나타냅니다.
Auto Resolve merged two conflicts in the Pending Changes view
그림 10: 세개의 내용 충돌 중 두개에 대해 성공적으로 자동 해결로 병합함
 

Bill은 
AllTests.java의 내용을 그림 11과 같이 충돌편집기를 이용해 수작업 병합을 하기로 합니다.

Conflict Compare Editor allows Bill to merge in Markus's conflicting change into his local copy of AllTests.java
그림 11: 내용 충돌을 수작업 병합하기 위해 충돌 편집기 사용함


Markus는 MoneyTest test suite 라인 주석을 풀었고 Bill는 해당 변경사항을 존중합니다. 충동편집기를 이용해 Markus의 변경사항을 자신의 로컬 파일로 병합합니다. 작업이 완료되면, 파일을 저장(Ctrl-s)하고 병합하여 해결 실행합니다. 보류중인 변경사항 보기에서 충돌은 사라지고, Bill은 변경 사항을 스트림으로 전달합니다. 그림 12.

Pending Changes view shows no conflicts
그림 12: 충돌이 해결되어 변경세트를 스트림으로 전달할 수 있음
 

Markus와 Bill은 여느 자원에 대한 히스토리 보기 상에서 이전 변경사항이나 병합을 알아볼 수 있습니다. 그림 13은 
SimpleTest.java 자원에 대한 변경 히스토리를 나타냅니다.
Previous changes and merge for the resource SimpleTest.java
그림 13: 자원 SimpleTest.java은 Bill이 병합했음
 


첫열의 병합 그래프는 Bill과 Markus가 
파일의 같은 초기버전을 수정했다는 것을 알려줍니다 - 각 사용자가 만든 버전이 초기버전과 직접 연결되었습니다. 그래프 최상단 노드는 두개의 인입라인를 갖습니다. 즉, 두 버전의 내용이 함께 병합되었습니다. Bill의 가장 최근 변경사항과 Markus의 변경사항이 병합되었습니다.

The next example illustrates how Auto Resolve takes care of merging your content changes into a resource that has been renamed in the stream.

예2: Markus가 개명한 파일에 Bill이 내용을 추가합니다. 그리고 개명한 파일에 변경사항을 자동 해결을 시도합니다.

Bill은 JUnit 테스트용 SimpleTest.java에 테스트 메쏘드 testBoolean()를 추가합니다. Markus는 JUnit 테스트를 리팩토링하고 SimpleTest.java를 ComplicatedTest.java로 개명합니다. 그림 14은 Bill이 SimpleTest.java에 잠재적 충돌을 가짐을 보여줍니다.
Pending Changes view shows potential conflict on file renamed by Markus and modified by Bill
그림 14: SimpleTest.java에 대한 송신할 수정과 수신할 개명간의 잠재적 충돌

Bill은 Markus의 변경세트를 허용합니다. 이를 통해 내용 충돌(Bill은 내용을 추가, Markus은 Java 클래스명을 변경)과 구조 충돌(Markus가 파일명을 변경) 둘다 발생합니다. 그림 15, Bill은 마우스를 충돌 아이콘 위에 가져가 어떻게 충돌을 해결할지에 대한 툴팁정보를 얻습니다.

User can get detailed tool-tips by hovering on a conflict in the Pending Changes view
그림 15: SimpleTest.java에 대한 내용 충돌과 이동 충돌
 

Bill은 Markus의 개명 결정에 동의합니다. 자신의 변경사항(새 메쏘드 추가)을 Markus의 변경사항과 병합하려 합니다. 툴팁이 제안한 '자동 해결'을 선택합니다. 충돌이 사라집니다, 그림 16. Bill의 송신가능 변경세트는 새 이름을 참조합니다.

Pending Changes view shows Auto Resolve successfully merged Bill and Markus's changes
그림 16: 충돌 해결됨
 

Bill은 송신가능 변경사항을 선택해서 변경 비교 편집기를 엽니다. Bill은 자동 해결로 Markus가 개명한 테스트 파일에 자신의 새 메쏘드가 삽입되었음을 확인합니다, 그림 17.

Compare Editor shows Bill's outgoing change
그림 17: 충돌 해결됨
 

애자일 환경에서는, 자주 리팩토링이 발생합니다. Jazz 자원은 히스토리 손실없이 개명됩니다. Jazz는 내부적으로 각 자원에 고유 번호를 부여하고, 자원의 상태, 이름, 부모 폴더를 기억하기에 가능합니다. 자동 해결은 위와 같은 일상적인 구조 충돌을 처리합니다.

다음 예들은 조금 덜 발생하는, 보다 진전된 충돌유형을 다룹니다. 대개 광범위한 리팩토링 작업으로 누가 무엇을 하는 지를 이해하기 힘들 때 발생합니다. 다음 경우는 한 폴더 전체를 삭제하고 다른 사람은 그 폴더내 자원에 대한 변경사항을 전달한 상황입니다.

예3: Bill은 폴더를 삭제하고, Markus는그 폴더에 파일을 추가합니다. Bill은 Markus의 변경사항을 '이동'으로 재배치합니다.

Bill은 프로젝트에서 Money 코드를 삭제키로 합니다. 그는 money 패키지와 모든 내용을 삭제합니다. 그리곤, Markus가 삭제했던 폴더에 새 JUnit 테스트를 릴리즈했음을 알아챕니다, 그림 18.
Pending Changes view shows Markus added a file into the folder Bill deleted
그림 18: 송신가능 폴더 삭제와 수신가능 해당 폴더에 파일추가 간의 잠재적 충돌
 

Bill은 Markus의 수신가능 변경세트를 조사합니다. 그는 Markus의 새 테스트가 필요하지만, VectorTest.java 파일과 함께 같은 samples 패키지에 있어야합니다. Bill은 Markus의 변경세트를 허용하고 Markus의 새 테스트 관련 구조 충돌을 조사합니다. 여느 때처럼, Bill은 충돌관련 툴팁을 통해 옵션을 평가합니다, 그림 19.

Pending Changes view shows a structural conflict
그림 19: 구조 충돌관련 툴팁
 

Bill은 Markus의 새 테스트를 samples 폴더로 옮기기로 합니다. 메뉴을 통해 이동합니다, 그림 20.

Bill selects 'Move' under the popup menu of the conflicted resource
그림 20: 충돌 항목 이동... 조치


충돌 항목 이동 창이 나타납니다. Bill은 충돌항목을 작업공간 상의 아무 폴더로 이동할 수 있습니다. 그는 ListTest.java를 samples 폴더로 이동합니다, 그림 21.

Move Conflicted Items dialog allows Bill to move the conflicted item to any folder under his workspace
그림 21: 총돌 항목 이동 참
 

Bill은 충돌항목 이동 창에서 OK를 클릭합니다. 충돌은 사라지고, Bill은 samples 패키지 아래에 Markus의 새 테스트 ListTest.java를 볼수 있습니다. 그는 Java 파일을 수정해 새 폴더로 패키지 선언을 변경합니다. 모든 컴파일 성공 후, Bill은 변경 세트를 전달합니다. 그림 22는 ListTest.java가 samples 폴더로 이동된 걸 나타냅니다.

Pending Changes view shows no more conflict
그림 22: 충돌이 해결되어 변경세트 전달가능함
 

Bill은 충돌을 해결하기 위해 최선의 선택을 했습니다. 다른 상황에선, 모든 Money 코드를 삭제한 후 Bill은 Markus의 새 테스트가 필요없다고 결정할 수도 있습니다. 그럴 경우, 자원 
ListTest.java에 대한 충돌을 내 변경사항으로 해결하면, ListTest.java 파일은 money 폴더와 함께 삭제되어 충돌이 해결됩니다.

혹은 money 폴더를 삭제하는 것이 좋지 않다고 판단하고, Bill은 money 패키지와 하위 모든 내용을 삭제하는 송신가능 변경 세트를 간단히 버리기 할수도 있습니다.

예4 - Bill과 Markus가 같은 파일에 다른 파일 특성을 설정합니다.

Bill은 새 파일 query.xml을 허용하고, 파일 특성을 조사합니다 (그림 23).
File properties for resource query.xml
그림 23: 자원 query.xml에 파일 속성이 부적절히 설정되어 있음
 


Markus가 체크인한 자원 query.xml에 대한 MIME 유형 application/unknown과 행 분리문자 Mac을 보고 탄식합니다. 디폴트 설정 즉text/plain과 Platform가 더 좋았을겁니다. Bill은 디폴트로 설정하고 'Finish'를 누른 뒤, 변경사항을 전달하려 합니다. Markus가 한발 먼저 해당 자원에 대한 파일 특성을 바로잡은 변경세트를 전달합니다. Bill이 해당 변경세트를 허용하여 충돌이 발생합니다 (그림 24).

Conflict on file properties for query.xml
그림 24: Bill과 Markus 둘다 자원 query.xml에 대한 파일 특성을 수정함
 

Bill이 충돌항목을 더블클릭해 충돌 비교 편집기에서 차이점을 조사합니다 (그림 25).
Compare Editor showing file properties for resource query.xml
그림 25: 충돌 비교 편집기 상의 query.xml의 MIME 유형과 행 분리문자 설정 충돌
 
충돌이 두건 있습니다. MIME 유형의 경우, Markus는  application/xml으로, Bill은 디폴트 text/plain으로 설정했고, 행 분리문자의 경우, Markus는 CRLF (Windows)로, Bill은 Platform으로 설정했습니다. Bill은 고심끝에 MIME 유형은 Markus 설정 application/xml으로 하고, 행 분리문자는 자신의 선택 Platform이 실용적이라 판단합니다. Bill은 MIME 유형을 충돌 편집기에서 application/xml으로 변경하고 병합하여 해결 처리합니다. 끝! 그림 26은 Bill이 전달할 변경사항을 나타냅니다. 자원 query.xml은 이제 MIME 유형으로application/xml를, 행 분리문자로 Platform를 갖습니다.
Bill verifies the file properties he merged manually
그림 26: Bill이 파일 특성 MIME 유형과 행 분리문자를 수작업으로 병합
 


주의.
 파일 특성 충돌은 내용 충돌과 유사합니다. 같은 특성이 다른 두 개발자가 변경하면, 위에서 보듯 명시적으로 병합해야 합니다. 자동 해결은 다음 경우를 처리할 수 있습니다 - Bill이 MIME 유형만 변경하고, Markus는 행 분리문자만 변경한 경우, 자동 해결은 Bill과 Markus의 변경사항을 자동해결합니다.

예5 - Bill이 미지(unknown) 유형의 파일을 자동 병합하려 합니다.

Bill는 모든 파일의 저작권 내용을 수정하는 작업을 합니다. 그러는 동안 Markus는 웹사이트에서 사용하는 스크립트의 개선한 버전을 전달합니다. 그 결과, Bill은 script.pho 파일에 대한 충돌을 갖습니다 (그림 26).
Bill has a conflict on a file with an unknown extension php
그림 26: Bill은 미지 확장자 .php를 갖는 파일의 충돌을 자동 해결 시도함
 Bill은 이 충돌을 자동 해결하기로 합니다 - 깜놀 - 웬 창이 나타나 .php 확장자에 대한 적절한 내용 병합자를 선택하도록 요청합니다 (그림 27).
Bill associates the php extension to the text merger
그림 27: .php 확장자와 Text 내용 병합자를 연관
 

Bill은 php 파일 형식에 대해 잘 알지 못하지만 - Markus는 전문가 - php는 바이너리가 아니고 텍스트 파일 형식이라 확신합니다. Bill은 '텍스트' 병합자를 올바로 선택합니다. Bill은 앞으로 Eclipse가 이 연관을 기억하도록 체크(환경설정에 저장)합니다. 자동 해결은 이후 진행되고, Markus의 코드 변경 사항과 Bill의 저작권 갱신 작업이 병합됩니다. Bill은 병합된 결과를 전달합니다 (그림 28).

Php file successfully merged by the text content merger
그림 28: 미지 확장자 유형 .php 파일을 텍스트 내용 병합자로 성공적으로 병합함
 

주의. Markus는 이클립스 PHP 플러그인을 통해 훌륭한 PHP 스크립트 편집기와 디버거 지원을 받습니다 (e.g. see PHPEclipse). 이들 플러그인은 php 확장자를 텍스트 파일 형식으로 자동 등록합니다. Bill은 php를 텍스트 파일 형식으로 수작업으로 등록할 수도 있습니다 : 이클립스 > 창 > 환경 설정 > 일반 > 컨텐츠 유형 > 텍스트 > 추가 > php (그림 29).

Associating .php to the Text content type through Eclipse preferences
그림 29: 이클립스 환겨설정에서 .php 확장자를 텍스트 컨텐츠 유형으로 설정
 

예6 - Bill과 Markus가 같은 이름의 파일('evil twin')을 생성합니다.

Bill은 'Add instructions to run tests' 타스트를 완료하고 JUnit Examples 플러그인에서 테스트하는 방법을 기술 한 readme.txt 파일을 추가합니다. 하지만 Markus가 작성한 수신가능 변경세트가 전달을 못하게 막고 있습니다. 그림 30은 같은 위치에 같은 이름의 자원을 Markus와 Bill이 생성했음을 보여줍니다.
Bill and Markus both created a readme.txt file
그림 30: Bill과 Markus가 같은 위치에 같은 이름의 파일 readme.txt를 생성함
 

Bill은 수신가능 변경세트를 허용합니다. 보류중인 변경사항 보기는 readme.txt 자원에 충돌이 있음을 알려줍니다 (그림 31).

Conflict - two files with the same name and location were created
그림 31: Bill은 readme.txt 두 자원 처리방식을 결정해야 함
 


Bill은 충돌 항목을 더블클릭해 충돌 비교 편집기를 엽니다. 왼편은 Bill의 readme.txt이고, 오른편은 Markus의 readme.txt 파일입니다 (그림 32).

Conflict compare editor showing two files with the same name
그림 32: 위치 충돌하는 두개의 서로다른 readme.txt 파일을 보여주는 충돌 비교 편집기
 


Bill은 Markus의 내용이 흥미롭다 생각하고, Markus의 내용을 복사해서 왼편에 붙여넣기를 하고, 저장을 한 후, 병합하여 해결 처리를 합니다 (그림 33).
Appended right content to the left pane
그림 33: Bill은 Markus의 내용을 자신의 readme.txt 파일에 적용함
 


Bill은 이제 JUnit 스트림으로 변경사항을 전달할 수 있습니다 (그림 34).

Bill delivers his readme.txt over Markus's readme.txt
그림 34: Bill은 자신의 readme.txt 파일을 전달하여 Markus의 readme.txt를 대체함 (병합됨)


Bill의 readme.txt 파일은 Markus의 readme.txt 파일을 대체합니다. Bill의 readme.txt는 Markus의 readme.txt 내용을 포함합니다.

주의.
 위는 'evil twin'이라 알려진 충돌 유형을 해결하는 여러 방법 중의 하나입니다.
  1. Bill은 자신의 변경세트를 버리고, Markus의 readme.txt 파일에 자신의 내용을 추가할 수도 있습니다.
  2. Bill은 Markus의 변경사항을 허용하기 전이나 후에 그의 readme.txt 파일의 이름을 변경할 수도 있습니다.
  3. Bill은 충돌 항목에 대한 이동... 조치를 통해 Markus의 readme.txt의 이름을 변경할 수도 있습니다 (그림 35).


Renaming conflicted item to resolve evil twin case
그림 35: Bill은 자신의 readme.txt와의 충돌을 해결하기 위해 Markus의 readme.txt 이름을 변경할 수 있음

충돌 항목 이동 창은 예3에서도 사용되었습니다.

Bill은 'evil twin' 충돌 유형을 해결하기 위한 최선을 선택할 수 있습니다. 어떤 경우에는 파일의 이름을 변경해야 하고, 어떤 경우에는 하나의 파일만 유지하고 내용을 병합해야 합니다. Jazz 소스 제어는 두가지 경우를 지원하는 데 필요한 도구를 지원합니다.
 

예7 - Bill과 Markus가 충돌하는 심볼릭 링크를 생성합니다.

2.0.0.2 이후부터, 심볼릭 링크는 지원하는 플랫폼에서 버전관리됩니다. Bill은 Jazz SCM에 공유되지 않은 로컬 작업공간 상의 파일을 가리키는 심볼릭 링크를 JUnit Examples 프로젝트에 생성하고 전달합니다. Markus 또한 심볼릭 링크를 자신의 작업공간에 만들었고, Bill의 수신가능 변경사항을 알게됩니다 (그림 36).
Bill and Markus both created a symbolic link called 'link'
그림 36: Bill과 Markus 둘다 'link'라는 심볼릭 링크를 생성함


Markus는 Bill의 변경사항을 허용합니다. 보류중인 변경사항 보기에서 심볼릭 링크에 대한 충돌을 보여줍니다 (그림 37).

Markus must resolve the conflict on the symbolic link
그림 37: Markus는 심볼릭 링크에 대한 충돌을 해결해야 함


Markus는 충돌 항목을 더블클릭해서 충돌 비교 편집기를 엽니다. 왼편은 Markus의 변경사항이고, 오른편은 Bill의 변경사항입니다.

Markus must resolve the conflict on the symbolic link
그림 38: Markus는 심볼릭링크에 대한 충돌을 해결해야 함


Markus는 Bill이 전달한 링크 대신 자신의 심볼릭 링크를 선택하기로 결정하고 충돌을 병합하여 해결 처리를 합니다. 그림 39는 병합된 변경세트를 보여줍니다.

Markus has resolved the symbolic link conflict
그림 39: Markus는 심볼릭링크 충돌을 해결함


주의.
 심볼릭링크 충돌은 파일 특성 충돌과 유사합니다. 해결할 파일의 내용은 없습니다. 해결할 특성은 링크가 가리키는 경로 뿐입니다. 충돌은 자동 해결할 수 없습니다.

결론

잠재적 충돌 인지를 통해 개발자는 원하지 않는 충돌을 해결하려 선제적 조치를 취할 수 있습니다 : 예를 들어, 자신의 변경사항을 버리기 하거나, 다른 사람으로 하여금 해당 변경사항을 스트림에서 되돌리기하도록 요청하는 것입니다.

Jazz는 건강한 병렬 및 팀 중심 개발 과정에 충돌은 내재함을 알고 있습니다. 충돌은 보류중인 변경사항 보기를 통해 노출되며 해결됩니다. 대부분의 충돌은 내용 충돌로, 같은 자원이 스트림과 자신의 로컬 작업공간에서 변경될 때 발생합니다. 자동 해결과 충돌 편집기는 개발자가 자신의 로컬 내용에 제안된 변경사항을 병합하는 과정을 지원합니다. 구조 충돌은 덜 빈번하며, 대개 대대적인 리팩토링 개발 과정에서 발견됩니다 : 예를 들면 같은 자원을 두명의 개발자가 옮기거나 수정할 때 발생합니다. 충돌 툴팁은 해결 옵션을 상세히 보입니다. Jazz는 충돌 해결하는 동안에 옮겨 지거나 개명된 자원의 이력도 보존합니다. 이러한 유연성은 잦은 리팩토링을 요하는 애자일 또는 XP 프로그래밍 방법론을 따는 팀이나 빠르게 규모가 커지는 프로젝트의 팀을 위한 자산입니다.

댓글 없음:

댓글 쓰기