서론
블로그를 운영하다 보면 글을 쓰는 것 외에도 반복적인 작업들이 생깁니다. README 업데이트, 추천 글 관리, 코드 포맷팅 등 손이 가는 일들이 쌓이면 글쓰기에 집중하기 어려워집니다. 이번에 Git Hooks와 GitHub Actions를 활용해 이런 작업들을 자동화하면서 겪었던 과정을 정리해보려 합니다.
자동화 이전의 문제점
수동 작업의 반복
- README에 최신 글 목록을 직접 업데이트해야 했음
- 추천 글을 선정할 때마다 수동으로 마크업 수정
- 마크다운 포맷이 파일마다 제각각
원격 저장소 충돌
- GitHub Actions가 자동으로 커밋을 생성하면 로컬과 충돌 발생
- push 전에 매번 pull을 해야 하는지 확인 필요
품질 관리 부재
- YAML front matter 오류를 빌드 후에야 발견
- 비공개 키 같은 민감한 파일이 실수로 커밋될 위험
구축한 자동화 시스템
전체 흐름
로컬 커밋
↓
pre-commit: 코드 품질 검사
↓
post-commit: 새 포스트 AI 분석
↓
git push
↓
pre-push: 원격 동기화 확인
↓
GitHub Actions: README 자동 업데이트
네 단계의 자동화를 통해 커밋부터 배포까지 일관된 품질을 유지할 수 있게 되었습니다.
pre-commit: 커밋 전 품질 검사
pre-commit 프레임워크를 도입해 커밋 전에 자동으로 검사를 수행합니다.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: check-xml
- id: detect-private-key
- id: fix-byte-order-marker
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
files: 'docs/_posts/.*\.md$'
args: ['--prose-wrap', 'always', '--print-width', '80']
각 hook의 역할은 다음과 같습니다.
check-yaml: YAML 문법 오류 사전 차단detect-private-key: 비공개 키 파일 커밋 방지prettier: 마크다운 포맷 통일 (80자 줄바꿈)
기존에 작성된 170개 포스트는 .prettierignore에 등록해 불필요한 변경을 방지했습니다.
post-commit: AI 기반 추천 글 분석
새 포스트를 커밋하면 자동으로 Claude CLI를 호출해 추천 글 적합성을 분석합니다.
# .git/hooks/post-commit
NEW_POSTS=$(git diff-tree --no-commit-id --name-only -r HEAD \
| grep -E '^docs/_posts/.*\.md$')
if [ -n "$NEW_POSTS" ]; then
bash scripts/check_recommended.sh "$NEW_POSTS"
fi
분석 스크립트는 다음 과정을 거칩니다.
- 기존 추천 포스트 정보 추출 (Ruby 스크립트)
- 프롬프트 템플릿에 새 포스트 정보 주입
- Claude CLI로 분석 실행
- 추천 여부, 점수, 평가 이유 출력
## 평가 기준
- 독창성: 새로운 시각이나 접근법을 제시하는가
- 실용성: 독자에게 실질적인 도움을 주는가
- 구조화: 논리적으로 잘 정리되어 있는가
- 공감성: 독자가 공감할 수 있는 내용인가
- 성찰: 개인적인 통찰이 담겨 있는가
- 카테고리 균형: 기존 추천 글과의 다양성
이를 통해 추천 글 선정에 일관된 기준을 적용할 수 있게 되었습니다.
pre-push: 원격 충돌 방지
GitHub Actions가 자동으로 커밋을 생성하기 때문에, push 전에 원격 저장소와 동기화가 필요합니다.
# .githooks/pre-push
BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [ "$BRANCH" = "main" ]; then
git fetch origin $BRANCH
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse origin/$BRANCH)
BASE=$(git merge-base HEAD origin/$BRANCH)
if [ "$LOCAL" = "$REMOTE" ]; then
echo "이미 동기화됨"
elif [ "$REMOTE" = "$BASE" ]; then
echo "로컬이 앞서 있음, push 진행"
else
echo "원격에 새 커밋 있음, rebase 실행"
git pull --rebase origin $BRANCH
fi
fi
핵심은 git merge-base를 활용해 로컬과 원격의 관계를 파악하는 것입니다. 원격에 새 커밋이 있으면 자동으로 rebase를 수행해 충돌을 방지합니다.
.githooks/ 디렉토리를 사용하면 hook을 버전 관리할 수 있어 다른 환경에서도 동일한 설정을 적용할 수 있습니다.
git config core.hooksPath .githooks
GitHub Actions: README 자동 업데이트
두 개의 워크플로우가 push 시 자동 실행됩니다.
최신 글 목록 업데이트
# .github/workflows/bog-post-workflow.yml
- name: Update blog posts
uses: gautamkrishnar/blog-post-workflow@v1
with:
feed_list: "https://kaestro.github.io/feed.xml"
feed.xml에서 최신 포스트를 가져와 README의 지정된 영역을 업데이트합니다.
추천 글 목록 업데이트
# .github/workflows/count_recommended.yml
- name: Count recommended posts
run: |
ruby -ryaml -e '
posts = Dir.glob("docs/_posts/**/*.md")
.map { |f| [f, YAML.load_file(f, permitted_classes: [Date])] }
.select { |_, meta| meta["recommended"] == true }
.sort_by { |_, meta| -meta["date"].to_time.to_i }
.first(5)
'
recommended: true가 설정된 포스트를 스캔해 상위 5개를 README에 반영합니다.
결과
이번 자동화 구축으로 다음과 같은 효과가 있었습니다.
- 커밋 전 YAML/XML 오류 자동 검출
- 새 포스트 작성 시 AI 기반 품질 피드백
- push 전 원격 충돌 자동 해결
- README 최신 상태 자동 유지
- 마크다운 포맷 일관성 확보
특히 pre-push hook 덕분에 GitHub Actions의 자동 커밋으로 인한 충돌을 신경 쓰지 않아도 되어 편해졌습니다. 글쓰기에만 집중할 수 있는 환경을 만드는 것이 목표였는데, 어느 정도 달성한 것 같습니다.