任务清单¶
这一页基于仓库内部的 docs/TASKS.md,但目标不是简单把勾选框搬过来,而是解释:为什么这个项目必须按阶段拆任务,为什么这些任务顺序不能乱。
为什么要拆任务¶
“用 Python 实现 Git”听起来像一句话,实际上不是一个单点功能,而是一串强依赖能力:
- 先有仓库结构;
- 再有对象库;
- 再有 index;
- 再有 commit 和 refs;
- 再有工作区状态比较;
- 再有 checkout、reset、stash、merge;
- 再有 pack 和远端同步;
- 最后还要有安全边界和真实测试把这些东西兜住。
如果不拆任务,项目很容易退化成“不断往 CLI 里塞功能分支判断”,最后任何一个命令都可能误删文件或写坏仓库状态。
高层任务顺序¶
这个项目的任务顺序大体是:
- 先把文档和工程约束立住;
- 再搭项目基础骨架;
- 再做仓库初始化;
- 再做对象数据库;
- 再做管道命令;
- 再做 Index V2;
- 再做本地提交闭环;
- 再做 refs 和 branch;
- 再做 status、rm 和工作区差异;
- 再做 checkout 与 switch;
- 再做 tag、reset、stash;
- 再做 merge;
- 再做 pack、clone、fetch、push 和服务端;
- 最后用真实测试把整条链路验证起来。
这个顺序是有依赖关系的。比如:
- 没有 tree 和 commit,就谈不上
commit -m; - 没有 index,就谈不上“暂存区 vs 工作区 vs HEAD”;
- 没有路径保护,就不应该急着放开
reset --hard和rm。
文档与工程约束不是前戏,而是基础设施¶
任务清单的第一组不是代码,而是规则:
- 拆分 PRD;
- 建立项目结构规划;
- 建立 SDD 工程要求;
- 明确必须用
unittest; - 明确核心行为测试不允许用 mock 替代;
- 明确危险操作必须保护用户电脑;
- 明确 SOLID 和 DRY;
- 明确中文注释规范;
- 明确 Git LFS 不在范围内。
对于复杂系统项目,这些不是“写文档的人爱做的事”,而是后面代码是否还能维持清晰的前置条件。
中间几层任务为什么关键¶
对象数据库¶
对象数据库是整个项目最底层的基础。如果对象 header、SHA-1、zlib 压缩、对象路径和对象校验都不可靠,后面所有命令都是建在沙子上。
Index V2¶
很多初学者会低估 index。实际上,index 是 Git 从“文件快照存储”走向“可控状态机”的关键。没有 index,add、status、merge conflict stage、write-tree 都会失去准确含义。
Refs 和分支¶
分支不是神秘容器,本质就是 ref 指向 commit。把 refs 系统单独拆出来,能让 checkout、log、reset、merge 的行为都变得更容易解释。
工作区改写命令¶
一旦项目开始做 checkout、switch、reset --hard、rm 这类命令,就必须把“用户真实文件系统安全”当成一等需求,不然仓库功能越多,风险越大。
后半段任务为什么更难¶
Stash¶
stash 不是简单复制文件,而是要同时处理中间状态、工作区状态、HEAD 基线和后续应用逻辑。
Merge¶
merge 不是只拼字符串。它至少要涉及:
- DAG 遍历;
- 最近公共祖先;
- 快进判断;
- 三方合并;
- 冲突标记;
- index stage 1/2/3;
- 冲突未解决时禁止 commit。
Pack 和远端¶
到了 pack 和远端阶段,项目已经不只是“本地仓库小工具”,而是在移动对象历史、生成二进制包、更新远端引用。这一步对格式正确性和一致性要求很高。
测试任务为什么放得这么重¶
项目最后有一整套 unittest,而且强调:
- 用真实临时目录;
- 用真实
.pygit; - 用真实对象文件;
- 用真实 index;
- 用真实工作区;
- 不用 mock 假装核心 Git 行为存在。
原因很简单:这个项目不是在测“函数被调用了没”,而是在测仓库状态是否真的正确。
当前状态¶
内部任务清单当前已经全部打勾。对于外部读者,这代表的不是“项目永远结束了”,而是:
- 第一版完整功能边界已经闭合;
- 本地使用已经可用;
- 自建
.pygit专用服务端已经可用; - 后续扩展应该在现有结构和规则上继续,而不是推倒重来。