距离 DeployX 上一篇文章发布已经过去一段时间,插件也从 1.0.2 一路迭代到了 1.0.5。这期间收到的最多反馈集中在两点:

  • "部署完了发现有问题,能不能直接在 IDEA 里回滚?我不想再开 SFTP 手动覆盖。"
  • "能不能直接浏览远程服务器上的文件?想顺手改个配置、看个日志,还得开终端 vim 实在太重了。"

好消息是:这两个诉求在 1.0.5 里都落地了。除此之外,1.0.3 ~ 1.0.5 这三个版本还顺手解决了一批让人头疼的 Bug(比如密钥认证同步报权限错误、更新报告把 GLIBC 报错当成文件、备份文件名全都叫 backup_xxx),并做了一次脚本编辑器的大重构。

这篇文章就把这段时间的更新一次性讲清楚。如果你还没用过 DeployX,建议先看上一篇文章了解"备份 - 增量同步 - 解压 - 重启"的基础闭环,本文更聚焦于"在这之后又加了什么"。


一、1.0.5:两个重量级新功能

1. 部署回滚——出了问题,一键退回上个版本

1.0.5 之前,DeployX 已经能自动帮你做部署前备份,但备份出来的文件怎么用?还是得手动开终端、tar 解压、覆盖回去——本质上是"备份很自动,恢复很手动"。

这次新增的部署回滚把恢复这一环也补齐了。在「历史」Tab 中,凡是带备份的部署记录前面会带一个 🔄 图标,点一下即可回滚:

历史 Tab 中带可回滚标识的记录

为了防止误操作,回滚前会弹出一个确认对话框,把关键信息一次性摆清楚:

  • 目标服务器、远程路径
  • 备份文件路径
  • 文件数量(支持预览备份文件列表)
  • 原始部署时间

回滚确认对话框

确认后进入执行进度对话框:实时状态、进度条、执行日志一应俱全。回滚完成后会自动刷新历史列表,并弹出一个"回滚成功"的系统通知。底层是基于 tar 解包恢复,复用已有的 SshConnection 执行远程命令,错误处理和日志记录都走统一链路。

一个值得说的细节:只有 DEPLOY 类型、canRollback=true、且 backupFilePath 非空的记录才显示回滚按钮。也就是说 Sync / Quick Push 这类本来就不做备份的操作不会出现"回滚"入口,避免产生"回滚到哪儿"的歧义。

2. 远程文件浏览器——在 IDE 侧边栏浏览/编辑远程文件

这是我个人最满意的一个功能。以往想看一眼服务器上的某个配置文件、或者临时改一行 application.yml,要么开 SSH 终端用 vim,要么开 SFTP 工具下载下来改完再传回去。现在 DeployX 在 IDE 右侧侧边栏内置了一个远程文件浏览器,体验几乎和 IDEA 的项目视图一样:

远程文件浏览器树形界面

核心能力一览:

  • 浏览:懒加载目录树,显示文件大小 / 修改时间 / 文件类型图标;支持切换服务器、路径跳转(带历史记忆,每台服务器最多记 20 条)、新建 / 删除目录、刷新。
  • 编辑双击远程文本文件直接在 IDE 主编辑器中打开,完整的语法高亮、行号、代码折叠。Ctrl+S 自动把改动写回远程服务器。超过 5MB 的文件会拒绝打开并提示改用下载,避免卡死。
  • 上传 / 下载:从项目视图或系统文件管理器拖拽本地文件到浏览器树,自动上传到对应远程目录并在完成后刷新;反过来,从浏览器树拖拽文件到项目视图即可下载到本地。当然,右键菜单也支持下载。
  • 在终端中打开:右键文件或目录选「在终端中打开」,自动拉起对应服务器的 SSH 终端并 cd 到所在目录。
  • 自动定位:首次打开会按当前项目路径匹配目录映射,自动跳到对应远程目录;每台服务器上次打开的目录也会被记住。

入口有三个:右键菜单 DeployX -> 浏览远程文件Alt+Shift+Z 快捷菜单、以及 DeployX 工具窗口「操作」Tab 服务器旁边的文件夹按钮。

侧边工具栏 DeployX -> 浏览远程文件(窗口文件夹按钮)

右键菜单 DeployX -> 浏览远程文件,或 Alt+Shift+Z 快捷菜单,或工具窗口文件夹按钮

底层用持久化 SFTP 通道复用 + 自动重连 + 异常自动重试,浏览延迟很低、连接也稳定。整个窗口是非模态的,浏览远程文件完全不会阻塞你本地的编辑工作。


二、1.0.3 ~ 1.0.4:补齐批量部署、双向同步与配置迁移

虽然标题说的是"后续到 1.0.5",但 1.0.31.0.4 两个版本里也有几个非常实用的能力,一并列在这里。

1. 多服务器批量部署(1.0.3 / 1.0.4

服务器选择对话框现在支持按住 Ctrl/Shift 多选。选多台服务器后,文件会分组并行上传到所有选中服务器(线程池,最多 4 并发)。终端也支持同时打开多个服务器连接。

服务器选择对话框多选

对于"一份改动要同时刷到测试一、测试二、预发"这种场景,这条能力直接把部署时间从"逐台相加"压到"取最慢的一台"。

2. 从服务器拉取(双向同步)(1.0.4

之前 DeployX 只能"本地 -> 远程"。1.0.4 新增了 Pull from Server(从服务器拉取):把远程与本地不同的文件拉到本地,rsync 模式按大小 / 修改时间只传差异文件,SFTP 降级时递归下载整个远程目录。

入口和上传对称——右键菜单、Alt+Shift+Z 快捷菜单都有「从服务器拉取」。拉取同样会写历史(带 PULL 类型标识,摘要显示「远程 -> 本地」方向),历史的「重新部署」对 PULL 记录会自动执行「重新拉取」。

3. 配置导入导出(AES-256-GCM 加密)(1.0.3

换电脑 / 多人协作时最痛的就是重配一遍服务器和映射。1.0.3 支持一键导出全部插件配置(服务器含密码、映射、脚本)为 AES-256-GCM 加密的 JSON 文件,在另一台机器上用密码解密导入即可。ID 冲突时可选覆盖或新增。

1.0.4 进一步增强:导出时可选择把 SSH 密钥文件内容一并加密导出,导入到新机器时自动解密保存到 ~/.deploy-x/keys/,服务器配置的密钥路径自动指向本地文件,彻底不用手动拷密钥。

4. 服务器分组与标签(1.0.3

服务器新增 group 字段和逗号分隔的 tags,方便在服务器数量变多后做过滤管理。

5. 传输失败自动重试 + 部署后系统通知(1.0.3

  • 传输失败时自动重试最多 3 次(间隔 2 秒),只对网络 / 连接类失败重试,认证失败和路径不存在不重试。
  • 批量上传 / 部署完成后,当 IDE 窗口未聚焦时弹出 OS 级系统通知(Linux 走 libnotify,macOS 走通知中心,Windows 10/11 改用 PowerShell 调 WinRT Toast API),同时始终显示 IDE 气泡通知。挂着部署去干别的,回来一眼就知道结果。

三、一批"折磨人"的 Bug 修复

这几个版本里修了不少隐蔽但影响很大的 Bug,挑几个有代表性的说说。

1. 密钥认证同步报 Permissions 0644 for 'xxx' are too open

这是个经典坑:插件内置终端用的是 JSch 库(不检查私钥文件权限),而 rsync 走的是系统 ssh(OpenSSH 强制要求私钥权限为 0600)。于是同一把密钥,终端能连,rsync 同步直接报错。

1.0.5 的解法是自动权限修复:检测到私钥权限过松时,自动创建一个临时副本并设置成 0600,传输完成后自动清理。用户无需手动 chmod,也不影响原密钥文件。

2. 更新报告把 GLIBC 报错当成"已传输文件"

有些测试服务器的 shell 初始化或工具链(mise / asdf 等)会因为 GLIBC 版本不足打印类似下面的错误:

/lib64/libc.so.6: version 'GLIBC_2.18' not found (required by ...)

之前的解析逻辑会把它当成 rsync 的文件传输行,写进更新报告的"实际更新的文件"里,导致报告"总文件数"虚增、错误信息被误列。

1.0.5 做了两层修复:先加了基于子串的诊断行过滤(not foundrequired byglibclibc.soshared object 等);再从根本上改用 rsync 的 --out-format=::%n:: 定界输出精确识别文件传输行(默认选项分支),无定界行时回退启发式解析,兼容用户自定义 rsync 选项与 SFTP 后端。

3. 备份文件全叫 backup_xxx,根本分不清来源

之前备份统一命名 backup_{时间戳}.tar.gz,攒几次之后完全不知道哪个备份对应哪次部署。

1.0.5 改为以备份源名为前缀 + _bak + 日期,例如 updates_bak_20260712_025456.tar.gz;多文件时为 xxx_nfiles_bak_{时间戳}.tar.gz。同时还修了 .tar.gz 这类双扩展名备份时扩展名被错误拆分(foo.tar.gz -> foo.tar_bak_...gz)的问题,以及备份成功后返回目录路径而非具体文件路径、导致回滚时 test -f 校验失败的问题。

4. 配置导入后服务器丢失密码(1.0.4

导入加密配置后,密码明明写进了 PasswordSafe,但 SSH 连接还是失败。根因是导入流程把 server.copy(password = "") 的副本传给了 ServerManager,导致内存里的密码是空的。1.0.4 改为直接传带密码的 ServerConfig(写入 servers.json 时仍会清空密码字段),行为与现有逻辑完全一致。

5. rsync 拉取方向反转(1.0.4

「从服务器拉取」用 rsync 模式时,--files-from 命令把本地目录当源、远程目录当目标,实际变成了上传……根因是命令构造函数固定了"本地 -> 远程"的顺序。1.0.4 改为按 options.direction 动态交换:PULL远程源 -> 本地目标PUSH 时维持 本地源 -> 远程目标


四、重构:脚本编辑器全面复用 IDEA 编辑器能力

这是 1.0.5 里工程量最大的一项重构。在此之前,项目里所有脚本 / 命令编辑场景用的都是 Swing 原生组件(JBTextArea + 手写的 LineNumberGutter),纯文本输入、硬编码字体、无语法高亮、无补全、主题还得手动适配。

1.0.5 把这 8 处场景全部迁移到了 IDEA 平台的 EditorTextField

脚本编辑器改造前后对比(左无高亮,右有语法高亮/行号)

  • 可编辑场景ScriptEditDialog 命令模板编辑区、CommandFieldWithScriptButton 多行编辑、CommandFullscreenDialog 全屏编辑
  • 只读预览场景ScriptRunDialog 命令预览、ScriptTabPanel 脚本库预览
  • MappingEditDialog 的前置 / 后置命令输入自动跟随升级

改造后统一获得了语法高亮、行号、代码折叠、当前行高亮、主题自适应等编辑器能力。新增的 ScriptEditorFactory 会自动探测 Shell Script FileType(IDEA Ultimate 默认提供),找不到时降级 PlainText,保证不依赖外部插件。

迁移过程中还顺手修了几个 EditorTextFieldDialogWrapper 里的老问题:回车键触发"确定"按钮(拦截 Enter 手动换行)、粘贴多行命令变成一行(强制 setOneLineMode(false))、Tab 键被焦点切换拦截(拦截 Tab 手动插入缩进)。手写的 LineNumberGutter.kt 也随之删除——平台内置 gutter 完全够用了。


五、其它体验优化

  • 历史记录持久化实际传输文件HistoryRecord 新增 transferred_files 字段,结构化保存 rsync 实际传输的文件路径(不再只存于报告字符串里),增量同步时能精确反映本次变更的文件。
  • 历史详情改为弹窗对话框:原先右侧常驻的详情面板(JSplitPane)占用水平空间又关不掉,改为双击历史记录或点「查看详情」弹出 HistoryDetailDialog,关闭即消失,历史面板恢复单列列表布局。
  • 历史按钮间距统一:移除弹性 HorizontalGlue,按钮间距全部改为固定值(功能按钮间 3px、回滚 / 查看详情与清空间 6px),间距统一可预测。
  • 清空按钮图标语义修正:「清空历史」按钮原来用的是时钟样式的 AllIcons.Vcs.History,容易被当成"查看历史",改为垃圾桶图标 AllIcons.Actions.GC;「清空日志」按钮也同步统一。
  • 工具栏按钮紧凑化:改为 icon-only 的无边框风格,节省路径栏空间。
  • 大文件拆分DeployService 抽取出 BackupService / ReportBuilder / RemotePathUtils / UiButtonFactory,单文件复杂度降低,对外 API 不变,瘦身约 190 行。

完整的变更清单可以看项目的 CHANGELOG.md


六、升级与反馈

1.0.5 已经发布到 JetBrains 插件市场,在 IDE 里 Settings -> Plugins -> 搜 DeployX -> 更新 即可,或者直接到 GitHub Releases 下载最新压缩包。

插件市场 1.0.5 更新
下一步我打算继续打磨远程文件浏览器的体验(比如支持远程文件搜索、批量操作),以及把回滚做得更精细(支持选择任意一次历史备份回滚,而不只是最近一次)。如果你有想要的功能或踩到的坑,欢迎到 GitHub Issues 提,也欢迎 Star 支持一下 😄

如果这篇文章对你有帮助,欢迎转发给身边还在 IDEA / XShell / SFTP 之间反复横跳的同事,咱们一起把部署这件小事变得不那么烦。

Q.E.D.


寻门而入,破门而出