Git Hosting Platforms: GitHub, GitLab, Gitea, Forgejo, Codeberg 对比

先分清两层:Git 和平台 GitHub、Gitea、Forgejo、Codeberg 底层用的都是标准 Git。它们之间的区别不在版本控制,而在包在 Git 外面的那层平台: 版本控制层:Git 负责提交历史、分支、合并,服务器上存的是普通的 Git bare 仓库。本地的 git clone、git push、git pull 在哪个平台上都一样。 平台层:提供 Web 界面、用户和权限、Issue、Pull Request、Wiki、Release、CI 集成等。这些 Git 本身没有,是各平台自己实现的。 另外,这几个名字不是同一类东西: 名字 类型 说明 GitHub 托管服务(闭源) 微软旗下,2018 年被收购 GitLab 平台软件 + 托管服务 有开源社区版,可自建;也有 gitlab.com Gogs 平台软件(开源) Go 编写的轻量 Git 服务,Gitea 的前身 Gitea 平台软件(开源) 2016 年从 Gogs 分叉,可自建 Forgejo 平台软件(开源) 2022 年从 Gitea 分叉,可自建 Codeberg 托管服务(非营利) 运行 Forgejo 的公共实例,codeberg.org 分叉关系:Gogs → Gitea → Forgejo Gogs:早期的 Go 语言自建 Git 服务,单个二进制就能跑,资源占用小。但基本由一位维护者主导,合并社区贡献慢。 Gitea:2016 年社区从 Gogs 分叉出来,采用社区治理,功能迭代快,后来成了自建 Git 服务的主流选择之一。 Forgejo:2022 年 Gitea 的域名和商标被转到新成立的营利公司 Gitea Ltd,部分社区成员担心项目被商业公司控制,于是分叉出 Forgejo。Forgejo 由非营利组织 Codeberg e.V. 托管,一开始是 Gitea 的“软分叉”(持续同步上游),2024 年起变成硬分叉,不再跟随 Gitea 代码。 所以 Gitea 和 Forgejo 目前的界面和用法仍然很像,但功能细节已经开始分化。Forgejo 的一个重点方向是联邦化(ForgeFed 协议),目标是不同实例之间能互相关注、提 Issue、提 PR。 ...

Created 27276-09-27 · Updated 27276-09-27 · 2 min · 267 words · -

WeChat QR to PDF: 微信扫码查看与下载 PDF

设计目标:用户用微信扫事先印好的二维码,在手机里查看 PDF,并能下载。技术栈固定为自购域名、GitHub 私有仓库、Cloudflare Pages、离线生成二维码。不使用 Hugo,也不需要后端。 域名购买、DNS 切到 Cloudflare、Pages 绑自定义域名的操作步骤,与本站博客相同,见 Hugo + Cloudflare Pages 搭建个人博客。本文只写和「微信扫码 + PDF」有关的设计选择。 目标与非目标 目标 微信扫码打开 HTTPS 页面,能预览 PDF 页面上提供下载 PDF 源文件放在 GitHub 私有仓库里,不在 GitHub 网页上公开浏览 更新 PDF 时尽量不换二维码(同一 URL 覆盖文件即可) 非目标 不做登录、不做按人授权。知道链接的人都能打开 不接入微信公众号、JS-SDK、微信支付 不在微信里做「仅好友可见」之类的权限 单文件超过 Cloudflare Pages 限制(25 MiB)时,本方案不够,需改对象存储 整体结构 二维码里只放一个 URL,不放 PDF 本身。扫码等于用微信内置浏览器打开这个地址。 Printed QR --> https://files.example.com/catalog/ | +-- index.html landing page +-- catalog.pdf the file 组件 作用 自购域名 二维码里的长期地址,例如 files.example.com GitHub 私有仓库 存放 HTML 和 PDF,只有仓库成员能在 GitHub 上看到 Cloudflare Pages 从私有仓库拉取并托管静态文件,对外提供 HTTPS 二维码图片 事先生成、打印或贴到物料上,内容是落地页 URL 仓库私有只挡住 GitHub 上的浏览和 clone。部署到 Pages 之后,站点是公开的。这是预期行为:扫码的人没有 GitHub 账号,也必须能打开。 ...

Created 28286-08-28 · Updated 28286-08-28 · 2 min · 413 words · -

GitHub CODEOWNERS:自动分配 PR Reviewer

概述 CODEOWNERS 是 GitHub 的一个约定文件:声明仓库里哪些路径由哪些人/团队"负责"。当 PR 改动了某个路径下的文件,GitHub 会自动把对应的 owner 加进 PR 的 Reviewers 列表。配合分支保护规则里的 “Require review from Code Owners”,还可以强制要求这些 owner 必须 approve,PR 才能合并。 它解决的问题:团队变大之后,“这段代码改了应该找谁 review” 不再是靠口头约定或者人肉记忆,而是写进仓库、可版本管理、对所有协作者可见的规则。 文件位置 GitHub 按以下顺序查找,只会使用第一个找到的: 仓库根目录:CODEOWNERS .github/CODEOWNERS docs/CODEOWNERS 文件名区分大小写,没有扩展名,也不支持在多个位置同时生效。 基本语法 语法风格类似 .gitignore:一行一个路径 pattern,后面跟一个或多个 owner。 # 默认 owner,匹配仓库里所有文件 * @wiloon # 某个目录下的文件由指定团队负责 /infra/ @starlabrys/engineering # 具体文件可以指定多个 owner,任意一个 approve 都算数 /docs/architecture.md @wiloon @some-teammate # 用邮箱也可以(必须是该用户在 GitHub 账号上验证过的邮箱) *.sql db-owner@example.com Owner 可以是: @username:单个 GitHub 用户 @org/team-slug:某个组织下的团队 email@example.com:用户在 GitHub 上验证过的邮箱 匹配规则:后面的 pattern 优先级更高 和 .gitignore 不同,.gitignore 靠 ! 取消忽略;CODEOWNERS 没有取消符号,而是文件里越靠后的匹配行优先级越高——如果一个文件同时匹配多条 pattern,以最后一条为准。 ...

Created 17176-07-17 · Updated 17176-07-17 · 2 min · 285 words · -

GitHub Personal Access Token:Classic vs Fine-grained

GitHub 的 Personal Access Token(PAT)有两套互相独立、并列的机制:Classic 和 Fine-grained。两者各自有独立的设置页面和独立的 token 值,互不共享权限、互不影响——改了一个的 scope,对另一个没有任何作用。 对比 Classic token (ghp_...) Fine-grained token (github_pat_...) 权限粒度 粗粒度,按 scope 打勾(repo、admin:org、workflow …),一个 scope 覆盖你有权限的所有仓库/组织 细粒度,创建时指定 Resource owner(个人账号或某个具体组织),再选具体仓库(全部/指定几个),每个仓库单独授予 Contents / Administration / Issues 等权限 作用范围 只要本人对某组织/仓库有权限,token 默认就能操作(除非组织手动 Restrict) 天生绑死在创建时选的 Resource owner,只能代表操作那一个账号或组织下的资源 安全性 权限范围大,一旦泄露风险高 权限可以缩得很小,泄露影响面小,GitHub 官方推荐新场景一律用这个 过期时间 早期可选"永不过期" 设计上引导必须设置过期时间 组织侧控制 只有"全允许 / 全禁止"的粗暴开关(组织 Settings → Personal access tokens → Tokens (classic)) 组织可以看到每一个申请访问本组织资源的 fine-grained token,逐个 Approve / Deny / 撤销,可审计 Fine-grained 要解决的问题 Classic token 加 scope 解决不了几个结构性问题,这也是 GitHub 推出 fine-grained token 的原因: ...

Created 13136-07-13 · Updated 13136-07-13 · 1 min · 186 words · -

Hugo + Cloudflare Pages 搭建个人博客

本文记录这个博客的搭建方式,从买域名到发布一个静态站点。技术选型和步骤与本站的实现保持一致。 这套技术栈长什么样 一句话概览:用 Hugo 把 Markdown 编译成静态页面,源码在 GitHub,Cloudflare Pages 连接 GitHub 仓库并在 Cloudflare 侧构建、托管,域名解析和 CDN 也在 Cloudflare。 各部分的分工: 组件 作用 Hugo 静态站点生成器,把 content/ 下的 Markdown 编译成 HTML GitHub 存放源码,作为部署的触发源 Cloudflare Pages 连接 GitHub 仓库,执行 hugo --minify 构建并托管产物 Cloudflare DNS 域名解析,把自定义域名指向 Pages 项目 Cloudflare CDN 边缘缓存与加速,Pages 默认自带 整个流程没有用 GitHub Actions,也没有容器化构建,构建这一步完全由 Cloudflare Pages 在它自己的环境里完成。基础站点的构建命令就是一句 hugo --minify;本站为了顺带生成搜索索引,把它包成了一个很短的脚本(见下文进阶模块),思路一样。 基础模块 这一部分从 0 到「能访问」。 买域名 域名可以在任意注册商购买,我最早是在 GoDaddy 买的。以 GoDaddy 为例: 打开 godaddy.com,在搜索框里输入想要的域名,看是否可注册。 选一个后缀(.com、.dev 等),加入购物车,结账。注意第一年常有促销价,续费价通常更高,下单前看清续费价格。 结账时可关掉 GoDaddy 自家的一堆增值服务(邮箱、隐私保护等),后面把 DNS 切到 Cloudflare 后这些大多用不上。 Cloudflare 自己也能直接注册域名(Cloudflare Registrar,按批发价、免费 WHOIS 隐私保护),但支持的后缀有限。如果想要的后缀在它的列表里,直接在 Cloudflare 买、省去后面改 Nameserver 的步骤也可以;后缀不在列表里就按上面的思路在别的注册商买,再把 DNS 切过来。 ...

Created 9096-07-09 · Updated 9096-07-09 · 3 min · 452 words · -

Giscus:基于 GitHub Discussions 的评论系统

Giscus 是一个基于 GitHub Discussions 的评论系统,评论数据完全存储在 GitHub,无需额外的数据库或第三方平台。适合托管在 GitHub Pages、Cloudflare Pages 等静态站点。 工作原理 Giscus 把每篇页面的评论映射到 GitHub Discussions 中的一个 Discussion,通过在页面嵌入 <script> 标签加载评论组件。 页面与 Discussion 的映射方式: 映射方式 说明 pathname(推荐) 按页面 URL 路径匹配,最通用 title 按文章标题匹配 og:title 按 Open Graph 标题匹配 前置条件 GitHub 仓库需开启 Discussions 功能:仓库 Settings → Features → Discussions ✓ 安装 Giscus GitHub App:github.com/apps/giscus → Install → 选择目标仓库 获取配置参数 访问 giscus.app,填写仓库名和配置选项,页面底部会生成完整的 <script> 标签,从中获取: data-repo-id(格式 R_kgDO...):仓库 Node ID data-category-id(格式 DIC_kwDO...):Discussion 分类 ID Discussion 分类推荐选 Announcements:只有维护者能在 GitHub 网页直接新建 Discussion,普通用户只能通过 Giscus 组件留言,防止垃圾内容。 ...

Created 16166-06-16 · Updated 16166-06-16 · 1 min · 181 words · -

Fork 项目同步与提交 PR 的完整流程

概述 在参与开源项目开发时,通常的工作流程是:Fork 主仓库 → 在自己的仓库开发 → 保持与主仓库同步 → 提交 Pull Request。本文记录这个完整的操作流程。 前置准备 添加上游仓库 首次 fork 项目后,需要添加原始仓库(上游仓库)作为远程仓库: # 添加上游仓库 git remote add upstream <原始仓库的 git 地址>igin https://github.com/your-username/project.git (fetch) origin https://github.com/your-username/project.git (push) upstream https://github.com/original-owner/project.git (fetch) upstream https://github.com/original-owner/project.git (push) origin: 你的 fork 仓库 upstream: 原始仓库(上游) 保持本地主分支同步 在开发新功能前,或定期需要将上游仓库的最新变更同步到本地: 1. 获取上游仓库的最新变更 git fetch upstream 这会下载上游仓库的所有分支和提交,但不会合并到本地。 2. 切换到本地主分支 git checkout main # 或者 git switch main 3. 检查当前状态 git status 确保工作区是干净的,没有未提交的更改。 4. 合并上游主分支 git merge upstream/main 为什么 main 分支用 merge 而不是 rebase? ...

Created 2026-02-02 · Updated 2026-02-02 · 3 min · 457 words · -

给开源项目提交 Pull Request 完整指南

概述 给开源项目贡献代码是参与开源社区的重要方式。本文记录了从 Fork 仓库到提交 Pull Request (PR) 的完整流程。 前置准备 Fork 仓库 在 GitHub 上打开你想贡献的开源项目 点击右上角的 Fork 按钮 将仓库 Fork 到你自己的账号下 克隆你的 Fork git clone https://github.com/你的账号/仓库名.git cd 仓库名 配置上游仓库 添加上游仓库(只需做一次) git remote add upstream https://github.com/官方账号/官方仓库.git 验证 remote 配置 git remote -v 输出应该类似: origin https://github.com/你的账号/仓库名.git (fetch) origin https://github.com/你的账号/仓库名.git (push) upstream https://github.com/官方账号/官方仓库.git (fetch) upstream https://github.com/官方账号/官方仓库.git (push) 同步上游代码 在开始新功能开发前,确保你的本地代码与上游保持同步: # 拉取上游最新代码 git fetch upstream # 切换到 main 分支 git checkout main # 合并上游的 main git merge upstream/main # 推送到你的 fork git push origin main 创建功能分支 不要直接在 main 分支上开发,应该创建新的功能分支: ...

Created 1016-02-01 · Updated 1016-02-01 · 2 min · 370 words · -