Admin 패널에 Git 브랜치 뷰어를 만든 이유
GitHub만으로는 부족했습니다
개인 블로그를 모노레포로 운영하면서 브랜치가 꽤 많이 쌓였습니다. 기능별로 브랜치를 따서 작업하고, 머지하고, 또 새 브랜치를 만들고. 그런데 문제는 머지 후 삭제하지 않은 브랜치가 로컬과 원격 모두에 방치되고 있다는 것이었습니다.
GitHub에 들어가면 원격 브랜치 목록은 볼 수 있습니다. 하지만 GitHub이 보여주는 건 push된 상태뿐입니다. 로컬에만 있는 브랜치, 지금 체크아웃된 브랜치, 그리고 git worktree로 병렬 작업 중인 디렉토리 정보는 GitHub에서 확인할 방법이 없습니다.
터미널에서 git branch -a를 치면 되긴 합니다. 하지만 Admin 패널에서 글을 쓰다가 "지금 어떤 브랜치에서 작업 중이지?"를 확인하려고 매번 터미널로 전환하는 건 번거로운 일이었습니다.
만들게 된 구체적인 이유
계기는 두 가지였습니다.
첫째, 방치된 브랜치 정리가 필요했습니다. feat/hybrid-search, feat/tiptap-editor 같은 브랜치들이 이미 main에 머지된 뒤에도 원격에 그대로 남아 있었습니다. 로컬에도 마찬가지였습니다. 어떤 브랜치가 아직 살아있는 작업이고 어떤 브랜치가 정리 대상인지, 마지막 커밋 날짜를 보면 바로 판단할 수 있을 것이라 생각했습니다.
둘째, worktree를 활용한 병렬 작업 현황 파악이었습니다. git worktree를 사용하면 하나의 레포에서 여러 브랜치를 동시에 체크아웃할 수 있습니다. 다만 "지금 어떤 worktree에서 어떤 브랜치가 작업 중인지"를 한눈에 보려면 git worktree list를 쳐야 하는데, 이것도 웹에서 바로 확인할 수 있으면 편하겠다는 생각이 들었습니다.
GitHub과의 차이점
정리하면 이런 차이가 있습니다.
| 항목 | GitHub | Admin Git Info |
|---|---|---|
| push 안 한 로컬 브랜치 | 볼 수 없음 | 표시됨 |
| 현재 체크아웃된 브랜치 | 알 수 없음 | current 표시 |
| git worktree 목록 | 개념 자체가 없음 | 경로/브랜치 표시 |
| 로컬 커밋 상태 | push 후에만 반영 | 즉시 반영 |
| 마지막 커밋 날짜 | 브랜치 페이지에서 확인 | 한 화면에 모두 표시 |
핵심은 GitHub이 "원격 저장소의 상태"를 보여주는 반면, 이 페이지는 "개발 머신의 실시간 상태"를 보여준다는 점입니다.
웹브라우저에서 git 정보를 조회하는 원리
브라우저에서는 직접 파일 시스템에 접근하거나 git 명령을 실행할 수 없습니다. 보안상 당연한 제약입니다. 그래서 백엔드 서버가 중간 다리 역할을 합니다.
브라우저 (React)
↓ HTTP GET /admin/git/info
NestJS 백엔드
↓ child_process.execFile('git', [...])
로컬 git CLI 실행
↓ stdout 파싱
JSON 응답으로 반환
↓
브라우저에서 테이블 렌더링
Node.js의 child_process.execFile을 사용하면 서버에서 시스템 명령어를 실행할 수 있습니다. exec 대신 execFile을 쓴 이유는 shell injection 방지 때문입니다. exec는 셸을 통해 명령을 실행하므로 인자에 ; rm -rf / 같은 것이 들어갈 수 있지만, execFile은 인자를 배열로 전달하기 때문에 이런 위험이 없습니다.
로컬 브랜치 조회
git의 --format 옵션을 활용하면 원하는 정보만 깔끔하게 추출할 수 있습니다.
git branch --format='%(HEAD)\x1f%(refname:short)\x1f%(objectname:short)\x1f%(subject)\x1f%(creatordate:relative)'
각 필드의 의미는 이렇습니다.
%(HEAD)— 현재 브랜치면*, 아니면 공백%(refname:short)— 브랜치 이름 (예:main)%(objectname:short)— 마지막 커밋 해시 (예:265a515)%(subject)— 커밋 메시지%(creatordate:relative)— 상대 시간 (예:2 days ago)
구분자로 \x1f(Unit Separator)를 사용했습니다. 커밋 메시지에 |나 ,가 포함될 수 있기 때문에, ASCII 제어 문자를 구분자로 쓰면 파싱이 깨지지 않습니다.
원격 브랜치 조회
원격 브랜치도 동일한 방식입니다. -r 플래그만 추가하면 됩니다.
git branch -r --format='%(refname:short)\x1f%(objectname:short)\x1f%(subject)\x1f%(creatordate:relative)'
다만 이 정보는 마지막 git fetch 시점의 스냅샷이라는 점을 알아두어야 합니다. 원격 브랜치의 실제 최신 상태를 보려면 먼저 git fetch를 실행해야 합니다.
Worktree 목록 조회
git worktree list --porcelain
--porcelain 옵션을 붙이면 프로그램에서 처리하기 쉬운 고정된 텍스트 형식으로 출력됩니다. 각 worktree마다 경로, HEAD 커밋, 브랜치 정보가 한 블록으로 나옵니다.
서비스 초기화 시 레포 루트 탐지
한 가지 주의할 점이 있었습니다. NestJS가 실행되는 process.cwd()가 반드시 git 레포의 루트 디렉토리와 같지 않을 수 있습니다. 모노레포 구조상 백엔드 패키지 디렉토리에서 실행될 수도 있기 때문입니다.
그래서 서비스 초기화 시 git rev-parse --show-toplevel을 실행해서 실제 레포 루트 경로를 한 번 찾아두고, 이후 모든 git 명령에 이 경로를 cwd로 전달하는 방식을 사용했습니다.
async onModuleInit() {
const { stdout } = await execFileAsync('git', ['rev-parse', '--show-toplevel'], {
timeout: 5000,
});
this.repoRoot = stdout.trim();
}
프론트엔드 구현
프론트엔드는 기존 Admin 패널의 패턴을 그대로 따랐습니다. React Query의 useQuery 훅으로 데이터를 가져오고, 테이블 형태로 렌더링합니다. staleTime을 60초로 설정해서 불필요한 재요청을 줄였고, 수동 새로고침 버튼도 추가했습니다.
페이지는 세 섹션으로 나눠집니다.
- 로컬 브랜치 — 현재 브랜치는 초록색으로 하이라이트, 각 브랜치의 마지막 커밋 정보 표시
- 원격 브랜치 — 브랜치명과 마지막 커밋 해시, 메시지, 날짜 표시
- Worktrees — 각 worktree의 경로, 브랜치, HEAD 해시 표시
보안 고려사항
이 기능은 Admin 패널에서만 접근 가능합니다. NestJS의 JwtAuthGuard와 RolesGuard를 통해 admin 역할을 가진 사용자만 호출할 수 있도록 했습니다. 그리고 이 Admin 패널 자체가 로컬에서만 실행되는 도구이기 때문에, 외부에서 접근할 수 있는 경로는 없습니다.
execFile을 사용해서 shell injection을 방지한 것도 중요한 부분입니다. 읽기 전용 git 명령만 실행하고, 사용자 입력이 git 명령 인자에 포함될 여지가 없습니다.
돌이켜 생각해보면
사실 터미널에서 git branch -a 한 줄이면 되는 일이긴 합니다. 하지만 Admin 패널에서 글을 쓰다가 컨텍스트 전환 없이 바로 확인할 수 있다는 건, 생각보다 편한 경험이었습니다.
특히 원격 브랜치의 마지막 커밋 날짜를 한눈에 볼 수 있으니, "이 브랜치는 3개월 전이 마지막이네, 정리해야겠다"는 판단을 빠르게 내릴 수 있게 되었습니다. 작은 도구지만, 로컬 개발 환경의 상태를 시각적으로 파악할 수 있다는 점에서 나름 유의미한 작업이었다는 생각이 듭니다.
관련 글
Claude Code Skills로 Git Worktree 병렬 개발 환경 자동화하기
Claude Code Skills로 git worktree 기반 병렬 개발 환경을 자동화한 경험을 공유합니다. 환경변수 복사, 포트 격리, Docker DB 분리, E2E 테스트 대응, Slack 알림까지 포함된 워크플로우를 만들었습니다.
Claude Code Skills 실전: 브랜치 정리를 자동화한 cleanup-branch 스킬
병합 완료된 브랜치를 정리할 때마다 워크트리 해제, 디렉토리 삭제, 로컬/리모트 브랜치 삭제를 순서대로 기억해야 했습니다. Claude Code Skills로 이 과정을 자동화한 경험과 SKILL.md 전문을 공유합니다.
NestJS Cron으로 Grafana Cloud 서버 메트릭을 Slack에 자동 보고하기
NestJS 스케줄러와 Grafana Cloud Prometheus API를 연결해 매일 아침 서버 상태를 Slack으로 자동 보고하는 시스템을 구축한 과정을 정리했습니다. 이미 갖춰진 인프라를 활용해 최소한의 코드로 일일 리포트를 만드는 방법입니다.