Cursor "Apply" 静默失败

点 Apply 之后文件没变也没报错——通常是基准快照过期、文件在外部被改、或写入被锁住。

在 Composer 或 chat 里点了 Apply,按钮变绿、Cursor 显示”Applied”,但回到编辑器文件内容一点没变;或者刚改完瞬间被 revert 回去。这通常不是模型问题,而是 Apply 这一步要做的”把 diff 缝回当前文件”动作和你磁盘上的实际文件状态对不上——Cursor 拿的基准快照已经过期,于是它选择放弃改动而不是强写。

要修,要先分辨:是 Cursor 自己的 diff 引擎认怂,还是文件根本写不进去。

常见原因

按出现频率排序。

1. Apply 时的基准快照与磁盘当前内容不一致

Composer 在生成 diff 时拍了一次文件快照。如果你在它思考期间(或之前会话里)保存过、用外部编辑器改过、或 git checkout 切了分支,apply 时基准对不上就会被丢弃。

如何判断:apply 失败的同时打开 View → Output → Cursor,看是否有 apply: snapshot mismatchbase does not match current 一类日志。

2. 目标文件在 workspace 之外或被 .cursorignore 排除

如果 Cursor 给出的路径是绝对路径或指向 workspace 外(比如 ~/.config/...),Apply 默认不允许写。.cursorignore 命中的文件 Composer 可以读出来但通常不会主动写回。

如何判断:把模型给的路径粘到 Cmd+P,如果打不开或显示”file not in workspace”就是这种。

3. 文件只读 / 权限不足 / 被其他进程锁

常见场景:node_modules 里的文件、Linux 下用 sudo 创建的文件、Windows 上被另一编辑器锁定、macOS 上 Xcode 项目里的 pbxproj 被 Xcode 占着。

如何判断:在终端 ls -l <file>,若不是当前用户可写就是权限问题;Windows 用 handle.exe 或资源监视器看谁在占用。

4. Composer 给的是大段重写而非局部 diff

模型选择 “rewrite whole file” 时,Apply 需要做整文件替换。如果你的文件 > 2000 行或最近改过几处它没看到的地方,Cursor 的合并算法会判定冲突过大、直接静默放弃。

如何判断:在 Composer 里点那条消息的 “View Diff”,如果整页都是红 + 绿,多半是 full-rewrite。

5. 文件没保存,未保存改动和 diff 冲突

编辑器里这个文件标签上有圆点(未保存),磁盘版本和编辑器缓冲区已经不同。Apply 应用的是磁盘版本,回写后被编辑器的脏缓冲区”盖回去”。

如何判断:apply 前看文件标签,有圆点就先 Cmd+S。

6. Cursor 自己 hung 住 / extension host 崩了

Apply 走的是 extension host 进程。Output → Extension Host 里若出现 Extension host terminated unexpectedly,Apply 静默失败是必然结果。

如何判断:Cmd+Shift+P → “Developer: Show Running Extensions” 看 Cursor 自家扩展是不是红的。

动手前先确认

  • 确认问题是在 chat / Composer / Cmd+K 哪个入口出现;三者走的是不同 apply 路径。
  • 复现前先 commit 一次或开 branch,避免 apply 把未保存改动覆盖。
  • 记下 Cursor 版本(Cursor → About)和当前模型(右下角下拉),同样问题在不同模型上行为差异很大。

需要收集的信息

  • Cursor 版本、操作系统、当前模型(如 claude-sonnet-4, gpt-5)、是否走 Cursor 自家代理还是 BYOK。
  • 仓库大小(文件数、行数)、是否有 .cursorignore、最近一次完整索引时间。
  • 完整复现路径:选了哪些文件 / Cmd+K 还是 Composer / prompt 全文 / 报错或异常输出截图。
  • View → Output → Cursor 面板最近 100 行日志。

最短修复路径

按收益排序,前 3 步通常解决 80%。

Step 1:先保存,再 apply

最朴素也是命中率最高的一步。Cmd+S 保存目标文件后立即点 Apply。如果同时编辑多文件,Cmd+K Cmd+S 全保存。

Step 2:缩小 diff 粒度

如果 Composer 一次要改 5 个文件 / 300 行,回到 chat 让它”先只改 X 文件”或”只输出针对函数 foo 的 diff”。小 diff 的 Apply 成功率显著更高。

Prompt 改写示例:
原:refactor 整个 auth 模块
改:只改 src/auth/login.ts 里 handleLogin 这一个函数;其它文件先不动

Step 3:检查文件可写性 + workspace 归属

# macOS / Linux
ls -l path/to/file
chmod u+w path/to/file        # 给当前用户写权限

# 确认文件在 workspace 内
realpath path/to/file
# 应该是当前打开 workspace 的子路径

如果路径在 workspace 外,把它先复制进来、apply 完再移回去;或者改用 Cmd+K(行内编辑)而不是 Composer。

Step 4:检查 .cursorignore

打开仓库根的 .cursorignore,看目标文件是不是被命中:

# 典型会误伤的规则
*.generated.ts
src/legacy/**

临时注释掉对应规则,重启 Cursor 让它重新读取,再 apply 一次。

Step 5:用 chat 拷代码手动粘贴作 fallback

打开 chat,让它 output only the final file content as a single code block,复制到剪贴板,回到文件 Cmd+A → 粘贴 → Cmd+S。这条永远成功,只是没有自动合并。

Step 6:重启 extension host

Cmd+Shift+P → “Developer: Reload Window”(比退出整个 Cursor 快)。如果还不行,再 “Developer: Restart Extension Host”。问题持续就退到 Cursor 升级前的版本:Cursor → Settings → “Switch to previous version”。

怎么确认已经修好

  • 重启 Cursor 后再触发一次原操作,确认不是会话内的临时状态。
  • 切换到另一个仓库 / 另一台机器复现,区分是 Cursor 配置问题还是项目本身问题。
  • 让同事打开同一个仓库重试,确认不是只有你的本地缓存被修好。

如果还是没修好

  • 把复现路径缩到最小:单文件、单 prompt、不开任何上下文。
  • 回滚最近一次 Cursor 升级 / settings.json / .cursorrules 改动,确认是否变量是这一项。
  • 在 Cursor 的 Discord 或 forum.cursor.com 搜同一错误文案;附 Cursor 版本 + 模型 + 复现 prompt。
  • 抓 View → Output → Cursor 的日志,贴 Bug Reports 频道。

预防建议

  • Apply 前永远先 Cmd+S,让磁盘版本 == 编辑器版本。
  • 开 Composer 期间不在 Cursor 之外编辑同一文件(特别是别在 Vim/VS Code 双开)。
  • 大重构拆成多条 prompt,单次 diff 控制在一两个文件以内。
  • 用 git 维护 commit 节奏,每次大 apply 前 commit 一次,失败回滚秒成本。
  • .cursorignore 加注释,标清楚哪些规则会影响 apply 能否写回。

相关阅读

标签: #排查 #Cursor #排查 #apply 失败