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 界面 ![](https://picture-guan.oss-cn-hangzhou.aliyuncs.com/20250525202048.png) 有 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)