[기술정리] Git Actions을 통한 자동 merge CI 세팅 전략 - DDAL-KKAK-DOT/DDALKKAK GitHub Wiki
작성자: 조하은
1. 개요
GitHub Actions를 활용하여 Pull Request에 대한 자동 merge 기능을 구현하는 가이드입니다. 특정 조건(승인 개수, 타겟 브랜치 등)을 만족할 때 자동으로 PR을 병합하여 개발 워크플로우를 효율화할 수 있습니다.
주요 기능
- 승인 기반 자동 병합: 지정된 수 이상의 승인을 받으면 자동 병합
- 브랜치 제한: 특정 브랜치(dev-be, dev-fe 등)로의 PR만 대상
- 안전장치: Draft PR, 작성자 자가 승인 등 예외 상황 처리
- 상세 로깅: 병합 과정과 결과에 대한 투명한 로그 제공
2. 선택지 비교
방법 1: 기존 액션 + 라벨 방식
# pascalgn/automerge-action의 기본 설정
MERGE_LABELS: "automerge"
MERGE_REQUIRED_APPROVALS: 3
장점
- 간단한 설정
- 검증된 액션 사용
단점
- 라벨을 수동으로 추가해야 함
- 승인 수 체크가 부정확할 수 있음
- 디버깅이 어려움
https://github.com/DDAL-KKAK-DOT/DDALKKAK/pull/56
방법 2: 커스텀 스크립트 + 액션 조합 ⭐ 권장
# GitHub Script로 승인 수 직접 계산 후 조건부 병합
steps:
- name: Check approvals count
uses: actions/github-script@v7
- name: Auto merge PR
if: steps.check-approvals.outputs.should-merge == 'true'
장점
- 정확한 승인 수 계산
- 세밀한 조건 제어
- 투명한 로깅
- 라벨 불필요
단점
- 설정이 복잡함
- YAML 코드가 길어짐
방법 3: 써드파티 액션 사용
다양한 커뮤니티 액션들이 존재하지만, 보안과 안정성 측면에서 공식 액션 조합을 권장합니다.
3. 설정방법
3.1 워크플로우 파일 생성
.github/workflows/automerge.yml
파일을 생성하고 다음 내용을 추가합니다:
name: Auto Merge (3+ approvals, dev-be & dev-fe)
on:
pull_request_review:
types: [submitted]
# 동시성 제어: 같은 PR에 대해 하나의 워크플로우만 실행
concurrency:
group: automerge-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
automerge:
if: |
github.event.review.state == 'approved' &&
(github.event.pull_request.base.ref == 'dev-be' || github.event.pull_request.base.ref == 'dev-fe') &&
github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Check approvals count
id: check-approvals
uses: actions/github-script@v7
with:
script: |
const { data: reviews } = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
const prAuthor = context.payload.pull_request.user.login;
// 최신 리뷰만 고려 (같은 사용자가 여러 번 리뷰한 경우)
const latestReviews = {};
reviews.forEach(review => {
if (!latestReviews[review.user.login] ||
new Date(review.submitted_at) > new Date(latestReviews[review.user.login].submitted_at)) {
latestReviews[review.user.login] = review;
}
});
// PR 작성자 제외하고 승인된 리뷰만 카운트
const approvals = Object.values(latestReviews).filter(review =>
review.state === 'APPROVED' && review.user.login !== prAuthor
).length;
const approvedReviewers = Object.values(latestReviews)
.filter(review => review.state === 'APPROVED' && review.user.login !== prAuthor)
.map(review => review.user.login);
console.log(`PR Author: ${prAuthor}`);
console.log(`Current approvals (excluding author): ${approvals}`);
console.log(`Approved by:`, approvedReviewers);
core.setOutput('approvals', approvals);
core.setOutput('should-merge', approvals >= 3);
core.setOutput('approved-reviewers', approvedReviewers.join(', '));
- name: Auto merge PR
if: steps.check-approvals.outputs.should-merge == 'true'
uses: pascalgn/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MERGE_METHOD: squash
MERGE_LABELS: ""
MERGE_REQUIRED_APPROVALS: 0
MERGE_FORKS: false
MERGE_DELETE_BRANCH: true
MERGE_COMMIT_MESSAGE: pull-request-title
- name: Log merge result
if: steps.check-approvals.outputs.should-merge == 'true'
run: |
echo "✅ PR #${{ github.event.pull_request.number }} to ${{ github.event.pull_request.base.ref }} has been auto-merged"
echo "📊 Total approvals: ${{ steps.check-approvals.outputs.approvals }}"
echo "👥 Approved by: ${{ steps.check-approvals.outputs.approved-reviewers }}"
- name: Log insufficient approvals
if: steps.check-approvals.outputs.should-merge == 'false'
run: |
echo "⏳ PR #${{ github.event.pull_request.number }} needs more approvals"
echo "📊 Current approvals: ${{ steps.check-approvals.outputs.approvals }}/3"
echo "👥 Approved by: ${{ steps.check-approvals.outputs.approved-reviewers }}"
3.2 브랜치 보호 규칙 설정
Repository Settings > Branches에서 대상 브랜치(dev-be, dev-fe)에 대한 보호 규칙을 설정합니다:
- Require pull request reviews 활성화
- Required number of approvals: 3으로 설정
- Dismiss stale reviews 활성화 (선택사항)
- Require review from code owners 활성화 (선택사항)
3.3 권한 설정
기본 GITHUB_TOKEN
으로 충분하지만, 브랜치 보호가 강하게 설정된 경우 개인 액세스 토큰이 필요할 수 있습니다:
- GitHub Settings > Developer settings > Personal access tokens 생성
repo
권한 부여- Repository secrets에 토큰 추가
- 워크플로우에서
${{ secrets.YOUR_TOKEN_NAME }}
사용
3.4 커스터마이징 옵션
타겟 브랜치 변경
# 단일 브랜치
github.event.pull_request.base.ref == 'main'
# 여러 브랜치
(github.event.pull_request.base.ref == 'dev-be' ||
github.event.pull_request.base.ref == 'dev-fe' ||
github.event.pull_request.base.ref == 'staging')
승인 수 변경
# 2개 승인으로 변경
core.setOutput('should-merge', approvals >= 2);
병합 방식 변경
env:
MERGE_METHOD: merge # 일반 병합
MERGE_METHOD: squash # 스쿼시 병합
MERGE_METHOD: rebase # 리베이스 병합
4. 정리
동작 프로세스
- 트리거: PR에 승인 리뷰가 제출됨
- 필터링: 승인된 리뷰이면서 대상 브랜치로의 PR인지 확인
- 승인 수 계산: GitHub API를 통해 정확한 승인 수 계산
- 조건 검사: 3개 이상의 승인을 받았는지 확인
- 자동 병합: 조건을 만족하면 squash 병합 실행
- 정리: 병합 후 소스 브랜치 삭제
주의사항
- 동시성: 여러 승인이 동시에 들어와도 안전하게 처리됩니다
- 중복 리뷰: 같은 사용자의 최신 리뷰만 고려됩니다
- 작성자 제외: PR 작성자의 승인은 카운트에서 제외됩니다
- Draft PR: 초안 상태의 PR은 자동 병합되지 않습니다
모니터링
Actions 탭에서 워크플로우 실행 로그를 통해 다음 정보를 확인할 수 있습니다:
- 현재 승인 수
- 승인한 사용자 목록
- 병합 성공/실패 여부
- 부족한 승인 수
트러블슈팅
병합이 실행되지 않는 경우:
- 브랜치 보호 규칙 확인
- GitHub Token 권한 확인
- 워크플로우 로그에서 승인 수 계산 결과 확인
예상보다 적은 승인 수가 카운트되는 경우:
- 작성자 자가 승인 여부 확인
- 변경 요청 후 재승인 여부 확인
- 중복 리뷰어 존재 여부 확인
이 설정을 통해 안전하고 효율적인 자동 병합 시스템을 구축할 수 있습니다.