4회차실습 1845–80분

브랜치로 업무, 기획 문서, PM 데이터 나누기

gh pr list로 보이는 작업은 PR이 된 작업뿐이다. PR을 만들기 전의 브랜치, 병합 뒤에 남은 브랜치, 어느 업무인지 이름으로 알 수 없는 브랜치는 보이지 않는다. 또 Project의 Status는 현재 값만 남으므로 “LP-04는 언제 시작했는가”에 답할 수 없다. 이 실습은 브랜치를 세 가지 용도로 나눈다. 개발 브랜치는 업무와 연결하고, 기획 문서 브랜치로 결정을 PR 리뷰에 올리고, PM 데이터 브랜치에는 평일마다 Project 스냅숏을 쌓는다.

진행
설명 10분, 실습 25분
결과
브랜치 이름 규칙, 브랜치 현황 보고, pm-data 브랜치, 스냅숏 워크플로
명령
gh issue develop, branch-report.sh, git switch --orphan, gh secret set, gh variable set, gh workflow run
cd ~/gh-pm-lab
source pm-lab/env.sh

1브랜치 세 종류

종류이름 규칙만드는 사람기본 브랜치와의 관계Launchpad 예
개발 브랜치업무키-설명개발자PR로 합친다lp-03-signup-store, lp-03-dup-fix
기획 문서 브랜치docs/업무키-설명PMPR로 합친다docs/lp-01-policy, docs/lp-01-policy-v2
PM 데이터 브랜치pm-dataPM이 만들고 GitHub Actions가 채운다합치지 않는다. 이력을 공유하지 않는 orphan 브랜치다pm-data

이름에 업무 키를 넣으면 브랜치 목록만으로 업무를 찾을 수 있다. 실습 9에서 만든 docs/lp-01-policy가 첫 번째 기획 문서 브랜치다.

2업무와 개발 브랜치 연결

gh issue develop은 이슈에 연결된 브랜치를 만든다. 연결된 브랜치는 이슈 화면의 Development 칸에 보이고, 그 브랜치에서 만든 PR도 이슈와 함께 보인다. 개발자는 저장소 복제본에서 아래처럼 실행한다. --name을 주지 않으면 GitHub가 이슈 번호와 제목으로 이름을 정한다.

gh issue develop 3 -R "$PM_REPO" --name lp-03-signup-store --base main --checkout

PM은 업무에 어떤 브랜치가 연결되어 있는지만 확인한다.

3결정을 기획 문서 PR로 검토받기

10월 26일 재신청 정책이 바뀌었다. 정책 문서(docs/signup-policy.md)는 개발자가 그대로 구현하는 기준이므로, PM이 기획 문서 브랜치에서 고치고 PR 리뷰를 받는다. 실습 9에서 복제한 저장소 폴더에서 실행한다.

cd "$PM_REPO_NAME"
git switch main && git pull -q
git switch -c docs/lp-01-policy-v2
sed -i.bak 's/^| 재신청 | .*|$/| 재신청 | 같은 이메일로 다시 신청하면 최신 신청으로 덮어쓰고 동의 시각을 갱신한다 |/' docs/signup-policy.md
rm docs/signup-policy.md.bak
git diff
git commit -am "docs: 재신청 정책을 덮어쓰기로 변경 (LP-01)" -m "법무 검토 의견. 적용 범위는 토론 #17에서 정했다."
git push -u origin docs/lp-01-policy-v2
gh pr create --title "[LP-01] 재신청 정책 변경: 최신 신청으로 덮어쓰기" --body "Refs #1, #3. 토론의 채택 답을 반영한다."
cd ..

본문에 닫는 키워드(Closes) 대신 Refs를 썼다. 이미 닫힌 LP-01을 이 PR이 다시 열거나 닫지 않게 하려는 것이다. 리뷰어는 gh pr diff에서 바뀐 정책 한 줄을 보고 승인하거나 변경을 요청한다. 병합된 시점이 결정이 확정된 시점이고, 그 PR 주소를 결정 기록의 “관련” 칸에 적는다.

4브랜치 현황 읽기

branch-report.sh는 GraphQL 한 번(브랜치 100개마다 한 번)으로 모든 브랜치의 마지막 커밋과 연결된 PR을 읽고 판정을 붙인다. 브랜치를 지우지는 않는다. 아래는 11월 6일(Sprint 2 마지막 날)에 실행한 결과다.

판정뜻PM이 할 일
리뷰 중, 초안 PR열린 PR이 있다실습 9의 PR 읽기 명령으로 본다
병합됨 · 삭제 후보PR이 병합되었는데 브랜치가 남았다저장소 설정에서 병합 후 자동 삭제를 켠다
PR 없이 멈춤PR이 없고 마지막 커밋 뒤 --stale-days(기본 3) 작업일이 지났다회의에서 계속할지, 업무로 등록할지 묻는다
작업 중 · PR 없음PR은 없지만 최근에 커밋이 있다기다린다

이 결과에서 회의 안건은 spike/email-provider 하나다. 10월 21일 이후 12작업일 동안 커밋이 없고 업무 키도 없다. 토론 #19(베타 초대 메일 발송 도구)와 같은 주제이므로, 실습 19에서 그 토론과 함께 다룬다. 병합된 브랜치는 저장소 설정 하나로 앞으로 자동으로 지워진다.

gh repo edit "$PM_REPO" --delete-branch-on-merge

5PM 데이터 브랜치

Project의 Status 변경 이력은 API로 조회할 수 없고, 저장소 이벤트 API도 최근 90일까지만 돌려준다. 그래서 평일마다 Project 항목 목록 전체를 JSON 파일 하나로 저장한다. 날짜별 파일을 비교하면 업무가 처음 In Progress가 된 날을 하루 단위로 찾을 수 있다. 이 파일들은 코드가 아니므로 기본 브랜치와 이력을 공유하지 않는 orphan 브랜치 pm-data에 둔다. 개발자의 복제본과 PR 목록에는 섞이지 않는다.

스냅숏은 GitHub Actions가 평일 18시 17분(한국 시각)에 찍는다. 키트의 워크플로 파일을 기본 브랜치에 PR로 추가한다. 예약 실행은 기본 브랜치에 있는 워크플로 파일만 읽는다.

cd "$PM_REPO_NAME"
git switch main && git pull -q
git switch -c ci/pm-snapshot
mkdir -p .github/workflows
cp ../github-pm-starter-kit/templates/workflows/pm-snapshot.yml .github/workflows/
git add .github/workflows/pm-snapshot.yml
git commit -m "ci: Project 스냅숏 워크플로 추가"
git push -u origin ci/pm-snapshot
gh pr create --fill
cd ..

PR이 병합되면 워크플로가 쓸 토큰과 값을 저장소에 넣는다. 워크플로가 기본으로 받는 GITHUB_TOKEN은 그 저장소에만 권한이 있어 사용자나 조직이 소유한 Project를 읽지 못한다. 그래서 Project를 읽을 수 있는 토큰을 따로 만든다. classic 토큰이면 read:project와 repo 범위를 고른다.

gh secret set PM_TOKEN -R "$PM_REPO"
gh variable set PM_OWNER -R "$PM_REPO" --body "$PM_OWNER"
gh variable set PM_PROJECT -R "$PM_REPO" --body "$PM_PROJECT"

첫 줄은 토큰 값을 입력받는다. 화면에 보이지 않으며 저장소 비밀값으로만 저장된다. 예약 시각을 기다리지 않고 한 번 실행해 확인한다.

예약 실행의 제약
  • 정각 무렵에는 GitHub Actions 예약 실행이 밀리거나 빠질 수 있다. 키트의 워크플로는 17분에 실행하도록 적었다.
  • 공개 저장소에서 60일 동안 활동이 없으면 예약 실행이 자동으로 꺼진다. gh workflow enable pm-snapshot.yml로 다시 켠다.
  • 하루를 빠뜨려도 다음 스냅숏에서 Status가 보인다. 그 사이의 변화는 하루 늦게 기록된다.

6스냅숏이 쌓이면 보이는 것

아래는 Launchpad의 스냅숏 23개(10월 12일~11월 11일)를 날짜별로 세어 쌓은 누적 흐름도(cumulative flow diagram, CFD)다. 띠의 세로 두께는 그날 그 Status에 있던 업무 수이고, 띠 경계 사이의 가로 거리는 업무가 그 단계를 지나는 데 걸린 대략의 시간이다. 진행 중 업무 수(WIP), 처리량, 처리 시간의 관계는 실습 15의 리틀의 법칙과 같다.

10월 22일부터 27일까지는 LP-02 하나가 In Review에 머물렀다(PR #9, 변경 요청 뒤 재검토). 10월 30일에는 PR 두 건(#20, #21)이 함께 리뷰를 기다려 In Review 띠가 2가 된다. 이 구간들은 실습 21에서 “PR 생성 → 첫 리뷰” 대기 시간으로 다시 나온다.

  • 팀의 브랜치 이름 규칙(개발, 기획 문서, PM 데이터)을 정했다.
  • 기획 문서 브랜치에서 정책 한 줄을 고치고 PR을 만들었다.
  • branch-report.sh 결과에서 회의 안건이 될 브랜치를 찾았다.
  • pm-data 브랜치를 만들고 스냅숏 워크플로를 한 번 실행했다.

마치며...

브랜치는 개발자의 작업 공간이면서 PM에게는 기록의 단위다. 이름에 업무 키를 넣으면 브랜치가 업무와 이어지고, 기획 문서를 PR로 바꾸면 결정이 리뷰와 함께 남고, 데이터 브랜치에 스냅숏을 쌓으면 GitHub가 남기지 않는 Status 이력이 생긴다. 다음 실습에서는 이슈 타임라인과 토론을 읽어 기간 안의 논의를 한 문서로 정리한다.