首页
/ free-programming-books 贡献指南:免费编程资源清单的准入标准、Markdown 格式与 CI 全自动校验

free-programming-books 贡献指南:免费编程资源清单的准入标准、Markdown 格式与 CI 全自动校验

2026-09-07 12:00:55作者:丁柯新Fawn

free-programming-books 是一个以「多语言免费编程图书清单」为核心资产的仓库,它的数据文件遍布 books/courses/casts/more/ 四个目录,并由 GitHub Actions 自动校验每一条新增链接的排序与格式。本仓库中的 CONTRIBUTING-np.md(及其英文原版 docs/CONTRIBUTING.md)系统规定了「什么样的资源能收录、怎么写进列表、怎样通过自动化检查」。这篇文章将以此为骨架,结合仓库内的目录结构与 CI 工作流实现,完整讲解从发现一条学习资源到成功合入的一条合规路径。

仓库内容结构:四类目录承载六种资源清单

在动手贡献之前,先弄清楚这份仓库放的是什么。根目录下维护学习资源的实际数据目录有四个:

目录 存放内容 对应资源类型
books/ 各语言的编程图书列表 Books(图书)
courses/ 各语言的课程列表 Courses(课程)
casts/ 各语言的播客与录屏列表 Podcasts & Screencasts(播客与录屏)
more/ 交互式教程、在线 Playground、编程竞赛题集 Interactive Tutorials、Playgrounds、Problem Sets & Competitive Programming

例如英文图书清单拆成了按语言与按主题两个入口文件 books/free-programming-books-en.md,实际清单则分置于 free-programming-books-langs.md(按编程语言)与 free-programming-books-subjects.md(按主题)中。此外还有 scripts/(含 RTL/LTR 脚本 rtl_ltr_linter.py)与 .github/workflows/ 的 CI 工作流文件作为质量保障设施。

贡献前必读:协议、行为准则与三条快速原则

贡献者需要先理解两份具有约束力的仓库内文档:

  • 贡献者许可协议:凡向仓库贡献内容,即视为同意仓库的 LICENSE 许可条款。
  • 贡献者行为准则:贡献行为需遵守 docs/CODE_OF_CONDUCT.md(该文件同样提供多语言翻译版)。

在此基础上,CONTRIBUTING-np.md 用三条原则概括了协作精神:

  1. 只收录真正免费的内容。"一个可以轻松下载图书的链接"不等于"免费图书的链接"。仓库不接受需要提交有效邮箱地址才能取得书籍的页面,但欢迎收录"请求提供邮箱(非必需)"的条目。
  2. 不懂 Git 也能贡献:发现仓库中不存在的资源时,可以打开 Issue 附带链接建议;熟悉 Git 的贡献者则走 Fork + Pull Request(PR)流程。
  3. 先选对六种清单之一:不同形态的学习资源对应不同目录,乱放是常见的首个 PR 被拒原因。

六类资源清单:先给资源精准归类

CONTRIBUTING-np.md 定义了六种列表类型,判别的第一步是"看资源如何自我介绍":

  • Books(图书):PDF、HTML、ePub、基于 gitbook.io 的站点、Git 仓库等形态的学习材料。
  • Courses(课程):非图书形态的系统化学习材料,例如 MIT OpenCourseWare 的《Introduction to Algorithms》课程。
  • Interactive Tutorials(交互式教程):允许用户输入代码或命令并立即求值反馈的交互式网站(此处的 evaluate 不是"打分")。
  • Playgrounds(在线游乐场):在线交互式网站、游戏或桌面软件,用于编写、编译(运行)并分享代码片段,常支持 fork 后动手改写。
  • Podcasts and Screencasts(播客与录屏):音频播客与录屏教程。
  • Problem Sets & Competitive Programming(题目集与竞赛编程):通过解决简繁不一的问题来评估编程技能的网站或软件,可带或不带代码评审、可与其他用户比较结果。

对应仓库实际位置:Books 与 Courses 分别进入 books/courses/,播客/录屏进入 casts/,而交互式教程、Playgrounds 与题目集分别对应 more/ 下的 free-programming-interactive-tutorials-*.mdfree-programming-playgrounds*.mdproblem-sets-competitive-programming.md

内容与链接的准入红线(Guidelines)

无论提交哪个类别,以下来自 CONTRIBUTING-np.md 的规则构成"能收录什么"的判定标准:

免费性验证

  • 确保链接指向的资源确实免费,必要时二次核实;若在 PR 中注释说明"为何认为该资源免费",能显著帮助管理员审阅。
  • 不接受托管于 Google Drive、Dropbox、Mega、Scribd、Issuu 及其他同类文件上传平台的链接。

权威性与链接形态

  • 优先权威来源:作者官网优于编者网站,编者网站优于第三方网站。
  • 安全优先:同一域名提供相同内容时,https 永远优于 http
  • 根域去尾斜杠http://example.com 而非 http://example.com/
  • 最短链接优先http://example.com/dir/ 优于 http://example.com/dir/index.html
  • 禁止短链接:任何形式的 URL 缩短服务链接都不可用。
  • "当前版"优于"版本号版":通常 http://example.com/dir/book/current/ 优于 http://example.com/dir/book/v1.0.0/index.html

SSL 证书问题三步处理法

当链接存在过期证书、自签名证书或其它 SSL 问题时,按顺序处理:

  1. 替换:如可行,换成对应的 http 版本(移动端处理证书异常往往更麻烦);
  2. 保留:若没有 http 版本,但在浏览器中通过添加例外或忽略告警仍可经 https 访问,则保留;
  3. 删除:否则直接移除该链接。

多格式与多版本

  • 同一资源存在多种格式时,分别添加链接并注明格式。首选单一链接能便捷访问各格式;确有需要时,多链接也合理,但每多一条链接都意味着后续维护成本。
  • 同一资源散落于互联网多处时,取最权威来源;若对应不同版本且版本差异值得保留,则每个版本单独列一条并加注(参见仓库维护方在对应 Issue 中的格式讨论)。

提交粒度与其它细节

  • 原子提交优先:一个提交尽量只做增/删/改中的一件事;PR 前不强制 squash(该规则本身不会被强制,仅属维护便利)。
  • 旧书在标题中标注出版日期;适当位置补充作者(可用 et al. 缩写长作者表)。
  • 未完成的在写书籍加 in process 标注;经 Internet Archive Wayback Machine 恢复的资源加 archived 标注。
  • 下载前要求邮箱或账号的资源,用括号加语言适配的注释,例如 (email address requested, not required)

列表文件的 Markdown 格式规范

CONTRIBUTING-np.md 用一个独立章节把格式讲得极其细致,这些细节决定了 PR 能否通过自动化 lint。所有清单都是 .md 文件。

标题层级与空行

  • 列表以**索引(Index)**开头,索引用字母序罗列并链接全部章节与子章节。
  • 章节使用三级标题 ###,子章节使用四级标题 ####
  • 空行规则严格固定:
    • 最后一个链接与新章节之间保留 2 个空行;
    • 标题与其章节内第一个链接之间保留 1 个空行;
    • 两条链接之间 0 个空行;
    • 每个 .md 文件末尾保留 1 个空行。

示例:

[...]
* [An Awesome Book](http://example.com/example.html)

### Example

* [Another Awesome Book](http://example.com/book.html)
* [Some Other Book](http://example.com/other.html)

条目书写的六个"对与错"

格式规范中最容易踩坑的细节,全部集中在单条链接条目上:

1. ]( 之间不得有空格

BAD : * [Another Awesome Book] (http://example.com/book.html)
GOOD: * [Another Awesome Book](http://example.com/book.html)

2. 作者用单个空格环绕的短横 - 分隔

BAD : * [Another Awesome Book](http://example.com/book.html)- John Doe
GOOD: * [Another Awesome Book](http://example.com/book.html) - John Doe

3. 链接与格式标注之间留一个空格

BAD : * [A Very Awesome Book](https://example.org/book.pdf)(PDF)
GOOD: * [A Very Awesome Book](https://example.org/book.pdf) (PDF)

4. 作者在前,格式在后

BAD : * [A Very Awesome Book](https://example.org/book.pdf)- (PDF) Jane Roe
GOOD: * [A Very Awesome Book](https://example.org/book.pdf) - Jane Roe (PDF)

5. 多格式条目格式

BAD : * [Another Awesome Book](http://example.com/)- John Doe (HTML)
GOOD: * [Another Awesome Book](http://example.com/) - John Doe (HTML) [(PDF, EPUB)](https://downloads.example.org/book.html)

6. 旧书年份并入标题

BAD : * [A Very Awesome Book](https://example.org/book.html) - Jane Roe - 1970
GOOD: * [A Very Awesome Book (1970)](https://example.org/book.html) - Jane Roe

特殊状态标注

未完成书籍与归档链接各有约定写法:

GOOD: * [Will Be An Awesome Book Soon](http://example.com/book2.html) - John Doe (HTML) *( :construction: in process)*
GOOD: * [A Way-backed Interesting Book](https://web.archive.org/web/20211016123456/http://example.com/) - John Doe (HTML) *( :card_file_box: archived)*

关于免费许可证标注(如 (CC BY-SA))以及支持的许可证缩写集合(CC BYCC BY-NCCC BY-SACC BY-NC-SACC BY-NDCC BY-NC-NDGFDL)与分步添加方法,英文原版 docs/CONTRIBUTING.md 中有更完整的补充章节,提交前可对照阅读。

字母序排列规则

所有清单内的条目必须严格按字母序排列,规则看似简单却需注意两个细节:

  • 标题首字母相同者,按第二个字母排序,依次类推,如 aa 排在 ab 之前;
  • 空格参与比较:one two 排在 onetwo 之前。

如果看到位置错误的链接,不必手工猜测该换哪两行——直接查看 linter 错误信息,它会明确提示需要交换的行号。

元数据设计:一条条目的最小信息集

仓库的清单只保留最小元数据集:标题、URL、创作者、平台与访问备注。对于每类元数据,CONTRIBUTING-np.md 都划定了边界。

标题

  • 不发明标题:尽量取自资源本身,禁止编辑式命名;唯一例外是旧作品——把年份放在标题后的括号里,帮助读者判断内容时效。
  • 不用全大写(ALLCAPS):通常用标题大小写,拿不准时跟随资源本身的写法。
  • 禁用 emoji

URL

  • 不允许短链;URL 中的追踪参数必须清除
  • 国际化 URL 应做转义处理(浏览器地址栏通常渲染为 Unicode,请使用复制粘贴得到的形态)。
  • https 恒优先于已实现 HTTPS 站点的 http 版本。
  • 不接受"指向中间页而非资源本体"的链接。

创作者署名

  • 适当为免费资源创作者署名,翻译者同样应被署名
  • 翻译作品应署原作者,其它贡献角色建议采用 MARC relators 编码,如:
* [A Translated Book](http://example.com/book.html) - John Doe, `trl.:` Mike The Translator

其中 trl.: 即 MARC 中 "translator"(译者)的关系代码。

  • 作者列表用逗号 , 分隔各项;过长可用 et al. 缩写;不允许给创作者挂链接
  • 汇编或混编作品须说明创作性质,例如 GoalKicker / RIP Tutorial 这类书应标注为"Compiled from StackOverflow documentation"。
  • 创作者姓名中不包含 "Prof."、"Dr." 等敬称。

限时课程与试用

  • 不收录六个月后就得移除的内容。
  • 有限注册窗口或时长的课程不收录;只限时免费的资源也不收录

平台与访问备注

  • 课程类:平台是资源描述的重要组成(Coursera、edX、Udacity、Udemy 等课程平台普遍要求账号),依赖平台的课程须在括号中注明平台名。
  • YouTube:由播放列表构成的课程不把 YouTube 列为平台,而是列 YouTube 创作者;一般不链接单条 YouTube 视频,除非时长超一小时且结构类似课程/教程,此种情况需在 PR 描述中注明;禁止 youtu.be/xxxx 短链。
  • Leanpub:允许收录需免费访问但要求 Leanpub 账号的书籍,并加访问备注 *(Leanpub account or valid email requested)*

资源归类判定:边界在哪里

"哪些资源能进清单"还取决于对"书性(book-ness)"与流派的判断。

明确不收录的类型

博客、博文、文章、(除主宿主外的一般)网站、非课程/录屏的视频、书的章节、书的试读片段、IRC 或 Telegram 频道、Slack 或邮件列表。竞赛编程清单对这些排除项略宽松,且仓库收录范围由社区共同决定,想调整范围应通过 Issue 提议。

"像不像书"的特征集

仓库对"书性"并不苛刻,以下特征构成判断参考:有 ISBN;有目录;提供可下载版本(尤其 ePub);有版本迭代;不依赖交互内容或视频;力图全面覆盖主题;内容自包含。实际收录的很多书籍并不全备这些特征,仍需结合上下文判断。

书 vs. 课程

两者有时难以区分:课程常配有教科书(教科书进图书清单);课程包含讲义、练习、测验、笔记等教学辅助。单个讲座或视频不成其为课程;一份 PowerPoint 也不是课程。

交互式教程 vs. 其它形态

一句口诀:"如果能打印出来且不丢失其本质,它就不是交互式教程。"

CI 自动化:格式与链接如何被机器守护

贡献流程的最后一环是自动化。仓库在 .github/workflows/fpb-lint.yml 中通过 GitHub Actions 安装并运行 fpb-lint(对应文档所述 lint 工具,其全局包名为 free-programming-books-lint),在每次 Pull Request 上对 books casts courses more 全部目录执行检查,确保列表按字母排序且遵守格式规范,并将错误日志作为 artifact 输出供 PR 查看。

URL 有效性的验证则交由 .github/workflows/check-urls.yml 实现,它在 push 与 PR 事件上基于 tj-actions/changed-files 找出变更的 .md/.yml 文件,逐文件运行 awesome_bot(参数含 --allow-redirect --allow-dupe --allow-ssl)并汇总报告。按 CONTRIBUTING-np.md 中描述的传统触发方式,也可以推送一条包含如下提交消息的提交来显式触发校验:

check_urls=free-programming-books.md free-programming-books-en.md

一次可检查多个文件,用单个空格分隔各文件名;多个文件时构建结果以最后一个被检查文件的结论为准——因此即便看到绿色构建,也应在 PR 末尾点击 "Show all checks" → "Details" 检查完整构建日志。

对阿拉伯语(*-ar.md)、希伯来语(*-he.md)、波斯语(*-fa_IR.md)、乌尔都语(*-ur.md)等 RTL 语言文件,另有 .github/workflows/rtl-ltr-linter.yml 在带 RTL 标签或变更文件命中 RTL 语言时,调用仓库自带脚本 scripts/rtl_ltr_linter.py(依赖 python-bidiPyYAML)检查 RTL/LTR 混排。其修复规则在 docs/CONTRIBUTING.md 中有明确示范:RTL 文本内嵌的 LTR 词(如 HTML、JavaScript)后紧接追加 ‏,LTR 符号(如 C#C++)后追加 ‎,例如将 * كتاب الأمثلة في R 修正为 * كتاب الأمثلة في R‏

端到端:提交一份合规 PR 的检查清单

将全文规则串成一条可执行路径,贡献者提交前可逐项核对:

  1. 确认免费:二次核验资源免费且非限时免费,在 PR 描述中附一句理由。
  2. 确认形态:对照六类清单确定目录归属,并确认目标语言文件存在(例如中文图书进 books/free-programming-books-zh.md,课程进 courses/free-courses-zh.md)。
  3. 排除红线:非云盘托管、非短链、无追踪参数、非博客/文章/视频等不收录类型;URL 取最权威来源并优先 https
  4. 选准插入点:按字母序定位插入行,确保 aaab 前、one twoonetwo 前。
  5. 逐字符核对格式]( 无空格;- 环绕作者;作者在前、格式在后;标题无 ALLCAPS、无 emoji;必要时补年份与 in process/archived 标注。
  6. 提交并验证:尽量原子提交;推送后查看 PR 上 fpb-lint 与 URL 检查结果,位置错误时依据 linter 报错交换指定行;对 RTL 语言文件注意工作流是否被触发及 ‏/‎ 修复是否到位。

完成以上六步,一条新增的学习资源就符合了仓库面向人(审阅者)与机器(linter)的全部约定,能够以较低的返工成本通过评审合入这份全球多语言免费编程资源清单。

登录后查看全文
热门项目推荐
相关项目推荐