LabHub
배우기 러닝패스 코스

Git in Practice

There Is Only One Question That Picks a Strategy

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

브랜치 전략을 고르는 질문은 "어떤 그림이 예쁜가"가 아니라 "장애가 났을 때 이 저장소에서 원인 커밋을 어떻게 찾을 계획인가"다.

Concept map: Git 입장에서 그 브랜치는 머지된 적이 없다 · 커밋 하나하나가 빌드되고 동작해야 하고, 커밋의 크기가 작아야 한다. · 새 커밋 · 머지를 되돌린 뒤에 같은 브랜치를 다시 병합하면 아무 변경도 들어오지 않는다.

왜 이게 필요했나

Git Flow, GitHub Flow, Trunk-Based 는 서로 다른 배포 주기를 전제로 만들어졌다. 전제를 무시하고 이름만 가져오면 매일 마찰이 생긴다.

전략 브랜치 종류 병합 빈도 맞는 곳
Git Flow 5종 이상 주 1~2회 정기 릴리스, 모바일 앱, 패키지
GitHub Flow 2종 일 1~3회 CD 를 실천하는 SaaS
Trunk-Based 1~2종 일 5~10회 이상 브랜치 수명 1일 이내, Feature Flag 필수

Trunk-Based 는 CI 요구 수준이 매우 높다. Feature Flag 없이 시작하면 미완성 코드가 그대로 배포된다. 반대로 GitOps 환경에서 Git Flow 의 release 브랜치는 자동 동기화 패턴과 마찰이 크다. 그래서 GitOps 를 쓴다면 GitHub Flow 또는 Trunk-Based 를 권한다.

공통 규칙 하나는 어디서나 통한다. 3일 이상 살아 있는 feature 브랜치는 merge conflict 의 온상이다.

어떻게 동작하나

병합 방식은 세 가지고 각각 다른 것을 남긴다.

체리픽은 저장된 diff 를 오려 붙이는 것이 아니다. Git 은 애초에 diff 를 저장하지 않고 스냅숏만 저장한다. 그래서 대상 커밋의 부모 트리를 공통 조상으로 삼아 삼자 병합을 수행한다. 체리픽이 충돌하는 이유가 여기에 있다.

현장에서 만나는 모습

핫픽스를 릴리스 브랜치에서 고치고 main 에 반영하지 않아 다음 릴리스에서 같은 버그가 되살아나는 일은 어느 팀에나 한 번은 생긴다. 릴리스 브랜치를 운영한다면 "핫픽스는 반드시 main 으로도 가져온다"가 정책 문장으로 적혀 있어야 한다.

태그도 마찬가지다. 가벼운 태그는 그냥 포인터라 누가 언제 왜 붙였는지 남지 않는다. 릴리스 태그는 -a 로 주석을 붙여야 나중에 조사에 쓸 수 있다.

이력은 조사를 위해 남긴다

브랜치 전략의 값어치는 평상시가 아니라 사고가 났을 때 드러난다. "어제까지 되던 것이 오늘 안 된다" 는 상황에서 원인 커밋을 찾는 표준 도구는 이분 탐색이다. Git 은 git bisect 로 이것을 반자동으로 해 준다. 정상인 커밋과 고장 난 커밋을 알려 주면 중간 지점을 체크아웃해 주고, 사람이 좋다/나쁘다만 답하면 범위를 반씩 줄인다. 커밋 1,000개 중 원인을 찾는 데 열 번이면 충분하다.

이분 탐색이 잘 되려면 이력이 두 가지 조건을 만족해야 한다. 커밋 하나하나가 빌드되고 동작해야 하고, 커밋의 크기가 작아야 한다. 중간에 동작하지 않는 커밋이 섞여 있으면 사람이 좋다/나쁘다를 답할 수 없어 그 지점을 건너뛰어야 하고, 스쿼시 머지로 PR 하나가 커밋 하나가 되어 있으면 탐색이 그 PR 앞에서 멈춘다. "이 PR 안 어딘가" 까지만 알아내고 나머지는 손으로 읽어야 한다는 뜻이다. 앞에서 스쿼시 머지가 이분 탐색 해상도를 PR 크기로 고정한다고 한 말이 이 대목이다.

원인 커밋을 찾은 다음의 선택도 미리 정해 두어야 한다. 되돌리는 방법은 둘이고 성질이 완전히 다르다.

머지 커밋을 되돌릴 때는 한 가지가 더 필요하다. 부모가 둘이므로 어느 쪽 줄기를 유지할지 -m 1 처럼 지정해야 하고, 보통 1번이 병합을 받은 쪽(main)이다. 그리고 머지를 되돌린 뒤에 같은 브랜치를 다시 병합하면 아무 변경도 들어오지 않는다. Git 이 보기에는 이미 병합된 커밋들이기 때문이다. 되돌린 것을 다시 넣으려면 되돌림 커밋을 한 번 더 되돌려야 한다는 사실을, 급한 상황에서 처음 배우지 않는 편이 좋다.

다음 실습에서 할 것

저장소를 처음부터 만들고, 기능 브랜치를 --no-ff 로 병합해 통합 기록을 남기고, 작은 수정은 빨리 감기로 올리고, 릴리스 태그를 붙이고, 릴리스 브랜치의 핫픽스를 체리픽으로 main 에 반영한 뒤, 병합된 브랜치만 골라 정리합니다. 마지막에는 이 저장소의 실제 숫자를 세어 전략 비교표를 씁니다.