English Version: [A Practical Git Workflow Based on GitHub Flow | Home Page](https://en.gnblink.com/posts/git-workflow/)
## Why Git?
Git/Github 是开发者最高频使用的工具/平台,无论开发什么,只要涉及多人协作,git 就是默认的"公共语言",有时即使一个人独自开发,git 也依然是最可靠的版本控制方案甚至极简部署工具。
项目一旦用上 git,相当于一个人掌握了某种超能力,可以随时给世界打点(commit),根据打点让时光倒流(版本控制),还可以看到世界是怎么被不同人影响的(查看每一次改动的作者与原因),剔除出对这个世界不好的影响因素(找出导致 bug 的代码),保证主世界线收束(审查 PR、保护主分支)。
What a superpower!
想掌握这种控制时间、协作与秩序超能力吗?从这篇文章迈出第一步吧!
### 我为什么写一篇介绍 git 的文章?
在 [MIT 的 The Missing Semester of Your CS Education](https://missing.csail.mit.edu/) 中就有一章专门讲 [Version Control (Git)](https://missing.csail.mit.edu/2020/version-control/),反映了一个现实问题:Git 是开发中不可或缺的工具,但却往往是计算机教育中被忽略的"空白地带",很多 CS 学生直到进入职场,才在手忙脚乱中被迫补上这一课。不过我作为一个幸运的 CS 学生,在 Northeastern 的 CS5520 Mobile App Development 课程里碰到一位很 practical 的老师 —— [Neda Changizi](https://www.linkedin.com/in/nedachangizi/),她的教学并不拘泥于理论,而是紧扣"实际开发中会碰到什么、用什么、做什么"来设计课程,Git 和 GitHub 自然也成了教学的一部分:**以 [GitHub flow](https://docs.github.com/en/get-started/using-github/github-flow) 方法为原型**,每次写作业都要新建 branch,然后经历一系列 add, commit, push, pull request, merge, checkout main, pull。尤其在期末项目中,GitHub 几乎成了我们小组的"办公室" —— 我们在那里讨论、同步进度、review 对方的代码、解决 merge conflict,每天都在上面高频协作。
| 工作流名称 | 主分支策略 | 特点总结 | 适用场景 |
| ----------------------------------------- | --------------------------- | -------------------------------- | ----------------------- |
| Centralized Workflow | 只有 main | 所有开发直接在主分支上进行,类似 SVN | 小团队或个人项目,适合刚学 Git |
| ==Feature Branch Workflow (GitHub Flow)== | main + 功能分支 | 每个功能一个分支,合并需 Pull Request | 多人协作,CI/CD,现代 Web 项目 |
| Git Flow | main + develop + 功能/热修/发布分支 | 分支多,规则清晰,适合版本迭代明确的大项目 | 传统软件开发,版本发布节奏明确 |
| Trunk-Based Development | 只有 main(或 trunk) | 直接在主分支开发,频繁合并,需配合 feature toggle | 大型 agile 团队,追求持续部署与极速迭代 |
虽然我在这之前也接触过 GitHub,自学过一些命令和原理,也写过一些 side projects,但这是我第一次在**真实的多人开发中,从头到尾、系统而规范地使用 Git**。这一过程也让我真正体会到版本控制不仅是工具,更是一种思维方式:它帮助我们记录、协作、追踪、理解整个项目的演进轨迹。现在回头看,我能明显感觉到自己在开发习惯上的成熟 —— 不再是临时查命令、随手操作,而是建立起了"Git-first"的工作流程意识。
我当时也已经习惯[[用卡片法搭建自己的可复用代码知识库|用卡片笔记法(zettelkasten)整理我在 CS 中学习到的概念和方法]],关于 git 的这一张卡片一直是我最常打开 check 的一张。后来另一门课也有一个 team project,其中一个队友不太熟悉 Git,我干脆把那张卡片导出成 PDF 发给了她作为“入门手册”。
所以当我决定搭建一个 tech blog 时,脑海里浮现的第一篇文章就是这篇:**基于 Github Flow 的 Git 总体工作流程**。
为了 cover 整体的同时避免冗长的篇幅,这篇笔记不会介绍 Git 的基础知识原理,也不会手把手教学,它更像一张实际开发中的 cheat sheet,**总结了我作为一个已经掌握 GitHub 基本操作的开发者,在日常项目协作中遵循的一套标准流程和反复用到的命令。** 也就是说我不会截图教你如何在 GitHub 里创建账号和 repository,也不会提醒你要先 cd 进入某个文件夹再 git clone,如果你看不懂其中的一步或者运行后报错,我鼓励你把整篇文章复制粘贴给 GPT 并且指出你不懂的那一步。
如果你已经:
- 有 Github 账号
- 懂得怎么建立 repository
- 已经在 shell 里以 ssh 连接了 GitHub 账号
- 已经用 GitHub 进行过一些 add, commit, push 的操作
但仍然对实际开发中的 GitHub 使用流程感到模糊 —— this article is written for you!
## Let's Git
我会先列出总体的流程,其中包含 6 个大的阶段,然后再分章具体解释每一个大阶段内部应该做什么。
### 总体流程
1. [创建并且链接本地文件夹和远程的仓库](#创建-repository-并且连接本地和远程)
2. 保证本地和远程的文件同步一致
- 如果远程是最新的,[[#Pull]] 远程的内容到本地
- 如果本地是最新的,ACP,见[[#保存修改和推送到远程 (Develop and Add, Commit, Push)|保存修改和推送到远程]]
3. 创建并切换到新分支,在新分支上开发,见[[#管理 Branch]]
4. 保存更新,并且把本地代码推送到远程,见[[#保存修改和推送到远程 (Develop and Add, Commit, Push)|保存修改和推送到远程]]
5. 把远程的分支代码和代码合并,见 [[#Pull Request and Merge]]
6. 在本地切换回主分支,拉取最新代码 [[#Pull]]
7. 继续回到第三步
### 创建 Repository 并且连接本地和远程
第一步当然是创建 repository,我们有远程和本地两个 repository,而且初始化时要保证两者的一致和连接。
按照习惯,你可以选择:先创建远程 repository 或者 先创建本地 repository。
#### 方法 1:在远程创建 repository,然后 clone 到本地
1. 在 GitHub 上创建 Repository
2. 进入想要的目标文件夹,将远程 repository clone 到本地
```bash
git clone <repository-url>
```
#### 方法 2:在本地创建项目文件夹,在远程创建 repository,然后把两者连接起来
1. 在本地创建项目文件夹,然后初始化 git
```bash
git init
```
2. 在 GitHub 上创建 Repository
3. 把两者关联起来
进入文件夹,输入:
```bash
git remote add origin <repository-url>
```
4. 把本地的修改提交到远程(不要忘记这一步):
```bash
git add .
git commit -m "Initial commit"
git push -u origin main
```
### 管理 Branch
> [!SUCCESS] Good Practic in Github Flow: 为新开发创建新 branch
> Main 是我们的主分支,每一次新开发,你都应该创建一个和开发相关的新分支,而不是直接在主分支上开发
#### 查 (READ)
- 查看分支 (Read)
- 查看包括目前所有 branches 的 list:
```bash
git branch
```
- 切换到一个具体的 branch 查看该 branch 下的代码:
```bash
git checkout <name>
```
- 如果你不喜欢命令行操作,你也可以在 VScode 里看到分支的图形界面:`shift+command+p`,输入 git check 然后选择:`Git: Checkout to...`
#### 增 (CREATE)
- 新分支 (Create)
- 创建 new branch:
```bash
git branch <name>
```
- ==快捷合并:创建分支并切换到该分支==
```bash
git checkout -b <name>
```
等价于:
`git branch <name>; git checkout <name>`
#### 删 (DELETE)
- 删除 (Delete)
- 删除本地分支:
```bash
git branch -D <name>
```
- 同时删除本地和远程分支:
```bash
git branch -d feature-branch && git push origin --delete feature-branch
```
- 自动删除所有已 merge 的本地和远程分支:
```bash
git branch --merged main | grep -v "main" | xargs -I {} git push origin --delete {}
```
#### 合并 (MERGE)
- 合并 (Merge)
- 将现在所在的分支,合并到目标分支:
```bash
git merge <target-branch-name>
```
#### 现状
目前我们有四个地方:
1. 本地主分支:`main`
2. 远程主分支:`origin/main`
3. 本地特定分支:`<your-branch-name>`
4. 远程特定分支:`<origin/your-branch-name>`
你现在在 **本地特定分支**,和此分支相关的开发都要在这个分支上开发,但是最终的目的是【合并到主分支】,经历了以下几个步骤:
- 本地特定分支 → 远程特定分支:Add, Commit, Push
- 远程特定分支 → 远程主分支:Pull Request and Merge
- 远程主分支 → 本地主分支:Pull
### 保存修改和推送到远程 (Develop and Add, Commit, Push)
目的:将 本地特定分支 的内容推送到 远程特定分支,经历了 4 个区域和 3 个命令。
```
工作区(Working Directory)
↓ git add
暂存区(Staging Area / Index)
↓ git commit
本地仓库(Local Repository)
↓ git push
远程仓库(Remote Repository)
```
#### ADD
- Add:只要你进行了修改,可以随时 add,将本地的修改添加到暂存区。
add的一个重要作用是区分本地的修改要不要提交到git,改了但是不想提交的话可以不add。
- 你可以只 add 一个文件:
```bash
git add <file-name>
```
- 你也可以 add 所有的修改:
```bash
git add .
```
#### COMMIT
- Commit:当你完成了一个主要的目标或者功能,并且想把它记录下来的时候,进行一次 commit。
相当于把暂存区的更改打包为一个“快照(commit)”,记录这次更新以便查阅和回退。
- m=message,短暂描述这次修改了什么的信息
```bash
git commit -m "Add feature X"
```
- 可以进入编辑器详细描述
```bash
git commit
```
- [[Git commit的书写规范]]
#### PUSH
- Push:当你进行了一系列 commit,而且希望同步到远程仓库时,进行一次 push,把本地修改同步到远程仓库。
- 第一次推送一个新分支:
```bash
git push -u origin <branch-name>
```
- 推送到当前 branch 的远程仓库:
```bash
git push
```
- 推送到指定 branch:
```bash
git push origin <branch-name>
```
#### 一些常用操作
1. 打包成一套一次性命令
```
git add .
git commit
git push -u origin main
```
2. 用 VSCode 的 GUI 界面

有 commit 且无新 change 时,commit 那个键会变成 push
### Pull Request and Merge
目的:将 远程特定分支 的内容合并到 远程主分支,代表代码被接受。
- 进入 GitHub Repository 主页,会弹出新的 branch pushes 让你"Compare & pull request",或者进入 Pull requests tab 手动填写一个 Pull request
- base: main ← compare: xxx,即对比这两个,没问题的话把 xxx 合并入 main
- 填写 title 和 description
- 点击 **Create pull request**
- 在新的 pull request 界面里,可以
- 指派 reviewer
- 关联 issue(可选)
- 评论和讨论
- 根据反馈解决问题/conflicts,继续 [[#保存修改和推送到远程 (Develop and Add, Commit, Push)|ACP]],新的更新会自动同步到这次 Pull Request
- 没有问题之后,点击 **Merge pull request**,代码就会被合并到主分支
### Pull
目的:将 远程主分支 的内容拉取到 本地主分支。
- 在本地,从特定分支切换回主分支 `git checkout main`
- 在本地主分支上运行 pull 将远程内容拉取到本地:`git pull`
## 简化与进阶
这里只是介绍了 GitHub 从头到尾闭环的一个最基础的完整流程。
简化的话,如果是个人开发非常小的项目,有时候不会用到其他分支,偷懒直接 push 到主分支上即可,比如我的 Hugo 博客。
进阶的话,那要学的可还多了……
我自己的真实经历:
几个月前掌握了 add, commit, pull, push, checkout branch, merge 的我:我已经彻底掌握了 git,我就是团队合作、版本控制的天才,我要写一篇技术博客专门教大家怎么用 GitHub
现在在研究 log, HEAD, diff, fetch, checkout, reset, rebase, reflog, stash, cherry-pick 的我:什么都不是,什么都不懂,感谢 gpt 保姆的不离不弃,求求 git 不要让我丢掉或者搞乱我想要的代码就行 😭
## 参考链接
[GitHub flow - GitHub Docs](https://docs.github.com/en/get-started/using-github/github-flow)