merge-code-from-devs
Quy trình nhập (merge) code từ nhánh developer (ví dụ: development-yen) vào nhánh chính (development) — THÔNG QUA SCRIPT AN TOÀN. Agent KHÔNG gọi lệnh git trực tiếp. Script tự: resolve đúng repo từ tê
SKILL.md.claude/skills/_archived-sasuco/merge-code-from-devs/SKILL.md
GitHubMerge Code Từ Developer Branch — SASUCO InvoiceEasy
⚠️ TUYỆT ĐỐI KHÔNG tác động vào nhánh
maintrong toàn bộ quy trình này. Chỉ làm việc với:development(nhánh nhận) vàdevelopment-<tên>(nhánh nguồn).
🛑 NGUYÊN TẮC CỐT LÕI (v2 — sau sự cố 13/08/2026): Agent KHÔNG gọi lệnh git trực tiếp. Mọi thao tác git chạy qua script trong
scripts/. Agent CHỈ: chạy script → đọc kết quả JSON → báo cáo → chờ user duyệt. Lý do: agent gọi git tay từng gây CWD sai repo → xóa file nested repos (sự cố 09/08 + 13/08).
� RÀNG BUỘC AGENT (bắt buộc tuyệt đối):
- Chỉ được chạy script (
node .../scripts/*.cjs) và đọc output.- KHÔNG được tự ý thực hiện bất kỳ lệnh git/khác nào ngoài script (vd:
git merge,git checkout,git push,git reset,git stash, sửa file repo...).- Khi script báo lỗi → chỉ báo cáo lại cho user kèm nội dung lỗi + gợi ý; KHÔNG tự sửa bằng lệnh tay.
- Khi script yêu cầu xác nhận (exit 2 /
waiting-confirm) → DỪNG, báo user, chờ duyệt rồi mới chạy lại với--yes.- Mọi kết quả đều lấy từ JSON script xuất ra — không tự suy đoán trạng thái git.
💡 Nếu user gõ script trực tiếp (không qua skill) mà quên tham số: script sẽ hiển thị prompt hỏi nhập đầy đủ
--portal,--branch,--target(kèm danh sách giá trị hợp lệ). Khi chạy từ terminal thật (TTY), user nhập tay; khi agent chạy (không TTY), script báo lỗi yêu cầu truyền tham số.
�📖 Tài liệu phân tích giải pháp đầy đủ:
docs/giai-phap-merge-an-toan-2026-08-13.md
B0 — Xác Định Repo Cần Merge (BẮT BUỘC ĐẦU TIÊN)
🎯 ĐẦU VÀO BẮT BUỘC (Hỏi user nếu thiếu)
| # | Đầu vào | Ví dụ |
|---|---|---|
| 1 | Portal app cần merge (nhánh nhận = development của repo đó) |
portal: kiemthu / portal: invoice / portal: ketoan |
| 2 | Lập trình viên nguồn (nhánh nguồn = development-<tên>) |
development-yen / development-tuan |
❌ Thiếu 1 trong 2 → DỪNG và hỏi (không đoán).
🚫 GIỚI HẠN PHẠM VI — CHỈ merge repo PORTAL app, CẤM TUYỆT ĐỐI mọi repo khác
⛔ NGUYÊN TẮC CỐT LÕI: merge CHỈ được thực hiện giữa các branch trong repo PORTAL app (thư mục
src/modules/<App>). CẤM tuyệt đối merge vào:
- ❌ root —
D:\JDX-SOUCRE-MAIN-FE-PORTAL\Jdx-portal-root- ❌ docker —
D:\JDX-SOUCRE-MAIN-FE-PORTAL\Jdx-portal-root\Docker- ❌ agentskill —
D:\JDX-SOUCRE-MAIN-FE-PORTAL\Jdx-portal-root\.github- ❌ Bất kỳ thư mục/repo nào nằm NGOÀI
src/modules/Lý do: các repo này quản lý cấu hình/deploy/skill toàn cục — merge sai sẽ lan tác động hoặc xóa file nested repos (sự cố 09/08 + 13/08/2026). Script tự chặn cứng ngay khi nhận
--portal root|docker|agentskillhoặc path ngoàisrc/modules/(báo lỗi, exit 1).
🛡️ LỚP BẢO VỆ KỸ THUẬT — script tự kiểm tra TRƯỚC khi merge (tất cả đều BLOCK nếu sai)
| # | Lớp bảo vệ | Cơ chế | FAIL = |
|---|---|---|---|
| 1 | Alias cấm | FORBIDDEN_MERGE_ALIASES chặn ngay root/docker/agentskill khi nhận --portal |
Dừng |
| 2 | Phạm vi đường dẫn | resolveMergeRepoPath yêu cầu repoPath nằm TRONG src/modules/ (so sánh path chuẩn hóa) |
Dừng |
| 3 | show-toplevel khớp | git rev-parse --show-toplevel phải bằng đúng thư mục repo mong muốn (chống CWD/alias sai) |
Dừng |
| 4 | Remote URL khớp | checkRemoteMatch — origin URL phải chứa repo đúng của portal (vd jdx-portal-kiemthu). Chống clone nhầm repo vào thư mục portal |
Dừng |
| 5 | Validate branch | validateTargetBranch + validateSourceBranch — đích phải development*, nguồn phải development-<tên>; cấm main/master, cấm merge chính nó |
Dừng |
✅ Chỉ cần 1 lớp FAIL → script DỪNG ngay, không merge. Agent chỉ báo cáo kết quả JSON cho user. Lớp 4 là bổ sung mới (2026-08-13): ngăn trường hợp thư mục
src/modules/<App>bị thay bằng clone của repo khác.
Kiến trúc 12 repo độc lập
Dự án có 12 Git repo riêng biệt (1 Root + 1 Docker + 1 .github + 9 Portal). Script resolve repo từ alias portal qua PORTAL_MAP — agent KHÔNG cần nhớ đường dẫn.
✅ CHỈ 9 repo PORTAL app sau được merge (hợp lệ):
Alias (truyền --portal) |
Thư mục git (so với root) |
|---|---|
invoice / invoiceapp |
src/modules/InvoiceApp/ |
admin / adminapp |
src/modules/AdminApp/ |
partner / partnerapp |
src/modules/PartnerApp/ |
sso / ssoapp |
src/modules/SsoApp/ |
ketoan / ketoanapp / accounting |
src/modules/KetoanApp/ |
crm / crmapp |
src/modules/CrmApp/ |
taisan / taisanapp |
src/modules/TaiSanApp/ |
kiemthu / kiemthuapp |
src/modules/KiemThuApp/ |
baseindex / baseindexapp |
src/modules/BaseIndexApp/ |
🚫 CẤM TUYỆT ĐỐI (script từ chối exit 1 — kể cả khi user yêu cầu):
| Alias | Thư mục git (so với root) |
|---|---|
root |
./ |
docker |
Docker/ (chỉ 1 nhánh master) |
agentskill |
.github/ |
⚠️ Merge portal app → repo CHỈ nằm trong
src/modules/<App>. Script luôn chạy git vớicwdchỉ định + kiểm tragit rev-parse --show-toplevel+ chặn phạm vi 2 lớp (FORBIDDEN_MERGE_ALIASES+ path nằm trongsrc/modules/ở cảresolveRepoPathlẫnresolveMergeRepoPath) + kiểm tra remote URL (checkRemoteMatch) — không thể lan sang root/docker/agentskill/portal khác kể cả khi terminal CWD sai hoặc thư mục bị clone nhầm repo.
Quy Trình Tổng Quan (v2 — Script Tự Động)
🚀 CÁCH NHANH: Chạy 1 lệnh duy nhất
main-merge.cjsđể tự động hoàn thành toàn bộ quy trình (pre-check → chờ duyệt → merge → post-check). Dùng 3 script bước rời khi cần tách kiểm soát từng giai đoạn.
B0: Xác định REPO (alias) + LẬP TRÌNH VIÊN nguồn — hỏi user nếu thiếu
B1: 🖥️ Chạy SCRIPT 0 — main-merge.cjs (điều phối) — KHÔNG --yes
→ Chỉ chạy pre-check → JSON { ok, errors, warnings } → exit 2 (chờ duyệt)
B2: Báo cáo kết quả pre-check cho user → 🛑 CHỜ DUYỆT
B3: 🖥️ Chạy LẠI main-merge.cjs --yes (tự động: backup 2 bên + merge --no-ff + post-check)
→ JSON tổng hợp { backupsCreated, mergeCommit, ok, errors }
B4: Báo cáo tổng hợp → đóng task
─── HOẶC tách bước (khi cần kiểm soát từng giai đoạn) ───
B1: 🖥️ 1-check-pre-merge.cjs (kiểm tra TRƯỚC)
B2: Báo cáo → 🛑 CHỜ DUYỆT
B3: 🖥️ 2-merge-safe.cjs (backup 2 bên + merge --no-ff)
B4: 🖥️ 3-check-post-merge.cjs (kiểm tra SAU)
Agent KHÔNG được: gõ
git checkout/merge/push/reset/...trong terminal. Mọi thứ script lo.
B0.5 — SCRIPT 0: main-merge.cjs (Điều Phối — 1 Lệnh Hoàn Thành)
Đây là entry point chính — 1 lệnh tự động chạy đủ quy trình. Không cần nhớ thứ tự 3 script.
# Bước 1 — chạy KHÔNG --yes (chỉ pre-check, DỪNG chờ duyệt, exit 2):
node .claude/skills/merge-code-from-devs/scripts/main-merge.cjs \
--portal <alias> --branch <nguồn> [--target development]
# Bước 2 — sau khi user duyệt, chạy LẠI với --yes (merge + post-check, có thể thêm --push):
node .claude/skills/merge-code-from-devs/scripts/main-merge.cjs \
--portal <alias> --branch <nguồn> [--target development] --yes [--push]
Tham số:
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
--portal <alias> |
✅ | CHỈ portal app (kiemthu / ketoan / ...) — cấm root/docker/agentskill |
--branch <nguồn> |
✅ | Nhánh dev nguồn (vd development-tuan) — phải bắt đầu development- (nhánh cá nhân); cấm main/master/development (nhánh chính)/branch lạ làm nguồn |
--target <đích> |
❌ | Mặc định development — phải bắt đầu development*, cấm main/master |
--yes |
❌ | Có thì chạy trọn (merge + post-check); thiếu thì chỉ pre-check rồi dừng — bắt buộc cho cả main-merge lẫn 2-merge-safe |
--push |
❌ | Có thì push origin/<đích> sau merge (mặc định KHÔNG push) |
🔴 Ràng buộc branch (script tự chặn):
--target main/master❌ |--targetkhông bắt đầudevelopment❌ |--branch main/master❌ |--branch development(nhánh chính) ❌ |--branchkhông bắt đầudevelopment-(branch lạ) ❌ |--branchtrùng--target❌ (merge chính nó).
Luồng bên trong (main-merge.cjs):
[B1] PRE-CHECK → resolve repo + show-toplevel khớp + fetch + working tree sạch
+ branch tồn tại + không file xóa (D) → lỗi chặn = DỪNG ngay
[B2] CONFIRM → không --yes: dừng (exit 2) để agent báo cáo, chờ user duyệt
[B3] MERGE-SAFE → backup 2 bên IDEMPOTENT (chỉ tạo mới nếu CHƯA có backup cùng commit;
chạy lại nhiều lần sẽ DÙNG LẠI backup cũ, không tạo trùng)
+ switch <đích> + merge --no-ff (conflict → abort, KHÔNG resolve)
[B4] POST-CHECK → đúng branch + tree sạch + backup còn + mọi commit nguồn vào đích
Exit code: 0 = xong toàn bộ · 1 = lỗi chặn/abort · 2 = pre-check PASS, đang chờ duyệt (chạy lại với --yes).
B1 — SCRIPT 1: Kiểm Tra TRƯỚC
node .claude/skills/merge-code-from-devs/scripts/1-check-pre-merge.cjs \
--portal <alias> --branch <nguồn> [--target development]
Script tự kiểm tra (mỗi mục FAIL đều chặn merge):
| # | Kiểm tra | FAIL = |
|---|---|---|
| 1 | Portal hợp lệ + repo tồn tại + .git + repoPath nằm trong src/modules/ |
Dừng |
| 2 | show-toplevel khớp repo mong muốn |
Dừng (chống sai repo) |
| 2b | Remote URL khớp — origin chứa repo đúng của portal (vd jdx-portal-kiemthu) |
Dừng (chống clone nhầm repo) |
| 3 | Working tree sạch (không tracked M/D) | Dừng |
| 4 | Branch nguồn tồn tại (local/remote) | Dừng |
| 5 | Branch đích tồn tại | Dừng |
| 6 | Diff nguồn..đích KHÔNG có file xóa (D) | Dừng (chống mất code) |
| 7 | 🔴 Nguồn phải chứa MỌI commit của đích (git rev-list --count nguồn..đích = 0) |
Dừng — BẮT BUỘC cập nhật nhánh nguồn trước |
| 8 | 🔴 Branch hợp lệ (--target ≠ main/master, bắt đầu development*; nguồn phải bắt đầu development- (vd development-tuan), cấm main/master/development/branch lạ) |
Dừng |
Exit code: 0 = sẵn sàng · 1 = lỗi chặn · 2 = cảnh báo (báo user quyết định).
Cảnh báo (KHÔNG chặn — chỉ báo user xác nhận):
- Nhánh nguồn không có commit mới so với đích (merge sẽ tạo commit rỗng)
- Đã tồn tại nhánh backup (script sẽ dùng lại, không tạo trùng)
Agent đọc JSON → báo cáo user:
✅ Pre-check PASS: repo đúng (show-toplevel khớp, remote jdx-portal-kiemthu khớp),
working tree sạch, nguồn development-tuan có 90 commits mới, không file xóa.
⚠️ WARN: đã có 2 nhánh backup — script sẽ dùng lại backup cùng commit, không tạo trùng.
👉 Có merge không? (yes/no)
B2 — 🛑 CHỜ USER DUYỆT (BẮT BUỘC)
KHÔNG chạy 2-merge-safe khi chưa có xác nhận
yes. Lỗi chặn (exit 1) → tuyệt đối không merge.
B3 — SCRIPT 2: Merge An Toàn (Backup 2 Bên)
# KHÔNG --yes → chỉ pre-check rồi DỪNG (exit 2, chờ duyệt) — KHÔNG merge
node .claude/skills/merge-code-from-devs/scripts/2-merge-safe.cjs \
--portal <alias> --branch <nguồn> [--target development]
# Có --yes → thực hiện merge thật
node .claude/skills/merge-code-from-devs/scripts/2-merge-safe.cjs \
--portal <alias> --branch <nguồn> [--target development] --yes [--push]
🔴 Bắt buộc
--yes— nếu chạy2-merge-safetrực tiếp không có--yes, script chỉ chạy pre-check rồi DỪNG (exit 2). Không có cơ chế "merge ngầm".
Script tự thực hiện (an toàn tuyệt đối):
1. Resolve repo từ alias → verify .git + show-toplevel khớp + validate branch (chặn main/lạ/trùng)
2. Chạy lại pre-check (lỗi chặn → ABORT ngay) — không --yes: DỪNG chờ duyệt (exit 2)
3. git fetch origin (lỗi mạng → WARN, không chặn)
4. Đảm bảo branch nguồn local
5. TẠO BACKUP 2 BÊN IDEMPOTENT (git branch — không đổi working tree):
backup/<nguồn>-<ts> backup/<đích>-<ts> (dùng lại nếu đã có cùng commit)
6. git switch <đích>
7. git merge <nguồn> --no-ff --no-edit
→ FAIL/CONFLICT: git merge --abort → báo lỗi (KHÔNG resolve thủ công)
8. [--push] git push origin <đích> (mặc định KHÔNG push)
Exit code: 0 = merge thành công · 1 = lỗi (đã abort, working tree nguyên trạng).
Agent đọc JSON → báo cáo:
✅ Merge thành công: backup/development-tuan-20260813-153000, backup/development-20260813-153000
Merge commit: abc1234
B4 — SCRIPT 3: Kiểm Tra SAU
node .claude/skills/merge-code-from-devs/scripts/3-check-post-merge.cjs \
--portal <alias> [--target development] [--source <nguồn>]
Script tự kiểm tra:
- Remote URL khớp repo portal mong đợi (chống kiểm tra nhầm repo)
- Branch hiện tại — CHỈ CẢNH BÁO nếu không ở đích (vì
main-merge/2-merge-safetự quay về branch gốc sau merge — không còn là lỗi chặn) - Working tree sạch sau merge
- Nhánh backup tồn tại
git log <đích>..<nguồn>rỗng → mọi commit nguồn đã vào đích (bắt buộc truyền--source <nguồn>)- HEAD là merge commit hợp lệ
Exit code: 0 = đạt · 1 = có vấn đề (báo user, dùng backup khôi phục).
B5 — Báo Cáo & Đóng Task
## 📋 BÁO CÁO MERGE — {Tên repo} `{nguồn}` → `{đích}`
| Bước | Kết quả |
|------|---------|
| Pre-check | ✅ PASS (hoặc ⚠️ WARN N) |
| Backup | `backup/{nguồn}-{ts}`, `backup/{đích}-{ts}` |
| Merge | ✅ commit `{hash}` (hoặc ❌ abort — conflict) |
| Post-check | ✅ PASS |
| Push | ✅/❌ (--push) |
- Lỗi chặn (pre-check FAIL / merge abort) → báo user hướng khắc phục, không tự ý merge
- Thành công + user duyệt → có thể
--push
Quy Tắc Vàng
| ✅ ĐƯỢC | ❌ KHÔNG ĐƯỢC |
|---|---|
Chạy script trong scripts/ + đọc JSON |
Gọi lệnh git trực tiếp trong terminal |
| Chỉ chạy script, nhận kết quả, báo cáo user | Tự ý thực hiện bất kỳ lệnh khác (git/script/sửa file repo) ngoài script |
| Hỏi đủ 2 đầu vào: portal app + dev nguồn | Merge khi thiếu thông tin (đoán mò) |
Truyền --portal đúng alias 1 trong 9 portal app |
Merge vào root / docker / agentskill / repo khác — script chặn (exit 1); agent không được hỏi, đề xuất, hay làm theo nếu user yêu cầu merge repo cấm |
--target bắt đầu bằng development (vd development) |
--target main/master hoặc target lạ (script chặn) |
--branch là nhánh cá nhân development-<tên> (vd development-tuan) |
--branch main/master, --branch development (nhánh chính), branch lạ, hoặc --branch trùng --target (script chặn) |
| Chạy trên đúng repo portal (remote khớp, show-toplevel khớp) | Merge khi repo sai / remote lạ / clone nhầm repo (script chặn) |
Đọc kết quả 1-check-pre-merge → chờ user duyệt |
Tự merge khi chưa xác nhận |
| Để script tạo backup 2 bên | Tự tạo/xóa backup thủ công |
Merge --no-ff (script tự) |
--squash / --ff-only |
| Conflict → script abort (báo user) | Agent tự resolve conflict / git checkout --ours/--theirs |
| Kiểm tra post-merge trước khi báo thành công | Bỏ qua post-check, báo "xong" vội |
| Chỉ merge repo được chỉ định (script cô lập) | Merge lan sang repo khác |
🛡️ Script KHÔNG chứa lệnh xóa/reset commit (
git reset,git branch -D,git push --force,git clean). Backup tạo ra không bị script xóa — giữ làm phao cứu sinh.🧑💻 User chạy trực tiếp: nếu quên tham số, script hiển thị prompt nhập đầy đủ
--portal/--branch/--targetkèm danh sách hợp lệ — gõ giá trị rồi Enter để tiếp tục.
Xử Lý Sự Cố
| Tình huống | Cách xử lý |
|---|---|
1-check-pre-merge FAIL "SAI REPO" |
Báo user, chạy lại với --portal đúng |
1-check-pre-merge FAIL "working tree bẩn" |
Báo user commit/stash trước |
1-check-pre-merge FAIL "file xóa (D)" |
BLOCK — nhánh nguồn đi sau, cần cập nhật nguồn trước |
1-check-pre-merge FAIL "THIẾU N commit của đích" |
BLOCK — BẮT BUỘC nhánh nguồn phải merge development vào rồi push TRƯỚC, sau đó mới merge lại |
2-merge-safe abort (conflict) |
Báo user, dùng backup hoặc cập nhật nguồn trước khi merge lại |
3-check-post-merge FAIL |
Báo user, hướng dẫn khôi phục từ backup/* |
| Script lỗi runtime | Báo user kèm log — không tự sửa script trừ khi được yêu cầu |