升级
用 git 把新版 ShipKit 合并进你的项目:把发布仓库加为 remote,合并版本 tag,解决冲突,并把迁移一起带过来。
你的项目和 ShipKit 共享代码,所以新版本的到来方式和任何上游更新一样:一次 git 合并。你的提交历史原样保留,模板的改动叠加在上面,两边改到同一处时 git 会明确指出来。
版本是怎么发布的
购买后,你的 GitHub 账号会被邀请为 ShipKit 发布仓库的协作者。仓库里每个版本都是 main 上的一个提交,打着 v<version> 的 tag(v0.5.0、v0.6.0……),并在仓库的 Releases 页面附有发布说明,列出新增的迁移、新增或改名的环境变量,以及破坏性变更。版本号遵循 semver:minor 版本可能带迁移和可选的环境变量;major 版本意味着有破坏性变更,或新增了必需的环境变量。
合并之前先读发布说明。它会告诉你冲突大概出现在哪里,合并后还要做什么。
添加 remote(只需一次)
用你受邀的那个发布仓库的 SSH 或 HTTPS 地址:
git remote add shipkit <release-repo-url>
git fetch shipkit --tags
git tag -l 'v*'
如果你的项目是直接克隆发布仓库得来的,origin 已经指向它了。把它改名为 shipkit,再把你自己的仓库加为 origin:
git remote rename origin shipkit
git remote add origin <your-repo-url>
合并前想先看看某个版本改了什么:
git diff v0.5.0 v0.6.0 --stat
合并一个版本
从干净的工作区出发,单独开一个分支,这样升级出了问题也没有任何损失:
git switch -c upgrade-v0.6.0
第一次合并怎么做,取决于你的项目是怎么开始的。
项目是克隆来的
你的历史里已经包含了起步时的那个模板提交,git 有共同祖先,只会给你看那之后的变化:
git merge v0.6.0
以后每次升级都是同一条命令,换成下一个 tag 即可。
项目是复制来的
如果你是下载了文件,或者把文件复制进一个新的 git init 仓库,那你的历史和模板的历史毫无关联,直接合并会报 “refusing to merge unrelated histories”。需要显式允许:
git merge v0.6.0 --allow-unrelated-histories
没有共同祖先,git 就分不清哪些是你的修改、哪些是模板的变化,两边只要有差异的文件都会变成冲突。如果你知道自己复制的是哪个版本,有更好的办法:先把那个版本记为“已合并”,不改动你的任何文件,再合并新版本:
git merge v0.5.0 --allow-unrelated-histories -s ours -m "Record ShipKit v0.5.0 as merged"
git merge v0.6.0
第一条命令只是把两段历史连起来(-s ours 让你的文件保持原样)。第二条就成了普通的三方合并,只带进 v0.5.0 到 v0.6.0 之间的变化。经过这一次,你的项目就和克隆来的一样了:以后每次升级都是 git merge <tag>。
解决冲突
冲突集中在你改过模板的地方。几种常见情况:
-
src/config/*(app-config.ts、plans.ts、landing.ts):几乎总是要保留你的值,再加上模板新增的字段。 -
messages/en.json、messages/zh.json:两边都加了键。两组都保留,注意别漏了逗号。 -
bun.lock:不要手改。取模板的版本,再让 bun 根据package.json把你自己的依赖加回来:git checkout --theirs bun.lock bun install -
你删掉的模块:如果新版本改了你已删除的功能里的文件,git 会报 “deleted by us”。用
git rm让它保持删除状态,再搜一下新版本有没有往共享文件里加新的[feature: <name>]块,一并删掉。每个模块牵涉哪些文件,见删除功能。 -
.dev.vars.example:取模板的版本,再把新增的键抄到你自己的.dev.vars里。
所有文件都解决后,git add 再 git commit。中途想放弃,git merge --abort 会回到合并前的状态。
迁移
迁移文件在 drizzle/ 里,按编号排列,drizzle/meta/ 里有对应的 snapshot 和 journal 记录。D1 按文件名记住哪些迁移已经执行过。
如果你没有自己的迁移,drizzle/ 目录直接用模板的,然后执行:
bun run db:migrate:local
如果你加过自己的迁移,新版本的迁移文件会和你的撞车:两边都占了下一个编号,drizzle/meta/_journal.json 也会冲突。你的迁移已经在自己的数据库上执行过了,所以保留它们,把模板的改动重新生成为你的下一个迁移:
drizzle/meta里两边都改过的文件保留你的版本:git checkout --ours -- drizzle/meta/_journal.json,git status里显示为 “both added” 的 snapshot 也照此处理。- 找出新版本新增的迁移文件——
drizzle/里的.sql文件,以及drizzle/meta/里只有新版本才有的 snapshot(git status会把它们列为新文件,发布说明里也会写出迁移名)。先读一遍那些.sql,再用git rm全部删掉。 - 确认
src/里是合并后的 schema——各功能的schema.ts就是普通源码,和其他文件一样参与合并。 - 运行
bun run db:generate。它会拿合并后的 schema 和你最新的 snapshot 比较,把模板的改动写成排在你之后的新迁移。 - 如果删掉的文件里有数据变更(用
UPDATE或INSERT做的回填),db:generate是看不到的。用bunx drizzle-kit generate --custom --name <name>建一个空迁移,按新版本里的顺序把语句粘进去。
然后执行 bun run db:migrate:local。迁移如何生成和执行,见数据库。
上线前检查
安装依赖,重新生成生成物,跑完整的测试:
bun install
bun run cf-typegen # wrangler.jsonc 有变化时
bun run build # 顺带生成 src/paraglide,typecheck 需要它
bun run typecheck
bun run check
bun run test
bun run e2e
之后重启开发服务器:环境变量只在启动时读取。把你改过的页面都点一遍——测试覆盖的是模板本身的行为,而不是你的改动。
部署升级
把分支合并到 main,然后:
bunx wrangler secret put <NEW_KEY> # 发布说明里每个新增的键
bun run db:migrate:remote
bun run deploy
和任何 schema 变更一样,先迁移再部署。如果由 CI 负责部署,远程有未执行的迁移时它会拒绝部署。见部署。
这类工作交给编程 agent 做得不错。把本页和发布说明给它,并要求它遇到拿不准的冲突时停下来问你,而不是自己猜。见配合 AI 编程助手。