2026 年新生暑培 C++ 技术实践培训的项目作业。
你要用 C++ 从零写出一个命令行版本控制工具。它有工作区、暂存区、提交、分支和合并, 数据全部存成可以直接用编辑器打开的目录和文本文件。
这不是真实 Git 的替代品,也不读写真实 Git 的 .git 格式。第 7 讲结束时,你会用真实的 Git
把你自己写的这个项目推送到你的远程仓库。
这是作业仓库,main 分支里的 src/ 全是待你填写的 TODO,一共 13 处。
你不需要新建工程,也不需要每讲重新开一个目录:从第 5 讲到第 7 讲,你一直在同一份代码上往前走。
# 1. 在 GitHub 上点 Fork,把本仓库复制到你自己的账号下
# 2. 克隆你自己的那一份(把 <你的用户名> 换掉)
git clone https://github.com/<你的用户名>/minigit.git
cd minigit
# 3. 编译并运行第 5 讲的测试
cmake -S . -B build -DMINIGIT_LESSON=5
cmake --build build
ctest --test-dir build --output-on-failure现在测试会失败,这是正常的。失败的那一条断言就是你这一讲要完成的第一个需求。 详细的环境准备见 docs/environment.md。
| 讲次 | 任务书 | 你要写什么 | 完成后能做到 |
|---|---|---|---|
| 第 5 讲 | lesson05/README.md | Commit 的序列化与解析、Stage 的增删列清 |
把选中的文件存进暂存区,且不受工作区后续修改影响 |
| 第 6 讲 | lesson06/README.md | init add status commit log |
在本地完成多次提交,重启程序后仍能查看历史 |
| 第 7 讲 | lesson07/README.md | branch checkout merge,以及命令行接线 |
建分支、切回来、快进合并,然后把项目推到远程仓库 |
接口在 include/minigit/ 里已经定死了,全程不会变。第 6 讲不会推翻你第 5 讲写的东西,
第 7 讲也不会推翻第 6 讲。你只会一直往上加。
仓库里有两个标签,装着上一讲的参考实现:
| 标签 | 内容 | 给谁用 |
|---|---|---|
lesson06-start |
第 5 讲的参考实现 | 第 5 讲没写完,但想跟上第 6 讲的人 |
lesson07-start |
第 6 讲的参考实现 | 第 6 讲没写完,但想跟上第 7 讲的人 |
用法写在对应讲次的任务书里。这是掉队时的补救措施,不是省事的办法。 直接把参考实现抄完,你能交上作业,但这门课对你就没有任何意义了。 真卡住的时候,先问助教 —— 讲明白一个卡了两小时的 bug,比抄一份能跑的代码值钱得多。
minigit/
├── README.md 你正在读的这份
├── DESIGN.md 数据模型和模块职责,写代码前先读它
├── CMakeLists.txt 用 -DMINIGIT_LESSON=5|6|7 选当前讲次的测试
├── include/minigit/ 4 个头文件,接口固定,不要改
├── src/ 你要填的 5 个源文件
├── data/ 受版本控制管理的数据目录,minigit 只管这里
├── lesson05/ lesson06/ lesson07/
│ ├── README.md 本讲任务书与验收清单
│ └── tests.cpp 本讲的可执行需求
└── docs/
├── environment.md Windows / macOS / Linux 环境配置
├── git-ssh.md 真实 Git 与 SSH:fork、密钥、推送
├── submission.md 最终要交什么
└── faq.md 常见报错速查
lessonNN/tests.cpp 是累积的:第 6 讲的测试包含第 5 讲的全部断言,第 7 讲包含前两讲的。
所以往后写的时候,早先写好的部分会被一直反复检验。
minigit init 初始化本地仓库
minigit add data/<file> 记录待提交文件
minigit status 查看暂存区
minigit commit -m "<message>" 创建快照与提交记录
minigit log 查看提交历史
minigit branch <name> 创建分支
minigit checkout <name> 切换分支
minigit merge <name> 执行受限的分支合并
minigit help 查看用法
全部完成后,下面这段应该能跑通:
./minigit init
echo first > data/note.txt
./minigit add data/note.txt
./minigit commit -m "first"
./minigit branch feature
./minigit checkout feature
echo feature > data/note.txt
./minigit add data/note.txt
./minigit commit -m "feature work"
./minigit checkout main
./minigit merge feature
./minigit log命令必须在仓库根目录执行。add 只管理 data/ 下的普通文件,不接受绝对路径、..、目录或符号链接。
写之前先知道边界在哪,可以省下大量纠结:
- 不读写真实 Git 的
.git对象格式,没有 SHA 哈希和内容去重; - 不记录文件删除、重命名和权限变化;
- 不做三方合并和冲突标记,
merge只实现快进(fast-forward),做不到就明确拒绝; - 不实现网络、远程仓库、权限系统和 SSH —— 推送用的是真实 Git,mini-git 本身不联网;
- 只在当前目录识别仓库,不向父目录搜索
.minigit。
这些边界是课程设计的一部分,不是没写完。
推送到你自己的 fork 后,GitHub Actions 会分别按第 5、6、7 讲编译并运行测试, 你会看到三个独立的检查结果,像一个进度条:
第 5 讲 ✅
第 6 讲 ❌
第 7 讲 ❌
fork 出来的仓库默认关闭 Actions,需要你到自己仓库的 Actions 标签页点一次 "I understand my workflows, go ahead and enable them"。
见 docs/submission.md。简单说:在你自己的 fork 里写代码, 一边写一边用真实 Git 提交,第 7 讲配好 SSH 后推送上去。
本课程不允许使用 AI 生成代码、用自然语言直接编程,或让编程智能体替你操作。 所有实现、阅读、调试和验证都要你自己完成。
遇到问题可以查 docs/faq.md、提 Issue、或在答疑课上问。 贴报错信息时请去掉个人敏感内容。任何情况下都不要上传或发送你的 SSH 私钥。