# GitHub 协同工作流 v2，仅用 GitHub 管理团队

Original: <https://lifelonglearn.ing/github-team-workflow>

Author: [奶爸](https://lifelonglearn.ing/users/3b04650c-8231-499b-8ef0-381fc4d7efb0)

Published: 2024-10-10T05:58:50Z

Updated: 2026-09-27T06:57:43Z

Version: 2

眨眼间加入现在团队已近 5 年，很喜欢之前 on-site 的时候大家中午下午一起去技术交易大厦地下餐厅和小店吃饭的日子。加入团队的第二年就开始远程，到现在，其实些许有些遗憾，大家面对面的时间也没多久就进入远程工作了，但是我也喜欢当下的远程的办公方式，随时都可以跟家人一起吃饭。

在公司团队建设过程中发现了一些问题，主动制定了一些配合 GitHub 的工作流程。分享给大家，欢迎一起讨论优化。本文全部基于最大程度的利用 GitHub 来工作来写，能不用第三方服务就不用第三方服务。也会涉及一些其他的东西，比如管理内部 Web 服务。

> **为什么将 GitHub 作为大本营 all in GitHub？**
> 对团队整体的技术沉淀很有帮助，无论是 feature 还是 bug，通过代码的 commit 关闭 issue 就可以使代码与 issue 建立连接，将每部分代码与最初的问题或需求关联起来，无论多久，再回头看下 commit 信息和 issue 都知道这个 commit 解决了什么问题。
> 其次所有数据都在一个平台利于维护，互相关联，谁能保证几年后多个平台的内容都不丢且还能好好关联在一起？

## 人员管理 Teams

这里说的是 GitHub 组织的 Teams 设置，建立一个 **All** 的 Team，把所有人拉进去，这一个操作是为了给全体人员一个基本的权限，以区别内部及外部人员。*比如说临时需要一个外部人员加入 GitHub 做些什么，就不需要每个需要保护仓库都要设置他不能访问。*

![image.png](https://lifelonglearn.ing/upload/0698dfff-0103-e69a-92ba-751ae32126cd.png)

在组织设置中将成员权限默认为​**无权限**​，这个操作是保护所有的仓库，没有特别指定权限就无法访问所有仓库，在接下来的操作中进行不同岗位的​**权限隔离**​。直接拿我司的 GitHub 设计来说吧，都是我一手设计的。

**其他安全设置**

* 通过 repo ruleset / org ruleset 禁止删除主分支和主分支 force push

### Teams 结构示例

```plaintext
｜- All 全体内部人员都在这个组里面，这是最基本的权限控制
   ｜- QA 测试岗位人员（目前产品岗也放在这里）
   ｜- iOS 维护 iOS 平台代码的人员
   ｜- Android 维护 Android 平台代码的人员
   ｜- Operation 运营岗位人员
   ｜- Backend 后端岗位人员
｜- Audit 外部提供审计服务的人员
```

「​**All**​」 下面的子 Team 会继承 All 分组的权限，「​**Audit**​」 Team 是外部人员分组，默认对所有仓库无读写权限，这样可以在有外部审计需求时单独对要审计的仓库给予「​**Audit**​」Team 读或写的权限。

### 仓库结构示例

```plaintext
｜- [company_name]-issues 给「All」小组读写权限，这是整个公司的中转站，公司内所有产品的 issue 都在这里处理，所有内部人员都可以创建、评论及修改，开发可以通过 commit message 中使用 「close [组织名]/[company_name]#[issue_id]」在对应仓库进行开发时自动更新 issue 状态
｜- [product_name]-iOS 给「iOS」小组读写权限，因为所有仓库默认权限为无权限，所以除「iOS」小组内成员之外，其他所有人都无法看到或编辑这个仓库，是非常好的权限隔离
｜- [product_name]-Android 给「Android」小组读写权限，同上
```

**[company\_name]-issues** 这个仓库给了「​**All**​」读写权限，是整个公司所有人员的信息中转站，这样测试人员可以在这个仓库提交公司内所有产品的 bug，产品可以在这提所有需求开发的 issue。

开发小组继承了「​**All**​」小组的权限，所以他们可以在需求开发结束后或者 bug 修复后的 pull request 里面跨仓库关闭 issue，这样就实现了联动、闭环。如果你的开发人员不知道如何跨仓库联动 issue，参考这个文档 [https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue](https://lifelonglearn.ing/r/go?url=aHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vaXNzdWVzL3RyYWNraW5nLXlvdXItd29yay13aXRoLWlzc3Vlcy9saW5raW5nLWEtcHVsbC1yZXF1ZXN0LXRvLWFuLWlzc3Vl)

这样设计即针对人员隔离了代码仓库，又兼备了相互联动的能力。

## 内部 Web 服务

比如我们公司有内部 yapi 在线 API 文档、一些内部的管理后台。

此时可以通过 [Cloudflare Zero Trust](https://lifelonglearn.ing/r/go?url=aHR0cHM6Ly9kZXZlbG9wZXJzLmNsb3VkZmxhcmUuY29tL2Nsb3VkZmxhcmUtb25lLw==) 结合 GitHub Oauth2 保护公司内部 Web 服务，所有内部服务的服务器不提供公开访问，在 Cloudflare Zero Trust 中创建应用将 Web 服务通过 Cloudflare 转发出来，设置鉴权方式为 GitHub 登录，且只有公司组织的人才能登录，这样就保护了公司内部的 Web 服务。

这样在有 **人员离职** 时也非常好处理，直接在 GitHub 处将人员移除，公司内部的 Web 服务自然就无法再访问了。

## 内部密码管理

一定要使用如 Bitwarden 类的密码管理软件的 Team 功能，且与公司有关的所有账户都要使用公司提供的邮箱及其他信息注册。避免有人员离职密码遗失或泄漏产生负面影响。

## GitHub 协同工作流 v2

这是我写在公司 **[company\_name]-issues** README 中的内容。

### 设计规范

#### 制作索引（Storybook/Components）

整个产品内的配色、字体、组件都要有一个集合，所有 UI 的组成部分都源自这个集合，不能展示相同内容在一个产品中有各种各样的展示方式。

* 配色列表：颜色、适用场景
* 字体列表：大小、字重、适用场景
* 组件列表：像 Web 开发的组件库的文档一样，有一个组件列表，产品内所有界面的 Button、弹窗提醒 等的体验都应该是一致的

设计师的每个界面的每一部分都要源自最基本的 ​**配色列表**​、​**字体列表**​、​**组件列表**​，不能随心所欲这里这个字号字重那里哪个字号字重，这个背景这个颜色，那个背景又不知道什么颜色。

#### 配合开发

设计师要引导开发进行组件化，在代码中同样要将 ​**配色列表**​、​**字体列表**​、**组件列表** 实现出来。使产品的界面相关代码灵活可读易维护。

### 需求管理

* **需求池​** `https://github.com/[company_name]/[company_name]-issues/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone`：这是未设置 **milestone** 的 issue 列表，从这个列表追踪尚未排期的需求。
* **遗留 Issue** `https://github.com/[company_name]/[company_name]-issues/issues?q=is%3Aissue+is%3Aopen+milestone%3A*+sort%3Aupdated-desc` *可能存在 milestone 已结束，issue 验收没跟上后期又打开的情况，如果未更新 milestone 可能会被遗忘，从这里看是否存在仍开启的结束的 milestone 的 issue*

#### #1 创建 Issue

1. 创建 Issue（每个 issue 代表着一个 feature 或 bug）
2. 关联 Project（每个 project 代表公司内每个产品）
3. \*关联 Milestone 排期（每个 milestone 就是每个产品的每个版本计划）*不是必要操作，不关联 milestone 视同进入需求池​*

#### #2 添加 Label

一个 issue 由 3 类标签标记，一种是基本标签，说明这个 issue 的基本性质，是一个新需求还是老需求优化还是一个 bug；一种是优先级标签，说明开发安排优先级；还有就是验收标签，说明在这个 issue 关闭时有哪些人员需要对其负责；如需添加新的 label 类型，联系 @naiba

##### 基本标签

* 新增的 功能/UI 需求 `feature`
* 已实现的旧 UI/代码 优化：`improve`
* 已实现的旧 UI/代码 出现问题：`bug`

##### 优先级

* 优先级：`P0` > `P1` > `P2` > `P3`
  * `P0` 最高优先级：程序无法正常运行或程序无法跑通-无法正常启动、异常退出、crash、资源不足、死循环、崩溃或严重资源不足
  * `P1` 高优先级：核心功能无法完成、功能报错、数据错误等，但不会影响程序运行
  * `P2` 中优先级：一般功能性Bug，产品中的不符合产品需求或用户使用的缺陷
  * `P3` 低优先级：操作不方便，布局不合理等一类的易用性相关的缺陷

##### Close 后负责人

![image.png](https://lifelonglearn.ing/upload/d6f43972-1de9-d862-bef2-67a93e7f91c5.png)

* `test/validation/pending` 测试
* `ui/validation/pending` UI

#### #3 分配 Issue

##### 注意事项

**避免打扰** 在被 assign 能立马能处理这个 issue 时在 assign 给相关人，避免太多邮件打扰别人

**避免冲突** 避免多个需求同一时间改动同一部分代码出现冲突，解决冲突可能很耗时

**避免失控** 避免启动依赖尚未完成的需求的新需求的开发，慢就是快

##### 分配流程

1. 在需求准备好后再 **assign 给工程师**
2. 设置验收责任人
   1. 涉及 UI 改动，需要在 issue 中与 设计师 关联（或本身就由其创建）
   2. 设计逻辑改动，需要在 issue 中与 测试工程师 关联（或本身就由其创建）
   3. 比如 `@` 一下，或者一并 assign，以方便在完成需求由相关负责人来验收

#### #4 进入开发

此部分为工程师接到 issue 后执行的操作。

1. 预估开发周期，在 Issue 界面右侧边栏修改 Start、End 时间
2. 开发结束时使用 commit 信息关闭 Issue，格式如下 [https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue](https://lifelonglearn.ing/r/go?url=aHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vaXNzdWVzL3RyYWNraW5nLXlvdXItd29yay13aXRoLWlzc3Vlcy9saW5raW5nLWEtcHVsbC1yZXF1ZXN0LXRvLWFuLWlzc3Vl)
   ```
   做了哪些改动
   [空一行]
   fix BitizenWallet/bitizen-wallet-issues#issue编号
   ```

**血泪经验**

* 非必要在 checkout 需求分支后不要 merge 上游改动，避免上游 force push 导致的历史断层，rebase 起来是灾难。
* 不要相信其他人的代码，从根上确认前人的工具类符合你想要的逻辑。

#### #5 结果验收

![image.png](https://lifelonglearn.ing/upload/f8fe1ea2-2ead-9c69-a8b6-244982c4c5aa.png)

* `test/validation/pending` 由测试工程师测试
* `ui/validation/pending` 由 UI 测试
* 测试完成后将对应的 `(test/ui)/validation/pending` 改成 `(test/ui)/validation/passed`
* 如果发现问题未完全解决直接 reopen，开发重新解决

每个 issue 从开启到关闭都有人负责，凡事有交代，件件有着落，事事有回音。

#### #6 进入下一个 milestone

* 整理分配给具体工程师头上已完成未分配的需求
* 取消已分配未开始的需求的分配，要在下一个 milestone 重新安排任务（可能有更紧急的任务进来，要留出人手）
* 回到 **#1**

**大道至简，减轻所有人的负担，精益自己的工作流程。**
