← 홈Setup Tip

Setup Tip

Setup Tip — 스택 PR은 맨 위에서 닫아라, 아래부터가 아니라

A ⊂ B ⊂ C 형태로 쌓인 PR을 아래부터 squash로 머지하면, 위쪽 PR의 커밋 신원이 바뀌어 아래 PR들이 0-diff 상태로 열려 남는다. 최상단 한 번의 merge commit이 스택 전체를 정확히 종결시킨다.

문제

한 작성자가 같은 베이스 위에 연속된 세 개의 PR을 올리는 경우가 있다. 아래 PR의 변경이 위 PR에 그대로 포함되어 있는 스택 구조다. 리뷰가 끝나면 습관적으로 아래부터 하나씩 squash 머지하게 되는데, squash는 원래 커밋들을 버리고 새 커밋 하나를 만든다. 그 순간 위쪽 PR의 헤드는 베이스의 조상이 아니게 되고, 플랫폼은 아래 PR을 자동으로 닫지 못한다. 결과적으로 변경은 전부 들어갔는데 목록에는 '변경 없음' 상태의 PR이 열려 남는다. 다음 사람은 이걸 미처리 백로그로 착각하고 다시 검토한다.

운영 패턴

1. 머지 전에 스택인지 먼저 확인한다. 각 PR의 헤드 커밋이 다음 PR의 이력에 포함되는지만 보면 된다.

2. 검증은 최상단 헤드 하나에서 한다. 스택 전체의 최종 상태가 그 커밋이므로, 아래 단계를 따로 빌드·테스트할 필요가 없다.

3. 머지는 최상단에서 merge commit 한 번으로 끝낸다. 커밋 신원이 보존되어 아래 PR들의 헤드가 베이스의 조상이 되고, 전부 자동으로 종결된다.

4. 자동 종결을 눈으로 확인한다. 닫혔다고 가정하지 말고 각 PR의 상태가 실제로 terminal인지 읽는다.

5. 아래 PR에도 한 줄씩 남긴다. 어떤 커밋으로 어디에 들어갔는지 적어 두면, 0-diff로 닫힌 PR이 유실이 아니라 흡수임을 다음 사람이 안다.

왜 중요한가

스택을 잘못 닫으면 손해는 두 번 발생한다. 처음에는 빈 PR이 열린 채 남아 백로그를 오염시키고, 다음에는 누군가 그 빈 PR을 되살리려다 이미 들어간 변경을 다시 적용한다. 둘 다 코드 문제가 아니라 종결 절차의 문제이고, 머지 방식 하나를 바꾸면 사라진다. squash는 독립적인 단일 PR에 좋은 기본값이지만, 이력의 포함 관계 자체가 의미를 가지는 스택에서는 그 의미를 파괴한다.

완료 기준

스택의 모든 PR이 terminal 상태이고, 각 PR에 어느 커밋으로 흡수되었는지 근거가 남아 있고, 베이스 브랜치에 최종 상태가 한 번만 들어가 있으면 완료다. 0-diff로 열려 있는 PR이 하나라도 남아 있으면 그 스택은 아직 닫히지 않은 것이다.