Lane và database
Lane là một bản sao độc lập của site dành cho một việc: có git worktree và branch riêng, các submodule nằm trên branch của chúng, một bản sao vendor/ và node_modules/, một database fork từ database của site, và port hoặc host name riêng. Bạn có thể chạy site cùng lúc với nhiều lane, và bỏ lane đi khi việc đã được merge.
Vì sao cần lane
- Một bản sửa gấp khi tính năng đang làm dở. Để nguyên branch tính năng, mở một lane trên
main, sửa, push, rồi xoá lane. - Nhiều AI agent cùng lúc. Mỗi agent một lane, nên không bao giờ sửa chung file, chạy migration trên chung database hay tranh nhau port.
- Review pull request với dữ liệu thật, ngay cạnh việc của bạn.
- Một migration rủi ro chạy trên bản sao dữ liệu thay vì dữ liệu thật.
git worktree thuần chỉ cho bạn code. Lane cho thêm database, .env, port, dependency đã cài và submodule đã khởi tạo, trong khoảng thời gian chừng bằng việc copy database.
Tạo lane
devkit lane new core-development crm-fix --start --progress
… git worktree add ~/Project/sites/core-development/.worktrees/crm-fix (branch feat/crm-fix)
… git submodule update --init --recursive
… copying vendor, node_modules
… forking database core_development to core_development_l1
… lane up core-development--crm-fix
lane core-development--crm-fix (index 1) on branch feat/crm-fix at ~/Project/sites/core-development/.worktrees/crm-fix
copied vendor (clonefile)
copied node_modules (clonefile)
database core_development_l1 forked from core_development (212 tables, 41250 ms)
url http://localhost:8107 (58310 ms)
core-development--crm-fix is up at http://localhost:8107 (PHP 8.3.36, db core_development_l1)
queue running
Lane có tên core-development--crm-fix: tên site, hai dấu gạch ngang, tên lane. Mọi lệnh nhận site đều nhận cả lane.
| Thành phần | Bạn nhận được | Đổi bằng |
|---|---|---|
| Tên | chữ thường, chữ số và dấu gạch ngang đơn, tối đa 32 ký tự | |
| Worktree | <site>/.worktrees/<name>; /.worktrees/ được thêm vào .git/info/exclude của site, nên không bao giờ hiện là untracked | |
| Branch | feat/<name>, tạo từ commit hiện tại của site nếu chưa có, hoặc checkout nguyên trạng nếu đã có | --branch, --base <ref> (chỉ với branch mới) |
| Submodule | khởi tạo đệ quy, mỗi cái được đưa lên branch của nó (branch mà submodule của site đang ở, nếu không thì branch trong .gitmodules) khi branch đó chứa commit đã ghi nhận; nếu không, nó vẫn ở trạng thái detached và devkit cảnh báo | |
| Bản sao | vendor/ và node_modules/, copy-on-write, cùng các --copy-files của site | devkit site set <site> --copy-files … |
| Database | <db>_l<index>, bản sao đầy đủ database của site | --schema-only, --no-fork-db |
| Port, URL | artisan: port riêng, http://localhost:<port>; caddy: https://<lane>.<site>.localhost | |
.env | template của site, render với database, port và URL của lane | template của site |
| Engine, PHP, stack | luôn theo site | trên site |
Fork kèm dữ liệu, chỉ schema, hay database trống
- Fork kèm dữ liệu (mặc định): mọi bảng cùng các dòng của nó. Việc copy chạy ngay trên database server, nên không có gì bị dump ra đĩa; database lớn mất một hai phút.
- Chỉ schema (
--schema-only): mọi bảng, không có dòng nào. Dùng khi đằng nào bạn cũng chạy migration và seeder. - Database trống (
--no-fork-db): không có bảng nào;lane uptạo database. Dùng khi chạymigrate:freshtừ đầu.
Muốn fork thì database của site phải tồn tại: chạy site một lần (devkit site up <site> sẽ tạo nó), hoặc dùng --no-fork-db.
Trong app
Lane mới… trong menu … của site, trong chi tiết site hoặc trong mục Lanes mở Lane mới từ <site>: Tên lane, Branch (Tạo feat/<name> từ một branch gốc, hoặc Dùng branch có sẵn), Database (Fork kèm dữ liệu, Chỉ schema, Database trống) và Chạy lane khi đã sẵn sàng (bật). Phần tóm tắt cho thấy thư mục, database và URL trước khi bạn bấm Tạo lane; sau đó từng bước hiện ra khi devkit báo về.
Nếu có lỗi
Mỗi bước sau worktree đều đăng ký một thao tác hoàn tác. Khi một bước lỗi, hoặc bạn bấm Ctrl-C, devkit gỡ những gì nó đã tạo theo thứ tự ngược lại: bản ghi, bản fork database, rồi worktree và branch nó đã tạo. Lỗi submodule chỉ là cảnh báo, không làm hỏng cả quá trình. Với --start, nếu lane up lỗi thì lane vẫn được giữ và devkit cho bạn biết cách thử lại hoặc xoá nó.
Cảnh báo về prefix Redis
Lane dùng Redis của site. Không có prefix riêng cho từng lane thì lane dùng chung cache key, session và queue với site: worker của lane có thể chạy job của site. Hãy đặt một biến {{lane.*}} trong template của site:
CACHE_PREFIX=webpress{{lane.suffix}}_
REDIS_PREFIX=webpress{{lane.suffix}}_
SESSION_COOKIE=webpress{{lane.suffix}}_session
{{lane.suffix}} là _l1, _l2… trong lane và rỗng với site, nên site vẫn giữ key của mình. lane new cảnh báo khi template không dùng biến {{lane.*}} nào.
Branch và submodule trong lane
- Commit và push từ thư mục lane như bình thường, hoặc dùng thanh branch của lane trong app, hoặc
devkit git push core-development--crm-fix(submodule trước). - Checkout branch khác bên trong lane vẫn được nhưng sẽ có cảnh báo: tên lane không còn khớp với branch của nó.
- Tab Modules và Extensions của lane hoạt động như với site.
devkit modules checkout core-development--crm-fix feat/crm-fix --createđưa mọi submodule lên branch của lane. vendor/vànode_modules/được copy là thư mục thật trong lane: chạydevkit exec <lane> -- composer installsau khi đổicomposer.lock, site không bị ảnh hưởng.
Chạy, dừng và liệt kê
devkit lane list # mọi lane
devkit lane list core-development # các lane của một site
devkit lane up core-development--crm-fix
devkit lane down core-development--crm-fix
lane up và lane down giống hệt site up và site down. Lane có process riêng (theo danh sách của site cho tới khi bạn đổi danh sách của lane), log riêng và thiết lập Xdebug riêng với engine artisan. Trong app, lane được liệt kê dưới site của nó trong Sites và Lanes, với cùng nút chạy, dừng và menu ….
Đặt lại database của lane từ site
Khi dữ liệu của lane đã lệch đi, hoặc site có dữ liệu mới bạn cần, hãy fork lại:
devkit db reset core-development--crm-fix --yes
devkit db reset core-development--crm-fix --yes --schema-only --safety
Web server và các process PHP của lane dừng trong lúc database hiện tại của site được fork sang một database tạm, rồi database tạm đó thay thế database của lane; sau đó chúng chạy lại. --safety giữ một snapshot dữ liệu của lane trước (pre_restore_<time>). Migration lane đã chạy mà site chưa chạy sẽ mất: hãy chạy lại. Không có --yes thì lệnh chỉ nói nó sẽ làm gì.
Trong app: menu … của lane → Đặt lại database từ <site>…, với Schema và dữ liệu hoặc Chỉ schema, và Tạo snapshot database của lane trước khi đặt lại (bật).
Xoá lane
devkit lane rm core-development--crm-fix --dry-run # những gì sẽ bị xoá, và việc nào sẽ mất
devkit lane rm core-development--crm-fix
devkit lane rm core-development--crm-fix --keep-db --delete-branch
lane rm dừng lane, xoá database và các snapshot của nó, gỡ worktree, chứng chỉ, log và các bản sao lưu .env, rồi trả lại port.
- Lệnh từ chối với
DIRTY_WORKTREEkhi lane hoặc một submodule còn thay đổi chưa commit (tính cả file untracked) hoặc có commit chưa nằm trên remote nào. Các commit có sẵn từ lúc tạo lane không được tính.--forcexoá bất kể. --keep-dbgiữ database và snapshot trên server.--delete-branchxoá luôn branch local. Không có nó, branch vẫn ở lại trong repository của site.- Mỗi bước đều chấp nhận việc đã được làm rồi, nên một lần
lane rmlỗi giữa chừng chỉ cần chạy lại.
Trong app: Xoá lane… hiện những gì --dry-run báo, với Giữ database và Xoá luôn branch local (cả hai tắt), và hỏi lại devkit ngay trước khi thực hiện.
Snapshot database
Snapshot là bản sao database của site hoặc lane trên cùng server, có tên <db>__snap_<name>. Nó được tạo bằng cùng cách copy nhanh phía server như khi fork lane, và site vẫn chạy bình thường.
devkit db snapshot shop before_upgrade # tên: a-z, 0-9, _ (tối đa 40)
devkit db snapshot shop # tên: thời điểm hiện tại, 20261026_143005
devkit db snapshots shop # mới nhất trước, kèm thời điểm tạo và dung lượng
devkit db restore shop before_upgrade --yes
devkit db snapshot rm shop before_upgrade --yes
Khôi phục
- Trước tiên devkit tạo một snapshot an toàn của dữ liệu hiện tại (
pre_restore_<time>), nên chính việc khôi phục cũng hoàn tác được.--safety=falsebỏ qua bước này. - Web server và các process PHP của site dừng (Vite vẫn chạy).
- Snapshot được copy vào một database tạm, rồi database tạm thay cho database đang dùng.
- Những gì đã dừng được chạy lại.
Không có --yes, db restore, db reset và db snapshot rm báo lỗi CONFIRM_REQUIRED và nói chúng sẽ làm gì, không thay đổi gì.
Trong app, tab Database trong chi tiết site liệt kê các snapshot với Khôi phục… và Xoá…, còn Tạo snapshot database… tạo một snapshot mới. Sheet khôi phục bật sẵn Tạo snapshot database hiện tại trước và ghi rõ ba bước; tắt nó đi sẽ hiện cảnh báo màu đỏ rằng dữ liệu hiện tại không thể lấy lại.
Truy vấn chỉ đọc
devkit db query shop "SELECT id, email FROM users ORDER BY id DESC LIMIT 5"
devkit db query shop "SHOW TABLES"
Một câu SELECT, SHOW, DESCRIBE hoặc EXPLAIN, chạy trong transaction chỉ đọc rồi rollback, trả về tối đa 500 dòng. Mọi thứ khác, câu lệnh thứ hai hay INTO OUTFILE đều bị từ chối. Lệnh này để kiểm tra nhanh và cho AI agent; việc thật thì dùng database client quen thuộc của bạn (port của stack có trong devkit stack list).
Giới hạn nên biết
- Chỉ bảng được copy. View, routine (procedure và function), trigger, event và sequence thì không; devkit liệt kê những thứ nó bỏ qua. Tạo lại chúng bằng migration nếu lane cần.
- Bản fork không được chụp tại một thời điểm duy nhất. Các bảng được copy song song trong lúc site vẫn chạy, nên dòng được ghi trong lúc copy có thể có ở bảng này mà không có ở bảng kia. Khi cần một snapshot nhất quán tuyệt đối, hãy dừng queue và scheduler của site (hoặc cả site) trước.
- Chỉ MySQL và MariaDB, trên cùng server: snapshot và bản fork nằm cạnh bản gốc và dùng đĩa của nó.
- Tối đa 99 lane mỗi site. Số của một lane không được dùng lại khi devkit vẫn còn liệt kê lane đó.
- Không thể ẩn riêng lane; ẩn site sẽ ẩn các lane của nó.
- Xoá thư mục lane bằng tay sẽ để lại bản ghi và database của nó (
lane listbáo worktree bị thiếu); chạydevkit lane rmđể dọn dẹp.