Git 또는 SVN? Nuance Healthcare가 Git 브랜칭 모델을 선택한 이유
Matt Shelton
개발자 애드보케이트
Nuance Healthcare의 Matt Shelton이 작성한 게스트 게시물입니다. Matt의 팀이 Subversion에서 Git으로 마이그레이션한 과정과 이유, 그 과정에서 겪은 상황에 대한 시리즈의 첫 번째 게시물입니다. Matt는 이 주제에 대해 Atlassian Summit 2015에서도 다룹니다. 이 시리즈를 통해 30분 분량의 강연에서는 설명할 수 없었던 모든 내용을 더 다양한 맥락에 걸쳐 알아볼 수 있습니다.
배경
저희 팀은 Nuance의 의료 부서 소속입니다. 미국 동부 지역에 있는 사무실과 집, 그리고 푸네에 있는 사무실에 지리적으로 분산되어 있습니다. 저희는 Java 웹 서비스를 개발하여 의료 시장에 NLP[1] 솔루션을 제공합니다.
대부분의 경우, 서비스 소비자는 EHR 공급업체 및 의료 분석 회사와 같은 또 다른 의료 소프트웨어 회사(당사 포함)입니다. 일부 제품을 병원에 직접 판매하기도 하는데, 애플리케이션의 최종 사용자는 의사에서 의료비 청구 직원에 이르기까지 다양합니다. 저나 여러분 같은 "일반적인" 사람들은 저희 팀에서 만드는 소프트웨어를 다룰 일이 전혀 없습니다.
우리 팀은 애플리케이션 수명 주기 관리 제품 조합에 대해 몇 번 경험했습니다. 처음부터 Rally Enterprise와 Seapine TestTrack Pro를 조합하여 사용했고, Rational Team Concert를 사용하여 약 14개월 동안 고되게 작업했으며, 결국에는 Atlassian 스택(Jira, Confluence, Bamboo, Crucible 및 Bitbucket)으로 완전히 마이그레이션했습니다. 그동안 Subversion 1.4/1.5와 준정상 트렁크/브랜치/태그 구조를 가진 SCM을 사용했습니다. 빌드 프로젝트와 종속성을 관리하는 데 maven을 계속 사용해 왔고, 얼마 전에는 Jira와의 긴밀한 통합과 유연한 빌드 및 배포 에이전트 기능을 활용할 수 있도록 지속적 통합(CI)을 위해 Jenkins에서 Bamboo로 전환했습니다. (현재) 우리가 사용하는 모든 것은 이유[2]가 있기 때문에 방화벽 뒤에 있습니다.
관련 자료
전체 Git 리포지토리를 이동하는 방법
솔루션 보기
Bitbucket Cloud에서 Git에 대해 알아보기
Git 또는 SVN?
저희는 4개 제품군에 걸쳐 약 10개의 개별 제품을 지원하는데, 제품 소유자들은 항상 우선 순위와 시기를 두고 씨름합니다. 당사의 작업에 대한 수요가 많다는 것은 좋은 일이며 이 말은 절대 불평이 아닙니다. 하지만 이 상황은 결국 이상한 케이던스로 릴리스를 끊고 스프린트 중간에 방향을 바꿔야 할 수도 있다는 것을 의미합니다[3].
종종 개발 프로세스는 정말 버겁게 느껴졌습니다. 저희 팀은 다음과 같은 대화를 주기적으로 나눴습니다.
나: 회귀 테스트를 위해 지금 QA에 1.8.0을 릴리스해야 합니다. 그래야 고객 Foo가 다음 주에 베타로 넘어갈 수 있어요. 개발자: 전 아직 트렁크에 있는 ABC-123을 작업하는 중이에요. 아직 완료하지 않았습니다. 나: Foo는 ABC-123가 필요하지 않아요. 다음 릴리스에 넣어도 됩니다. 개발자: 하지만 이미 몇 주 동안 이 작업을 했어요. 릴리스를 끊기 위해 분기할 수 있는 명확한 지점이 없습니다. 나: 음, 그럼 당신이 모든 변경 사항을 직접 끌어와야겠네요. 두 시간 안에 끝내지 않으면 QA를 제시간에 완료할 수 없습니다.
알아요, 제가 너무 못된 것 같죠! 그럴 의도는 전혀 없었고 물론 요점을 설명하기 위해 조금 과장한 면도 있습니다. 하지만 릴리스를 끊었다가 다음 릴리스[4]에 바로 다시 넣을 수 있도록 한 위치에 있는 코드를 일시적으로 빼낼 방법을 반드시 찾아야만 했습니다. 이런 상황은 항상 벌어졌습니다.
자, 어떤 분들은 이렇게 생각하실 겁니다. "Subversion이 브랜치를 지원해요, Matt..." 맞습니다. 저희도 SVN 1.4와 1.5에서는 가끔 그 기능을 사용했습니다. SVN에서 브랜칭은 잘 이루어지는 편이지만 병합은 아주 골치 아픈 일입니다. SVN이 성숙해지면서 확실히 좋아지긴 했습니다. 하지만 우리에게 더 좋은 옵션이 있다는 사실을 알았습니다. 그래서 SVN이냐, Git이냐 하는 문제가 떠오르자 Git을 사용하기로 했습니다.
참고: 최신 SVN(당시 1.8)을 잠깐 살펴보면서 문제를 해결할 수 있을 만큼 충분히 강력한지 확인했지만 완전히 만족하지는 못했습니다. 동료 그룹 중 하나는 대규모 Perforce 설정을 보유했고 우리에게 필요한 기능도 Perforce에 많았지만 도저히 라이선스 비용을 부담할 수 없었습니다. Mercurial도 잠시 살펴보았지만 결국에는 기존 팀이 Git에 익숙했기 때문에 Git이 올바른 방향이라는 사실을 깨달았습니다.
과장하여 표현하는 말이 아닙니다. Atlassian의 도구는 Git을 사용하는 팀에게 매우 유리합니다. 다른 SCM도 잘 작동합니다. SVN 통합도 특정 사용자 스토리의 변경 사항이 적용된 위치와 연결된다는 점에서 충분했습니다. 하지만 Bitbucket[5]을 대신 사용하는 팀을 위한 통합 기능은 Jira Software 인터페이스와 개발 경험에서 더 강력하고 더 자연스럽습니다. Bamboo에서도 마찬가지입니다.
이 사실을 알고 Summit 2013에서 아주 멋진 데모를 본 결과, 저는 팀에게 Git을 사용하도록 강력히 권장했습니다. 아무도 반대하지 않았고 우리는 이미 변경이 가능한 라이선스도 가지고 있었습니다.
Git 브랜칭 모델 선택
Git으로 변경하기로 결정한 후 겪었던 첫 번째 과제는 팀을 위해 구현할 Git 브랜칭 모델을 결정하는 것이었습니다. Atlassian의 Git 마이크로사이트 및 Summit 2013에서 진행된 이 훌륭한 프레젠테이션에서 브랜칭 모델이 무엇인지 더 자세히 설명합니다. 짧은 버전에서는 Git에서 브랜치를 사용하여 개발 워크플로를 강화하는 방법을 설명합니다.
SVN에는 제가 "필요하다는 걸 깨달을 때 만들기"라고 부르는 브랜칭 모델이 있었습니다.
- 최신 코드는
트렁크
에 있습니다. 트렁크에서 나온 릴리스는A.B.0-{build}
번호가 지정됩니다. - 트렁크 기반 릴리스에 수정이 필요한 경우(예: 1.2.0-64에 버그가 있는 경우) 브랜치가 만들어지고
A.B.C-{build}
를 릴리스합니다. 여기서 모든 릴리스가 이루어질 때마다C
가 증가합니다. 이러한 브랜치는 주어진A.B
에 존재하지 않을 수 있으며 심지어 둘 이상일 수도 있습니다. - 또한 태그 디렉터리에 모든 릴리스를 태그합니다.
버전에 대해 잠시 설명하자면, 몇 년 전에 개발 팀 관리 경험을 쌓고 있을 때 릴리스 엔지니어가 버전 관리 시스템을 가지고 있었습니다. 표현하자면 정말 직관적이지 않았습니다. 기본적으로 모든 릴리스는 이전 패치(A.B.n)에 대한 패치였으며, 패치가 시작된 위치는 전혀 고려하지 않았습니다. 대부분의 경우 무엇이 어디서 왔는지 알아내고 릴리스 순서를 파악하려면 svn log
를 확인해야 했습니다. 우리 팀은 참조용으로 트리를 인쇄해서 벽에 붙였습니다. 게다가 공개 릴리스 번호는 3.0, 3.1, 3.5, 4.0 또는 기본적으로 고객이 예상하는 번호인 경향이 있습니다. 하지만 우리 팀은 상자에 담긴 제품이 아니라 웹 서비스를 만든다는 사실을 기억하세요. 우리 API는 계약입니다. 몇 년 전에 저는 팀의 빌드와 그에 따른 릴리스가 시맨틱 버전 관리 규칙을 준수하도록 했습니다. 고위 경영진과 몇 차례 맞서야 했는데 이제는 다들 규칙이 필요한 이유와 내용을 잘 이해하고 있습니다. 그 이후로 더 이상 뒤돌아 보지 않게 되었습니다. 파트너들은 이러한 명확성을 높이 평가하고 있습니다.
앞서 릴리스(예: 1.2.0
)에 대해 작업하고 있는데 릴리스 날짜가 가까워졌음에도 기능에 대한 작업이 진행 중이었던 문제에 대해 언급했습니다. 해당 코드를 끌어내고 릴리스를 끊어 branches/1.2.1
로 분기한 다음 코드를 다시 병합해야 했습니다. 그동안 아무도 하드 드라이브 문제를 겪지 않기를 바라면서 말입니다[6].
공유 트렁크에서 전체 기능을 단독으로 제거하는 것은 번거로운 일입니다. 그 작업을 수행해야 할 때면 다들 질색했습니다. svn blame
은 강력한 diff 도구처럼 유용할 수 있지만 작업하기에는 여전히 성가신 일입니다. 저는 제 잘못된 계획 때문에 릴리스를 완성해야 하는 시점에서도 만반의 준비를 갖추지 못했다고 생각하여 종종 기분이 상하곤 했습니다[7]. 우리 팀은 이 어려움을 충분히 오랫동안 겪었습니다.
우리는 가끔 골칫거리를 피하기 위해 과도하게 수정하고 릴리스 전에 트렁크에 문제를 일으키지 않으려고 개발자들에게 며칠 동안 지켜보기만 하라고 요청했습니다(말하자면 사실상 코드 동결).
따라서 최소한 기능 브랜치가 필요하다는 것을 알았습니다. 적용할 수 있는 간단한 Git 브랜칭 모델이 있습니다. 프로덕션에 있는 항목을 위한 메인 브랜치 및 모든 기능, 버그 등을 위한 기능 브랜치를 사용하는 것입니다. 팀은 병합 순서를 관리하여 메인에서 제공하는 것이 릴리스용으로 제공되는 것과 같은지 확인해야 했습니다. 근본적으로 우리가 이전에 가졌던 것과 똑같고 기능 분리만 더 나아졌지만 우리는 직접 제어할 수 있는 자유를 원했습니다.
현재 환경에서는 몇 가지 버전을 프로덕션 환경에서 유지해야 하는 경우가 많으며 현재 작업 중인 것보다 2~3회 더 오래된 마이너 릴리스의 결함을 수정해야 할 수도 있습니다. 그래서 기능 브랜치 외에도 이전 릴리스의 문제를 해결할 수 있는 릴리스 브랜치 또는 이와 유사한 것이 필요했습니다. 장기 실행 지원 브랜치에서 수정한 다음 브랜치 스트림을 병합하여 수정 사항이 모든 지원 스트림에 적용되도록 합니다.
그 모델은 정말 유용해 보였고 우리의 요구 사항에 맞는지 알아보기 위해 이 모델로 프로토타입 상호 작용을 몇 차례 실행했습니다. 그들의 "강력한 앱"은 수정 사항을 개발 브랜치까지 롤링 병합하는 것입니다. 이 개념이 마음에 들었지만 시도할 때마다 Maven 종속성과 관련된 여러 문제에 부딪쳤습니다. 또한 한 버전에서 다른 버전으로 작업을 바로 병합하기를 원한다고 보장할 수도 없었습니다. 경우에 따라 버전마다 동일한 수정을 약간 다른 방식으로 구현해야 해서 직접 병합은 불가능했습니다.
일부 팀원은 "git-flow"라는 이 모델의 변형을 강력히 선호했습니다. Git-flow는 브랜치 이름 지정 규칙 및 병합 가이드라인으로 Vincent Driessen이 작성했습니다. 팀에게 매우 자연스럽게 느껴졌고 "x를 해야 할 때 어떻게 해야 합니까?"라는 질문을 많이 제거했기 때문에 구조도 마음에 들었습니다. 해답은 아주 분명했습니다. git-flow가 무엇인지 제가 설명하기 보다는 Atlassian 자습서에서 자세한 내용을 확인하는 것이 좋을 것 같습니다.
git-flow와 관련하여 남은 유일한 격차는 프로덕션에서 장기 실행 릴리스를 어떻게 해야 하는가였습니다. 메인은 계속 진행되고 있기 때문에 이전 릴리스의 버그 수정에 git-flow 핫픽스 워크플로를 사용할 수 없었습니다. 반면 우리는 지원 브랜치가 항상 필요하지는 않았습니다.
대부분의 경우 프로덕션 환경에서 최신 릴리스만 패치하는 핫픽스로도 충분합니다. 다시 돌아가야 할 때나 어떤 이유에서든 호환성을 유지해야 할 때만 지원이 필요합니다. 우리는 지원의 사용 사례를 더 자세히 살펴보고 핫픽스와 마이너 버전 업그레이드 대신 지원 브랜치를 사용하도록 선택하는 기준을 생각해 냈습니다.
1. 이 코드는 개발에 쉽게 다시 병합할 수 없습니다.
2. 파트너/고객은 최신 릴리스와 함께 제공되는 인터페이스 변경을 처리할 수 없습니다.
3. 변경할 수 없는 내부 종속성이 있습니다.[8]
두 개의 git-flow 확장 패키지[9] 모두 지원 브랜치 개념을 지원합니다. 이 개념은. git-flow 초안에는 포함되지 않지만 포함이 보장될 만큼 널리 사용되고 있습니다.
Git-flow는 우리가 좋아하는 워크플로와 함께 우리에게 필요한 도구 지원을 제공했습니다. 다음 게시물에서는 개발 프로세스를 나타내는 데 사용한 POC 프로젝트에서 이것을 실제로 사용해 보았을 때 어떤 일이 발생했는지 살펴보겠습니다. 제게는 유익한 학습 경험이었습니다!
[1]: 자연어 처리. 여러분의 생각을 읽을 수 있습니다. (사실 아닙니다.)
[2]: Atlassian의 Cloud 제품에는 매력적인 점이 많지만 일단 지금은 서버와 데이터를 철저히 제어해야 합니다. 개인적으로 PHI 데이터로 많은 작업을 수행할 필요는 없지만, 우리 소프트웨어는 그렇게 하고 있으며 가능한 한 안전하게 유지하는 것이 중요합니다.
[3]: 쉿... Ken Schwaber에게는 비밀입니다.
[4]: 며칠 후였을 수도 있습니다.
[5]: 이전에는 Stash로 알려져 있었습니다. 안녕, Atlassian 가을 리브랜딩!
[6]: 언제라도 이전 커밋에서 꺼낼 수 있다는 것을 알고 있습니다. 농담입니다.
[7]: 보통은 그렇지 않았습니다. 일반적으로 다른 팀원의 기간이 앞당겨져서 우리가 신속하게 대응해야 했기 때문입니다.
[8]: 이것은 제 블로그에서 다루기 힘든 것 중 하나입니다. 그냥 믿어주세요. "이유"입니다.
[9]: Vincent Driessen의 원본 패키지는 더 이상 유지 관리되지 않습니다. 하지만 새 포크는 정기적으로 업데이트됩니다.
Footnotes
[1]: Natural Language Processing. WE CAN READ YOUR THOUGHTS. (No. Not really.)
[2]: There is a lot that is attractive about Atlassian's cloud offerings, but we need to keep our fingers wrapped tightly around our servers and data for the time being. While we don't personally need to do much with PHI data, our software does and it's important to keep it as secure as possible.
[3]: Shhhh... don't tell Ken Schwaber.
[4]: Which might have only been a few days later anyway.
[5]: Formerly known as Stash. Hello, Atlassian Fall Rebranding!
[6]: I know we could always pull it out of the previous commit. I was kidding.
[7]: This wasn't usually the case - generally it was because someone else's timeframe moved up and we had to react quickly.
[8]: This is one of those things I can't get into on my own blog. Just trust me. "Reasons".
[9]: The original package by Vincent Driessen isn't being maintained any longer. A new fork, however, is regularly updated.
이 문서 공유
다음 토픽
여러분께 도움을 드릴 자료를 추천합니다.
이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.