[Backlog] Git操作 | 任务数据结构 | Markdown 处理
第3章:Git操作
欢迎回到Backlog.md
!
通过前两章的学习,我们掌握了通过命令行界面(CLI)和Web界面及服务端进行任务管理的方法。
本章将聚焦项目管理的核心要素——版本控制。
为什么需要Git?
Git作为先进的版本控制系统,为文件变更追踪和团队协作提供强大支持。
Backlog.md将项目数据(任务、决策等)存储于backlog
目录的Markdown文件中,这些md文件的每次变更都需要版本控制机制。
Backlog.md集成Git主要实现四大功能:
- 变更追踪:精确记录文件修改内容与时间节点
- 版本快照:通过提交(commit)保存里程碑版本
- 协同更新:获取团队成员在相同仓库中的修改内容
- 分支管理:支持在独立分支处理任务变更(详见跨分支任务解析)
Git操作组件:智能版本管家
Backlog.md内置Git操作模块,作为与Git交互的专用代理。
当核心协调器需要版本控制时,即调用该组件完成以下操作:
典型功能包括:
- 文件暂存(
git add
) - 提交快照(
git commit
) - 状态检测(
git status
) - 分支查询(
git branch
) - 远程同步(
git fetch
)
核心代码
Git操作模块通过GitOperations
类封装底层命令执行,关键代码位于src/git/operations.ts
:
// src/git/operations.ts(简化核心方法)
export class GitOperations {private projectRoot: string; // 项目根目录路径// 执行Git命令的核心方法private async execGit(args: string[]): Promise<{ stdout: string; stderr: string }> {const proc = Bun.spawn(["git", ...args], {cwd: this.projectRoot // 确保在项目目录执行});const [stdout, stderr] = await Promise.all([new Response(proc.stdout).text(),new Response(proc.stderr).text()]);if (await proc.exited !== 0) {throw new Error(`Git命令执行失败: git ${args.join(" ")}\n${stderr}`);}return { stdout, stderr };}// 文件暂存方法async addFile(filePath: string): Promise<void> {await this.execGit(["add", filePath]);}// 提交变更方法async commitStagedChanges(message: string): Promise<void> {const { stdout } = await this.execGit(["status", "--porcelain"]);if (!stdout.trim()) throw new Error("无待提交变更");await this.execGit(["commit", "-m", message]);}
}
测试用例验证关键功能(src/test/git.test.ts
):
describe("Git操作测试套件", () => {it("应正确识别Git仓库", async () => {const gitOps = new GitOperations(projectPath);expect(await gitOps.isGitRepository()).toBeTrue();});it("应成功提交任务文件变更", async () => {await core.createTask(testTask);await gitOps.addFile("backlog/tasks/task-1.md");await gitOps.commitStagedChanges("新增任务");const log = await gitOps.getCommitHistory();expect(log).toContain("新增任务");});
});
总结
Backlog.md通过深度集成Git实现任务文件的版本控制,其Git操作模块作为智能代理,自动化处理版本提交、变更追踪等核心功能。
这种设计既保留了Git的强大能力
,又通过抽象简化了用户操作
。
(还是我们站在需求角度,再套一层实现的思想)
下一章将深入解析任务数据的存储结构。
任务数据结构
第4章:任务数据结构
在上一章Git操作中,我们了解了Backlog.md如何利用Git追踪文件变更。
现在让我们深入文件内部,探索任务数据的组织方式。
数据结构的本质(如同烹饪食谱)
想象编写食谱时需要遵循的标准格式:
- 标题:菜品名称
- 配料:所需材料清单
- 步骤:烹饪流程
- 准备时间:预估耗时
这种标准格式就是数据结构的具象化体现。在计算机领域,数据结构定义了相关数据元素的组织方式
任务数据结构:任务蓝图
Backlog.md的任务数据结构是每个任务必须遵循的标准化模板,包含以下核心字段:
// src/types/index.ts(简化接口定义)
export interface Task {id: string; // 唯一标识符(如task-001)title: string; // 任务标题status: string; // 当前状态(待办/进行中/已完成)assignee: string[]; // 负责人列表createdDate: string; // 创建日期labels: string[]; // 分类标签dependencies: string[]; // 前置任务IDdescription: string; // 详细说明priority?: "high" | "medium" | "low"; // 优先级
}
该数据结构作为系统的"通用语言
",贯穿CLI、核心协调器、Web界面等模块
实际应用流程
CLI创建任务的典型流程:
该流程涉及:
- CLI
解析
用户输入参数 - 核心协调器生成
元数据
- 数据结构实例化
- Markdown文件持久化存储
Markdown文件存储规范
Frontmatter格式
一种用于在文件开头(如Markdown、HTML等)以结构化方式存储元数据的约定,通常以YAML、TOML或JSON形式编写,内容用特定标记(如---
)包裹,便于工具快速读取标题、日期、标签等信息而不解析全文。
示例:
---
title: "示例文章"
date: 2023-01-01
tags: [教程, 技术]
---
任务数据采用Frontmatter格式
存储:
---
id: task-95
title: 添加任务优先级字段
status: 已完成
assignee: ["@claude"]
created_date: "2025-06-20"
labels: ["功能增强"]
priority: high
---
## 描述
为任务添加优先级字段以支持工作排序...
技术特点:
YAML格式
存储结构化数据- Markdown正文存储长文本
- 文件命名规范:ID+标题
- 版本兼容性处理(可选字段)
系统级价值
该数据结构设计带来三大优势:
- 跨模块一致性:CLI创建、Web展示、文件存储使用相同数据规范
- 扩展灵活性:通过可选字段(priority)支持功能演进
- 自动化处理:依赖
关系跟踪
、状态机转换
等核心功能的基础
下一章将深入解析Markdown处理机制如何实现数据
与文件
的双向转换。
第5章:Markdown 处理
欢迎回到 Backlog.md 教程!在上一章中,我们学习了数据模型(类型),以及 Backlog.md 如何通过蓝图(如 Task
接口)定义数据结构。
我们看到当通过 CLI 创建任务时,输入内容会被核心逻辑组织成结构化的 Task
对象后再存储。
但这个
Task
对象究竟保存在哪里?
正如我们在Git 集成所学,Backlog.md 将所有task以纯 Markdown 文件形式存储在 Git 仓库中。
这就是 Markdown 处理 的核心作用所在。
文件格式:带 YAML 前言的 Markdown
让我们再次回顾 Backlog.md 在 Markdown 文件中的存储方式。
在 backlog/tasks/readme.md
的示例中,任务文件采用特定结构:
---
id: task-1
title: "Bootstrap Backlog.md Project Definition with Initial Tasks"
status: "Done"
assignee: ["@MrLesk"] // 多责任人时使用列表格式
created_date: 2025-06-03
labels: ["project-setup", "meta"]
---## 描述定义初始的 Backlog 工作目录...## 验收标准- [x] .backlog 目录结构已创建
...
两个 ---
之间的部分是 YAML 前言,键名(id
, title
, status
等)直接映射到 Task
数据模型的字段。第二个 ---
之后的内容用于描述和其他自由文本区域。
双向转换机制
Markdown 处理包含两个核心操作:
操作类型 | 输入 | 输出 | 应用场景 |
---|---|---|---|
解析 | 原始 Markdown 文件内容 | 结构化数据对象(如 Task ) | 读取文件以展示或操作数据 |
序列化 | 结构化数据对象(如 Task ) | 格式化后的 Markdown 字符串 | 保存或更新数据对象到文件 |
解析流程(Markdown → 数据对象)
当执行 backlog task view task-1
时:
序列化流程(数据对象 → Markdown)
当执行 backlog task update task-1 --status "进行中"
时:
代码实现
解析器实现 (src/markdown/parser.ts
)
使用 gray-matter
库进行 YAML 解析:
// 解析函数简化示例
export function parseTask(content: string): Task {const { frontmatter, content: description } = parseMarkdown(content);return {id: String(frontmatter.id || ""),title: String(frontmatter.title || ""),status: String(frontmatter.status || ""),assignee: Array.isArray(frontmatter.assignee) ? frontmatter.assignee.map(String): [String(frontmatter.assignee || "")],createdDate: new Date(frontmatter.created_date),description: description};
}
序列化器实现 (src/markdown/serializer.ts
)
数据重组示例:
// 序列化函数简化示例
export function serializeTask(task: Task): string {const frontmatter = {id: task.id,title: task.title,status: task.status,assignee: task.assignee,created_date: task.createdDate.toISOString()};return matter.stringify(task.description, frontmatter);
}
模块协同关系
Markdown 处理层作为核心逻辑与文件系统之间的桥梁:
-
文件读取场景:
- 文件系统提供原始字符串
- 解析器生成结构化对象
- 核心逻辑操作对象数据
-
文件写入场景:
- 核心逻辑准备更新后对象
- 序列化器生成标准格式文本
- 文件系统执行持久化存储
这种分层设计使得:
- 核心逻辑无需关注文件格式细节
- 文件格式变更
不影响上层业务逻辑
Git 集成
只需处理文本差异