DevOps · Git · Collaboration

브랜치 - 같은 파일을 여럿이 고칠 때

코드를 고치는 사람이 둘이 되면 미완성을 둘 자리가 필요해진다. 갈라놓는다는 발상이 무엇을 풀어주고, 그 대신 무엇을 시작시키는지 본다.

·갈래와 합류 1편
목차
  1. 같은 파일을 둘이 동시에 고친다
  2. 다 되기 전에 올리면 남이 막힌다
  3. 갈라놓는다 - 본선과 지선
  4. 만드는 건 공짜다, 비싼 건 돌아오는 쪽이다
  5. 갈라진 순간부터 차이가 쌓인다
  6. 갈라놓지 않는 선택도 있다
  7. 브랜치가 사는 것과 파는 것
  8. 실무에서: 브랜치 하나가 변경 하나를 뜻하게 한다
  9. 정리

코드를 고치는 사람이 하나일 땐 없던 문제가 둘이 되는 순간 생긴다. 내 미완성이 남의 눈앞에 있다는 것이다.

같은 파일을 둘이 동시에 고친다

결제 화면을 두 사람이 만지고 있다. 한 사람은 할인 코드 입력칸을 새로 붙이는 중이고, 다른 사람은 같은 화면의 버튼 배치를 바꾸는 중이다.

저장소는 하나다. 둘의 변경이 결국 한 자리에 쌓여야 한다. 그런데 두 사람의 일은 끝나는 시점이 다르다. 버튼 배치는 오늘 끝나고, 할인 코드는 사흘 걸린다.

여기서 질문이 하나 생긴다. 사흘짜리 일은 그동안 어디에 둬야 하나.

다 되기 전에 올리면 남이 막힌다

가장 단순한 답은 “그냥 공용 자리에 올린다”다. 그러면 이런 일이 생긴다.

  • 반쯤 만든 코드가 빌드를 깨뜨린다. 그때부터 나머지 사람 전부가 막힌다.
  • 안 깨졌더라도 화면이 반쯤 만들어진 상태다. 이 상태로 배포되면 사용자가 그걸 본다.
  • 그래서 다들 조심하게 된다. “지금 저 화면은 누가 고치는 중이니 건드리지 말자.”

마지막 줄이 특히 나쁘다. 사람이 순서를 지켜 한 명씩 고치면 충돌은 안 나지만, 그 대가로 기다리는 시간을 낸다. 사람이 늘수록 기다림도 늘어난다.

그럼 반대로 다 될 때까지 내 컴퓨터에만 두면 어떨까. 이번엔 사흘치 작업이 노트북 하나에만 있다. 백업도 없고, 남이 미리 볼 수도 없고, 문제가 있어도 아무도 모른다.

그래서 필요한 건 셋을 동시에 만족하는 자리다. 올려두되, 본선에는 아직 섞이지 않고, 남이 볼 수는 있는 자리.

갈라놓는다 - 본선과 지선

철도를 떠올리면 그림이 맞다.

열차가 다니는 선로가 본선이다. 여기서 공사를 하려면 열차를 세워야 한다. 그래서 선로를 새로 놓는 공사는 본선 옆에 지선을 내서 거기서 한다. 본선은 그동안 계속 열차를 나른다. 지선 공사가 끝나면 그때 본선에 이어 붙인다.

브랜치가 그 지선이다. 다들 쓰는 줄기(대개 main)가 본선이고, 내가 판 브랜치가 거기서 갈라져 나온 지선이다. 사흘짜리 일은 지선 위에 쌓인다. 그동안 본선은 막히지 않는다.

미완성을 본선 위에 올리면 · 갈래 없음

본선 완료 완료 미완성 완료 완료 완료 미완성 하나 뒤로 전부 묶인다 배포✕ 못 나감

미완성을 지선으로 빼면 · 갈래 하나

본선 완료 완료 완료 완료 완료 미완성 지선에서 계속 배포✓ 언제든 나감

같은 일 여섯 개다. 미완성이 본선 위에 있으면 그 뒤가 통째로 묶이고, 본선 옆으로 빠지면 본선은 계속 나간다.

위와 아래의 차이는 하나다. 미완성이 본선 위에 있느냐, 본선 옆에 있느냐.

만드는 건 공짜다, 비싼 건 돌아오는 쪽이다

여기서 비유가 한 번 깨진다. 밝혀두는 게 낫다.

실제 철로는 지선 하나를 놓는 것부터가 큰 공사다. 땅을 파고 자재를 들여야 한다. 그래서 지선은 함부로 못 낸다. 브랜치는 그렇지 않다.

git에서 브랜치는 커밋 하나를 가리키는 이름표 한 줄에 가깝다. 파일을 복사하지도, 저장소를 한 벌 더 만들지도 않는다. 그래서 하나를 더 만드는 값이 사실상 0이다. 실험 삼아 만들었다가 아니다 싶으면 지워도 잃는 게 없다.

이 차이를 짚어두는 이유가 있다. 브랜치의 비용을 “만들 때 드는 것”으로 오해하면 이 시리즈의 나머지가 안 읽힌다. 비용은 전부 돌아오는 쪽에 있다. 지선을 내는 건 공짜인데, 본선에 다시 잇는 건 공짜가 아니다.

갈라진 순간부터 차이가 쌓인다

갈라놓고 나면 내 지선 위에 커밋이 쌓인다. 그런데 본선도 가만히 있지 않는다. 다른 사람들이 계속 거기에 올린다.

그래서 브랜치를 만든 순간 같이 시작되는 게 하나 있다. 내가 갈라져 나온 지점과 지금의 본선 사이에 벌어지는 차이다.

이 차이의 성질이 중요하다.

  • 내가 아무것도 안 해도 자란다. 남들이 본선을 바꾸니까.
  • 시간에 따라 자란다. 오래 갈라져 있을수록 벌어진다.
  • 보이지 않는다. 내 지선에서 일하는 동안은 본선이 어떻게 변했는지 안 보인다.

지선에 있는 동안은 이게 문제가 아니다. 문제가 되는 건 돌아올 때다. 이어 붙일 자리가 갈라질 때와 달라져 있으면, 그 어긋난 만큼을 사람이 손으로 맞춰야 한다.

이 시리즈가 계속 되돌아올 자리가 여기다.

갈라놓지 않는 선택도 있다

그렇다면 아예 안 갈라놓는 선택도 있다. 모두가 본선에 곧장 올리는 것이다.

이 방식에는 값이 있다. 차이가 자랄 틈이 없다. 늘 최신 본선 위에서 일하니 이어 붙일 자리가 어긋나지 않는다.

대신 앞에서 본 문제가 그대로 돌아온다. 미완성이 즉시 남에게 보인다. 그래서 이 선택은 조건이 붙는다. 한 번에 올리는 변경이 그 자체로 말이 되게 작아야 한다. 반나절 만에 끝나고, 올려도 아무것도 안 깨뜨리는 크기여야 한다.

정답이 있는 갈림길이 아니다. 갈라놓으면 미완성을 감출 자리를 얻는 대신 차이를 떠안고, 안 갈라놓으면 차이를 안 만드는 대신 일을 잘게 쪼개야 한다. 어느 쪽이 싼지는 팀과 일의 모양이 정한다.

브랜치가 사는 것과 파는 것

정리하면 브랜치는 이런 거래다.

산다판다
미완성을 본선 밖에 둘 자리갈라진 동안 벌어지는 차이
언제 남에게 보일지 고를 권한합칠 때 한꺼번에 치르는 비용
버려도 되는 실험 공간지선이 본선을 못 보는 시간

가운데 줄이 브랜치의 알맹이다. 브랜치는 “코드를 나누는 도구”라기보다 **“보여줄 시점을 내가 고르게 해주는 도구”**다. 그 권한을 사는 값으로 차이를 떠안는다.

마지막 줄이 왜 대가 쪽에 있는지도 여기서 보인다. 내가 지선에 있는 동안 본선이 어떤 결정을 내렸는지 나는 모른다. 남이 같은 문제를 이미 다르게 풀어놨을 수도 있다.

실무에서: 브랜치 하나가 변경 하나를 뜻하게 한다

브랜치를 쓰기 시작하면 곧 만나는 것들이 있다.

한 지선에 관련 없는 일 둘을 담지 않는다. 할인 코드를 만들면서 눈에 띈 오타를 같이 고쳐 넣으면, 나중에 할인 코드를 통째로 되돌릴 때 오타 수정까지 딸려 나간다. 되돌리는 단위가 곧 지선의 단위다.

지선 이름이 무엇을 하는 갈래인지 말하게 한다. 사람 이름만 붙은 지선은 며칠 지나면 본인도 뭐였는지 모른다. 남이 봤을 때 “이건 아직 살아 있는 갈래인가”를 판단할 수 있어야 한다.

지선은 왕복표다. 편도가 아니다. 만들 때부터 언제 돌아올지가 대충이라도 정해져 있어야 한다. 돌아오지 않는 지선은 브랜치가 아니라 그냥 다른 저장소다.

그리고 이 셋보다 큰 조건이 하나 있다. CI/CD 글에서 본 원칙, 본선에 들어오는 것은 언제든 나가도 되는 상태여야 한다는 것이다. 지선은 그 원칙을 지킬 수 있게 해주는 장치다. 아직 나가면 안 되는 것을 밖에 세워두니까.

바꿔 말하면 지선을 두는 이유는 본선을 자유롭게 하려는 게 아니라 본선을 항상 깨끗하게 두려는 것이다.

정리

푸는 문제미완성을 어디에 둘 것인가
발상본선 옆에 지선을 내고 거기서 일한다
만드는 값거의 0. 이름표 한 줄이다
진짜 비용돌아올 때 치른다
갈라진 뒤내가 아무것도 안 해도 본선과의 차이가 자란다
안 갈라놓으면차이는 없지만 일을 잘게 쪼개야 한다

브랜치를 배울 때 대개 “어떻게 만드나”부터 배우는데, 만드는 건 이 이야기에서 가장 싼 부분이다. 어려운 건 전부 반대쪽에 있다.

다음 글은 그 반대쪽으로 간다. 지선이 본선으로 돌아오는 방법이 둘이고, 둘은 남기는 모양이 다르다.