DevOps · Git · Collaboration

브랜치 전략 - 오래 가르거나 자주 합치거나

이름 붙은 브랜치 전략들은 결국 하나를 정한다. 지선을 얼마나 오래 두었다가 되돌리나. 배포 주기·롤백 비용·팀 크기가 그 답을 어떻게 정하는지 본다.

·갈래와 합류 3편
목차
  1. 전략이 정하는 건 사실 하나다
  2. 오래 가르는 쪽: 갈래마다 자리를 준다
  3. 자주 합치는 쪽: 본선 하나로 되돌린다
  4. 미완성인데 어떻게 합치나 - 기능 플래그
  5. 배포 주기가 전략을 정한다
  6. 되돌리는 값이 전략을 정한다
  7. 팀 크기와 리뷰 속도가 전략을 정한다
  8. 전략이 파이프라인을 정한다
  9. 실무에서: 대개 그 사이 어딘가다
  10. 정리

합치는 방법을 정하고 나면 남는 질문은 하나다. 언제 합치나.

전략이 정하는 건 사실 하나다

브랜치 전략이라는 이름이 붙은 규칙들은 대개 그림 한 장으로 소개된다. 어떤 줄기가 있고 어디서 갈라져 어디로 합쳐지는지가 화살표로 그려져 있다.

그 그림들에서 이름과 화살표를 걷어내면 남는 건 하나다. 지선을 얼마나 오래 두었다가 본선으로 되돌리나. 줄기를 몇 개 두는지, 무슨 이름을 붙이는지는 그 답에서 따라 나온 결과다.

그래서 이 글은 이름 붙은 전략들을 하나씩 소개하지 않는다. 양 끝을 세워두고, 우리 팀이 그 사이 어디에 서야 하는지를 정하는 조건들을 본다.

오래 가르는 쪽: 갈래마다 자리를 준다

한쪽 끝은 갈래를 여러 개 두고 오래 유지하는 방식이다. git flow가 대표적이고, 대개 이런 모양이다. 나가 있는 것만 담는 줄기, 다음 릴리스를 모으는 줄기, 기능마다 나는 지선, 출시 직전에 다듬는 지선, 급한 수정을 위한 지선.

규칙이 많아 보이지만 이 모양이 나온 자리를 보면 이해가 쉽다. 버전을 묶어서 내보내는 제품이다.

  • 릴리스가 분기에 한 번쯤이다. 나가는 단위가 크고, 나가기 전에 묶어서 다듬는 기간이 있다.
  • 나간 버전이 사용자 손에 설치돼 있다. 회수할 수 없다.
  • 그래서 이미 나간 버전만 따로 고쳐줘야 하는 일이 생긴다. 다음 버전에 넣는 것과는 다른 일이다.

이 조건이면 “지금 나가 있는 것”과 “지금 만드는 것”이 동시에 존재해야 하고, 그 둘은 서로 다른 자리가 필요하다. 줄기가 여러 개인 이유가 이것이다.

산다: 어느 시점의 상태든 이름 붙은 자리가 있다. 나간 버전만 골라 고치는 게 가능하고, 출시 전에 기능을 통째로 빼는 것도 가능하다.

판다: 지선이 오래 산다. 그리고 규칙이 많아서 사람이 규칙을 기억해야 한다. 어느 줄기에서 갈라져 어디로 돌아가는지가 매번 판단거리가 된다.

자주 합치는 쪽: 본선 하나로 되돌린다

반대쪽 끝은 트렁크 기반(trunk-based)이다. 본선 하나만 오래 살고, 지선은 두더라도 아주 짧게 둔다. 하루나 이틀, 길어도 며칠이다.

오래 가르는 쪽 · 지선이 주 단위로 산다

본선 지선 1 약 2주 반 지선 2 약 2주 반 1주 2주 3주 4주 합류 2번한 번에 몇 주치

자주 합치는 쪽 · 지선이 하루 이틀 산다

본선 지선 1 지선 2 1주 2주 3주 4주 합류 12번한 번에 하루치

같은 4주, 같은 사람 둘이다. 오래 가르면 되돌리는 횟수가 적은 대신 한 번이 크고, 자주 합치면 그 반대다.

같은 기간인데 위쪽은 합류가 두 번이고 아래쪽은 열두 번이다. 한 번에 되돌리는 양이 그만큼 다르다.

산다: 차이가 자랄 시간이 없다. 지금까지 본 비용의 원천이 갈라져 있는 시간이었으니, 시간을 줄이면 그 비용이 통째로 줄어든다. 그리고 통합 문제를 하루 안에 안다.

판다: 본선이 늘 나가도 되는 상태여야 한다는 규율. 이게 만만치 않다. 하루에 열 번씩 본선이 바뀌는데 매번 사람이 확인할 수는 없으니 검증이 자동이어야 하고, 아직 안 끝난 기능을 감출 다른 수단도 필요하다.

미완성인데 어떻게 합치나 - 기능 플래그

당연한 반문이 여기서 나온다. 사흘 걸리는 기능을 매일 본선에 넣으면 반쯤 만든 화면이 그대로 나가는 것 아닌가.

답은 이렇다. 코드는 합치되 켜지 않는다. 새 기능을 설정값 하나로 켜고 끌 수 있게 만들어두고, 기본을 꺼짐으로 둔다. 코드는 본선에 매일 들어가지만 사용자는 아무것도 못 본다. 이걸 기능 플래그(feature flag)라고 부른다.

왜 이게 트렁크 기반과 짝인지가 여기서 보인다. 브랜치를 왜 가르나를 본 글에서, 브랜치가 사는 것 가운데 알맹이는 언제 남에게 보일지 고를 권한이었다. 트렁크 기반은 그 권한을 브랜치에서 회수해 플래그로 옮긴다. 감추는 자리가 코드 밖(지선)에서 코드 안(플래그)으로 옮겨간 것이다.

그러니 이것도 공짜가 아니다.

  • 플래그는 분기다. 코드 안에 조건문이 하나 늘고, 켠 경우와 끈 경우가 둘 다 돌아가야 한다.
  • 다 쓴 플래그를 걷어야 한다. 안 걷으면 조건문만 쌓여서 아무도 못 읽는 코드가 된다.
  • 켜고 끄는 조합이 는다. 플래그가 열 개면 상태가 열 가지가 아니라 그보다 훨씬 많다.

비용이 사라진 게 아니라 자리가 옮겨간 것이다. 지선을 관리하지 않는 대신 플래그를 관리한다.

배포 주기가 전략을 정한다

이제 무엇이 답을 정하는지 본다. 첫 번째가 배포 주기다.

분기에 한 번 나가는 제품과 하루에 열 번 나가는 서비스는 같은 전략을 쓸 수 없다.

  • 배포가 드물면 한 번에 나가는 단위가 크다. 나가기 전에 묶어 다듬는 기간이 필요하고, 나간 것과 만드는 것이 오래 공존한다. 갈래마다 자리를 주는 쪽이 맞는다.
  • 배포가 잦으면 나가는 단위가 작다. 묶어둘 이유가 없고, 나간 것은 곧 다음 것으로 덮인다. 자리를 나눌 이유가 사라진다.

여기서 짚을 게 하나 있다. 인과가 한 방향이 아니다. 배포 주기가 전략을 정하기도 하지만, 전략이 배포 주기를 정하기도 한다. 오래 사는 지선을 두면 배포는 저절로 뜸해진다. 합칠 게 큰 덩어리로만 준비되니까.

그래서 “우리는 배포가 뜸해서 오래 가르는 쪽”이라는 말은 절반만 맞을 수 있다. 뜸한 게 조건이 아니라 결과일 수도 있다.

되돌리는 값이 전략을 정한다

두 번째는 잘못 나갔을 때 되돌리는 값이다. 이게 전략을 생각보다 크게 정한다.

지선을 오래 두는 이유를 파고들면 대개 “확실해질 때까지 붙들어 두려고”다. 그런데 그 붙들기의 값은 되돌리기가 얼마나 비싼가에 달려 있다.

무중단 배포에서 본 것처럼 롤백이 스위치 한 번이면, 나가서 확인하고 아니면 되돌리는 게 앞에서 몇 주 붙드는 것보다 싸다. 붙들어 봐야 진짜 트래픽에서 드러날 문제는 어차피 안 나온다.

반대로 되돌리기가 비싼 곳도 있다. 사용자 기기에 설치되는 소프트웨어, 심사를 거쳐야 나가는 앱, 한 번 보낸 뒤 회수할 수 없는 것들이다. 이런 곳에서는 앞에서 오래 붙들고 다듬는 게 맞다.

브랜치 전략이 배포 쪽 사정에서 따라 나온다는 게 여기서 보인다. 브랜치만 놓고 고르는 문제가 아니다.

팀 크기와 리뷰 속도가 전략을 정한다

세 번째는 사람 쪽이다.

지선이 짧으려면 리뷰가 빨라야 한다. 리뷰가 이틀씩 밀리는 팀에서 “하루 안에 합친다”는 지킬 수 없는 규칙이다. 코드는 하루 만에 다 됐는데 지선은 사흘을 산다.

사람이 많으면 본선이 자주 바뀐다. 오래 사는 지선이 여럿이면 그것들이 서로 부딪히기 시작한다. 각자 자기 지선에서 같은 파일을 다르게 고쳐놓고, 먼저 합친 사람이 이기고 나머지가 전부 다시 맞춘다.

혼자면 갈래 자체가 필요 없을 수도 있다. 감출 남이 없고 기다릴 리뷰가 없으면 브랜치가 사는 것들이 대부분 무의미해진다.

즉 팀 크기는 양쪽으로 작용한다. 클수록 오래 사는 지선의 대가가 커지고, 동시에 짧게 유지하기도 어려워진다. 그래서 큰 팀일수록 일을 쪼개는 능력과 리뷰를 빨리 돌리는 능력에 전략이 걸린다.

전략이 파이프라인을 정한다

마지막은 도구 쪽이다. CI/CD 글에서 본 게이트가 여기서는 전제 조건이 된다.

자주 합치는 쪽은 자동 검증 없이는 성립하지 않는다. 본선이 하루에 열 번 바뀌는데 매번 사람이 확인할 방법이 없다. 검증이 자동이 아니면 트렁크 기반을 흉내 내는 것은 그냥 확인 없이 본선에 밀어 넣는 일이 된다.

오래 가르는 쪽도 파이프라인이 필요하지만 모양이 다르다. 줄기마다 도는 게 다르다. 기능 지선에서는 빠른 검사만 돌리고, 출시 지선에서는 무거운 검사까지 다 돌리고, 본선에서는 배포까지 간다.

순서를 뒤집으면 안 되는 이유가 여기다. 전략을 먼저 고르고 파이프라인을 맞추는 게 아니라, 감당할 수 있는 파이프라인이 고를 수 있는 전략을 정한다.

실무에서: 대개 그 사이 어딘가다

실제로 많이 쓰이는 건 양 끝이 아니라 중간이다. 본선 하나에 짧게 사는 기능 지선을 붙이고, 리뷰를 거쳐 합치면 그대로 배포되는 모양이다. GitHub flow라고 부르는 것이 대체로 이 꼴이다.

이름 붙은 전략을 통째로 가져오는 게 목적이 아니다. 고를 때 답해야 할 것은 다섯 개다.

질문짧은 쪽으로 미는 답긴 쪽으로 미는 답
얼마나 자주 내보내나하루에 여러 번분기에 한 번
되돌리는 데 얼마가 드나스위치 한 번회수할 수 없다
이미 나간 버전을 따로 고쳐야 하나아니다그렇다
리뷰가 며칠 걸리나몇 시간며칠
미완성을 감출 수단이 브랜치 말고 있나있다없다

다섯 개가 한쪽으로 몰리는 팀은 드물다. 대개 섞여 나오고, 그러면 답도 중간이 된다. 그 중간이 우리 전략이다. 남이 쓰는 이름을 가져다 붙이는 것보다 이 다섯 답을 적어두는 편이 실제로 도움이 된다.

한 가지만 덧붙이면, 이 다섯 개는 고정된 조건이 아니다. 리뷰 속도도 파이프라인도 우리가 바꿀 수 있는 것이고, 바뀌면 답도 옮겨간다. 전략을 한 번 정하고 몇 년을 두는 게 이상한 이유가 이것이다.

정리

오래 가르는 쪽자주 합치는 쪽
줄기갈래마다 자리를 준다본선 하나
지선 수명주 단위하루 이틀
산다시점마다 이름 붙은 자리. 나간 버전만 고칠 수 있다차이가 자랄 틈이 없다. 통합 문제를 즉시 안다
판다오래 사는 지선의 비용. 기억할 규칙이 많다본선을 늘 깨끗하게 둘 규율. 자동 검증과 플래그
맞는 곳버전을 묶어 내보내는 제품. 되돌리기가 비싼 곳자주 내보내는 서비스. 롤백이 싼 곳

전략은 취향이 아니라 조건에서 따라 나온다. 배포 주기, 되돌리는 값, 팀 크기, 리뷰 속도, 감출 수단이 정한다.

다음 글은 이 축의 한쪽 끝을 자세히 본다. 지선을 오래 두면 비용이 정확히 어떻게 자라는가.