yd-git-ship · git:20261004.9fdd0f0 · 2026-10-04 · sha256 ddfc0438ab3a3236
yd-git-ship git:20261004.9fdd0f0A
Immutable. This exact content never changes and is served at /api/v1/blob/ddfc0438ab3a3236.
--- name: yd-git-ship description: 'doksam GitLab 레포에 에이전트(Claude Code·Codex·Antigravity)가 작업을 올리는 절차 — 이슈 등록, batch/<agent>-<날짜> 브랜치, "[<model>] <type>: <desc> (#N)" 커밋, Closes MR, merge commit(squash 금지), CI 추적, commit-msg hook 설치. "커밋", "푸시", "MR", "머지", "올려", "이슈 등록", "ship" 등 git/GitLab 에 뭔가 남길 때마다 사용.' --- # yd-git-ship — 에이전트 작업을 GitLab 에 올리기 규칙 원본은 `~/.claude/ref-git-agents.md` (세 에이전트 공통). 이 스킬은 그 규칙을 따르는 **절차와 도구**다. 규칙과 이 문서가 다르면 원본이 우선. 스크립트 위치: 이 스킬 폴더의 `scripts/` (Claude `~/.claude/skills/yd-git-ship`, Codex `~/.codex/skills/yd-git-ship`, Antigravity `~/.gemini/config/skills/yd-git-ship` — 같은 사본). ## 0. 내 값 정하기 | | Claude Code | Codex | Antigravity | |---|---|---|---| | `AGENT` | `claude` | `codex` | `agy` | | 커밋 `-c` | `user.name=claude-ai user.email=claude-ai@doksam.com` | `codex-ai` / `codex-ai@doksam.com` | `agy-ai` / `agy-ai@doksam.com` | | 모델 태그 | 지금 도는 모델 이름, 예 `[Claude Opus 5.5]` | 예 `[GPT-6 Sol]` | 예 `[Gemini 3.8 Flash]` | 모델 태그는 추측하지 말고 자기 시스템 정보에 적힌 실제 모델명을 쓴다. ```bash SK=~/.claude/skills/yd-git-ship/scripts # 에이전트별 경로로 GL="$SK/glab-as.sh claude" # 토큰을 출력하지 않고 자기 계정으로 glab 실행 REPO=gitlab.doksam.com/<ns>/<repo> # -R 에는 호스트까지 붙인다. 명령은 그 레포 폴더 안에서 $GL api user | grep '"username"' # claude-ai 인지 확인 ``` ## 1. 시작 전 점검 ```bash git status -sb; git branch --show-current $GL api "projects/<ns>%2F<repo>/merge_requests?state=opened&author_username=claude-ai" # 내 열린 MR 있으면 그것부터 머지 $GL api "projects/<ns>%2F<repo>" | python3 -c 'import json,sys;p=json.load(sys.stdin);print(p["squash_option"],p["merge_method"])' $SK/install-hook.sh --check || $SK/install-hook.sh # 없으면 설치 → scripts/commit-msg.sh 를 첫 커밋에 포함 ``` - `squash_option` 이 `always` 면 squash 금지 규칙과 충돌하니 사용자에게 알린다. `merge_method` 가 `ff` 면 merge commit 이 안 생기니 역시 알린다. - 레포 AGENTS.md 에 "squash 머지" 같은 옛 문구가 있으면 원본 규칙이 우선이고, 이번 배치에서 같이 고친다. - jj 레포(`.jj/`)는 `jj commit` 이 git hook 을 안 돌린다. 커밋 제목을 직접 맞추고 push 전 `git log` 로 확인한다. ## 2. 이슈 작업 단위마다 이슈. 본문은 파일로 쓰고 "누가 판정하나"를 넣는다. ```bash $GL issue create -R $REPO --title "..." --description "$(cat body.md)" --yes ``` ## 3. 배치 브랜치 · 커밋 · push ```bash git switch main && git pull -q git switch -c batch/claude-$(date +%Y%m%d) # 같은 날 두 번째면 -2 git add <명시 파일만> # -A 금지, .env 금지 git diff --cached | grep -iE 'password|secret|token|glpat-' && echo "시크릿 확인" # 값이 있으면 멈춤 git -c user.name=claude-ai -c user.email=claude-ai@doksam.com commit -m "[Claude Opus 5.5] docs: ... (#N)" git push -u origin HEAD # 수시로 push, MR 은 아직 ``` - 이슈별로 커밋을 나눈다(merge commit 으로 합쳐도 이슈 단위 `git revert` 가 되게). - hook 이 막으면 메시지를 고친다. `--no-verify` 로 우회하지 않는다(오타 수준만 `YD_TRIVIAL=1`). ## 4. MR · 머지 ```bash $GL mr create -R $REPO --source-branch batch/claude-YYYYMMDD --target-branch main \ --title "[Claude Opus 5.5] <요약>" --description "$(cat mr.md)" --remove-source-branch --yes # mr.md 에 반드시: Closes #a #b ... (Refs 만 쓰지 않는다) $GL mr merge <iid> -R $REPO --remove-source-branch --yes # --squash 붙이지 않는다 ``` - push 직후 `mr merge` 가 `405 Method Not Allowed` 면 GitLab 이 아직 mergeability 를 계산 중이다(`detailed_merge_status: checking`). `mergeable` 이 될 때까지 몇 초 기다렸다가 다시 머지한다. - 이슈를 닫으면 안 되는 부분 작업이면, 그 부분만 다루는 이슈를 새로 만들어 `Closes` 한다. - 다른 에이전트가 먼저 머지해 충돌나면 `git merge origin/main` 으로 풀고 push (rebase·force push 금지). - glab 은 **그 레포 폴더 안에서** 실행하고 출력을 `| tail` 로 자르지 않는다. `mr create` 는 현재 폴더의 remote 를 source 로 잡아서, 다른 폴더에서 돌리면 `422 Source project is not a fork` 가 나는데 `tail` 이 그걸 가린다. 실패하면 `--recover` 로 재시도. ## 5. 머지 후 ```bash $GL api "projects/<ns>%2F<repo>/merge_requests/<iid>" | python3 -c 'import json,sys;m=json.load(sys.stdin);print(m["state"],m["merge_commit_sha"],m["squash"])' python3 $SK/ci_wait.py <ns>/<repo> <merge_commit_sha> # run_in_background 로. 배포 잡까지 끝나야 완료 $GL api "projects/<ns>%2F<repo>/issues/<N>" | grep '"state"' # opened 면 note + close git switch main && git pull -q && git branch -d batch/claude-YYYYMMDD git log -1 --format='%an %s' # 작성자·태그 확인 ``` `m["squash"]` 가 true 면 규칙 위반이다. 사용자에게 보고한다(되돌리려면 force push 가 필요하므로 임의로 고치지 않는다). ## 메모리 미러처럼 코드 없는 운영 갱신 main 직접 커밋이 허용되는 예외지만 제목 규칙은 지킨다: `[Claude Opus 5.5] chore: sync memory mirror (#N)`.