IT, MIND & CAREER / EDITORIAL DESK

흐름을 읽고, 다음 선택을 설계합니다.

기술의 변화와 사람의 판단, 그리고 오래 가는 커리어를 한 장의 리포트로 정리합니다.

EDITOR'S SELECTION

지금, 먼저 읽을 리포트

변화의 신호를 읽는 세 편의 이야기

THE ARCHIVE

최근 리포트

IT 커리어 & 성장 조회 5

CODEOWNERS를 넣었는데도 검토가 비는 이유

CODEOWNERS를 넣었는데도 검토가 비는 이유

저장소에 CODEOWNERS를 추가한 뒤에도 “누가 이 변경을 봤지?”라는 질문이 남는 경우가 있다. 파일 경로별 담당 팀을 적었고 풀 리퀘스트에도 리뷰 요청이 표시됐는데, 정작 병합은 그 담당자의 확인 없이 진행되었거나 승인 뒤에 바뀐 부분이 다시 읽히지 않은 채 남는 식이다. 이는 누군가 설정을 잘못했다는 뜻이라기보다, 서로 다른 역할을 하는 기능을 하나의 ‘검토 완료’ 표시로 읽었기 때문에 생기는 빈틈일 수 있다.

이 글은 GitHub 저장소에서 리뷰 운영을 맡은 테크 리드, 유지보수자, 플랫폼 담당자를 위한 글이다. GitHub의 CODEOWNERS 문서는 소유자가 바뀐 파일의 풀 리퀘스트에 자동으로 리뷰 요청을 받는다고 설명한다. 반면 보호 브랜치 문서는 코드 소유자 승인을 병합 조건으로 요구할 수 있고, 새 커밋이 들어왔을 때 기존 승인을 오래된 것으로 처리할 수 있다고 설명한다. 둘은 연동할 수 있지만 같은 제어가 아니다.

여기서 독자가 내려야 할 결정은 단순하다. 한 경로에 소유자를 적는 것만으로 충분한지, 아니면 그 경로의 병합·최신 변경·우회 권한까지 별도로 확인해야 하는지다. 이 글의 제안은 CODEOWNERS를 담당자 명부가 아니라 ‘검토 요청의 라우팅’으로 정의하고, 병합 가능 여부는 별도의 증거로 남기자는 것이다. 아래의 운영 기록은 GitHub의 공식 설정 형식이나 보안 인증 기준이 아니라, 변경을 닫기 전에 팀이 무엇을 확인했는지 남기기 위한 편집부 제안이다.

소유자는 기준 브랜치에서 결정된다

CODEOWNERS 파일은 .github/, 저장소 루트, docs/ 중 한 곳에 둘 수 있다. 여러 위치에 파일이 있으면 GitHub는 이 순서로 찾아 먼저 찾은 파일을 사용한다. 더 중요한 조건은 풀 리퀘스트의 기준 브랜치다. GitHub 문서는 리뷰 요청을 만들 CODEOWNERS 파일이 풀 리퀘스트의 기준 브랜치에 있어야 한다고 명시한다. 즉, 기능 브랜치에서만 소유자 파일을 고쳤다고 해서 그 풀 리퀘스트의 리뷰 요청 규칙이 즉시 바뀌는 것은 아니다.

이 조건은 특히 기본 브랜치와 릴리스 브랜치가 다른 저장소에서 중요하다. 기본 브랜치의 src/는 플랫폼 팀이 맡고, 릴리스 브랜치의 같은 경로는 유지보수 팀이 맡도록 운영할 수 있기 때문이다. 같은 파일을 보고 있어도 어느 브랜치로 병합하는 풀 리퀘스트인지에 따라 요청을 받을 팀이 달라질 수 있다. 그래서 리뷰 누락을 조사할 때는 먼저 “이 파일에 누가 적혀 있었나”보다 “어느 기준 브랜치의 어떤 CODEOWNERS 파일이 평가됐나”를 확인하는 편이 정확하다.

소유자로 지정된 사람이나 팀에는 쓰기 권한도 필요하다. 팀을 소유자로 쓸 때는 구성원 각자의 권한과 별개로 그 팀 자체가 표시 가능하고 저장소에 쓰기 권한을 가져야 한다. 문법 오류가 있는 행은 GitHub가 건너뛰며, 존재하지 않거나 접근 권한이 부족한 소유자도 할당되지 않는다. 이는 리뷰 요청이 보이지 않을 때 단순히 알림 설정만 볼 일이 아니라, 경로 패턴·대소문자·기준 브랜치·팀 권한을 함께 확인해야 한다는 뜻이다.

CODEOWNERS의 경로 패턴은 대부분 .gitignore와 비슷해 보여도 완전히 같지는 않다. 예를 들어 !로 제외하는 부정 패턴과 문자 범위 표기는 지원되지 않는다. 같은 패턴을 여러 줄에 나누어 쓰면 마지막 줄만 적용될 수 있다. 운영 문서에서 “이 디렉터리는 A와 B가 함께 소유한다”고 설명해도 실제 파일의 두 줄이 서로 덮어쓰면, 도구가 요청하는 사람은 의도와 달라진다. 이런 규칙은 정책 문서보다 파일 자체와 풀 리퀘스트 화면을 함께 읽어야 확인할 수 있다.

요청을 받는 것과 병합을 막는 것은 다르다

CODEOWNERS가 있는 파일을 바꾸면 GitHub는 해당 소유자에게 자동으로 리뷰를 요청한다. 하지만 문서가 설명하듯 소유자 승인을 병합 조건으로 요구하려면 보호 브랜치에서 Require review from Code Owners를 별도로 켜야 한다. 요청은 알림과 검토 경로를 만들고, 요구 승인은 병합 조건을 만든다. 이 구분을 하지 않으면 “소유자가 자동으로 요청됐으니 병합은 안전하게 막힐 것”이라는 잘못된 기대가 생긴다.

여러 소유자를 같은 패턴에 적는 경우도 기대를 분명히 해야 한다. GitHub 문서에 따르면 코드 소유자 검토가 요구될 때는 그 소유자들 가운데 한 명의 승인이 조건을 충족한다. 따라서 보안 팀과 도메인 팀이 모두 확인해야 한다는 규칙은 단순히 한 줄에 두 팀을 나란히 적는 것으로 표현되지 않는다. 필요한 다중 승인 수, 일반 리뷰어 승인, 필수 상태 검사, 대화 해결 같은 요구 사항은 보호 브랜치 또는 규칙 세트의 다른 설정과 함께 검토해야 한다.

소유자 지정은 권한 부여가 아니다. CODEOWNERS의 사람·팀은 저장소에 쓰기 권한이 있어야 소유자로 동작한다. 반대로 소유자로 표시된다는 사실만으로 그 사람이 병합 권한을 얻는 것도 아니다. 담당 경로, 리뷰 요청, 병합 권한은 서로 다른 질문으로 남겨야 한다.

보호 브랜치는 코드 소유자 검토 외에도 승인 수, 상태 검사, 대화 해결, 서명된 커밋, 병합 큐, 배포 성공 같은 조건을 조합할 수 있다. 모든 저장소에 많은 조건을 붙이라는 뜻은 아니다. 예를 들어 문서 경로의 경미한 수정과 배포 스크립트 변경은 되돌리기 어려움과 필요한 검토 근거가 다르다. 팀은 경로별로 어떤 조건이 필수인지 합의해야 하며, 그 합의가 없을 때 CODEOWNERS 파일은 실제 책임 경계보다 넓거나 좁은 알림 목록이 되기 쉽다.

GitHub은 보호 브랜치 규칙 대신 여러 규칙 세트를 함께 적용할 수 있다고도 안내한다. 하나의 보호 브랜치 규칙만 적용될 수 있는 제약과 달리 규칙 세트는 여러 개를 동시에 적용할 수 있다. 다만 기능이 더 많다는 이유만으로 기존 규칙을 일괄 전환할 근거가 되지는 않는다. 먼저 현재 어떤 규칙이 어떤 브랜치에 적용되는지, 그 규칙이 소유자 검토와 상태 검사를 실제로 요구하는지부터 확인해야 한다.

승인 후의 변경은 별도의 검토 대상이다

리뷰가 한 번 승인됐다는 사실은 그 순간의 변경분에 대한 판단일 뿐이다. GitHub은 새 커밋이 풀 리퀘스트의 차이에 영향을 주면 기존 승인을 오래된 것으로 처리하도록 선택할 수 있다고 설명한다. 또한 가장 최근의 검토 가능한 푸시를, 마지막으로 푸시한 사람과 다른 사람이 승인하도록 요구할 수도 있다. 두 설정은 이름이 비슷하지만 같은 효과를 약속하지 않는다. 전자는 변경된 차이에 맞춰 기존 승인을 무효화하는 방식을, 후자는 최신 푸시를 다른 사람이 확인했는지를 다루는 방식을 제공한다.

어느 쪽이 맞는지는 풀 리퀘스트의 크기와 작업 방식에 달려 있다. 오래된 승인을 모두 무효화하면 변경 추적은 분명해지지만, 바쁜 브랜치에서 베이스 브랜치 갱신만으로도 재승인이 자주 필요해질 수 있다. 최신 푸시의 별도 승인을 요구하면 모든 기존 검토를 버리지 않는 대신, 마지막 변경을 실제로 읽는 사람이 필요하다. 이 글은 어느 설정이 항상 낫다고 말하지 않는다. 팀이 선택한 설정이 무엇을 보장하고 무엇을 보장하지 않는지 기록하는 편이 더 중요하다.

기준 브랜치의 소유자 파일, 소유자 검토, 변경분 비교가 다시 검토 또는 병합 준비로 갈리는 모습

▲ 실제 규칙 설정 화면이 아니라, 기준 브랜치와 최신 변경분을 함께 확인해 재검토 여부를 정하는 흐름을 보여줍니다.

풀 리퀘스트가 승인된 뒤에도 자동 포맷터, 충돌 해결, 베이스 브랜치 갱신, 후속 수정이 차이를 바꿀 수 있다. 이때 확인해야 할 것은 ‘리뷰가 있었는가’ 하나가 아니다. 어떤 커밋 이후에 어떤 경로가 바뀌었는지, 그 경로의 소유자 검토가 요구되는지, 기존 승인이 유효한지, 상태 검사가 어떤 소스에서 나온 것인지가 서로 다른 증거다. 특히 같은 작업 이름을 여러 워크플로에서 쓰면 상태 검사 결과가 모호해질 수 있다는 GitHub의 경고도 있다. 리뷰 승인과 검사 통과를 한 줄의 완료 표기로 합치면, 문제를 나중에 추적하기가 어렵다.

변경을 닫기 전에 남길 검토 기록

아래 양식은 작은 저장소에서도 쓸 수 있도록 일부러 짧게 만들었다. 매 풀 리퀘스트에 형식적인 문서를 추가하자는 뜻은 아니다. 보호된 경로, 배포 스크립트, 보안 관련 파일처럼 누가 어떤 근거로 병합을 허용했는지 남겨야 하는 변경에서만 사용해도 된다. 실행하지 않은 설정이나 확인하지 못한 항목은 ‘통과’로 채우지 않고 비워 두거나 보류로 남긴다.

## 변경 검토 경계 기록

- 기준 브랜치와 적용 규칙: [대상 브랜치, 보호 규칙 또는 규칙 세트]
- 바뀐 경로와 소유자: [경로 패턴, 기준 브랜치의 CODEOWNERS에서 확인한 사람 또는 팀]
- 요청과 승인: [리뷰 요청 여부, 실제 승인자, 추가로 필요한 일반 승인]
- 최신 변경 확인: [승인 뒤 새 커밋 여부, 오래된 승인 처리 또는 최신 푸시 승인 조건]
- 독립 조건: [상태 검사, 대화 해결, 배포 조건 중 실제 적용된 것]
- 보류 또는 예외: [충족하지 못한 조건, 우회 권한 사용 여부, 재검토 담당과 조건]

이 기록의 중단 조건은 분명하다. 기준 브랜치의 소유자 파일을 확인하지 못했거나, 적용되는 보호 규칙을 설명할 수 없거나, 승인 뒤의 변경분을 누가 봤는지 알 수 없다면 ‘병합 준비’라고 적지 않는다. 이는 도구가 자동으로 부여하는 차단 규칙이 아니라, 사람이 설정과 변경 이력을 함께 읽기 위한 운영 규칙이다. 반대로 모든 칸이 채워졌다고 해서 코드의 품질, 보안, 배포 결과가 자동으로 보장되는 것도 아니다. 검토 경계 기록은 누락된 질문을 드러내는 도구이지 결과를 보증하는 증명서는 아니다.

기록을 남길 때는 개인의 반응 속도나 업무량을 평가하는 문서로 바꾸지 않는 편이 좋다. 경로의 소유자는 지식의 단일 보유자를 뜻하지 않을 수 있고, 휴가·교대·사고 대응처럼 평소와 다른 상황에서는 대리 검토와 우회 절차가 필요할 수 있다. 그런 예외가 생겼다면 단순히 승인자를 바꿔 적기보다, 어떤 경로의 어떤 변경을 왜 대리 검토했는지와 원래 소유자가 다시 확인해야 하는 조건을 남긴다. 이 메모는 예외를 영구화하기 위한 것이 아니라, 소유자 경계가 실제 운영과 맞지 않는 신호를 다음 규칙 검토에서 발견하기 위한 자료다.

리뷰가 비는 문제를 CODEOWNERS 파일의 줄 수로 해결하려 하면 담당자가 과도하게 늘거나 예외 경로가 숨을 수 있다. 먼저 소유자 요청이 필요한지, 병합을 실제로 막아야 하는지, 최신 변경을 다시 읽어야 하는지를 분리해 보자. 그 뒤 각 질문에 맞는 GitHub 설정과 사람의 검토 근거를 연결하면, ‘누가 봤는가’와 ‘무엇을 근거로 병합했는가’를 같은 체크 표시로 처리하지 않게 된다.

원문을 다시 확인할 곳

  • GitHub Docs — About code owners: 기준 브랜치의 CODEOWNERS 사용, 파일 위치 우선순위, 쓰기 권한, 경로 문법, 코드 소유자 검토 요구와 한 명 승인 조건을 확인할 수 있다.
  • GitHub Docs — About protected branches: 코드 소유자 승인 요구, 오래된 승인 처리, 최신 푸시의 별도 승인, 상태 검사와 브랜치 보호의 적용 범위를 확인할 수 있다.
  • GitHub Docs — About rulesets: 규칙 세트가 여러 규칙을 함께 적용할 수 있는 범위와 보호 브랜치 규칙과의 차이를 확인할 수 있다.

원문 참고 자료

이 글의 사실 확인과 추가 읽기를 위한 원문입니다. GitHub Docs — About code owners

커리어 아키텍트
IT & Mind Trends 에디토리얼 팀 — 클라우드 분산 아키텍처 및 행동 과학 트렌드를 연구하고 실무 트레이드오프를 검증하여 전달합니다.
이전 글
다음 글