写在前面
说来惭愧,我用 GitHub 已经很多年了,但真要问我"GitHub 到底是什么",我第一反应还是:"就……放代码的地方?"
这个回答大概相当于说"支付系统就是转钱的地方"——不能说错,但基本等于没说。
最近 AI 编程工具一波接一波,Copilot、各种 Coding Agent 都在往 GitHub 上"住",我突然意识到:这个我天天打开、却从没认真了解过的网站,可能正在变成整个软件世界的基础设施。于是决定系统地折腾一遍,顺便写下来。
按照惯例,本文的阅读体验大致如下:
系好安全带,我们出发。
第一章:入门——先把 Git 和 GitHub 分清楚
Git 是工具,GitHub 是平台
很多新手(包括当年的我)会把 Git 和 GitHub 混为一谈。其实它们的关系很简单:
- Git:一个分布式版本控制工具,装在你电脑上,负责记录代码的每一次变化。
- GitHub:一个基于 Git 的云端协作平台,把你的 Git 仓库放到网上,再加上协作、社区、自动化、AI 等一大堆能力。
打个比方:Git 是记账本,GitHub 是银行。你可以自己在家记账,但想跟别人对账、转账、做联名账户,就得有个大家都信任的机构。
一段八卦:Git 是怎么来的
2005 年之前,Linux 内核一直用一个叫 BitKeeper 的商业版本控制工具,对开源社区免费。后来双方闹翻,BitKeeper 收回了免费授权。
Linus Torvalds 的反应很符合他的人设:既然没有好用的,那我自己写一个。
据说他只用了大约十天就写出了 Git 的第一个可用版本,并很快用它来管理 Linux 内核本身。至于为什么叫 "Git"——这个词在英式俚语里有点"讨厌鬼"的意思,Linus 自嘲说他总是以自己的名字给项目命名,Linux 是这样,Git 也是这样。
三年后的 2008 年,几个年轻人觉得 Git 好用但门槛太高,于是做了 GitHub,口号是"Social Coding"。再后来的故事大家都知道了:2018 年微软以 75 亿美元收购 GitHub,当时社区一片哀嚎,一大批人宣布"迁移到 GitLab"。
然后……大部分人又默默回来了。这大概就是"从放弃到真香"。
Git 的四个区域
理解 Git,最重要的是搞清楚代码在哪几个地方"流转":
Working Directory
你正在改的文件] -->|git add| B[暂存区
Staging Area
准备提交的改动] B -->|git commit| C[本地仓库
Local Repository
你电脑上的历史] C -->|git push| D[远程仓库
Remote Repository
GitHub 上的历史] D -->|git pull / fetch| C C -->|git checkout / restore| A
为什么要有"暂存区"这个中间层?因为你可能改了十个文件,但只想把其中三个作为一次提交。暂存区就像购物车,先挑好,再结账。
分支:平行宇宙
分支(Branch)是 Git 最强大的概念。你可以从主线拉出一个"平行宇宙",在里面随便折腾,折腾好了再合并回来;折腾坏了,直接删掉,主线毫发无损。
小知识:GitHub 新建仓库的默认分支名,在 2020 年从 master 改成了 main。所以如果你看到老教程里写 git push origin master 结果报错,不是你的问题,是时代变了。
第二章:上手——第一次 push 的血泪史
最常用的命令
先上一张速查表,覆盖日常 90% 的场景:
| 场景 | 命令 |
|---|---|
| 克隆一个仓库 | git clone <url> |
| 查看当前状态 | git status |
| 添加改动到暂存区 | git add <file> 或 git add . |
| 提交 | git commit -m "说人话的提交信息" |
| 推送到远程 | git push |
| 拉取远程更新 | git pull |
| 新建并切换分支 | git switch -c feature/xxx |
| 查看提交历史 | git log --oneline --graph |
| 撤销工作区改动 | git restore <file> |
| 临时藏起改动 | git stash / git stash pop |
新手三大坑
坑一:密码不好使了。 2021 年 8 月起,GitHub 不再支持用账号密码进行 Git 操作。你需要配置 SSH Key,或者使用 Personal Access Token。很多人第一次 push 就卡在这里,对着"Authentication failed"怀疑人生。
# 生成 SSH Key
ssh-keygen -t ed25519 -C "your_email@example.com"
# 把公钥内容复制到 GitHub → Settings → SSH and GPG keys
cat ~/.ssh/id_ed25519.pub
# 测试连接
ssh -T git@github.com坑二:提交信息写成"update"。 打开某些仓库的历史,你会看到一整屏的 update、fix、改了点东西、再改一次、这次真的好了。三个月后的你,会想穿越回去打死现在的你。
推荐使用 Conventional Commits 规范:
feat: 新增用户登录功能
fix: 修复金额精度丢失问题
docs: 更新 README 安装说明
refactor: 重构订单状态机坑三:把不该传的东西传了上去。 node_modules、target/、.idea/、.env……请在第一次提交前就写好 .gitignore。GitHub 新建仓库时可以直接选模板,别偷懒。
第三章:协作——Fork 与 Pull Request
如果说 Git 是 GitHub 的引擎,那 Pull Request(PR) 就是 GitHub 的灵魂。
想给一个开源项目贡献代码?你没有它的写权限,怎么办?流程是这样的:
几个过来人的建议:
- 先开 Issue 再写代码。 吭哧吭哧写了三天,提 PR 后维护者回一句"我们不打算加这个功能",那种感觉谁经历谁知道。
- 一个 PR 只做一件事。 一个改了 87 个文件、同时修 Bug 加功能顺手格式化代码的 PR,基本等于一份辞职信。
- 读 CONTRIBUTING.md。 大部分成熟项目都写了贡献指南,规定了代码风格、提交规范、CLA 签署等要求。
第四章:进阶——GitHub 不只是放代码的地方
GitHub Actions:免费的 CI/CD
在仓库里创建 .github/workflows/ci.yml,每次 push 就能自动跑测试:
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Test
run: go test ./... -race -coverActions 的玩法远不止 CI:定时爬数据、自动发版、自动给 Issue 打标签、自动同步博客……只要能写成脚本的事,基本都能塞进去。我见过有人用它每天自动签到、自动更新个人主页的"最近在读"。生命在于折腾,Actions 就是折腾的温床。
其他值得一用的能力
GitHub Pages:免费托管静态网站,很多技术博客、项目文档都放在上面。
Dependabot:自动扫描依赖漏洞,并直接帮你提一个升级 PR。对于依赖动辄几百个的 Java 和 Node 项目,这是救命功能。
Secret Scanning:检测你是否把 AWS Key、数据库密码之类的东西提交了上去。注意,它是"事后提醒",不是"事前拦截"的万能保险。
Codespaces:浏览器里打开一个完整的云端开发环境,适合临时改点东西,或者在 iPad 上假装自己在工作。
Releases 与 Packages:发布版本、托管 Docker 镜像和 Maven/npm 包。
第五章:GitHub vs GitLab——一个"叛徒"的自白
写到这里必须坦白一件事:在很长一段时间里,我其实是 GitLab 的忠实用户,而且是本地部署的那种。内网一台服务器,装上 Omnibus 包,配好域名和 Runner,所有代码、CI、镜像都在自己手里,那种掌控感非常踏实。
后来,我还是"叛逃"到了 GitHub。这一章就聊聊两者的区别,以及我为什么最终换了阵营。
GitLab 是谁
GitLab 诞生于 2011 年,比 GitHub 晚三年,走的是 Open Core(开放核心) 路线:核心功能以开源的社区版(CE)提供,高级功能放在付费的企业版(EE)里。
它最大的两个卖点:
- 可以完整地自建部署:免费的社区版就能装在自己的服务器上,代码不出内网。
- 一体化 DevOps 平台:代码托管、CI/CD、镜像仓库、项目管理、安全扫描,全部开箱即用,不需要拼凑第三方服务。
概念对照表
从 GitLab 迁移到 GitHub,第一件事是重新适应一套"方言":
| 维度 | GitHub | GitLab |
|---|---|---|
| 合并请求 | Pull Request(PR) | Merge Request(MR) |
| 组织结构 | Organization + Team,组织本身不能嵌套 | Group 可以多层嵌套 Subgroup |
| CI/CD 配置 | .github/workflows/*.yml,可以有多个 | .gitlab-ci.yml,一个入口文件 |
| 执行器 | GitHub 托管 Runner 或自托管 Runner | GitLab Runner |
| 自建方案 | GitHub Enterprise Server(付费) | 社区版免费自建,企业版付费 |
| 平台本身是否开源 | 否 | 核心开源 |
| 插件生态 | Actions Marketplace,数量庞大 | 模板和组件,相对较少 |
| 开源社区 | 全球最大 | 规模小得多 |
| AI 能力 | Copilot 及编码 Agent | GitLab Duo |
同一条流水线,两种写法
同样是"推送后跑 Go 测试",两边的写法是这样的:
GitLab CI(.gitlab-ci.yml):
stages:
- test
test:
stage: test
image: golang:1.22
script:
- go test ./... -race -coverGitHub Actions(.github/workflows/ci.yml):
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- run: go test ./... -race -coverGitLab 的写法更"脚本化",直接指定镜像、写命令;GitHub 的写法更"积木化",大量步骤是 uses: 引用别人写好的 Action。前者直观,后者复用性强。说实话,单论 CI 的设计,我至今仍觉得 GitLab CI 的 stages 模型更清晰。
当年我为什么选 GitLab
公平地说,当年选 GitLab 一点都不冤:
- 代码不出内网:对安全和合规有要求的场景,自建是刚需,而 GitLab 社区版免费就能做到。
- CI 一体化:在 GitHub Actions 出现之前(Actions 是 2019 年才正式推出的),GitHub 要做 CI 得接 Travis、Jenkins 之类的第三方服务,而 GitLab 早就内置了。
- 多层 Group 管理项目方便:项目一多,按"部门/业务线/服务"多层组织,结构非常清楚。
为什么最终选择了 GitHub
第一,我不想再当 GitLab 管理员了。
本地部署的代价,是你得同时扮演开发者和运维。GitLab 升级不能随便跳版本,需要按官方的升级路径一站一站地升;每次大版本升级都伴随数据库迁移,升级前得先备份、心里还得默默祈祷。再加上 CI 产物和镜像仓库慢慢吃满磁盘、Runner 时不时罢工、证书到期忘了续……到后来我发现,自己伺候 GitLab 的时间,快赶上写代码的时间了。
迁到 GitHub 之后,这些事情全部消失了。省下的不是服务器钱,是心力。
第二,内网是孤岛,GitHub 是广场。
本地 GitLab 上的代码,只有自己和少数几个人能看到。而我日常依赖的开源库、想提 Issue 的项目、想学习的代码,全都在 GitHub 上。在两个平台之间来回切换,就像工作在一座城、生活在另一座城,每天通勤。
第三,Actions Marketplace 的复用红利。
在 GitLab 上,很多流水线步骤我都是自己写 shell 脚本。到了 GitHub,大部分常见需求——缓存依赖、构建 Docker 镜像、发布 Release、部署到云——都有现成的 Action,uses: 一行搞定。自己造轮子的乐趣是有的,但不是每个轮子都值得造。
第四,AI 时代投下了决定性的一票。
这是最关键的原因。Copilot 原生集成在 GitHub 里;主流的 AI 编码工具和 Agent,几乎都优先对接 GitHub 的 Issue、PR 和 Actions;MCP 生态里与 GitHub 相关的工具也是最丰富的。更微妙的一点是:大模型本身"读"过大量 GitHub 上的工作流和讨论,它们对 GitHub 的那一套操作天然更熟悉。
当你的 AI 同事都住在 GitHub,你也很难不搬过去。
第五,写作和分享的需要。
写博客之后,文章配套的示例代码需要一个读者能直接访问的地方。放在内网 GitLab 上,读者看不到;放在 GitHub 上,读者可以直接 clone、Star、提 Issue 指出我的错误。代码和文章形成了闭环。
怎么选?
或有严格的合规要求?} Q1 -->|是| Q2{预算充足,且看重
GitHub 生态?} Q2 -->|是| GHES[GitHub Enterprise Server] Q2 -->|否| GLSelf[自建 GitLab] Q1 -->|否| Q3{看重开源社区、
Actions 生态和 AI 工具?} Q3 -->|是| GH[GitHub] Q3 -->|否| Q4{想要一体化 DevOps,
又不想自己运维?} Q4 -->|是| GLCloud[GitLab.com] Q4 -->|否| GH
说句公道话
GitLab 并没有输。在金融、政企这类对数据主权和合规要求很高的场景,本地部署的 GitLab 至今仍是很多团队的首选,它的一体化体验和自建友好度,GitHub 也没能完全替代。
我换平台,本质上是因为我的场景变了:个人项目更需要的是社区、生态和 AI,而不是内网和管控。
如果非要打个比方:本地部署的 GitLab 像是自己盖的一栋房子,结构、门锁、水电全由你说了算,但漏水了也得你自己修;GitHub 像是住进了市中心的公寓,物业全包,楼下就是全世界的程序员,代价是房子不完全属于你。
年轻的时候想要一栋自己的房子。后来发现,我其实更想住得离人群近一点。
第六章:开源协议——代码公开 ≠ 开源
这一章是很多开发者的知识盲区,也是最容易给公司埋雷的地方。
一个反直觉的事实
放在 GitHub 上公开的代码,如果没有附带开源协议,默认是"保留所有权利"的。 你可以看,但在法律上不能随意复制、修改、商用。
所以如果你希望别人能用你的代码,请一定加一个 LICENSE 文件。
两大门派
开源协议大体分两派:
- 宽松派(Permissive):随便用,保留版权声明就行,你拿去做闭源商业产品也没问题。代表:MIT、BSD、Apache 2.0。
- 著佐权派(Copyleft,俗称"传染性"协议):你可以用、可以改,但如果分发修改后的版本,必须用同样的协议开源。代表:GPL、AGPL。
主流协议对比
| 协议 | 可闭源商用 | 修改后须开源 | 明确专利授权 | 代表项目 |
|---|---|---|---|---|
| MIT | ✅ | ❌ | ❌ | React、Vue |
| BSD | ✅ | ❌ | ❌ | FreeBSD |
| Apache 2.0 | ✅ | ❌(需注明修改) | ✅ | Kubernetes、Kafka、Dubbo |
| MPL 2.0 | ✅ | 仅修改过的文件 | ✅ | Firefox |
| LGPL | ✅(动态链接时) | 仅修改库本身时 | v3 有 | glibc |
| GPL v2/v3 | ❌(分发时) | ✅ 整个衍生作品 | v3 有 | Linux、Git |
| AGPL v3 | ❌ | ✅ 网络提供服务也算 | ✅ | Grafana、Nextcloud |
几个关键区别
MIT 和 Apache 2.0 有什么不同? 都很宽松,但 Apache 2.0 多了专利条款:贡献者自动授予你相关专利的使用权;如果你反过来起诉别人说这个项目侵犯你的专利,你的授权会自动终止。这也是为什么企业主导的项目更喜欢 Apache 2.0。
GPL 的"SaaS 漏洞"。 GPL 只在分发软件时才要求开源。如果你修改了 GPL 代码,只部署在自己的服务器上提供服务,不把软件分发给别人,那就不触发开源义务。
AGPL 专门堵这个漏洞。 只要用户通过网络使用了你的服务,就视同分发。所以很多做商业后端系统的公司,在合规清单里会直接把 AGPL 标红——引入一个 AGPL 组件,理论上可能要求你把整个服务的源码都交出来。
怎么选?
也必须开源吗?} Q1 -->|不在乎,越多人用越好| Q2{关心专利问题吗?} Q2 -->|不关心,要最简单的| MIT[MIT] Q2 -->|关心,企业级项目| Apache[Apache 2.0] Q1 -->|是的,改进要回馈社区| Q3{主要以什么形式被使用?} Q3 -->|作为库被别人引用| LGPL[LGPL / MPL 2.0] Q3 -->|作为独立软件分发| GPL[GPL v3] Q3 -->|作为网络服务运行| AGPL[AGPL v3]
近几年的"协议战争"
最近几年还有一个趋势值得关注:一些明星开源公司把协议改成了"源码可见但限制商用"的类型,比如 BSL、SSPL、Elastic License。原因很现实——云厂商直接拿开源项目包装成托管服务卖钱,原作者却赚不到。
结果就是社区分裂出了一批分支:Elasticsearch 之后有了 OpenSearch,Redis 之后有了 Valkey,Terraform 之后有了 OpenTofu。开源世界的政治斗争,一点不比公司内部少。
第七章:AI 时代——GitHub 为什么变得更重要了
如果说过去十几年 GitHub 是"程序员的社交网络",那么在 AI 时代,它正在变成三样东西。
1. AI 的教科书
大模型为什么会写代码?很大程度上是因为它们读过海量的公开代码、Issue 讨论、PR 评审和文档。而这些内容,相当一部分就来自 GitHub。
这也带来了新的争议:如果模型学习了 GPL 协议的代码,再生成相似的代码给闭源产品用,算不算违反协议?围绕 Copilot 的诉讼争的就是这个问题,目前法律层面还没有完全定论。开源协议这门"老学问",在 AI 时代突然变得前沿起来。
2. AI 开源生态的主战场
PyTorch、Transformers、llama.cpp、vLLM、Ollama、LangChain,以及层出不穷的 Agent 框架和 MCP Server,几乎都在 GitHub 上开发。
AI 领域的迭代速度快到离谱:一篇论文早上挂出来,下午 GitHub 上就有复现,晚上就有人提了优化 PR,第二天已经有三个衍生项目。这种速度,离不开 GitHub 这套开放协作的基础设施。
(顺便一提,模型权重和数据集更多托管在 Hugging Face,可以理解为"AI 界的 GitHub",两者是互补关系。)
3. 人与 AI Agent 的协作工作台
这是我认为最有意思的变化。
仔细看 GitHub 的核心流程:Issue 描述需求 → 分支隔离改动 → PR 提交变更 → CI 自动验证 → 人工 Review → 合并。这套流程本来是为人与人协作设计的,但它恰好也是 AI Agent 写代码最需要的"安全护栏"。
人类描述需求] --> A[🤖 AI Agent
领取任务] A --> B[🌿 新建分支
编写代码] B --> P[📬 提交 PR] P --> C{⚙️ CI 自动测试} C -->|失败| A C -->|通过| R{👀 人类 Review} R -->|要求修改| A R -->|批准| M[✅ 合并到 main]
AI 可以生成代码,但它会犯错;分支保证错误不会污染主线,CI 保证基本质量,Review 保证最终有人负责。当写代码的成本趋近于零,审查、验证和信任反而成了最稀缺的东西,而 GitHub 恰好掌握着这一整套机制。
所以现在的情况是:你给一个 Issue 打上标签分配给 AI,过一会儿它就提了个 PR 过来,测试全绿,描述写得比你还清楚。
这时候你的心情,大概就是本文标题的后半句。
第八章:放弃——那些让人想删库跑路的瞬间
说了这么多正经的,终于到了本系列的保留节目。以下是我亲身经历或亲眼目睹的"放弃时刻",以及对应的急救方案。
放弃姿势一:merge conflict
<<<<<<< HEAD
BigDecimal amount = order.getAmount();
=======
long amount = order.getAmountInCents();
>>>>>>> feature/refactor两个人改了同一行,Git 不知道听谁的,于是把选择权交还给你。急救:冷静,读懂两边的意图,手动保留正确的版本,删掉标记,git add 后提交。多人协作时,小步提交、频繁同步主干,是减少冲突的唯一正道。
放弃姿势二:rebase 之后,提交"消失"了
git rebase -i 是整理提交历史的神器,也是新手的噩梦。一顿操作之后,git log 里少了几个提交,冷汗直流。
急救:git reflog。它记录了 HEAD 的每一次移动,几乎所有"丢失"的提交都能在这里找回来:
git reflog
# 找到操作前的那条记录,例如 HEAD@{5}
git reset --hard HEAD@{5}记住这句话:在 Git 里,只要提交过,就很难真正丢失。 reflog 是你最后的后悔药。
放弃姿势三:把密钥提交上去了
这个最可怕。很多人的第一反应是再提交一次把它删掉——没用,它还在历史记录里,任何人翻历史都能看到。公开仓库里泄露的密钥,可能几分钟内就被自动化爬虫扫走。
急救的正确顺序是:
- 立刻作废并轮换这个密钥(这是最重要的一步,比清理历史优先得多)
- 再用
git filter-repo之类的工具清理历史 - 以后用环境变量或密钥管理服务,并把
.env写进.gitignore
放弃姿势四:git push --force 到 main
你本地的历史和远程不一致,push 被拒绝,你一怒之下加了 --force。然后,同事们过去两天的提交都没了。
急救:让还保留着完整历史的同事重新 push,或者从 reflog 里捞。预防:在 GitHub 的仓库设置里给 main 开启分支保护(Branch Protection),禁止 force push,要求必须通过 PR 合并。另外,真要强推,请用 git push --force-with-lease,它会在远程有你没见过的新提交时拒绝覆盖。
放弃姿势五:一个只有 Initial commit 的仓库
* a1b2c3d Initial commit这是最常见、也最温柔的放弃方式。每个人的 GitHub 主页上都有几个这样的仓库:宏大的项目名、精心写好的 README、清晰的规划,然后……就没有然后了。
急救:无。这是程序员的浪漫。
写在最后
一路写下来我发现,GitHub 其实是三层东西叠在一起的:
- 最底层是 Git:记录代码的历史,让你敢于折腾。
- 中间是协作:Fork、PR、Review、CI,让全世界的陌生人能围绕一份代码协作。
- 最上层是规则:开源协议定义了协作的边界,而 AI 正在成为这个协作网络里的新成员。
至于标题里的"放弃"——我想通了,学 GitHub 最终要放弃的不是 GitHub,而是两样东西:一是放弃"代码写完就完事"的想法,因为真正的工程是协作、验证和维护;二是放弃抵抗,因为在 AI 时代,你的代码、你的工作流、甚至你的 AI 同事,大概率都住在这里了。
好了,我要去给那几个只有 Initial commit 的仓库补点代码了。
大概吧。
生命在于折腾。Coding the world!
—— 乔人尹
评论
还没有评论,来说点什么吧。