vscode 默认将 .ipynb 当文本处理,导致 diff 难读、提交臃肿;需用 .gitattributes + nbstripout 剥离 outputs 和 execution_count,配合手动清空输出,才能实现干净的代码变更追踪。

VSCode 本身不特殊对待 .ipynb 文件——它把它们当普通文本文件走 Git 流程,但默认行为会导致 diff 难读、提交体积大、协作混乱。关键不是“能不能”,而是“怎么让 Git 看懂 Notebook 的真实变更”。
为什么直接 git add .ipynb 会出问题
因为 .ipynb 是 JSON 格式,保存时包含输出、执行计数、内核元数据等非代码内容。一次简单 print 输出,Git diff 可能刷出几百行变动,真正改的只有一行 print("hello")。
- 输出(
outputs字段)每次运行都变,导致无意义提交 - 执行序号(
execution_count)递增,纯扰动项 - 内核信息(
metadata.kernel)可能含本地路径,跨机器失效 - VSCode 自动保存的
metadata.language_info也可能随解释器微调而变
用 .gitattributes + jupyter nbstripout 过滤输出
这是目前最轻量、兼容性最好的方案:在提交前自动剥离 outputs 和 execution_count,保留干净的代码逻辑变更。
- 在项目根目录创建
.gitattributes,写入:*.ipynb filter=nbstripout
- 运行命令注册过滤器:
git config filter.nbstripout.clean "jupyter nbstripout"
git config filter.nbstripout.smudge cat
- 安装
nbstripout:pip install nbstripout
- 首次启用后,对已有
.ipynb文件需强制重置:git add --renormalize .
之后所有 git diff 只显示代码/Markdown 内容变更,git status 不再因输出刷新而误报修改。
VSCode 内置 Git 面板对 .ipynb 的限制
VSCode 的源代码管理视图(Ctrl+Shift+G)能识别 .ipynb 文件,但不支持图形化对比单元格级差异——它只展示 JSON 层面的文本 diff,和命令行 git diff 效果一致。
- 无法高亮某一行代码改动,只能看到整个 cell 的 JSON 块增删
- “暂存更改”按钮有效,但点开后看到的是压缩后的单行 JSON,可读性差
- 右键“打开更改”仍跳转到原始 JSON 视图,不是 Notebook 渲染态
- 若已配置
nbstripout,则 VSCode 面板中显示的 diff 会干净很多,但依然无语法高亮或 cell 结构感知
替代方案:jupyter-diff 与 pre-commit 钩子
如果团队对 Notebook 可读性要求高,且愿意加一层工具链,可以引入 jupyter-diff 提供的结构化比对,配合 pre-commit 自动清理。
- 安装:
pip install jupyter-diff
- 在
.pre-commit-config.yaml中加入:- repo: https://github.com/deshaw/jupyter-diff<br> rev: v0.7.0<br> hooks:<br> - id: jupyter-diff
- 这样每次
git commit前,会自动 strip 输出并生成 human-readable diff 到控制台 - 注意:VSCode 的提交界面不触发 pre-commit,必须走终端或配置 VSCode 使用 shell 提交命令
真正容易被忽略的是:即使用了 nbstripout,第一次提交前务必手动清空 notebook 中的 outputs(菜单栏 Kernel → Clear All Outputs),否则历史里仍残留脏数据;后续每次提交前也建议手动执行一次,避免有人绕过钩子直接 push。











