# jetbrains-diff-fix-tools **Repository Path**: rxbook/jetbrains-diff-fix-tools ## Basic Information - **Project Name**: jetbrains-diff-fix-tools - **Description**: Jetbrains系列IDE查看代码差异化设置在新窗口打开的问题研究:通过这个小工具,强制所有 JetBrains IDE 的差异(diff)以独立窗口打开,而不是缩成编辑器里的一个小标签页。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-05 - **Last Updated**: 2026-11-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # JetBrains Diff Fix Tools 强制所有 JetBrains IDE 的差异(diff)以**独立窗口**打开,而不是缩成编辑器里的一个小标签页。 专门解决这个恼人现象:在 `设置 → 高级设置 → 作为编辑器标签页打开差异`(`show.diff.as.editor.tab`)里取消勾选后,**过一会儿它自己又勾回来了**。 这是 JetBrains 平台的已知缺陷([YouTrack RIDER-136385](https://youtrack.jetbrains.com/issue/RIDER-136385),至今未修复):AI 编程插件(Qoder、GitHub Copilot 等)以"编辑器标签页型 diff"展示改动时,平台代码会把这条全局设置回写成 `true`。本工具在官方修复前提供完整解法。 克隆后一条命令即可运行,不需要安装 JDK;仓库文件夹可放在任意目录,也可整体移动。 --- ## 它做了什么 **两阶段修复**: | 阶段 | 手段 | 生效时机 | | --- | --- | --- | | 一、配置文件 | 改写各产品 `options/advancedSettings.xml` | 未运行的 IDE 下次启动生效 | | 二、进程内注入 | 用 IDE 自带运行时的 `jcmd` 动态加载代理,在进程内调用平台自己的 `AdvancedSettings.setBoolean()` | 运行中的 IDE **立即生效,无需重启** | 第二阶段的注入与"在设置界面手动取消勾选"走**完全相同的代码路径**,因此会同步更新内存值、触发变更监听并持久化,效果等价于人工操作。 > 为什么必须注入?因为 `advancedSettings.xml` 只在 IDE 启动时加载一次,运行期间取值走内存,退出时又把内存值写回磁盘——**从外部改文件对运行中的 IDE 完全无效,还会被覆盖回去**。 --- ## 支持平台 | 平台 | 脚本 | 定时自愈 | 状态 | | --- | --- | --- | --- | | macOS | `fix_jetbrains_diff_window.sh` | launchd | 已实测 | | Linux | `fix_jetbrains_diff_window.sh` | systemd user timer(无 systemd 时回退 cron) | 已实现,未在真机逐项验证 | | Windows | `fix_jetbrains_diff_window.ps1` | 任务计划程序 | 已实现,未在真机逐项验证 | 支持的 IDE:任意 JetBrains 产品。脚本通过读取各产品安装目录下的 `product-info.json` 来发现已安装的 IDE,**不依赖产品名白名单**,因此 JetBrains 以后推出新 IDE 无需改脚本。 **不需要安装 JDK**:仓库已内置构建好的 `agent/jbdiff-agent.jar`;需要重新构建时,脚本会自动使用任一已安装 IDE 自带的 JetBrains Runtime(JBR)。 --- ## 快速开始 ### 克隆代码 ``` git clone https://gitee.com/rxbook/jetbrains-diff-fix-tools.git cd jetbrains-diff-fix-tools ``` ### macOS ```bash # 立即修复一次 bash fix_jetbrains_diff_window.sh # 安装定时自愈(每 30 分钟自动纠正)+ Dock 一键应用 bash install/install-macos.sh --with-dock-app ``` ### Linux ```bash bash fix_jetbrains_diff_window.sh bash install/install-linux.sh ``` ### Windows ```powershell powershell -ExecutionPolicy Bypass -File .\fix_jetbrains_diff_window.ps1 powershell -ExecutionPolicy Bypass -File .\install\install-windows.ps1 ``` > 仓库文件夹可以放在**任意目录**,也可以整体移动——所有路径都从脚本自身位置推导,不依赖固定安装位置。 --- ## 命令用法 ### bash 版(macOS / Linux) ``` fix_jetbrains_diff_window.sh 执行修复,输出每个产品的结果 fix_jetbrains_diff_window.sh --dry-run 只预览,不写入任何文件、不注入进程 fix_jetbrains_diff_window.sh --quiet 静默模式,仅在有实际改动/失败时输出 fix_jetbrains_diff_window.sh --include-orphans 连已卸载产品的残留配置目录一并处理 fix_jetbrains_diff_window.sh --list 只列出探测到的已安装 IDE,不做修改 fix_jetbrains_diff_window.sh --help 查看帮助 ``` ### PowerShell 版(Windows) ``` .\fix_jetbrains_diff_window.ps1 执行修复 .\fix_jetbrains_diff_window.ps1 -DryRun 只预览 .\fix_jetbrains_diff_window.ps1 -Quiet 静默模式 .\fix_jetbrains_diff_window.ps1 -IncludeOrphans 含已卸载产品的残留配置目录 .\fix_jetbrains_diff_window.ps1 -ListOnly 只列出已安装 IDE ``` ### 退出码 | 码 | 含义 | | --- | --- | | 0 | 全部成功(或无需改动) | | 1 | 未找到配置目录,或没有可处理的已安装产品 | | 2 | 存在处理失败项或未处理的运行中 IDE | | 64 | 参数错误 | ### 环境变量(可选覆盖) | 变量 | 作用 | | --- | --- | | `JBDIFF_HOME` | 指定工具根目录 | | `JBDIFF_AGENT_JAR` | 指定注入代理 jar 路径 | | `JBDIFF_CONFIG_ROOT` | 指定 JetBrains 配置根目录 | | `JBDIFF_LOCKDIR` | 指定并发锁目录(仅 bash 版) | --- ## 输出示例 ``` [JetBrainsDiffFix] [PhpStorm2026.2] 配置文件已是 false [JetBrainsDiffFix] [IntelliJIdea2026.2] 配置文件已是 false [JetBrainsDiffFix] 已跳过 4 个未安装产品的残留配置目录(如需一并处理请加 --include-orphans)。 [JetBrainsDiffFix] 配置文件阶段完成:修改 0 个,已是目标值 2 个,失败 0 个。 [JetBrainsDiffFix] [PhpStorm pid=1978] 已即时生效:内存 true → false(当前会话立即独立窗口) [JetBrainsDiffFix] 运行中 IDE 阶段:即时生效 1 个,本就正确 0 个,未处理 0 个。 ``` --- ## 目录结构 ``` . ├── fix_jetbrains_diff_window.sh 主修复脚本(macOS / Linux) ├── fix_jetbrains_diff_window.ps1 主修复脚本(Windows) ├── build-agent.sh 重新构建注入代理(macOS / Linux) ├── build-agent.ps1 重新构建注入代理(Windows) ├── agent/ │ ├── JBDiffFixAgent.java 注入代理源码(约 180 行,行为可读可审) │ └── jbdiff-agent.jar 构建好的代理,开箱即用 ├── install/ │ ├── install-macos.sh 安装 launchd 定时任务 + Dock 应用 │ ├── install-linux.sh 安装 systemd user timer(或 cron) │ └── install-windows.ps1 安装任务计划程序 ├── apps/ │ └── JetBrainsDiffFix.app macOS 程序坞一键应用 ├── test/ │ └── JBDiffGhostAgent.java 端到端测试用"幽灵代理"(把值改回 true 以复现缺陷) ``` --- ## 工作原理 ### 配置文件路径 | 平台 | 路径 | | --- | --- | | macOS | `~/Library/Application Support/JetBrains/<产品><版本>/options/advancedSettings.xml` | | Linux | `~/.config/JetBrains/<产品><版本>/options/advancedSettings.xml` | | Windows | `%APPDATA%\JetBrains\<产品><版本>\options\advancedSettings.xml` | 改写策略是**保守**的:只增改目标 entry,兼容"单行自闭合 / 多行块 / 无该 entry / 无 map / 无组件 / 空文件"六种形态,绝不动其他任何设置项。 ### 已安装产品的发现方式 脚本不直接扫描配置目录(那样会把已卸载版本的残留目录也算进来),而是: 1. 在各平台的常规安装位置搜索 `product-info.json`; 2. 从中读取权威的 `dataDirectoryName`(如 `PhpStorm2026.2`); 3. 用它反查对应的配置目录。 这样输出里只会出现**你真正装着的**产品。 ### 进程内注入 ```bash "$IDE_HOME//bin/jcmd" "$PID" JVMTI.agent_load "$AGENT_JAR=status=$STATUS_FILE" ``` - `jcmd` 取自 IDE **自带**的运行时,不需要系统装 JDK; - `jcmd` 的路径按平台推导:macOS 为 `/Contents/jbr/Contents/Home/bin/jcmd`,Linux/Windows 为 `/jbr/bin/jcmd`; - `status=` 参数把回执文件路径显式传给代理,代理内部不假设任何平台目录布局,因此**同一份 jar 三平台通用**; - 代理编译目标为 Java 11,可被 JBR 17 / 21 / 25 等所有在用运行时加载。 ### 定时自愈的稳定性设计 定时任务**不直接指向仓库里的脚本**,而是指向一个位置固定的包装脚本(macOS/Linux:`~/.local/share/jetbrains-diff-fix/runner.sh`)。包装脚本再读记录文件(`~/.config/jetbrains-diff-fix/home`)定位仓库当前目录,记录失效时会在常见目录里兜底搜索。 因此**仓库整体移动后不需要重装任务**;实在找不到时会往日志里写明确报错,而不是静默空跑。 --- ## 安全性说明 注入代理是本仓库中最需要审视的部分,因此把它单独说明: - **代码完全开源可读**:`agent/JBDiffFixAgent.java` 不足 200 行,其中真正做事的部分只有几十行; - **行为极其有限**:只调用 `AdvancedSettings.setBoolean("show.diff.as.editor.tab", false)` 这一个平台 API,不读取任何代码、项目内容或凭据; - **机制是官方的**:`jcmd` 的动态 attach 是 JDK 官方诊断机制,仅对**同用户**进程可用,不需要 root/管理员权限; - **可完全避开**:如果你不希望有任何进程注入,只用阶段一(配置文件修复)也可以——重启 IDE 后同样生效,只是无法即时纠正运行中的实例。 --- ## 常见问题 **Q:安装新 IDE 或升级新版本后需要改脚本吗?** 不需要。已安装产品通过 `product-info.json` 自动发现,`jcmd` 路径自动推导,新版本会新建配置目录也自动覆盖。 **Q:输出里为什么没有我卸载掉的旧版本了?** 因为脚本改为按"已安装产品"反查配置目录,卸载残留默认跳过。确实想一并处理,加 `--include-orphans`(Windows 为 `-IncludeOrphans`)。 **Q:定时任务装了但好像没生效?** 先看日志:macOS 在 `~/Library/Logs/jetbrains-diff-fix.log`,Linux 用 `journalctl --user -u jetbrains-diff-fix`,Windows 在 `%LOCALAPPDATA%\jetbrains-diff-fix\fix.log`。另外 quiet 模式下"无改动"本来就不产生输出,日志为空通常代表一切正常。 **Q:能把这个文件夹移到别的位置吗?** 可以。移动后重跑一次对应的安装脚本即可(它会更新记录文件);即使不重跑,包装脚本也会在常见目录里兜底搜索。 **Q:能直接删掉 `agent/` 只用配置文件修复吗?** 可以。脚本在找不到 jar 时会打印提示并跳过阶段二,阶段一照常工作。 **Q:为什么不直接改 AI 插件?** 因为写回设置的是**平台代码**,AI 插件只是触发源。改插件既做不到(闭源 jar),也治不了其他同类插件。 **Q:等官方修复不行吗?** RIDER-136385 至今未修复且 2026.2 仍复现。欢迎去该单下 +1 推动,但日常工作不能等。 --- ## 重新构建注入代理 仓库已内置 `agent/jbdiff-agent.jar`,通常不需要构建。若修改了代理源码、或克隆后 jar 缺失: ```bash # macOS / Linux(自动使用 IDE 自带的 JBR,无需安装 JDK) bash build-agent.sh bash build-agent.sh --with-test # 同时构建端到端测试用的幽灵代理 bash build-agent.sh --clean # 清理构建中间产物 ``` ```powershell # Windows powershell -ExecutionPolicy Bypass -File .\build-agent.ps1 powershell -ExecutionPolicy Bypass -File .\build-agent.ps1 -WithTest powershell -ExecutionPolicy Bypass -File .\build-agent.ps1 -Clean ``` 打包工具优先用 JDK 的 `jar`;JBR 不含 `jar`,此时自动回退到系统的 `zip`(macOS/Linux)或 .NET 的 `System.IO.Compression`(Windows)。 --- ## 端到端验证 想确认"缺陷复现 → 自动纠正"整条链路可用: ```bash bash build-agent.sh --with-test ``` 然后对一个正在运行的 IDE 注入幽灵代理,把内存值改成 `true`(模拟 AI 插件的回写),再运行修复脚本,应看到: ``` [JetBrainsDiffFix] [PhpStorm pid=1978] 已即时生效:内存 true → false(当前会话立即独立窗口) ``` --- ## 卸载 ```bash # macOS bash install/install-macos.sh --uninstall # Linux bash install/install-linux.sh --uninstall ``` ```powershell # Windows powershell -ExecutionPolicy Bypass -File .\install\install-windows.ps1 -Uninstall ``` 卸载只移除定时任务、包装脚本与记录文件,**不会**改动 IDE 配置或删除仓库本体。 --- ## 已知限制 - 阶段二依赖 `jcmd` 的 attach 能力,若 IDE 以其他用户身份运行(或启用了额外的 JVM attach 限制),注入会失败——此时阶段一仍然生效,重启 IDE 即可; - 部分企业安全软件可能拦截动态 attach,表现为"进程内注入失败,跳过"; - Windows 与 Linux 版本按各平台官方路径与机制实现,但尚未在真机逐项验证,欢迎反馈问题。 --- ## 贡献 欢迎提 Issue 与 PR。以下方向尤其有帮助: - Linux 发行版(尤其是 Snap / Flatpak / Toolbox 安装方式)与 Windows 的实机验证反馈; - 新的触发源插件(除 Qoder、Copilot 之外还有哪些 AI 插件会触发回写); - JetBrains 官方修复 RIDER-136385 后的进展同步。 --- ## License [MIT](LICENSE)