devkit English

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ầnBạn nhận đượcĐổi bằng
Tênchữ 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
Branchfeat/<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)
Submodulekhở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 saovendor/ và node_modules/, copy-on-write, cùng các --copy-files của sitedevkit site set <site> --copy-files …
Database<db>_l<index>, bản sao đầy đủ database của site--schema-only, --no-fork-db
Port, URLartisan: port riêng, http://localhost:<port>; caddy: https://<lane>.<site>.localhost
.envtemplate của site, render với database, port và URL của lanetemplate của site
Engine, PHP, stackluôn theo sitetrê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 up tạo database. Dùng khi chạy migrate:fresh từ đầ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ạy devkit exec <lane> -- composer install sau khi đổi composer.lock, site không bị ảnh hưởng.
Copy-on-write diễn ra tức thì và không tốn dung lượng cho tới khi file thay đổi, trên APFS (macOS) và btrfs hoặc XFS (Linux). Trên ext4 đó là bản copy thường, lâu hơn và tốn dung lượng đĩa.

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_WORKTREE khi 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. --force xoá bất kể.
  • --keep-db giữ database và snapshot trên server.
  • --delete-branch xoá 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 rm lỗ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

  1. 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=false bỏ qua bước này.
  2. Web server và các process PHP của site dừng (Vite vẫn chạy).
  3. Snapshot được copy vào một database tạm, rồi database tạm thay cho database đang dùng.
  4. 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 list báo worktree bị thiếu); chạy devkit lane rm để dọn dẹp.