把笔记系统折腾到“终于稳定”这条路我走了两年。期间换过云笔记、试过同步盘、在图片路径上翻过车也差点因为一次冲突覆盖把半年随手记全赔进去。最终让我彻底安心的是 Markdown NAS Git 这个组合Markdown 负责写作格式NAS 负责数据归属和统一存储Git 负责版本回溯和多端同步。这套方案并不新鲜但把它调教到“像本地文件一样可靠”其实藏着大量细节今天把我的完整架构和踩坑记录都摊开来写给也想终结笔记焦虑的人一份可以直接照抄的作业。1. 选型复盘为什么别人家的全家桶笔记最后被我换成了这套组合1.1 云笔记软件真正让我难受的地方不是功能是数据主权很多人选笔记工具的第一反应是功能能不能双链、能不能多人协作、插件丰不丰富。但用久了你会发现真正决定长期体验的是两件事数据能不能自由迁出服务停了之后你还能不能打开自己的内容。我之前用过的某款云笔记导出功能导出来是一个专有的 HTML 压缩包换工具时格式全丢另一款同步盘类的工具某次多设备同时编辑冲突策略直接把我旧版文档覆盖了新版连找回入口都藏得很深。这两次经历让我彻底明白笔记系统的核心不是编辑体验而是数据主权。所谓的“自由”前提是文件本身保存在自己手里格式本身不依赖某家厂商的私有协议。Markdown 恰好同时解决这两个问题。它是纯文本记事本都能打开它是公开语法几乎所有笔记工具都支持它天然适合 Git 做版本管理因为文本 diff 可读性极好。这也是为什么我把写作底座彻底切到了 Markdown——不是因为它比所见即所得编辑器更酷而是因为它把“换工具的成本”降到了几乎为零。1.2 NAS 和 Git 不是重复建设它们各管一段刚开始我也有这个疑问NAS 本身就可以同步文件夹比如群晖的 Drive、飞牛 OS 自带的同步功能为什么还要再套一层 Git这不是多此一举吗实际跑下来会发现两者解决的问题完全不同NAS 解决的是存储位置与共享问题所有笔记集中放在一台自己控制的设备上电脑坏了数据还在手机清缓存数据还在出门在外也能读到自己写的东西。Git 解决的是版本与冲突问题文件级同步只能让你看到“最新状态”而 Git 能让你看到“每一次改动”。误删了段落可以精确恢复多设备同时写坏了一个文件可以通过版本记录找回同步冲突也不再是“覆盖了就没有了”而是变成清晰的分支记录。用一句话总结NAS 管的是“数据住哪里”Git 管的是“数据怎么变化”。两者组合后我基本不再担心“误删”和“被覆盖”这两件事而这两件事恰好在过去两年里都真实发生过。1.3 这套方案适合什么样的人说句实在话这套组合不适合所有人。它适合的是下面这类情况有一定动手能力愿意写几行命令笔记量以文本为主图片和附件占比不大追求十年后还能打开自己的笔记不希望把私人写作内容放在陌生服务器上。如果你完全不碰命令行可能用现成的笔记软件反而更顺。但如果你和我一样对“我的数据我做主”这件事有执念这套方案值得投入。我用的是一台旧主机刷的飞牛 OS 做 NAS群晖、威联通、玩客云刷的 NAS 系统都可以Git 相关的配置逻辑完全一致差别只在创建仓库时的目录路径。2. 仓库结构设计目录规范、图片路径与命名规则这些坑我全踩过2.1 单仓库还是多仓库我的答案是一个主仓库加一个附件库笔记系统的第一个架构决策就是仓库怎么划分。我见过有人按年份建一堆仓库也有人把所有东西塞进一个仓库。我最终用的是“一个主笔记库 一个独立附件库”的结构~/notes/ # 主仓库所有 Markdown 文本 ├── inbox/ # 临时收集箱定期清理归类 ├── blog/ # 输出型写作草稿 ├── tech/ # 技术笔记按主题分子目录 ├── life/ # 生活记录、读书笔记、卡片 └── README.md # 索引和说明主仓库只放.md文本文件所有图片、PDF、音频等二进制文件统一放到另一个附件目录并且这个附件目录不纳入 Git 仓库。为什么这么设计因为 Git 对文本文件非常友好对二进制文件则一言难尽。图片一旦被纳入 Git仓库体积会迅速膨胀clone 变慢历史里的每个图片版本都会永久占用空间。把大型附件排除在 Git 之外只同步到 NAS 的共享目录是让“笔记 Git 仓库保持轻盈”最关键的一条规则。2.2 图片路径相对路径 同级 assets 目录才是长久之计图片和附件是 Markdown 笔记里最大的坑我至少翻过三次车。第一次是早期图省事直接用截图工具自动生成的绝对路径比如C:\Users\xxx\Pictures\Screenshots\xxx.png。当时在 Windows 本地写得很开心换到 Mac 上打开笔记图片全部失效因为路径在另一台设备上根本不存在。这让我明白图片一定要用相对路径。第二次是写完一段笔记后从网页复制粘贴内容编辑器自动把图片转成了data:image/png;base64,...的一大段编码。这种内容嵌套在 Markdown 里文本 diff 时几乎没法看而且一旦笔记多了整个 md 文件臃肿到打开都卡。从那以后我给自己立了一条规矩图片一律先保存到本地再用相对路径引用。第三次是图片文件分散在各处有的放桌面有的放在下载目录有的临时丢在项目文件夹里结果某次整理目录时照片挪了位置所有引用全部失效。现在的固定做法是每篇笔记旁边建一个同名的 assets 文件夹引用路径永远是相对路径tech/ ├── docker-常用命令.md └── docker-常用命令.assets/ ├── 01-架构图.png └── 02-配置文件对比.pngMarkdown 里的引用写法是这样笔记文件无论移动到仓库里的哪个位置只要 assets 文件夹跟着一起走图片就永远不会断。我还在仓库根目录写了一则约定凡是复制粘贴的图片必须先存到对应 assets 目录再引用禁止直接粘贴 base64。2.3 命名规则给文件一个“能排序、能检索、不重名”的名字笔记多了之后真正麻烦的不是没地方放而是找不到。早期我的文件叫“新建文档.md”后来找一篇笔记像大海捞针。现在的命名规则很简单三条文件名采用日期前缀加主题20250119-docker网络模式总结.md按名称排序即按时间排序同一主题的系列笔记加序号20250120-git钩子实战-01-基础.md文件名不用空格和特殊符号用短横线连接单词避免在命令行和跨平台同步时出现转义问题。这套规则配合目录分类基本让我告别了“找不到笔记”的困境。顺便说一句Markdown 文件打开方式也是很多刚入门的人会卡住的地方——其实不需要专门的“阅读器”VS Code、Obsidian、Typora、Sublime Text 都能打开关键是你选一个长期使用的主力客户端这个我放到后面的编辑器章节展开。3. Git 同步核心用“裸仓库 钩子”在 NAS 上搭建版本中枢3.1 为什么要在 NAS 上建裸仓库而不是直接把笔记文件夹变成 Git 仓库这是整套方案里最关键的架构决策。很多人想当然地在 NAS 上把笔记文件夹git init一下然后在笔记本上把这个文件夹当成 remote 来 push。这个做法短时间能跑但它有一个致命问题NAS 上的工作目录会跟着 checkout 变动哪天你在 NAS 的网页界面上打开了这个文件夹不小心改了某个文件就会产生一堆冲突和脏状态。而且工作目录里的文件状态和 Git 的 HEAD 如果不一致push 上来时会报错或乱掉。正确做法是在 NAS 上初始化一个裸仓库bare repository它只存 Git 的版本数据不保存可读的工作目录。客户端 push 到裸仓库后再通过 Git 的 post-receive 钩子把最新内容自动 checkout 到一个 NAS 上的普通目录这样两个目录各司其职裸仓库负责版本逻辑普通目录负责给你提供一个可以直接浏览和读取的文件视图。这个结构最终长这样NAS ~/git/notes.git # 裸仓库接收所有 push NAS ~/sync/notes/ # 工作目录钩子自动更新可直接查看 笔记本 ~/notes/ # 本地工作目录日常写作 手机 Obsidian Vault # 也是同一个仓库的克隆3.2 NAS 端配置一分钟建好裸仓库和钩子以我刷了飞牛 OS 的 NAS 为例通过 SSH 登录进去执行下面几行命令# 在 NAS 上建立裸仓库 mkdir -p ~/git cd ~/git git init --bare notes.git # 再建一个用于展示的工作目录 mkdir -p ~/sync然后创建钩子脚本~/git/notes.git/hooks/post-receive内容就三行#!/bin/bash TARGET/root/sync/notes GIT_WORK_TREE$TARGET git checkout -f注意两点第一TARGET的路径要写你自己的实际路径不同 NAS 系统用户目录不同第二脚本创建后必须给执行权限否则钩子永远不会触发chmod x ~/git/notes.git/hooks/post-receive之后在任意一台电脑上把这个裸仓库 clone 下来就能开始写作git clone usernas-ip:~/git/notes.git每次本地git push之后NAS 的~/sync/notes目录会自动更新可以直接通过 NAS 的文件管理器或 SMB 共享浏览最新的笔记。钩子没生效是我见过最多人踩的坑症状是 push 成功但 NAS 目录纹丝不动八成就是忘了chmod x。3.3 免密推送SSH 密钥配置再也不用天天输密码如果每次 push 都要输一遍 NAS 的登录密码这套方案很快就让人失去耐心。所以第一步是配置 SSH 免密登录。在本地电脑上生成密钥如果你之前生成过可以跳过这一步ssh-keygen -t ed25519 -C notes sync然后把公钥追加到 NAS 的authorized_keys里cat ~/.ssh/id_ed25519.pub | ssh usernas-ip mkdir -p ~/.ssh cat ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys再在本地~/.ssh/config里给 NAS 起个别名省得每次记 IPHost mynas HostName nas-ip User root IdentityFile ~/.ssh/id_ed25519配置完就可以这样 clone 了git clone mynas:~/git/notes.git之后 push 和 pull 全程无感。踩坑提示NAS 如果开了不同的 SSH 端口还要在 config 里加上Port字段否则默认连 22 端口会直接超时。3.4 多设备同步的日常流程以及那些容易忽略的边界问题多设备场景下的日常节奏其实很简单写入前先git pull写完git commit然后git push。我习惯在提交前看一眼git status确认没有误改动别的文件。真正容易出问题的地方有三类第一类是行尾符差异。Windows 上 Git 默认会把换行转成 CRLFMac/Linux 上是 LF两边提交会导致整个文件 diff 一片红。解决方法是仓库根目录放一个.gitattributes文件* textauto *.md text eollf这样 Markdown 文件统一用 LF跨平台提交时就不会出现莫名其妙的全文差异。这个文件本身也应该提交到仓库里让所有设备共享同一套规则。第二类是多设备同时写同一个文件。两台设备在同一时间段编辑同一篇笔记后 push 的那一方会被拒绝提示 remote 有新提交。很多人会慌其实正确做法很简单先git pull --rebase把你的本地提交叠加到最新版本之上有冲突就手动解决然后再 push。--rebase比默认的 merge 产生的记录更干净不会留下一堆“Merge branch”的噪音提交。第三类是离线也能写。Git 的本地仓库天然支持离线提交——你在地铁上写了几段可以先 commit等到有网了再 push。不用担心丢失因为提交已经在本地历史里了。这一点比纯同步盘方案优雅很多同步盘没网的时候改文件一旦断了就是未知数。3.5 关于远程访问我推荐从简开始说到 NAS 的远程访问很多教程一上来就铺开各种复杂方案。我的建议是先保证局域网内的稳定体验再考虑出门在外怎么访问。如果你只是在家里的 Wi-Fi 下写作完全没有必要第一步就搞远程访问的配置。需要出远门读写笔记时可以优先使用 NAS 系统自带的官方远程访问服务或者直接在移动端用 Obsidian 的 Git 插件连接家里 NAS——但要提醒一句远程场景的稳定性受家庭带宽和网络环境影响较大不要指望它和本地一样流畅重要的 WIP 文件我会在本地保存一份副本。4. 多端写作体验编辑器选择与 Markdown 兼容性陷阱4.1 桌面端以 VS Code 为写作主力其他工具只当辅助Markdown 编辑器很多为什么最终以 VS Code 为主力因为它对 Markdown 的支持足够标准而且可以配合 Git 插件在编辑器内直接完成提交和推送不需要切换到命令行。我常用的插件是Markdown Preview Enhanced本地预览、markdownlint语法规则检查和Git Graph可视化查看提交历史。其中 markdownlint 能自动提醒表格格式、列表缩进、行长等问题对保持仓库整洁非常有帮助。这里有一个值得警惕的点很多 Markdown 编辑器都有自己的扩展语法比如 Typora 支持一些自定义的展开折叠、标签语法换到 VS Code 里就不渲染了。解决规则很简单——只用标准 Markdown 语法写作把扩展语法当作锦上添花而不是依赖。你永远不会因为切了一个编辑器而损失内容这一点比任何“漂亮”都重要。4.2 移动端Obsidian 配合 Git 插件也能做到全流程操作手机端的写作和查看我用的是 Obsidian。它本身不是一个 Git 工具但它有一个成熟的第三方插件叫Obsidian Git可以在应用内部执行 pull、commit、push不用打开命令行。首次配置时在 Obsidian 的社区插件市场里搜索 Git 并启用然后在插件设置里填好仓库路径开启“自动备份”选项。这样每次写完后Obsidian 会自动执行提交和推送体验接近云笔记。但移动端有两个实际坑要提醒。第一个如果你克隆的主仓库历史记录特别长手机会卡顿明显所以我的做法是移动端只保留最近几周的文件用git clone --depth 1浅克隆。第二个Obsidian 默认会为每个仓库建立一个隐藏的.obsidian配置目录如果不做处理它会进入 Git 仓库并产生大量噪音。我在根目录的.gitignore里加了一行.obsidian/这样不同设备的 Obsidian 配置各自独立互不干扰笔记内容照常同步。4.3 数学公式预览与导出的一致性陷阱值得单独写一段如果你的笔记涉及数学公式Markdown 的公式兼容性会是一个比想象中更麻烦的问题。在线预览、本地预览、导出 PDF 三处渲染结果可能都不一样尤其是复杂公式。先说最基础的一点不同编辑器用的公式渲染引擎不同。VS Code 的Markdown Preview Enhanced默认支持 KaTeX 渲染Typora 用的是 MathJax两者对“哪些语法能渲染”有细微差异。为了避免踩坑我只使用 LaTeX 公式的标准子集。行内公式的写法是$...$块级公式用$$...$$。真正容易翻车的是大括号多行公式cases 环境比如$$ f(x) \begin{cases} x 1 x 0 \\ 0 x 0 \\ x - 1 x 0 \end{cases} $$在 KaTeX 里这没问题在部分移动端预览器里却可能渲染失败原因是它们对cases环境的支持不完整。我的规避方案是重要的公式尽量写成单一表达式或数组环境把复杂的多行结构拆分成多个块级公式而不是堆在一个超长公式里。虽然没那么“学院派”但在跨设备渲染的可靠性上成倍提升。另一个常见问题是行内公式里的空格。标准 LaTeX 中行内公式以$包裹时$ x $和$x$是等价的但部分渲染器尤其是老版本的 KaTeX对前后带空格的行内公式支持不佳会出现解析失败。我的统一习惯是写成$x$不带空格彻底避开雷区。4.4 表格标准 GFM 表格的边界以及 Excel 转换的挣扎Markdown 的表格是 GFMGitHub Flavored Markdown扩展的一部分基础语法用竖线和短横线拼接。这个语法能覆盖的场景非常有限没有单元格合并、没有跨行列对齐只有左、右、居中三种。如果你的笔记里需要复杂表格标准 Markdown 表格并不可靠。我遇到过最尴尬的场景在一篇技术笔记里制作一个列数很多的对比表在 VS Code 预览正常但在手机上 Obsidian 里因为列数太多表格出现了横向溢出阅读体验一塌糊涂。后来我学到一个技巧列数超过六列的表格直接改用 Markdown 里的链接表格或退而求其次用列表呈现而不是硬写一个宽表格。另外很多人在网上搜“markdown 表格转 Excel”其实如果你经常需要把 Markdown 表格变成 Excel 或 CSV可以用 VS Code 的插件或者命令行工具pandoc一步完成pandoc input.md -t csv -o output.csv反过来Excel 表格粘贴成 Markdown 也能通过部分编辑器插件实现。我的原则是简单表格用 GFM 语法复杂数据一律外挂 CSV 文件用相对路径链接到笔记里这样既不破坏 Markdown 的可读性也不丢失数据。5. 数据可靠性保障备份策略、仓库维护与日常体检5.1 NAS 的磁盘阵列只是第一层保障别把它当成备份很多人在 NAS 上开了 RAID 就觉得数据安全了。RAID无论是 RAID1 还是 RAID5解决的是单块磁盘物理损坏时数据不丢失的问题它防不了误删、防不了恶意加密、防不了 NAS 主机整个被雷劈或者进水更防不了你在上面跑错命令。所以 RAID 只是冗余不是备份。我自己的记忆锚点是一句话备份的意思是“至少存在两份独立的数据副本并且用独立的方式恢复”。NAS 上的 Git 裸仓库是主副本它必须有一个不在同一台设备上的副本。5.2 我的轻量 3-2-1 备份方案完整的 3-2-1 原则是三份数据、两种介质、一份异地。对个人笔记这种量级不需要搞得像企业机房那样夸张但思路可以照搬第一份本地电脑的 Git 工作目录。第二份NAS 上的裸仓库日常推送的目标。第三份我每个月把 NAS 上的 notes.git 打包压缩然后拷到一个移动硬盘里平时放在办公室和家里的 NAS 物理分离。备份的具体命令可以写成一行tar -czf notes-$(date %Y%m%d).tar.gz -C ~/git notes.git不要觉得这很原始。对于一个以纯文本为主、体积在 1GB 左右的笔记仓库这种 tar 包备份方式简单到极致恢复时只需要解压再 clone 一下就能完全找回。关键是备份动作要定期发生不能想起来才做。5.3 仓库定期体检git gc 和体积控制Git 仓库用久了会积累很多松散对象我每周 commit 几次跑一两年后仓库可能会明显变大。这主要有两个原因一是每个历史版本里都有旧的对象文件二是不小心提交过的大文件即便后来删了历史里还留着。定期执行git gc可以压缩和优化仓库git gc --aggressive --prunenow还有一个命令我每次推送前会习惯性跑一下git count-objects -vH它会显示仓库占用的总大小如果发现仓库体积突然暴涨十有八九是误提交了大文件。这时候的补救不是简单删除文件再 commit——因为历史里还有——而是需要改写历史。对于个人笔记我一般用git filter-branch或者更友好的git filter-repo清理但这类操作会改写提交历史做完以后所有其他设备都需要重新 clone所以我的建议是能不碰历史就不碰重点在于提前预防大文件进仓库。5.4 一份可以按周执行的“笔记系统体检清单”稳定不是靠一次配置就一步到位的而是一套长期维持的习惯。我把自己的日常检查整理成了一个小清单每周大约花五分钟就能过完一遍检查项操作期望结果本地未推送提交git status工作区干净或是有明确未推送提交最近一次推送时间git log -1 --format%ci不超过这周NAS 远端状态git fetch git log origin/main..HEAD没有遗漏未推送的提交笔记仓库体积git count-objects -vH体积没有突然暴涨图片引用有效性find . -name *.md -exec grep -l !\[ {} \;抽查图片路径都能正常打开备份副本时间ls -lh backup/最近一次的 tar 包在一个月以内这套检查并不复杂但它能把很多“隐患”消灭在“事故”之前。我特别想强调图片引用有效性这一项这是 Markdown 笔记系统里最容易被忽视的问题等发现图片全部失效时往往已经一两周没看过旧笔记了。5.5 移动端仓库的维护技巧如果你跟我一样用 Obsidian 做移动端读取还有一件事值得留意手机上的浅克隆仓库长期只拉取不推送一旦哪天你想用手机编辑并推送可能会因为缺少完整历史而产生问题。我的做法是移动端尽量只读紧急编辑也先手动 commit等到回家后在电脑上统一排查。移动端真正适合的场景是快速记录和查阅处理版本冲突这类精细操作还是留给桌面端更靠谱。这一路走来几个最关键的经验沉淀回头再看这套 Markdown NAS Git 的笔记方案能稳定跑下来靠的并不是某个单点技术而是几个习惯的合力Markdown 格式保证内容永远可迁移NAS 保证数据归属自己Git 保证改动有迹可循而定期备份保证意外发生时还有退路。最后分享两个我现在仍在用的细节。第一个是提交规范我的 commit message 永远用一句话说清楚这次改了什么格式是“类型: 简述”比如docs: 补充docker网络模式章节这种。这样半年后回看修改历史还能准确知道当时做了什么事。第二个是写完一篇笔记后我会顺手运行一个 pre-commit 钩子脚本检查所有 Markdown 里的图片引用路径是否存在一旦发现残缺就直接拦截提交杜绝了图片失效问题扩散到仓库里。笔记系统的目标从来不是工具本身有多炫而是让你十年后还能轻松打开当年的记录并且每一句话都完好无损。这套方案帮我做到了希望这篇踩坑记录也能帮你少走一段弯路。