📚 Git Machete 배포 자동화 커스텀 스크립트 공유
Git Machete로 관리 중인 기능 브랜치(Leaf)들만 자동으로 추출하여, 지정한 배포 타겟 브랜치(deploy/*)에 안전하게 체리픽(Cherry-pick)하고 Push까지 마무리해 주는 자동화 스크립트의 설정 및 사용법을 공유합니다.
다수의 기능(Feature) 브랜치를 개발 서버나 스테이징 서버에 배포할 때 일일이 브랜치를 이동하며 머지/체리픽하는 작업은 번거롭고 실수가 발생하기 쉽습니다. 특히 체리픽을 사용할 때 발생하는 '중복 커밋으로 인한 충돌'을 방지하고, 충돌이 발생하더라도 스크립트가 멈추지 않도록 개선한 자동화 도구가 필요했습니다.
deploy -t dev -t stage 처럼 여러 배포 브랜치를 한 번에 지정하여 순차적으로 작업할 수 있습니다.git machete list childless를 사용하여 자식 브랜치가 없는 가장 끝단(완성된 기능)의 브랜치들만 타겟팅합니다.git cherry): 타겟 브랜치에 이미 반영된 커밋인지 사전 검사하여, 이미 반영된 변경사항이면 안전하게 스킵(Skip)합니다.-abort)한 뒤 다음 브랜치로 넘어갑니다.~/.zshrc 파일에 아래의 스크립트를 붙여넣습니다.# Git Machete Leaf 브랜치 자동 체리픽 & Push 스크립트
deploy() {
local targets=()
local branches=()
local base_branch="master"
# 1. 인자 파싱 (-t 또는 --target)
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target)
if [[ -n "$2" ]]; then
targets+=("$2")
shift 2
else
echo "❌ 오류: -t 또는 --target 뒤에 타겟 이름(dev, stage 등)을 지정해주세요."
return 1
fi
;;
*)
echo "❌ 알 수 없는 옵션입니다: $1"
return 1
;;
esac
done
if [[ ${#targets[@]} -eq 0 ]]; then
echo "⚠️ 사용법: deploy -t dev -t stage"
return 1
fi
# 2. Leaf 브랜치 목록 가져오기
branches=(${(f)"$(git machete list childless)"})
if [[ ${#branches[@]} -eq 0 ]]; then
echo "⚠️ 체리픽할 Leaf 브랜치가 없습니다."
return 1
fi
local original_branch=$(git branch --show-current)
# 3. 타겟 브랜치별 작업 수행
for t in "${targets[@]}"; do
local target_branch="deploy/$t"
local conflict_branches=()
echo "\n======================================"
echo "🚀 타겟 브랜치 준비: $target_branch"
echo "======================================"
git checkout "$target_branch" || {
echo "❌ $target_branch 브랜치로 이동할 수 없습니다."
continue
}
echo "⬇️ 원격 저장소와 동기화 중..."
if git rev-parse --abbrev-ref "$target_branch@{upstream}" >/dev/null 2>&1; then
git pull || { echo "❌ git pull 실패."; return 1; }
echo "✅ 최신 동기화 완료."
fi
echo "\n🔄 Machete Leaf 브랜치 체리픽 시작 (기준: $base_branch)..."
for b in "${branches[@]}"; do
if [[ "$b" == "$target_branch" || "$b" == "$base_branch" ]]; then
continue
fi
# git cherry를 사용하여 타겟 브랜치에 '아직 없는(+)' 커밋만 추출
local commits=($(git cherry HEAD "$b" "$base_branch" | awk '$1 == "+" {print $2}'))
# 적용할 새로운 커밋이 없다면 쿨하게 스킵
if [[ ${#commits[@]} -eq 0 ]]; then
echo " ⏭️ 이미 모두 반영된 브랜치입니다 (스킵): $b"
continue
fi
echo " 🍒 체리픽 시도 (${#commits[@]}개 새 커밋): $base_branch..$b"
if git cherry-pick --empty=drop "${commits[@]}" >/dev/null 2>&1; then
echo " ✅ 체리픽 성공: $b"
else
echo " 🚨 충돌 발생: $b -> 체리픽을 취소하고 건너뜁니다."
git cherry-pick --abort >/dev/null 2>&1
conflict_branches+=("$b")
fi
done
# 4. Push 및 요약
echo "\n⬆️ 원격 저장소로 Push 중..."
if git push -u origin "$target_branch" >/dev/null 2>&1; then
echo "✅ Push 완료!"
else
echo "❌ Push 실패."
fi
echo "\n--------------------------------------"
if [[ ${#conflict_branches[@]} -eq 0 ]]; then
echo "🎉 $target_branch 작업 완료! (충돌 없음)"
else
echo "⚠️ $target_branch 작업 완료 (일부 충돌 발생)"
for cb in "${conflict_branches[@]}"; do echo " - $cb"; done
echo "위 브랜치들은 수동 해결이 필요합니다."
fi
done
echo "\n======================================"
echo "원래 브랜치($original_branch)로 돌아갑니다."
git checkout "$original_branch"
}
1. 현재 브랜치 상태 확인 (git machete status)
현재 Machete 트리가 아래와 같이 구성되어 있다고 가정해 보겠습니다.
master
│
├── feature/login
│ └── web/20260310/amplitude-notification (Leaf 브랜치 1)
│
└── feature/payment
├── web/20260106/1-recommend-context (Leaf 브랜치 2)
└── web/20260310/books-frontend-bootstrap (Leaf 브랜치 3)
여기서 우리가 배포하려는 대상은 맨 끝단에 있는 3개의 Leaf 브랜치입니다.
2. .git/machete 파일 생성
아래와 같이 .git 폴더에 machete 파일을 생성합니다.
master
feature/login
web/20260310/amplitude-notification
feature/payment
web/20260106/1-recommend-context
web/20260310/books-frontend-bootstrap
3. 스크립트 실행
개발(dev) 환경과 스테이징(stage) 환경에 순차적으로 배포하고 싶다면 터미널에 아래와 같이 입력합니다.
deploy -t dev -t stage
4. 예상되는 터미널 출력 결과 (예시)
스크립트가 실행되면 아래와 같이 진행 상황을 보여줍니다.
======================================
🚀 타겟 브랜치 준비: deploy/dev
======================================
⬇️ 원격 저장소와 동기화 중...
✅ 최신 동기화 완료.
🔄 Machete Leaf 브랜치 체리픽 시작 (기준: master)...
🍒 체리픽 시도 (3개 새 커밋): master..web/20260310/amplitude-notification
✅ 체리픽 성공: web/20260310/amplitude-notification
⏭️ 이미 모두 반영된 브랜치입니다 (스킵): web/20260106/1-recommend-context
🍒 체리픽 시도 (5개 새 커밋): master..web/20260310/books-frontend-bootstrap
🚨 충돌 발생: web/20260310/books-frontend-bootstrap -> 체리픽을 취소하고 건너뜁니다.
⬆️ 원격 저장소로 Push 중...
✅ Push 완료!
--------------------------------------
⚠️ deploy/dev 작업 완료 (일부 충돌 발생)
다음 브랜치들은 충돌이 발생하여 건너뛰었습니다:
- web/20260310/books-frontend-bootstrap
위 브랜치들은 수동 해결이 필요합니다.
======================================
원래 브랜치로 돌아갑니다.
💡 결과 해석:
amplitude-notification: 정상적으로 새 커밋들이 추출되어 체리픽 및 Push 되었습니다.1-recommend-context: 이전 배포 때 이미 deploy/dev에 들어간 커밋들이라 스크립트가 똑똑하게 이를 인지하고 스킵했습니다.books-frontend-bootstrap: 다른 코드와 충돌이 발생했습니다. 스크립트는 멈추지 않고 해당 작업을 취소한 뒤 끝까지 실행되었으며, 개발자는 나중에 이 브랜치만 수동으로 체리픽하여 충돌을 해결하면 됩니다.git-machete CLI 툴이 설치되어 있어야 하며, .git/machete 파일에 브랜치 트리가 구성되어 있어야 정상 동작합니다.local base_branch="master" 부분을 바꾸면 다른 브랜치를 base 브랜치로 설정할 수 있습니다.