零依赖纯文本知识库:用文件夹+Git搭建永不过期的个人笔记系统
caveman 是我最近一直挂在嘴边的一个小项目代号外号叫“穴居人方案”。圈子里偶尔看到叫 caveman 的工具或开源项目思路大多差不多把知识管理这件事打回原形不用花哨的 App不用云端数据库就用文件夹、纯文本和几个简单脚本搭一套能扛十年、完全属于你自己的资料系统。我花了一个周末从零把它跑起来随后连续用了一个季度今天把整套过程和踩过的坑都摊开讲一遍。这个方案解决的核心问题是笔记类工具越做越重数据锁在别人平台上本地不想装全家桶又希望所有内容能长期保存、随时检索、可自动备份。如果你也受够了各种“笔记软件全家桶”或者对隐私和长期可迁移性有执念那按下面这套流程走下来你会得到一个只属于你的纯文本知识库整个过程大概只要一个小时。1. 为什么我会做“穴居人”这套东西1.1 现代知识管理工具的普遍痛点大概三年前我还在老老实实用商业笔记软件。一开始体验确实好界面好看、多端同步、文件夹随便建。但用得越久问题越明显。最难受的是数据锁死。某天想把笔记批量导出发现只能按册导出成 HTML 或者它自己的格式想迁移到别的工具几乎等于重新整理一遍。更别说离线访问要单独装客户端后台动不动要登录隐私上心里那道坎一直过不去。后来我切换成了所谓“第二大脑”类工具数据库本地存、也有一些开放性。但这类工具的问题在于太重。打开一个界面要等半天写一条临时想法要经过一堆概念和流程插槽等你想从里面找一个半年前随手记的灵感时反而比用文件系统的搜索还麻烦。对我这种技术背景的人它把简单的事情复杂化了。于是我开始反思知识管理最本质的需求其实只有三个。第一能快速记录第二能快速找到第三资料不会丢。这三个需求其实 1970 年代的设计就解决了就是文件系统、纯文本和版本管理。我把这个思路戏称为“穴居人思维”不追求花哨工具像穴居人一样用最原始、最可靠的东西反而是最耐用的方案。1.2 为什么是“caveman”而不是某个商业软件“caveman”这个词听起来糙但恰好说明了这套方案的核心精神。穴居人不会担心自己的火种被某个平台停服不会被“云同步”绑架。一个文件夹在手所有数据都是你的一个 Git 仓库在手所有历史版本都是你的一个 grep 在手所有内容都能被搜到。这个方案不是为了否定现代工具而是为了找回简单可控的感觉。每个文件都是标准 Markdown 纯文本没有私有格式任何设备、任何系统打开都不会乱码。文件夹的结构就是分类体系你可以按自己的习惯建立层级不用学习软件的“自定义标签”“双向链接”“数据库视图”这些概念。它是反对工具崇拜的工具越通用越经得起时间考验方案越简单越难出故障。这个思路适合什么样的人技术从业者、插件控、隐私敏感用户、长期写作者、自建博客玩家以及所有被商业笔记软件坑过的人。它不适合需要多人实时协同、离不开富文本排版、或者图片素材特别多还需要在线管理的人。认清这个边界很重要后面很多问题其实都是边界问题。2. 核心设计思路把文件夹当数据库用2.1 用目录结构代替数据库表caveman 的设计起点非常朴素把你的笔记库想象成一台文件柜而不是一个数据库。这台文件柜只需要几个抽屉。~/caveman/ ├── daily/ # 日记和日志按日期命名 ├── notes/ # 常青笔记主题性内容 ├── inbox/ # 临时想法收集箱 ├── assets/ # 图片、PDF等附件 └── README.md # 使用说明和索引文件为什么用这四个目录而不是更多因为需求膨胀会拖垮维护意愿。daily 放时间流内容notes 放主题性内容inbox 是应急口assets 放二进制文件。如果分类太多记录一个东西前要纠结“该放哪”几次下来就不想用了。四个目录意味着十五条规则足够覆盖我百分之九十九的使用场景。目录里所有的记录都是用日期加短标题作为文件名。例如2024-07-09-搭建博客的流程.md或notes/nginx-cool-timeout.md。日期前缀带来了几个意想不到的好处文件在系统层面天然按时间排序重名概率极低文件名本身就是元数据不需要特地在正文维护写作时间。标题要是没有就写untitled.md记下来再说内容永远优先于分类。2.2 纯文本格式与 front matter 的必要性正文一律用 Markdown 纯文本不引入任何私有格式。有人会问要不要像某些工具那样在每个文件头部写 YAML front matter就是三横线夹着title、tags、date那种我的经验是可以但能少就少。因为我经常用手机或其他脚本直接读取文件头部信息越少越不容易出错。我最终只保留了一个可选字段tags。其他信息都交给文件名、目录层级和 Git 提交历史去承担因为这三样东西本身就足够可靠。比如正文首行标题就是索引标题不需要在 front matter 里重复维护一份。如果你想加标签写在文件头部或者直接写成内联#标签都可以检索的时候统一用rg去匹配。这里有个生活化类比文件系统是最原始的“图数据库”——目录是父子关系发往同一处的文件可以互相同步全文搜索是即时索引。你不需要提前设计复杂的表结构文件本身就是行目录树本身就是索引搜索就是全表扫描。数据量只有几万个文件时全表扫描完全够快真的不用焦虑性能问题。真到了那个规模你盘一下自己的十年笔记量就会发现这完全不是瓶颈。2.3 为什么我坚持不用数据库和云服务caveman 最核心的设计判断就是不引入数据库、不把数据托付给第三方云服务。原因有三层。第一数据所有权。数据库的底层是特权格式换工具等于转换数据。而纯文本文件夹只依赖操作系统和文件编码标准这些基础技术不会被某一家公司淘汰。第二可组合性。文件可以被任何工具读写Git 可以做历史版本rsync 可以做备份SSH 可以远程访问甚至以后你不想用我的脚本了自己拿文件管理器操作都可以。第三故障排查难度低。数据库出问题很难修文件系统出问题可以用基础工具和备份恢复。方案越是依赖简单的机制系统崩溃时你需要的救生员越少。当然这不意味着与云完全绝缘。我依然用 Git 实现异地备份把它推到一个私有远程仓库用 GitHub 或任何你喜欢平台都可以。但这里的逻辑不同云只是备份存储介质不是数据的法定监护人。真出事的时候我不需要从某个平台“导出”只需要git pull就能拿到完整的历史记录。这是一个巨大的心理差别也是这个方案真正让人安心的地方。2.4 三个核心命令尽力避免发明轮子caveman 没有做成一个庞大的软件核心就是三个 shell 脚本或者三个函数caveman_new新建笔记、caveman_find搜索打开、caveman_sync同步备份。我把它们封装成 Bash 函数放在~/.bashrc或~/.zshrc里全 shell 通用零依赖的情况下也能退化成find加grep。为什么只做这三个因为一条知识从产生到复用的闭环就是记录 → 找到 → 备份。任何编辑、阅读、发布、统计功能都可以用现成工具挂接上去不必为每个功能自己造轮子。交互形态上我刻意没有做图形界面直接用终端和快捷键因为快是工具的第一美德。插一句很多人会觉得脚本方案“简陋”不如图形软件美观。但美观应该建立在数据组织方式上而不是皮肤上。我的数据是开放格式今天用命令行明天如果觉得不舒服写个 Web 界面套在这些文件上也就是半个晚上的事情。底层稳了上层随便换这种架构上的灵活性封闭生态给不了。3. 从零把 caveman 跑起来完整实操流程3.1 初始化仓库十分钟搭好底子下面这套流程是在 macOS 和 Linux 上都验证过的Windows 用户可以用 WSL 或用 Git Bash 模拟。第一步在用户目录下创建项目文件夹并初始化 Git 仓库mkdir -p ~/caveman/{daily,notes,inbox,assets} cd ~/caveman git init echo # Caveman README.md git add . git commit -m init这个过程做了几件重要的事mkdir创建四个顶级目录git init让整个笔记库从此有了历史版本管理README.md作为知识库的“引导页”我会在顶上写一句话提示自己“先搜再写、先记再理”。顺手git commit保证初始状态干净。这里你可能会问为什么assets目录也要纳入 Git 管理如果一个笔记里的配图只在本地备份的时候就会缺块。所以要把二进制文件一起放进去。真正的大文件另说后面会有归档策略。初始化完成之后你已经有了一台空白的“穴居人知识库”数据目录接下来给它装上记录入口。3.2caveman_new建立新笔记的正确姿势新笔记的入口脚本核心逻辑是生成日期前缀文件名创建空内容然后自动打开编辑器。我在~/.bashrc里加了这样一段函数caveman_new() { local dir$HOME/caveman local date$(date %Y-%m-%d) local title${1:-untitled} local slug$(echo $title | tr [:upper:] [:lower:] | tr - | tr -cd a-z0-9-) local file$dir/notes/${date}-${slug}.md if [ -e $file ]; then file$dir/notes/${date}-${slug}-$$.md fi if [ ! -f $file ]; then touch $file fi ${EDITOR:-vim} $file }使用方式就是caveman_new 我的新想法它会自动落到notes/2024-07-09-我的新想法.md并打开 vim。如果你只想快速记一句临时内容用caveman_new tmp然后写几行就行文件名不完美没关系以后可以用mv改。这段代码里有一个细节tr -cd a-z0-9-是为了剔除文件名里的特殊字符。我踩过名字里带斜杠、冒号的坑会造成目录层级错乱或者 Windows 不兼容。虽然 UTF-8 和中文系统下中文文件名没问题但为了跨设备稳定我还是把文件名的主体转成英文短横连接形式。正文里的标题随便中文文件名只负责唯一性和排序这样检索和迁移都非常省心。3.3caveman_find秒级全文定位记录只是开始更关键的是找到。我在所有依赖都安装的环境下用的方案是基于fdfzf这两个工具分别负责快速发现文件和模糊搜索caveman_find() { local file file$(fd . $HOME/caveman -e md -e txt | fzf --preview bat --stylenumbers --coloralways {} 2/dev/null || cat {}) [ -n $file ] ${EDITOR:-vim} $file }fd的作用是快速把所有 Markdown 文档路径列出来fzf提供一个交互式模糊匹配窗口文件的同时会实时预览。选中的文件直接用$EDITOR打开。如果想按内容搜关键词再加一层管道caveman_grep() { rg --color always -l $1 $HOME/caveman -g *.md | fzf }这一条命令会先全文搜索出包含关键词的文件列表再进入 fzf 选择。纯文本的好处在这类场景里特别明显数据散落在不同目录也不怕把搜索范围统一指向整个知识库根目录就行。如果没装 fd/fzf完全可以用系统自带的find和grep替代。只要你愿意用文件管理器的搜索框一样能搜到。所谓方案稳定说的就是即使工具链退化到原始状态核心流程也不会瘫痪。3.4caveman_sync自动备份与多机同步数据安全靠的是备份意识自动化让对象永远不用想起它。sync 脚本的职责只有两件事把本地修改提交到 Git 仓库再把远程仓库的最新状态拉下来合体。这是我在.bashrc里的版本caveman_sync() { cd $HOME/caveman || return git pull --rebase --autostash git add -A git commit -m sync on $(date %Y-%m-%d %H:%M:%S) --allow-empty git push }这段脚本的思路是先拉去远端最新内容并自动变基把本地有而远端没有的改动临时藏起来New 调整之后再释放。在大多数单机使用场景下这个流程足够保证两台设备之间不产生严重冲突。--allow-empty保证即使没有任何修改也要建立新的 commit这样每次同步都会留下一个时间戳复盘写到哪一阶段更容易。有人问为什么不挂 cron 定时跑我两个方式都试过。定时同步适合固定设备比如家里台式机但笔记本经常睡眠网络也不稳定定时任务经常错过或者报错。最终我保持手动 sync 加上事后几分钟补跑的习惯偶尔忘记了下一次 push 会把历史补齐不会丢内容。关键的教训是同步不等于备份三个月至少把一个完整 Git 仓库打包放到外部硬盘或对象存储一次这才是保底的备份方案。3.5 可选的发布能力一键生成静态站点纯文本的最后一块拼图是发布分享。有时候我希望把一些笔记公开成网页给朋友看或者自己远端访问。caveman 这次也顺便做了一个 30 行左右的 Python 小工具把所有 Markdown 转成单个静态 HTML 目录整个网站所有页面都是相互链接的。核心流程用 Python 的markdown库把.md转成 HTML 片段再套进一个简单模板含导航、时间、标题输出到~/caveman/site/。然后我用 Git 或 rsync 把这个site/目录推到多个托管平台。这种方法把“笔记库”和“博客发布”合并成同一个知识库写完即发布不需要 CMS 后台。当然纯手工用pandoc也一样可以pandoc file.md -s -o file.html。只是成批转换还是脚本方便。这部分是锦上添花没有它不影响核心闭环。4. 一路踩过来的坑常见问题与排查实录4.1 中文文件名与编码问题纯文本方案最怕的就是字符编码和文件系统兼容性。我一开始新文件名直接用中文标题当时在 macOS 没问题但同步到旧设备时出现乱码Windows 上甚至有些字符直接被拒绝作为文件名。最终的处理方案正如上文说的文件名只用英文短横格式正文标题保留中文。如果搜不到、找错了文件第一反应先查看编码统一文件编码和换行符为 UTF-8 与 LF。在 Git 层面可以设置git config core.quotepath false这样 git status/commit 记录能看到中文文件名而不是转义成\xxx的形式。别小看它排查问题的时候看到可读的文件名比看编码要快得多。4.2 移动端怎么处理caveman 最弱的一环是手机。因为整个库是文件夹结构手机上的文件 App 虽然能浏览和编辑但体验不如原生笔记软件。我的解决方案是折中手机上放一个只看不写的目录用 Syncthing 之类的文件同步工具把整个知识库同步过去偶尔有必须记录的内容先写到手机里的一个inbox/便捷记录.txt回家跑一次caveman_sync再手动归位。对技术人来说这个闭环完全可以接受。如果你真的需要在线编辑也可以把整个 Git 仓库推到一个私有仓库手机上用支持 Git 的编辑器改完再提交。但我不推荐作为主流程因为移动端输入效率低重内容还是要在电脑上沉淀。4.3 文件数量大了会不会卡我目前的知识库接近两千个 Markdown 文件fd和rg的响应都在毫秒级。按每天两篇算十年也才六七千文件性能压力不大。真正让我卡的是把大量图片也塞进了 Git 仓库一个几十 MB 二进制文件就会拖慢 pull/push。处理方法很简单assets里只保存小图大文件丢到网盘或对象存储单独在 README 里留链接和说明。如果未来真的到了上万文件级别不需要重构整个方案只需要按年份归档notes/2024/、notes/2025/搜索时带时间范围即可。文件系统的弹性往往超出想象系统瓶颈不在文件数而在你检索的时候有没有准确的关键词。这时候长期精心写文件名和正文首行就显得特别值钱。4.4 Git 冲突和误删恢复用 Git 做同步不可避免会遇到冲突。虽然--rebase --autostash让大部分场景自动完成但真冲突来的时候还是要在终端处理。我自己的经验冲突往往发生在同一文件在桌面包和笔记本上都有改动的情况。解决方案是避免“同一时段双端同时改同一个文件”实在不行打开冲突标记手动选择内容。误删文件是最常见的事故。好在我每次 sync 都 commit恢复只需要一行代码git log --oneline --all -- 被删文件路径 git checkout commit-hash -- 被删文件路径比起任何笔记软件自带的“删除备份”这种版本管理语境下的恢复操作永远可用哪怕文件已经被删三个月只要 commit 还在就能找回来。这也是纯文本方案最值得宣传的福利之一。4.5 编辑器与换行的统一打包前最后一个坑跨平台的换行符和编辑器差异。Windows 的记事本会默认用 CRLF导致 Git 提示文件被修改甚至造成渲染异常。我的解决方案是全局统一git config core.autocrlf input。编辑器统一用 vim/neovim 或者星门编辑器VS Code保存时强制启用 “End with newline” 和 “Trim Trailing White Space”这能让 diff 和全文搜索少一堆噪音。4.6 问题速查表问题现象可能原因解决方案文件名乱码文件名非 UTF-8文件名统一英文短横设置core.quotepath false手机端打不开/不便编辑文件数多工具慢手机用同步工具不在此端创作Git 大量文件冲突双端同改一文件避免双端同时编辑手动解决少量冲突即可push/pull 很慢仓库塞了大二进制大文件移出 Git 仓库用外链引用搜索到文件但打开失败编辑器路径或默认设置错误检查$EDITOR环境变量确认文件路径在本地存在同步时发生 rebase 错误本地有未提交改动先git stash或手动提交再 pull 后处理这个速查表是我实际使用中的经验浓缩比任何文档都管用。如果你是自己的方案建议同样维护一份自己的速查单随手记下踩过的坑回头翻很值得。5. 使用一个季度后我对 caveman 的真实体会与扩展方向真正上手用了一百天后我的感受可以浓缩成三点。第一检索变成了一种乐趣。任何时候想找一个半年前的灵感终端里caveman_find然后敲几个关键词几乎零等待。过去我用图形笔记软件想搜一个笔记要先等客户端加载再看着转圈像开盲盒一样。第二写作的摩擦被降到最低。起个文件名打开 vim正文直接敲没有字体弹窗没有排版工具栏让我非常专注于内容本身。第三心里踏实。所有数据躺在本地备份一次就是 git push十年后平台还在不在未知但我这些.md文件比我存过的大部分云盘活得都长。当然它也不完美。多人协同场景完全没有富文本、表格、日历视图也不存在连手机端都只能勉强看和轻量改。这个方案的代价是把很多需求和审美转移到自己的知识和脚本里如果你是团队协作型选手它并不合用。但如果是个人知识管理这套方案的收益远大于代价。后续扩展的方向我列在下面读者可以按自己的需求挂接。日记模板caveman_new daily支持生成当天日记的模板天气、心情、三件要事文件落到daily/2024-07-09.md。书摘和链接库每条资料存一个notes/book-书名.md头部写书籍元数据正文放摘抄、评论、引用链接。记账用 TSV 文件存记账记录配合 Unix 工具做月度汇总。这不是 Excel 的平替但秒开秒查。发布博客使用前文提到的静态站点生成脚本把notes中带public标签的笔记发布成站点。任务管理把任务文件丢进inbox每天写下“今天要做的”用待办勾选语法标记。我个人在实际操作中的一个小小体会是不要一上来就把自己这套方案设计成一个大平台。从一个目录、一个脚本开始用一周记录自己的想法再逐步加功能。等用顺手了工具和方法论会自然长成你自己的形状。最稳定的系统不是我写的代码而是这个习惯本身——不管工具多简陋只要你肯打开它写几行字它就是最好用的工具。最后想给大家一句忠告方案的核心不是技术而是你对资料的长期主义。穴居人方案的魅力不在脚本在于把复杂归还给简单把数据交还给你自己。