ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

caveman:基于纯文本与Git的极简个人知识库方案

2026/10/8 11:59:06 拓冰建站 浏览量
caveman:基于纯文本与Git的极简个人知识库方案 最近我把攒了两年的笔记体系彻底推倒重来换成了一个叫 caveman 的极简方案。caveman 直译过来就是穴居人、原始人名字听着像开玩笑但它确确实实是我每天都在用的个人知识库管理工具一堆按日期命名的 Markdown 纯文本文件、一个根目录、几个加起来两百行不到的 shell 脚本再加一个本地 git 仓库。核心理念和名字一致——像原始人把信息直接刻在石壁上那样把所有内容存成最朴素的纯文本不依赖云数据库不装 App不学复杂语法。这篇文章就围绕 caveman 的设计思路、核心脚本、日常工作流和踩坑记录展开给同样想做知识库减法的朋友一份可以直接照抄的参考。1. 「caveman」到底是个什么项目1.1 名字背后的理念很多人第一次听到 caveman 这个名字第一反应都是这什么复古玩意儿。其实这个名字本身就是对现代工具过度设计的一种回应。技术圈一直有caveman debugging的说法指的是不用调试器、只用 printf 或者 console.log 打日志来定位 bug 的原始调试方式。听起来土但真正遇到诡异问题的时候这种最直接的手段往往比花里胡哨的调试工具更快出结果。caveman 项目继承了同样的思路优先选择最简单、最直接、最少依赖的方案而不是功能越多越好。我起这个名字还有一点私心。每次打开那些功能繁多的笔记软件铺天盖地的模板、看板、脑图、白板、AI 助手我真正需要的其实只有六个字记下来能找到。工具一旦变重人的使用意愿反而断崖式下降。caveman 刻意把功能砍到只剩骨架用最少的机制撑起完整的管理流程。这和最近几年大家都在聊的数字极简是同一个逻辑把注意力从工具本身收回来放到内容上。你不需要学习如何分类、如何搭建复杂数据库只需要记住一件事——写。1.2 它解决了什么问题我先说说自己原先的痛点相信不少朋友也有同款笔记散落在四五个 App 里A 软件的内容没法直接搬去 B 软件换个平台就像搬了一次家。数据存在别人的服务器上离线打不开导出的格式千奇百怪有的干脆不给你导出。功能越更新越复杂可我想要的基础检索却越来越慢。记了三年笔记回头自己都忘了记过什么变成一个只写不看的数字囤积者。caveman 的目标就是终结这四件事。它把所有权完全还给用户每个文件都是标准 Markdown电脑上任何一个文本编辑器都能打开检索用 ripgrep上万篇笔记也能在毫秒级返回结果git 保证每次修改都有回退的可能归档交给命名和标签不做强迫症式的多级分类。工具本身零依赖——只要你的电脑有 bash、git 和一个文本编辑器就能跑不需要装运行时、不需要联网、不需要注册账号。1.3 它适合谁不适合谁用了一段时间之后我对 caveman 的适配人群有个清晰判断写作者和内容创作者需要稳定的素材库还要能随时导出成稿件。开发者和技术从业者习惯命令行愿意用 git 管理一切不排斥纯文本。对数据主权敏感的人不想把日记、想法、灵感交给第三方平台保管。被复杂工具折腾烦了、想找回一本笔记本手感的人。反过来如果你需要富文本排版、多人实时协同、手机上的丝滑编辑体验那 caveman 确实不适合你没必要硬上。工具选择是匹配问题不是高低问题后面我会专门聊这个边界。1.4 和主流笔记软件的对比我整理了一张表帮大家快速理解差异维度caveman主流云笔记数据存储本地纯文本文件云端私有格式离线可用完全可用受限检索速度毫秒级rg视服务端而定长期可读性永久取决于厂商存续版本回溯git 精确到行通常没有学习成本半小时上手功能要学一个月协同编辑较弱强这张表没有贬低云笔记的意思毕竟人家在协同和移动端上的体验是本地方案比不了的。但如果你把数据终身所有权放在第一位caveman 这条路线几乎是唯一的答案。2. 整体设计与技术选型2.1 为什么非纯文本不可这是整个项目最核心的决策。我试过各种高级格式最后全部迁移到纯文本理由可以用四个词概括长寿、透明、可检索、可版本化。长寿是硬道理。你在 1995 年写的 .doc 文件今天可能已经打不开了但 1970 年写下的一段纯文本到现在一字不差。纯文本没有版本兼容问题不管过十年还是二十年记事本、cat、less 都能读。透明指的是所有信息都是可见字符没有私有二进制格式没有必须用指定软件才能打开的绑定。你可以随时用最简单的工具查看任何一篇笔记不用祈祷厂商还活着。可检索这一点容易被低估。结构化数据库看着查询很方便但个人笔记的日常场景绝大多数其实是全文关键词搜索。纯文本恰好是全文检索最好的朋友rg 扫过几十万行内容几乎没有感知。可版本化让 git 成为天然搭档。diff 能精确到每一行随时回滚任意历史版本这是任何一种数据库视图都做不到的。纯文本是唯一能让版本管理这件事变得如此便宜的数据格式。2.2 目录结构与命名规范caveman 的目录结构刻意保持简单~/caveman/ ├── inbox/ # 临时捕获区快速记录碎片想法 ├── notes/ # 正式笔记按主题沉淀 ├── diary/ # 日记每天一篇 ├── assets/ # 图片、PDF 等附件 ├── README.md # 使用说明和索引 └── .git/ # 版本仓库设计上只保留四个一级目录就是为了避免过早分类。很多人搭知识库一上来先建十几层分类结果发现 80% 的内容根本不知道该放哪。我的做法是新内容先全部丢进 inbox每周回顾时再归档归档时遵循能不放分类就不放分类的原则。文件命名统一用日期-短横线标题.md比如20250603-咖啡拉花入门笔记.md。这个命名有三个好处第一按文件名排序就是按时间排序归档即时间线第二日期前缀保证文件名全局唯一不会因为同名而互相覆盖第三一眼就能看出创建时间不用打开文件查元数据。2.3 标签与元数据一行 tag 的设计我强烈不建议在纯文本笔记里用 YAML front-matter 做元数据。虽然静态博客系统都爱用这套但在个人笔记场景里front-matter 是纯噪音——占行数、容易缩进出错、解析还要额外工具。caveman 的约定更粗暴笔记正文第一行写一个以tag:开头的标签行。tag: 咖啡 生活 手冲 # 咖啡拉花入门笔记 今天试了新的拉花缸发现奶泡厚度是关键...这样设计的好处是 grep 或 rg 直接搜^tag: 咖啡就能把相关笔记全列出来。标签就是一行纯文本没有解析成本永远不会因为 YAML 缩进错误被气疯。标签的另一个原则是克制。每篇笔记最多三四个标签只标主题不标状态。状态是流动的比如待办已读这类标签应该直接删掉用标题文字表达就够了主题才是稳定的值得长期检索。2.4 检索方案rg 与 grep 的取舍检索是知识库的命脉caveman 默认用 ripgreprg没有 rg 时自动回落到底层 grep。选 rg 纯粹是因为速度它基于 Rust 实现自带并行扫描和智能过滤在几万文件里做正则搜索依然保持响应。这个差距在冷启动时特别明显grep 在大目录上可能要等几秒rg 基本感觉不到延迟。封装的时候我把底层命令细节全藏起来用户只需要输入关键词脚本负责拼参数。几个关键参数务必理解-i忽略大小写英文检索更友好。-n显示行号方便直接从结果跳转。--hidden让搜索结果包含隐藏文件避免遗漏。-l只输出文件名适合做结果列表 预览两段式展示。还有一个容易被忽视的细节搜索时必须排除assets/里的大附件目录和.git目录否则二进制文件会把结果列表搅得一塌糊涂。3. 核心实现从小脚本到完整工具链3.1 初始化一分钟搭好仓库caveman 的入口是一个叫caveman的 bash 脚本我放在~/bin/caveman然后在 shell 配置里加一行export PATH$HOME/bin:$PATH。初始化部分长这样#!/usr/bin/env bash set -euo pipefail NOTES_DIR${CAVEMAN_DIR:-$HOME/caveman} EDITOR${EDITOR:-vim} init() { mkdir -p $NOTES_DIR/{inbox,notes,diary,assets} touch $NOTES_DIR/README.md if [ ! -d $NOTES_DIR/.git ]; then git -C $NOTES_DIR init fi echo caveman initialized at $NOTES_DIR }这里有三个细节值得说一说。第一CAVEMAN_DIR环境变量允许随时更换根目录方便在不同项目之间切换笔记库。第二set -euo pipefail是 bash 脚本的安全带任何一步出错就立即停止避免在错误状态下继续写数据。第三目录用花括号展开一次建齐简洁省事。git init这一步看起来多余其实是整个系统的保险丝。后面所有的删除恢复、批量修改、多设备同步都建立在这个仓库上没有它很多东西就回到了裸奔状态。3.2 新建笔记自动化命名与模板新建笔记是最常用的操作必须足够快。我的实现是把命名和模板交给脚本人只需要输入标题new() { local title$* local date date$(date %Y%m%d) local filename$date-${title//\//-}.md local target$NOTES_DIR/inbox/$filename if [ -e $target ]; then filename$date-${title}-$(date %H%M%S).md target$NOTES_DIR/inbox/$filename fi cat $target EOF tag: # $title EOF $EDITOR $target }几个关键点${title//\//-}把标题里的斜杠替换成短横线防止一不小心创建了子目录如果文件名冲突自动追加时分秒后缀创建文件后立即交给$EDITOR打开不打断输入心流。模板默认只留tag:行和一级标题这符合先写正文、后补标签的习惯。你可以按需求定制比如加上日期、天气、心情字段但我的建议是保持最小化因为模板字段越多你新建一篇笔记的心理阻力就越大。3.3 检索与打开搜索到上下文的最后一公里检索命令是整套工具里最值得打磨的部分。我的实现分两层第一层是纯搜索结果find_note() { local query$* local toolrg command -v rg /dev/null 21 || toolgrep case $tool in rg) rg -i -n --hidden --glob !.git --glob !assets $query $NOTES_DIR ;; grep) grep -rin --exclude-dir.git --exclude-dirassets $query $NOTES_DIR ;; esac }实际输出效果大概这样~/caveman/inbox/20250603-咖啡拉花入门笔记.md 3:tag: 咖啡 生活 手冲 5:今天试了新的拉花缸发现奶泡厚度是关键... ~/caveman/notes/20250412-手冲咖啡水温控制.md 1:tag: 咖啡 手冲 生活 8:水温 92 度的时候甜感最明显93 度以上苦味增强。第二层是我个人使用频率最高的pick子命令。它先搜索让用户输入序号然后直接用编辑器打开对应文件。从突然想到一个关键词到打开原文继续阅读三秒内完成pick() { local query$* local result result$(rg -il --hidden --glob !.git --glob !assets $query $NOTES_DIR) if [ -z $result ]; then echo 没有找到匹配的笔记 return 1 fi local count count$(echo $result | wc -l) if [ $count -eq 1 ]; then $EDITOR $result else echo $result | nl read -rp 输入序号打开笔记: num $EDITOR $(echo $result | sed -n ${num}p) fi }rg -il只输出文件名nl给结果加行号sed -n ${num}p取出用户选择的哪一行。这个小循环让搜索-选择-打开一气呵成不用再去文件管理器里一层层翻。3.4 Git 集成版本管理与多设备同步git 在 caveman 里承担三个职责本地历史、误删恢复、多设备同步。本地历史通过这三个子命令实现save() { git -C $NOTES_DIR add -A git -C $NOTES_DIR commit -m update: $(date %Y-%m-%d_%H:%M) } undo() { local n${1:-1} git -C $NOTES_DIR checkout HEAD~$n -- . } logv() { git -C $NOTES_DIR log --oneline -20 }save一条命令完成暂存和提交消息自动带时间戳省去敲 commit message 的纠结。undo回滚最近 N 次修改是我在大批量误操作之后的救命稻草。logv快速浏览历史配合git show可以看任意一次改动的细节。多设备同步我实测过两种方案。第一种是 git 远程仓库放在自己的 NAS 或者私有的 git 服务器上同步前先git pull --rebase有冲突就手动解决冲突可控性最高。第二种是直接用一个支持双向同步的网盘工具同步整个目录胜在无感但两台设备同时写同一个文件时容易产生冲突副本。我更推荐第一种因为数据冲突的可控性高得多代价只是每次换设备前多敲一条命令。3.5 统计与回顾让知识库会自我生长一个只写不看的笔记库是没有价值的所以我加了一个stats子命令希望用数据反向提醒自己定期回顾stats() { local week_start week_start$(date %Y%m%d -d 7 days ago) echo 本周新增 find $NOTES_DIR/{inbox,notes,diary} -name *.md -newermt $week_start | wc -l echo 本周字数 find $NOTES_DIR/{inbox,notes,diary} -name *.md -newermt $week_start -exec cat {} | wc -m echo 标签排行 rg -h ^tag: $NOTES_DIR/{inbox,notes,diary} | sort | uniq -c | sort -rn | head -10 }这里有两个容易踩的小坑。第一统计字数用wc -m而不是wc -c前者按字符数统计对中文才准确后者按字节数会把中文文章的字数虚高一倍。第二tag 排行用的sort | uniq -c | sort -rn是 shell 里做词频统计的经典管道比临时写个 Python 脚本轻量多了。这套统计不追求精确目的是给出趋势感。每周日花十分钟看一眼就知道注意力落在哪些主题上哪些想法还停在碎片状态哪些主题值得继续深挖成文章。4. 日常使用工作流把 caveman 真正用起来4.1 捕获灵感的三种姿势碎片笔记的生命力在于捕获足够快。我实际用下来总结出三种姿势按场景切换。第一种是终端键盘流在电脑前工作时最常用。敲一句caveman new 咖啡拉花奶泡厚度脚本自动建文件、打开编辑器全程不用碰鼠标。第二种是极速追加流针对已经有主题、只想补一段内容的情况echo 补充今天发现 92 度水温甜感最明显 $HOME/caveman/inbox/20250603-咖啡拉花入门笔记.md我给这种操作配了一个 alias 叫nop几乎不需要思考成本。第三种是手机流在外面临时有想法先在手机备忘录里记一行每周回顾时统一批量拷进 inbox。三种姿势的共同原则是先记录不整理。捕获阶段任何对格式、标题、标签的纠结都是多余的整理是每周回顾才做的事情。这个顺序一旦颠倒工具就会变成负担。4.2 每周回顾从碎片到体系每周回顾是我整个系统里最重要的一环流程只有四步第一把 inbox 里所有文件打开扫一遍删除无价值的碎片和已经过时的临时想法。第二给保留的笔记补上tag:行想清楚这篇到底属于什么主题。第三用mv把笔记从 inbox 移动到 notes 或 diary 对应位置文件名和文件名内容都不需要改。第四跑一次caveman stats看本周的写作量和主题分布。这个流程放在每周而不是每天是刻意为之。整理批量做效率才高每天整理容易变成强迫症把本就不多的记录热情消耗干净。周日晚上泡杯茶把这一周的碎片归位那种一切尽在掌握的感觉比任何效率软件的通知提醒都有效。4.3 从笔记到文章导出与发布caveman 的笔记本身就是标准 Markdown导出成文章几乎零成本。我常用的链路是 pandoc 转 HTML 或 PDF或者直接复制进博客后台发布export_note() { local file$1 pandoc $file -o ${file%.md}.html --standalone }如果笔记里有图片记得把assets/里的附件和文章一起拷贝或者用相对路径引用。我早期在这里吃过亏图片用了绝对路径换了一台设备就全失效。现在的统一约定是图片放在assets/下笔记里用../assets/xxx.png这种方式引用整个目录拷到哪里都能正常显示。这条约定几乎不花成本却能避免未来无数次修复图片链接的麻烦。4.4 一个真实的一天拿我最近一个工作日记一记。早上在地铁上看到一篇文章讲了咖啡萃取压力对风味的影响我在手机备忘录里记了两行。到公司坐下终端里敲caveman new 咖啡萃取压力笔记把路上那两行补全顺手贴了一个从文章里摘的实验数据表。中午休息时翻旧笔记想起上个月写过一篇手冲水温的笔记用caveman pick 水温直接打开发现里面有个结论和上午那篇矛盾。下午我做了个简单验证把结论更新到两篇笔记里互相加了链接。晚上下班前跑caveman save提交今天的改动一天的输入、整理、修正闭环完成。真要说这套系统给我带来了什么那就是不再丢东西。每一个想法、每一次修正都有迹可循这是以前用云笔记时从未有过的踏实感。5. 常见问题与排查技巧实录5.1 中文关键词搜不到这是新用户最常遇到的头号问题我第一次用 grep 搜中文时也差点以为笔记写坏了。后来发现是编码问题老旧的 grep 在特定系统上按字节匹配而中文是多字节编码搜索一个中文词可能恰好落在字符边界中间自然什么都搜不出来。rg 内置 UTF-8 支持基本没有这个毛病。如果你只能使用 grep先确认系统 locale终端里敲locale看看LANG是否为 UTF-8。如果不是在 shell 配置里加一行export LANGC.UTF-8通常就能解决。另外不管用哪个工具尽量搜词而不是长句片段中文分词不是 grep 的职责搜太长反而容易失败。5.2 笔记多了之后检索变慢当目录膨胀到几万个文件之后即使 rg 也会开始感到吃力。我的经验是先做三步优化第一把assets/里的大文件彻底移出检索范围或者放到独立的附件目录第二删除无意义的空文件和临时草稿空文件会让扫描白费功夫第三如果确实需要频繁做全量搜索可以给 rg 建持久化索引。大多数情况下做完前两步检索就能回到毫秒级。真的等不到结果时瓶颈通常出在 shell 启动和编辑器加载而不是 rg 本身。5.3 误删文件怎么办误删是所有笔记工具都逃不过的事故。在 caveman 里只要删除前跑过caveman save一切都能找回来git log --all --full-history --oneline -- 被删文件 git checkout commit哈希 -- 被删文件第一条命令找到包含该文件的所有历史提交第二条命令把文件从指定提交恢复到工作区。如果目录里没有 git 仓库那就只能依靠网盘回收站或者外置备份。我的操作纪律是每周至少 commit 一次并且让 git 仓库有远程副本。这一条能做到99% 的误删都能恢复剩下的 1% 就只能靠备份了。5.4 多设备同步冲突怎么处理使用 git 方案之后最常见的冲突是同一篇笔记在两台设备上同时修改。git 会在文件里生成带标记的冲突块。我的处理套路是先git status找到冲突文件打开文件搜手动保留正确版本删掉其他冲突标记最后git add那个文件再 commit。为了避免冲突我养成了两个习惯每次换设备工作前先git pull --rebase同一个文件尽量集中在同一台设备上完成编辑。如果冲突频繁说明你的多设备工作流需要调整不要在同一时间在两台设备上改同一篇笔记这是 git 模型的天然约束顺着它走就不会难受。5.5 问题速查表现象可能原因解决方案中文搜不到locale 不是 UTF-8设置export LANGC.UTF-8或改用 rg检索越来越慢目录里混入大附件用--glob !assets排除附件目录误删了笔记没有可用备份git log --all找到历史版本恢复同步出现冲突标记两台设备同时修改同一文件手动保留正确版本后重新 commit编辑器没有正常打开PATH 或 EDITOR 未配置检查$EDITOR和$PATH是否正确这张表我一直贴在仓库的 README 里每遇到一次新问题就补充一条。时间久了这套系统连安全感都可以被检索到。6. 实操心得与边界思考6.1 我踩过的四个坑第一个教训是过度设计。第一版 caveman 我给笔记加了 JSON 索引、别名系统、双向链接结果维护成本比记笔记本身还高。后来全部删掉回归到rg加命名约定世界清净了。工具的复杂度必须和实际需求匹配caveman 这个名字本身就是个提醒别把工具做成琥珀宫。第二个教训是 commit 不及时。最早我一个月才提交一次有次误删了半个目录差点崩溃。后来改成每次工作结束就跑一次save加上 NAS 定期做镜像备份之后再也没有出现过数据安全事故。第三个教训是标签膨胀。有一段时间我每篇笔记标七八个标签结果搜索出来的结果比不搜还多。后来硬性规定每篇最多三四个标签遇到了某个标签下内容超过几十篇的情况就用子目录或标题来区分而不是继续加标签。第四个教训很不起眼但特别想说不要把纯文本和必须用终端绑在一起。caveman 的存储层是纯文本但编辑层可以是任何工具。我在手机上用任意 Markdown 编辑器打开同一个目录在桌面端用 VS Code 或者 vim 都毫无障碍。系统的灵活性来自存储的简单而不是工具的执念。6.2 这套理念的边界在哪里说句公道话caveman 不是万能的。遇到这些场景我会毫不犹豫换用别的工具多人实时协作请老老实实用在线文档复杂表格和富媒体展示请用专门的笔记软件如果你重度依赖 AI 辅助整理和语义检索纯文本方案还得做很多额外改造。工具始终是服务于人的不要为了极简而极简。但如果你和我一样核心诉求是数据自己掌握、几十年后可读、检索快到没有存在感那 caveman 这条路线确实经得起时间考验。互联网这些年最大的教训之一就是我们太容易把数据托付给看起来很美的平台然后某一天发现平台没了或者变了一切归零。纯文本加本地仓库是我能想到的对冲这个问题最便宜的方式。6.3 后续还能怎么扩展这套系统的扩展空间其实很大。我已经在做的有用 cron 每天自动git pull加git push实现无人值守的多设备同步在计划中的有给assets/里的图片做一个简单的 OCR 脚本把图片里的文字自动提取进索引还有人建议我写一个小的周报生成器每周一把上周的笔记变化汇总成一段摘要。其实核心思路就一句话存储保持原始工具保持轻量把复杂度留给未来真正需要的时候再去解决。你不需要一次性把系统设计完美因为知识的形态本来就会变。用最原子的方式存档将来怎么加工都好办用最花哨的方式锁死将来想迁移就难了。我个人做了 caveman 之后最大的变化不是记录数量变多了而是心里踏实了。以前总琢磨某个软件哪天会不会下架、数据怎么转移现在这些顾虑全都消失——整个知识库就是一堆 txt 一样的文件拷贝、备份、迁移都只是一条cp命令的事。这种原始的安全感恰恰是很多高级工具给不了你的。写到这里我已经在想下一篇笔记该怎么写了。