GitLab Sync (main → builds/dev/)
Skill này pair với gitlab-flow. Trong khi gitlab-flow lo phần feature → main, skill này lo phần sync main → builds/dev/<app> khi cần deploy QA mà gặp conflict.
Phạm vi: Chỉ tập trung vào
main → builds/dev/<app>. Các flow khác (release → builds/prod,cut release,cherry-pick hotfix) trong thực tế gần như không conflict (FF được) hoặc chỉ làm 1 vài lần/quý → không cần automation, Maintainer làm tay được. Nếu sau này phát sinh nhu cầu thì mở rộng skill.
Nguyên tắc cốt lõi
Code chỉ chảy 1 chiều từ
main→builds/dev/<app>. Conflict resolve TRÊN nhánh trung giansync/*, PR ngược vềbuilds/dev/<app>— KHÔNG BAO GIỜ lôi codebuilds/dev/*vàomain.
Hierarchy của branch (upstream → downstream) — Monorepo multi-app
┌──→ builds/dev/portal-web-admin ─┐
├──→ builds/dev/gift-web-admin │
main ────────┼──→ builds/dev/gift-api ├──→ deploy QA
├──→ builds/dev/portal-api │
└──→ builds/dev/<other-app> ─┘
| Tier | Branch | Vai trò |
|---|---|---|
| Source of truth | main |
Integration, đã review, đã pass gate. 1 cho cả monorepo |
| Deploy trigger (QA) | builds/dev/<app> |
1 nhánh cho mỗi app. Chỉ là điểm trigger CI/CD, KHÔNG chứa code mới |
| Ephemeral | sync/* |
Tạm thời, xoá ngay sau khi MR merged |
Key insight monorepo: code chung 1
mainnhưng nhiềubuilds/dev/<app>vì mỗi app deploy độc lập. Mỗi lần sync chỉ động vào 1 app, không sync hàng loạt trừ khi user yêu cầu rõ.
Rule không bao giờ vi phạm
- 🚫 KHÔNG commit thẳng vào
builds/dev/*— kể cả "sửa nhanh 1 dòng" - 🚫 KHÔNG PR
builds/dev/* → main— chiều ngược, làm rác main - 🚫 KHÔNG merge
feature/* → builds/dev/*trực tiếp — phải quamain - 🚫 KHÔNG resolve conflict bằng cách kéo
builds/devvào nhánh feature — code rác sẽ leo lên main - ✅ Conflict
main → builds/dev/<app>→ resolve trênsync/main-to-dev-<app>rồi PR vàobuilds/dev/<app>
Conventions
Sync branch naming
Format: sync/main-to-dev-<app>[-<date>]
| Use case | Tên nhánh ví dụ |
|---|---|
Sync main → builds/dev/portal-web-admin |
sync/main-to-dev-portal-web-admin |
Sync main → builds/dev/gift-api |
sync/main-to-dev-gift-api |
Sync main → builds/dev/portal-api |
sync/main-to-dev-portal-api |
| Sync 2 lần trong cùng ngày trên cùng app | thêm -2026-05-12-2 (lần 2 trong ngày) |
| Rule | Detail |
|---|---|
| Prefix | Luôn sync/ — KHÔNG dùng feature/, chore/, fix/ |
| Format | sync/main-to-dev-<app> — đọc 1 phát biết chiều và app nào |
| App slug | Bắt buộc. Khớp 100% với slug ở builds/dev/<app> |
| Date suffix | Optional, thêm khi cần phân biệt nhiều lần sync trong ngày |
| Tuổi thọ | Ephemeral — xoá ngay sau khi MR merged |
| Length | Target ≤ 60 chars. App slug dài quá → vẫn giữ nguyên (đừng viết tắt) |
Commit message khi resolve conflict
Format: chore(sync): resolve conflict main → builds/dev/<app>
| Ví dụ |
|---|
chore(sync): resolve conflict main → builds/dev/portal-web-admin |
chore(sync): resolve conflict main → builds/dev/gift-api |
- KHÔNG dùng type
feat/fix— sync không thêm logic mới, chỉ reconcile - Body (optional): mô tả file conflict + bên nào được giữ
- 🚫 KHÔNG
Co-Authored-By: Claude ...(kế thừa rule từgitlab-flow)
Target branch của MR
| Sync branch | MR target | KHÔNG được set target = |
|---|---|---|
sync/main-to-dev-<app> |
builds/dev/<app> |
❌ main, ❌ builds/dev/<app-khác> |
⚠️ Self-check trước khi tạo MR:
- Target bắt buộc là
builds/dev/<app>— KHÔNG được PR vàomain- Tên app trong sync branch phải khớp với app trong target. Vd
sync/main-to-dev-gift-api→ target bắt buộc làbuilds/dev/gift-api, KHÔNG được PR sangbuilds/dev/portal-api
Triggers & Procedures
"list build branches" / "show me các app trong repo" / "có những builds dev nào"
Liệt kê toàn bộ builds/dev/* hiện có — giúp user pick đúng app khi sync.
git fetch --all --prune
git ls-remote --heads origin "refs/heads/builds/dev/*" | awk '{print $2}' | sed 's|refs/heads/builds/dev/||' | sort
Output ví dụ:
gift-api
gift-web-admin
portal-api
portal-web-admin
Format report cho user:
## QA apps (builds/dev/<app>)
- gift-api
- gift-web-admin
- portal-api
- portal-web-admin
Hỏi tiếp: "Bạn muốn sync app nào?" → dùng trigger sync main to dev-<app>.
"sync main to dev-" / "sync main vào builds/dev/" / "resolve conflict builds/dev/"
Trigger chính. Xảy ra khi cần deploy QA cho 1 app nhưng main → builds/dev/<app> không fast-forward được.
Step 0 — Detect app slug từ input:
| Input pattern | Hành động |
|---|---|
sync main to dev-gift-api |
App = gift-api, target = builds/dev/gift-api |
sync main vào builds/dev/portal-web-admin |
App = portal-web-admin |
resolve conflict gift-api |
App = gift-api, target = builds/dev/gift-api |
sync main to dev (không có app) |
STOP, gọi trigger list build branches để user pick |
sync QA (chung chung) |
STOP, hỏi: app nào? |
Verify app tồn tại trước khi tiếp tục:
git fetch --all --prune
git ls-remote --heads origin "refs/heads/builds/dev/<app>" | head -1
- Output rỗng → STOP, báo "Không tìm thấy
builds/dev/<app>. Chạylist build branchesxem các app có sẵn" - Có output → tiếp tục Step 1
Step 1 — Verify tình huống có cần sync không:
git log --oneline origin/main..origin/builds/dev/<app> # commit có trên target mà main không có
git log --oneline origin/builds/dev/<app>..origin/main # commit có trên main mà target không có
| Output | Ý nghĩa | Hành động |
|---|---|---|
origin/builds/dev/<app>..origin/main rỗng |
Main không có gì mới so với target | STOP, báo "không có gì để sync" |
origin/main..origin/builds/dev/<app> rỗng |
Target là subset của main → FF được | Không cần sync branch, có thể PR main → builds/dev/<app> trực tiếp |
origin/main..origin/builds/dev/<app> có merge commit only |
Bình thường (kết quả sync trước) | Tiếp tục Step 2 |
origin/main..origin/builds/dev/<app> có non-merge commit |
Vi phạm rule "không commit thẳng builds/*" | Cảnh báo user, đề xuất chạy kiểm tra build hygiene trước khi sync |
Step 2 — Tạo sync branch từ main (KHÔNG từ target):
git checkout main
git pull origin main
git checkout -b sync/main-to-dev-<app>
Vd cho portal-web-admin: git checkout -b sync/main-to-dev-portal-web-admin
Step 3 — Merge target VÀO sync branch để lộ conflict:
git merge origin/builds/dev/<app>
| Kết quả | Hành động |
|---|---|
Already up to date |
Không có gì để resolve — báo user, xoá sync branch, kết thúc |
Fast-forward (rare) |
Không có conflict thật — có thể FF trực tiếp ở Step 6 |
CONFLICT (content): ... |
Bình thường, sang Step 4 |
error: refusing to merge unrelated histories |
Branch lệch nghiêm trọng — STOP, hỏi user |
Step 4 — Resolve conflict (giữ phía main):
git status # list file conflict
git diff --name-only --diff-filter=U # chỉ list file đang conflict
Quy tắc resolve:
| Tình huống | Bên nên giữ | Lý do |
|---|---|---|
| Code logic (function, component, API) | main (HEAD) |
Main là source of truth, đã review |
Config QA-specific trên builds/dev (API URL QA, debug flag) |
target (incoming) | QA env config không được leak lên main |
| Resolution không rõ | STOP, hỏi user | Không tự đoán — sync sai sẽ ảnh hưởng deploy |
Cách giữ phía main nhanh (khi chắc chắn 100%):
git checkout --ours <file> # giữ phía HEAD = main (vì sync branch tạo từ main)
git add <file>
Cách giữ phía target:
git checkout --theirs <file>
git add <file>
Cách edit thủ công (default — nên dùng cho code logic):
- Mở file, xoá marker
<<<<<<<,=======,>>>>>>> - Giữ đúng phiên bản logic mong muốn
git add <file>
Step 5 — Verify + commit:
git status # phải sạch, không còn file `U`
git diff --cached --stat # review những file thay đổi
Commit message:
git commit -m "$(cat <<'EOF'
chore(sync): resolve conflict main → builds/dev/<app>
Conflict file: <list>
Resolution: giữ phiên bản main cho logic, giữ phía target cho config env.
EOF
)"
🚫 KHÔNG
Co-Authored-By: Claude(xemgitlab-flowrule).
Step 6 — Push gate:
- Báo commit hash + nội dung
- DỪNG, hỏi user: "Đã commit
<hash>resolve conflict. Push lên remote và tạo MR không?" - Đợi xác nhận:
git push -u origin sync/main-to-dev-<app>
Step 7 — Tạo MR sync/* → builds/dev/<app> (KHÔNG về main):
glab mr create \
--source-branch sync/main-to-dev-<app> \
--target-branch builds/dev/<app> \
--title "chore(sync): main → builds/dev/<app>" \
--description "$(cat <<'EOF'
## Summary
- Sync code từ main về builds/dev/<app> để deploy QA
- Resolve conflict trên các file: <list>
## Resolution
- Logic code: giữ phía main
- Config env (nếu có): giữ phía target
## Test plan
- [ ] CI build pass trên sync branch
- [ ] Sau khi merge, deploy QA app <app> chạy được
- [ ] Smoke test golden path của app <app>
EOF
)" \
--remove-source-branch
Self-check trước khi chạy lệnh trên:
-
--source-branchbắt đầu bằngsync/ -
--target-branchlàbuilds/dev/<app>(KHÔNG phảimain) - App slug trong source khớp app slug trong target (
sync/main-to-dev-gift-api→builds/dev/gift-api, không phảibuilds/dev/portal-api) - Title có prefix
chore(sync): -
--remove-source-branchcó mặt (sync branch là ephemeral)
Step 8 — Sau khi MR merged:
git checkout main
git fetch --prune
git branch -d sync/main-to-dev-<app> # local đã xoá
# Remote tự xoá bởi --remove-source-branch
Báo user: deploy QA cho app <app> giờ có thể trigger (Maintainer push tag / chạy pipeline).
"sync main to dev-all" / "sync main vào tất cả builds/dev" / "deploy QA tất cả apps"
Khi cần sync main sang nhiều builds/dev/<app> cùng lúc. Skill chạy tuần tự từng app — KHÔNG gộp 1 sync branch chung.
Step 1 — List + confirm:
- Chạy trigger
list build branchesđể lấy danh sách - Hiển thị danh sách cho user, hỏi: "Sync hết tất cả app hay chỉ chọn vài app? Liệt kê app cần sync (cách nhau dấu phẩy) hoặc 'all'"
- Đợi user pick
Step 2 — Loop qua từng app:
Với mỗi app trong danh sách user chọn:
- Verify như Step 1 của trigger "sync main to dev-"
- Nếu không cần sync (target = subset của main) → skip, báo
[<app>] đã đồng bộ, skip - Nếu cần sync → chạy đầy đủ Step 2-8 cho app đó
- DỪNG sau mỗi app, hỏi user: "App
<app>đã có MR, xác nhận tiếp app kế tiếp không?" - User: "skip"/"next" → bỏ qua; "stop" → dừng toàn bộ
Step 3 — Tóm tắt cuối:
## Sync summary
✅ Đã tạo MR (chờ merge):
- sync/main-to-dev-portal-web-admin → !123
- sync/main-to-dev-gift-api → !124
⏭ Skip (đã đồng bộ):
- portal-api
- gift-web-admin
❌ Lỗi:
- notification-service (lý do: ...)
⚠️ KHÔNG dùng 1 sync branch chung cho nhiều
builds/dev/<app>. Mỗi app có config khác nhau, conflict khác nhau, MR phải tách riêng để dev đúng app review được.
"kiểm tra build hygiene" / "check builds/dev/ sạch không" / "audit all dev builds"
Audit định kỳ: phát hiện vi phạm rule "không commit thẳng builds/dev/*". Có 2 mode: single app hoặc toàn bộ.
Step 1 — Xác định scope:
| User input | Mode |
|---|---|
kiểm tra build hygiene portal-web-admin |
Single app |
audit all dev builds |
All apps — auto-list rồi loop |
Step 2 — So sánh từng build với main:
git fetch --all --prune
git log --oneline origin/main..origin/builds/dev/<app> # commit có trên build mà main không có
| Output | Diễn giải |
|---|---|
| Rỗng | ✅ Sạch — builds/dev/<app> đúng là subset của main |
Có merge commit only (Merge branch 'main') |
⚠️ Bình thường — kết quả các lần sync trước. Acceptable |
| Có commit không phải merge | ❌ VI PHẠM — có người commit thẳng vào builds/dev/* |
Step 3 — Nếu vi phạm, list ra:
git log origin/main..origin/builds/dev/<app> --no-merges --pretty=format:"%h %an %ad %s" --date=short
Báo user dạng table:
## ❌ builds/dev/portal-web-admin — 3 commit vi phạm
| Hash | Author | Date | Subject |
|---|---|---|---|
| abc1234 | nguyenvana | 2026-05-10 | hotfix nhanh login |
| def5678 | tranthib | 2026-05-08 | sửa config QA |
| 9876543 | lehvc | 2026-05-05 | test feature flag |
Step 4 — Đề xuất cleanup cho từng commit:
Option A — Cherry-pick về main (nếu commit có giá trị):
- Tạo
feature/<TASK-ID>-recover-from-build-<app>nếu thực sự cần - Cherry-pick từng commit
- PR về main như feature thường
Option B — Reset build về main (nếu commit là rác):
- Cần Maintainer + force-push permission
- Cảnh báo: sẽ mất commit đó vĩnh viễn
- Hỏi user xác nhận 2 lần trước khi đề xuất lệnh
git push --force-with-lease
KHÔNG tự chạy force-push. Đề xuất lệnh để user/Maintainer chạy.
Step 5 — Báo cáo tổng (Mode all):
## Audit summary
✅ Sạch (3): gift-api, portal-api, gift-web-admin
❌ Vi phạm (1):
- builds/dev/portal-web-admin (3 commit lạ)
Quick decision: user nói gì → trigger gì
| User nói | Trigger |
|---|---|
| "có app nào", "list builds", "show me apps" | list build branches |
| "sync main về QA cho portal-web-admin" | sync main to dev-portal-web-admin |
| "sync main về dev của gift-api" | sync main to dev-gift-api |
| "deploy QA hết các app" | sync main to dev-all |
| "check build/dev có sạch không" | kiểm tra build hygiene <app> |
| "audit all builds" | kiểm tra build hygiene (Mode all) |
Out of scope (làm tay nếu cần)
Các flow sau KHÔNG trong scope skill — Maintainer làm tay vì:
- Tần suất thấp (1 lần/quý hoặc ít hơn)
- Thực tế hiếm conflict (FF được)
- Cần judgment cao, không nên automation
| Flow | Tần suất | Lý do skip |
|---|---|---|
Cut release branch main → release/v<X.Y> |
Mỗi major/minor release | Không có conflict (release chưa tồn tại) |
Deploy prod release/v<X.Y> → builds/prod/<app> |
Release day | Gần như luôn FF (release = snapshot, builds/prod chỉ theo đuôi) |
| Cherry-pick hotfix về main | Khi có hotfix | Hiếm, Maintainer judgement |
| Cherry-pick bugfix release về main | Cuối release cycle | Hiếm, Maintainer judgement |
Nếu sau này 1 trong các flow trên trở nên thường xuyên + hay conflict → mở rộng skill.
Safety rules
- 🚫 KHÔNG tạo MR
builds/dev/* → maindưới bất kỳ hình thức nào, kể cả qua nhánh trung gian. Nếu user yêu cầu, từ chối và giải thích vi phạm rule 1-chiều - 🚫 KHÔNG
git push --forcevàomain,builds/dev/*— kể cả--force-with-lease. Reset chỉ làm khi user/Maintainer chủ động ra lệnh - 🚫 KHÔNG
git merge --strategy=oursđể "fake resolve" — sẽ skip thay đổi thật, gây lệch code thầm lặng - 🚫 KHÔNG dùng
git checkout --ours <file>cho code logic mà không đọc qua diff — chỉ dùng khi đã xác nhận phía main đúng - ✅ Mọi sync branch là ephemeral — đảm bảo
--remove-source-branchkhi tạo MR - ✅ Hỏi user trước khi resolve nếu không chắc bên nào đúng — đặc biệt với file config, .env, route definition
- ✅ Verify target branch của MR trước khi
glab mr create— đọc lại--target-branch2 lần - ✅ Sau mỗi sync MR merged: xoá local sync branch +
git fetch --pruneđể dọn reference cũ
Tools required
git(luôn có)glab(GitLab CLI) — cần để tạo MR sync. Tham khảo install: https://gitlab.com/gitlab-org/cli
Interaction với gitlab-flow
| Tình huống | Dùng skill |
|---|---|
| Feature mới từ Jira task → main | gitlab-flow |
| Review MR feature → main | gitlab-review |
| Merge feature MR vào main | gitlab-review |
| Sau khi feature merged main, cần deploy QA | gitlab-sync (main → builds/dev/) |
| Kiểm tra builds/dev có sạch không | gitlab-sync (kiểm tra build hygiene) |
2 skill này độc lập nhưng bổ sung nhau — gitlab-flow lo "code đi vào main", gitlab-sync lo "main đi ra builds/dev/<app> để deploy QA".