项目复盘 · 2026年8月20日
FilmManager 1.2.0:一次跨分支整合与桌面应用发布
从保护脏工作区、核对分支关系,到依赖治理、类型修复和 Windows 安装包发布。

FilmManager 最近完成了 1.2.0 版本发布。这次工作表面上是“合并两个分支”,实际同时涉及工作区保护、功能整合、依赖冲突、类型系统修复、自动发布和离线打包。
它更像一次小型发布工程,而不是一条简单的 git merge。
合并前先理解分支关系
当时 leaf 分支存在一批未提交修改,另一个版本分支则包含新的正式功能。直接执行合并,最大的风险并不是 Git 报冲突,而是工作区改动被覆盖、遗漏或混入无法解释的状态。
第一步先检查:
- 当前分支与工作区状态;
- 两个分支的共同祖先;
- 提交包含关系;
- 未提交文件与新版本修改的重叠范围。
结果发现版本分支已经包含 leaf 的历史提交,所以正式历史可以直接快进。真正需要保护的是工作区里若干重叠文件。
采用的流程是:临时保存工作区、快进分支、恢复修改,再比较恢复前后的文件增删统计。Git 没有产生冲突标记,但“没有冲突”不代表“没有丢内容”,因此仍需用差异和测试证明两边功能都保留。
把构建通过和类型正确分开看
合并后,生产构建和布局测试都通过,但独立 TypeScript 检查仍发现问题。其中一个是大缩略图组件里的 ref 被推断成只读引用;另外几项则是项目原有的工程边界问题:Web 工程引用了 preload 类型,却没有把对应目录纳入类型检查,Electron 拖拽区域也缺少 React CSS 属性声明。
这说明“能打包”不等于“类型系统已经完整工作”。构建工具可能只检查实际打包路径,独立类型检查则会暴露更广的工程边界。
最终处理包括:
- 明确可空、可变的 ref 类型;
- 让 Web TypeScript 配置包含 preload 类型;
- 为
WebkitAppRegion增加最小 CSS 类型扩展; - 移除原先用于绕过检查的
as never。
绕过类型可以暂时让红线消失,但也会让后续错误失去保护。补齐类型边界后,类型检查才重新成为可靠的约束。
删除一个没有被使用的依赖
依赖安装还暴露出 React 版本的 peer dependency 冲突。最初可以考虑升级 React,或者降低地图组件库版本,但继续检查后发现项目根本没有使用那个 React 地图封装,实际地图直接调用 Leaflet API。
因此最小、风险最低的方案是删除零引用依赖。
这次处理同时控制了锁文件差异。一次普通安装补入了大量可选依赖,产生数百行与当前问题无关的变化。为了保持提交聚焦,重新生成了仅包含必要删除的锁文件变更,并清理 TypeScript 产生的缓存文件。
依赖治理有时不是“选哪个版本”,而是先问它是否应该存在。
从版本号到公开 Release
功能整合完成后,将应用元数据、锁文件、README、产品说明和需求文档统一更新为 1.2.0。版本号如果只改一处,安装包、关于页面和文档很容易出现不同答案。
发布使用 v1.2.0 标签触发 GitHub Actions。Windows runner 自动完成:
- 安装依赖;
- 准备原生模块;
- 生产构建;
- 生成 Windows 安装包;
- 创建公开 Release;
- 上传安装程序、差分更新文件和更新描述。
发布后继续核对标签指向、工作流结论、Release 可见性和资产完整性。创建了 Release 页面并不代表交付完成,用户真正下载的文件必须存在且对应正确提交。
一次离线打包的备用路径
后来需要在本机直接生成安装包,但网络下载 Electron Builder 的签名工具与 NSIS 很慢。本机已经有完整的 Electron unpacked 产物,于是使用 Windows 自带的 IExpress 制作了一个每用户安装包。
这个备用方案包含应用文件、安装脚本、桌面与开始菜单快捷方式,以及卸载项。生成后验证了 PE 文件头和 SHA-256,并删除临时载荷。
它能解决“离线拿到可安装 EXE”的问题,但也有明确限制:没有代码签名,Windows 会显示未知发布者;更新体验也不如正式 NSIS 包。因此它适合作为受控环境下的应急交付,不应替代正式发布流水线。
复盘
这次发布最有价值的部分不是某个功能,而是一套判断顺序:
- 先理解 Git 历史,再执行合并;
- 先保护未提交工作,再处理重叠文件;
- 同时验证构建、类型、测试和锁文件;
- 先确认依赖是否真的被使用,再讨论版本兼容;
- 发布后验证资产,而不是只看工作流绿色。
版本发布的质量,最终体现在“另一个人能否明确知道自己拿到的是什么,以及能否稳定安装和运行”。