首页
/ 为 free-programming-books 贡献免费编程资源:收录标准、Markdown 条目规范与 CI 自动校验完全指南

为 free-programming-books 贡献免费编程资源:收录标准、Markdown 条目规范与 CI 自动校验完全指南

2026-09-07 09:34:41作者:舒璇辛Bertina

导读

free-programming-books 是一个以纯 Markdown 数据文件维护“可免费获取的编程学习资源”清单的大型开源项目,其核心不是代码,而是一套高度纪律化的内容贡献规范。本文以仓库内的权威指南 docs/CONTRIBUTING.md 为主线,完整解析其收录标准、六类资源清单的划分、Markdown 条目格式、元数据约定、RTL/LTR 双向文本处理,以及由 GitHub Actions 驱动的自动化质量门禁(格式 lint 与 URL 校验)。读完本文,你将能够按照与仓库维护者完全一致的标准提交链接、编写符合规范的清单条目,并读懂并修复 CI 报出的各类 lint 错误,从而写出一次通过校验的 Pull Request。

全文事实均取自本仓库内的指南文档、工作流定义与 linter 脚本源码,文中给出的仓库相对路径可点击继续阅读原始证据。

贡献前须知:协议、行为准则与两条参与路径

Contributor License Agreement 与行为准则

任何贡献者都需要先接受仓库的两项基础约定(见 docs/CONTRIBUTING.md):

  1. 贡献者许可协议(CLA):贡献内容等同于同意仓库根目录的 LICENSE(CC BY 许可);
  2. 贡献者行为准则(Code of Conduct):贡献行为需遵守 docs/CODE_OF_CONDUCT.md,该准则有大量语言译本,完整索引见 docs/README.md#translations

不懂 Git 也没关系:两条路径任选

核心原则是“先查重,再提交”:如果你找到的是仓库中尚未收录的免费资源:

  • 不会用 Git:直接在仓库的 Issues 中提出新链接的建议即可;
  • 熟悉 Git:Fork 仓库并提交 Pull Request(PR)。

无论走哪条路,最终内容都会进入同一套人工评审与自动化校验流程(见下文“自动化质量门禁”),这也是仓库将 Issue 设为新手友好入口的原因。

六类资源清单:先选对清单再动手

贡献的第一步是判断资源到底属于哪一种清单。仓库把学习资源分为 6 类(见 docs/CONTRIBUTING.md),分类错误是 PR 最常见的返工原因:

类型 判定要点 仓库对应数据文件
Books(书籍) PDF、HTML、ePub、基于 gitbook.io 的站点、Git 仓库等 books/free-programming-books-langs.mdbooks/free-programming-books-subjects.md 及各语言文件 books/free-programming-books-*.md
Courses(课程) 非书籍形态的学习材料,如 MIT OCW 的“算法导论”课程 courses/free-courses-en.md 及各语言 courses/free-courses-*.md
Interactive Tutorials(交互式教程) 让用户输入代码/命令并实时求值的交互网站(“求值”≠“打分”),如 Try Haskell、Try Git 一类 more/free-programming-interactive-tutorials-en.md
Playgrounds(编程游乐场) 在线交互网站、游戏或桌面软件:可写代码、编译/运行并分享代码片段,常支持 fork 动手试玩 more/free-programming-playgrounds.md
Podcasts and Screencasts(播客与录屏) 播客与屏幕录制教学 casts/free-podcasts-screencasts-en.md 及各语言 casts/free-podcasts-screencasts-*.md
Problem Sets & Competitive Programming(题目集与竞赛编程) 通过解决难易不等的问题来评测编程技能的网站/软件,可选代码评审与横向比较 more/problem-sets-competitive-programming.md

仓库佐证:CI 中的 fpb-lint 工作流 正是对这四大目录执行扫描:fpb-lint books casts courses more;RTL/LTR 双向文本 linter 同样扫描 books casts courses more 四个目录(见 rtl-ltr-linter 工作流)。这说明六类清单在物理上分属 books/courses/casts/more/ 四个顶层目录。

额外分类提示

  • 中文与英文:英文书籍被拆分为“按编程语言(By Programming Language)”与“按主题(By Subject)”两个主文件;通用主题书籍归入主题清单的 Programming 小节,其余按各自子类展开(见 books/free-programming-books-langs.md 开篇说明)。
  • 每个清单文件都以**字母序的 Index(目录)**开头,列出全部 ### 小节与 #### 子节的锚点链接。

链接收录指南:什么样的链接可以进清单

这一节是文档中约束最密集的部分,覆盖“是否免费”与“链接质量”两类判断(见 docs/CONTRIBUTING.md):

免费的边界

  • “能轻易下载到书”不等于“免费书”,只收录免费内容,请务必反复确认
  • 不收录要求提供可用邮箱才能取书的页面;但允许收录“请求邮箱(非强制)”的条目,并要在括号中加语言合适的注释,例如 (email address *requested*, not required)
  • 不接受托管在 Google Drive、Dropbox、Mega、Scribd、Issuu 及其他类似文件上传平台的链接
  • 若是旧书,建议在标题中附带出版年份;作者处也应署名(详见“元数据约定”一节)。

链接来源与 URL 形态

规则 说明 示例
权威来源优先 作者官网 > 出版社官网 > 第三方网站 优先链接到作者本人站点
禁止文件托管平台 不限于 Dropbox、Google Drive ——
https 优先 同域名、同内容时,https 优于 http ——
根域名去掉尾斜杠 http://example.com 优于 http://example.com/ ——
取最短链接 http://example.com/dir/ 优于 http://example.com/dir/index.html ——
禁用短链服务 不接受任何 URL shortener ——
“当前版”优先于“版本号” .../book/current/ 优于 .../book/v1.0.0/index.html ——
移除跟踪码 链接中的 tracking codes 必须清除 ——
国际化 URL 转义 需对非 ASCII URL 做转义处理 ——
链接须直指资源本身 不接受指向“别的页面”而非所列资源的 URL ——

证书/SSL 问题的三级处理

如果链接存在过期证书、自签名证书或任何 SSL 问题,按以下顺序处置:

  1. 若能找到对应的 http 版本则替换之(移动端处理证书例外往往很麻烦);
  2. 若没有 http 版本、但通过浏览器添加例外仍可访问,则保留该 https 链接;
  3. 否则删除该链接

多格式、多版本与多出处

  • 同一资源存在多种格式时,优先找一个入口即含多格式的单一链接;确无单一入口时,可为一个资源添加带格式注释的多个链接。每个链接都会带来维护负担,因此应尽量避免冗余;
  • 同一资源在不同位置存在时,取权威来源;若属不同版本且差异足够大,则分别作为独立条目并注明各自版本;
  • 条目若有“in process”“archived”“免费许可”等情况,使用下文规定的专有记号。

Git 提交习惯

  • 偏好原子提交(一次提交对应一个条目的新增/删除/修改),但 PR 前不必强制 squash
  • 维护者不会强制此规则,它只是为了便于审阅。

Markdown 条目格式规范:可被 CI 机器校验的排版

所有清单都是 .md 文件,格式会被 CI 用程序强校验,因此格式即规范。以下规则全部来自 docs/CONTRIBUTING.md,逐条落实才能通过自动化检查。

结构性规则

  • 每个清单文件顶部必须有 Index 目录,按字母序列出所有 ### 小节(含 #### 子节);
  • 小节用 ###(三级标题),子节用 ####(四级标题)
  • 空行规则(“空行数”指 Markdown 源文件中的空行):
    • 2 个空行:最后一个链接 与 下一个新小节之间;
    • 1 个空行:标题 与 本小节第一个链接之间;
    • 0 个空行:两个链接之间;
    • 1 个空行:每个 .md 文件结尾必须留一个空行。

标准布局示例:

[...]
* [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)

行内语法规则

  • ]( 之间不得有空格
BAD : * [Another Awesome Book] (http://example.com/book.html)
GOOD: * [Another Awesome Book](http://example.com/book.html)
  • 作者与链接之间用“空格-连字符-空格”(-)分隔:
BAD : * [Another Awesome Book](http://example.com/book.html)- John Doe
GOOD: * [Another Awesome Book](http://example.com/book.html) - John Doe
  • 格式说明与链接之间留一个空格,且作者在前、格式在后
BAD : * [A Very Awesome Book](https://example.org/book.pdf)(PDF)
GOOD: * [A Very Awesome Book](https://example.org/book.pdf) (PDF)
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)
  • 多格式:优先单链接;确需分开时,把次要格式以带说明的链接形式并到同一条目:
BAD : * [Another Awesome Book](http://example.com/)- John Doe (HTML)
BAD : * [Another Awesome Book](https://downloads.example.org/book.html)- John Doe (download site)
GOOD: * [Another Awesome Book](http://example.com/) - John Doe (HTML) [(PDF, EPUB)](https://downloads.example.org/book.html)
  • 旧书的出版年份放进标题括号内,而不是行尾:
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
  • 未完稿书籍in process 记号:
GOOD: * [Will Be An Awesome Book Soon](http://example.com/book2.html) - John Doe (HTML) *( :construction: in process)*
  • 通过 Wayback Machine 等归档服务恢复的资源archived 记号(应选用最近且完整的快照版本):
GOOD: * [A Way-backed Interesting Book](https://web.archive.org/web/<snapshot-id>/http://example.com/) - John Doe (HTML) *( :card_file_box: archived)*

免费许可标记(License Notes)

仓库鼓励收录采用免费开放许可(如 Creative Commons)的资源;标注格式统一为“格式之后、其他备注之前”的括号注释:

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

支持的许可短码(不携带版本号)

短码 全称
CC BY Creative Commons attribution
CC BY-NC Creative Commons non-commercial
CC BY-SA Creative Commons share-alike
CC BY-NC-SA Creative Commons non-commercial, share-alike
CC BY-ND Creative Commons no-derivatives
CC BY-NC-ND Creative Commons non-commercial, no-derivatives
GFDL Gnu Free Documentation License

添加许可注释的五步操作(来自 docs/CONTRIBUTING.md):

  1. 在资源页面确认许可——查看页脚、About 页或 LICENSE/Legal 区块;只标注“免费/开放内容许可”,不要写 “All Rights Reserved”;
  2. 将许可字符串归一化为上表短码且去掉版本号:例如 “Creative Commons Attribution 4.0” → CC BY;“CC BY-SA 3.0” → CC BY-SA;“GNU Free Documentation License” → GFDL
  3. 将许可放在格式之后、其他备注之前
    • 单一格式:* [A Very Awesome Book](https://example.org/book.pdf) - Jane Roe (PDF) (CC BY-SA)
    • 多格式:* [Awesome Guide](https://example.org/) - Jane Roe (HTML, PDF) (CC BY)
    • 带附加备注(如 archived / in process):* Old but Gold - John Doe (HTML) (CC BY) *( :card_file_box: archived)*
  4. 若不同版本/格式的许可不同,请拆成独立条目并各自标注正确许可;
  5. 不确定时,在 PR 中留言说明你认为该资源采用自由许可的依据与出处。

字母序规则:清单的排序基准

各小节内链接必须按字母序排列(见 docs/CONTRIBUTING.md):

  • 首字母相同则继续比较第二、第三个字符,依次类推:aa 排在 ab 之前;
  • 空格参与比较:one two 排在 onetwo 之前(空格比字符小);
  • 若发现错位链接,直接查看 lint 报错信息,它会告诉你哪两行需要互换。

元数据与细节约定

清单只维护最小元数据集合:标题、URL、创作者、平台与访问说明(见 docs/CONTRIBUTING.md)。每一项都有细化约定:

Titles(标题)

  • 不发明标题:标题取自资源自身,贡献者不得为编辑目的自拟标题;历史价值明显的旧作可在标题后加括号年份;
  • 禁止全大写:默认用 title case,不确定时沿用资源原始大小写;
  • 禁止 emoji

URLs

  • 禁止短链;必须移除跟踪码;国际化 URL 需转义;
  • 实现 https 的站点一律用 https
  • URL 必须直指资源本体,不欢迎“跳到别处”的页面。

Creators(创作者署名)

  • 适当署上创作者姓名,译者也要署名
  • 译作应同时署名原作者,推荐用 MARC relators 术语标注非作者角色的贡献,如译者为 trl.:
* [A Translated Book](http://example.com/book.html) - John Doe, `trl.:` Mike The Translator
  • 作者列表用逗号分隔;过长名单可用 “et al.” 缩写;
  • 创作者不允许外链;编者型作品需加说明,如 GoalKicker/RIP Tutorial 类应写作 “Compiled from StackOverflow documentation”;
  • 姓名不带 “Prof.”、“Dr.” 等敬称。

有时限的课程与试用(Time-limited Courses and Trials)

  • 不收录“六个月内就需要删除”的内容;
  • 有报名时段限制或明确持续期的课程不收录;
  • “限时免费”资源不收录

平台与访问说明(Platforms and Access Notes)

  • 课程清单中平台是资源描述的重要部分:不同平台有不同的访问模型与设施。虽然通常不收录需要注册的书籍,但许多课程平台(如 Coursera、EdX、Udacity、Udemy)没有账号就无法使用其核心设施,因此课程依赖平台时,应在括号内列出平台名;
  • YouTube:不把 YouTube 本身列为平台,而是尽量列创作者(它往往是子平台);一般不链接单个 YouTube 视频,除非时长超过一小时且结构上像课程/教程——此时务必在 PR 描述中说明;
  • 禁止 youtu.be/xxxx 类短链;
  • Leanpub:访问模型混杂(有的免注册可读、有的需 Leanpub 账号免费阅读)。鉴于其书目质量与访问模型流动性,允许收录后者,但需加访问说明 *(Leanpub account or valid email requested)*

边界判定:什么该收、什么不该收

“资源该进哪张清单”的第一条判断法则是看资源如何自我描述——它自称 book,那多半就该进书籍清单。以下是仓库明确不收录的类型(见 docs/CONTRIBUTING.md):

  • 博客、博客文章、文章;
  • 普通网站(托管“海量被收录条目”的站点除外);
  • 非课程/录屏形式的视频、书籍章节、书的试读样章;
  • IRC/Telegram 频道、Slack 群组与邮件列表。

竞赛编程类清单对上述排除项的执行尺度相对宽松;范围调整属于社区议题,建议通过 Issue 提出。仓库的收录边界最终由社区共同决定(见 docs/CONTRIBUTING.md)。

Books vs. Courses vs. Interactive Tutorials

  • 书感信号:有 ISBN、有目录、提供可下载版本(尤其 ePub)、有版本迭代、不依赖交互或视频、尽量全面自洽地覆盖主题。具备越多越像书,但也有大量收录条目并不齐备,须结合语境判断;
  • 课程:通常附带教材(教材本身归书籍清单);课程应有讲座、练习、测验、笔记或教辅,单条讲座视频或单份 PowerPoint 不是课程;
  • 交互式教程的硬判据非常直白:“如果打印出来仍不失其精髓,那它就不是交互式教程”

自动化质量门禁:贡献如何被机器校验

贡献指南明确告知:GitHub Actions 会在每次 PR 运行测试,确保清单按字母序排列并遵守格式规范(见 docs/CONTRIBUTING.md)。仓库内部实际部署了三道闸门:

1. 格式与排序 lint:fpb-lint

仓库通过 GitHub Actions 运行 free-programming-books-lint(fpb-lint)检查所有数据文件的排序与排版。fpb-lint 工作流 中的真实执行命令为:

- run: npm install -g free-programming-books-lint
- name: Run linter
  run: |
    fpb-lint books casts courses more &> output.log

它把完整报错写入 output.log 并作为 PR artifact 上传,维护者与贡献者都可直接下载查看;前文“错位链接看 lint 报错”正是依赖这一闸门。

2. URL 有效性校验:check_urls

URL 校验由 awesome_bot 驱动。触发方式是:推送一条提交信息中包含 check_urls=待检文件 的 commit,例如:

check_urls=free-programming-books.md free-programming-books-en.md
  • 可以同时指定多个文件,用单个空格分隔
  • 注意陷阱:校验多个文件时,构建结果以最后被检查的文件为准,因此可能看到“绿灯通过”的假象——提交者务必在 PR 底部的 “Show all checks” → “Details” 中查看构建日志末尾,确认每个文件都真实通过。

3. RTL/LTR 双向文本 lint(仅 RTL 语言文件)

仓库内置了独立的 Python 双向文本检查器 scripts/rtl_ltr_linter.py,其配置项集中在 scripts/rtl_ltr_linter_config.yml。对应工作流 .github/workflows/rtl-ltr-linter.yml 中安装依赖并执行的命令为:

pip install python-bidi PyYAML
python3 scripts/rtl_ltr_linter.py books casts courses more ${CHANGED_FILES_ARGS} --log-file rtl-linter-output.log

从源码结构看(scripts/rtl_ltr_linter.py),脚本先加载 YAML 配置中的默认值再与文件合并,支持按严重级别(error/warning/notice)分类输出,并会跳过代码块、行内代码与括号内容。判定是否属于 RTL 文件靠的是文件后缀规则(-ar/-he/-fa/-ur,见 scripts/rtl_ltr_linter.py),这也与指南所述“对 *-ar.md*-he.md*-fa.md*-ur.md 文件运行”一致。工作流仅在 PR 带 RTL 标签或改动文件命中上述语言时触发(见 .github/workflows/rtl-ltr-linter.yml)。

修复 RTL/LTR 排版错误:两个记号 ‏ 与 ‎

当清单混合了从右向左(RTL,如阿拉伯语、希伯来语、波斯语、乌尔都语)与从左向右(LTR,如英语、代码、技术名词)文本时,双向算法(Bidi)可能让浏览器渲染出与逻辑顺序不符的混乱排版。此时应使用 HTML 实体标记修正(见 docs/CONTRIBUTING.md):

  • RTL 语境中的 LTR 单词(如 “HTML”、“JavaScript”):在每个 LTR 片段后紧跟 &rlm;
  • RTL 语境中的 LTR 符号(如 “C#”、“C++”):在每个 LTR 符号后紧跟 &lrm;

例 1:LTR 单词收尾的条目

BAD:
<div dir="rtl" markdown="1">
* كتاب الأمثلة في R - John Doe (PDF)
</div>

GOOD:
<div dir="rtl" markdown="1">
* كتاب الأمثلة في R&rlm; - John Doe&rlm; (PDF)
</div>

例 2:混合 RTL 作者列表中的 LTR 片段

BAD:
<div dir="rtl" markdown="1">
* Tech Podcast - بودكاست المثال – Ahmad Hasan, محمد علي
</div>

GOOD:
<div dir="rtl" markdown="1">
* Tech Podcast - بودكاست المثال – Ahmad Hasan,&rlm; محمد علي
</div>

例 3:LTR 符号(如 C#)需 ‎

BAD:
<div dir="rtl" markdown="1">
* أساسيات C#
</div>

GOOD:
<div dir="rtl" markdown="1">
* أساسيات C#&lrm;
</div>

附带说明:这一规则同样可从配置得到印证——scripts/rtl_ltr_linter_config.yml 定义了约百个需要 &rlm; 的常见 LTR 关键词(HTMLJavaScriptPythonDockerGraphQL 等)与需要 &lrm; 的 LTR 符号模式(C#C++.NETNode.jsCI/CD 等),并同时识别 &rlm;/&lrm; 及其 &#x200F;/&#x200E; 等 Unicode 数字实体写法。

给新贡献者的自检清单

综合 docs/CONTRIBUTING.md 全文,可在提交 PR 前逐项自查:

  1. 资源确实免费?未使用需要邮箱才能取书的页面;没有 Google Drive/Dropbox/Mega/Scribd/Issuu 类托管链接;
  2. 属于六类清单中的哪一类?文件放对目录了吗?
  3. 链接是否权威、最短、https、无尾斜杠、无短链、无跟踪码;
  4. 条目是否位于本小节正确字母序位置;Index 与锚点是否同步更新;
  5. 排版是否满足 2/1/0/1 空行规则、]( 无空格、- 分隔作者、作者在格式前、旧书年份放标题内;
  6. 需要 in processarchived(CC ...) 或邮箱提示等记号时是否按规定书写;
  7. RTL 语言文件是否已按本小节规则补齐 &rlm;/&lrm;
  8. 最后确认 GitHub Actions 的 lint/URL 检查在 PR 上全部通过(多文件 URL 校验时注意查看构建日志末尾而非只看绿灯)。

如果你想把这个项目克隆到本地按上述流程贡献,可使用仓库地址执行:

git clone https://gitcode.com/GitHub_Trending/fr/free-programming-books

延伸阅读:仓库内的相关证据文件

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