Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4
7878 字
39 分钟
GitHub 进阶教程:Issues、Actions、Releases、分支保护

GitHub 进阶教程 —— Issues、Actions、Releases、分支保护#

接续《Git使用教程.md》《Git进阶教程.md》的 GitHub 平台进阶内容 基于 D:\desktop\double_car\ 项目的实战场景 远程仓库:git@github.com:forest-wang-sunshine/double_car.git 整理时间:2026-05-04


📑 目录#


阶段 8:GitHub 平台功能全景#

到这一阶段为止,你已经把 GitHub 当作”代码备份云盘”用得很顺。但 GitHub 真正的价值是它是一个完整的项目协作平台,下面这张图能让你看到全貌:

┌──────────────────────────────────────────────────────────────────┐
│ GitHub 仓库(Repository) │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Code ←── 你已经在用:放代码、看文件、看历史 │
│ │
│ Issues ←── 8.1:任务/Bug 追踪面板 │
│ │ │
│ └─ 关联 ──→ Pull Requests (你已会) │
│ │ │
│ └─ 触发 ──→ Actions (8.2 自动化) │
│ │ │
│ └─ 产出 ──→ Releases │
│ (8.3 发布) │
│ │
│ Settings ──→ Branches ──→ Branch Protection (8.4 保护规则) │
│ │
│ 其他:Discussions / Projects / Wiki / Pages / Insights │
│ │
└──────────────────────────────────────────────────────────────────┘

一句话总结四个功能:

功能一句话价值
Issues”记下要做的事和发现的 bug”
Actions”事情发生时自动跑一段脚本”
Releases”正式发布一个版本,并附上构建产物”
Branch Protection”禁止任何人直接污染 main 分支”

8.1 Issues —— 任务追踪与协作中心#

8.1.1 什么是 Issue#

Issue = 一张工单。任何”需要做但还没做”的事都可以变成一个 Issue:

  • 🐞 发现了 bug:后车在低速时编码器读数跳变
  • ✨ 想加新功能:增加超声波避障模块
  • 📚 文档要补:README 的硬件接线表缺 IPS200
  • ❓ 有疑问要讨论:PID 参数调到 1.7 之后是否还需要积分项?
  • 🔧 重构想法:element_manager 的 64 槽位机制可否抽象出 base 类型

每个 Issue 有唯一编号(如 #3),永久存在仓库里,方便追溯。

8.1.2 Issue 的核心字段#

打开任意一个 Issue,能看到这些字段:

┌────────────────────────────────────────────────────────────────┐
│ Title: 后车低速时编码器读数跳变 │
│ #3 Open / Closed │
├────────────────────────────────────────────────────────────────┤
│ │
│ Description (markdown): │
│ 现象:当 PWM duty < 5% 时,编码器 count 偶发跳变 ±2 │
│ 复现步骤:1. ... 2. ... │
│ 猜测原因:可能是脉冲计数中断的去抖逻辑漏掉了双沿 │
│ │
│ ──── 评论区 ──── │
│ forest: 我看了下 PIT_Demo.c:142,确实没有去抖 │
│ others: 建议加 RC 软件滤波再上滑动平均 │
│ │
├────────────────────────────────────────────────────────────────┤
│ Sidebar(右侧栏): │
│ Assignees: @forest-wang-sunshine │
│ Labels: bug, back-car, priority/high │
│ Milestone: v1.1 │
│ Linked PR: #5 │
│ Projects: 双车开发看板 │
└────────────────────────────────────────────────────────────────┘

8.1.3 创建一个 Issue#

  1. 仓库主页顶部菜单点 Issues 标签
  2. 右上角点 New issue
  3. Title(一句话能让人 5 秒看懂的标题)
  4. Description(markdown 格式,能贴代码、图片、链接)
  5. 右侧栏填可选字段(Labels、Assignees、Milestone)
  6. Submit new issue

好 Issue 标题的格式: [模块] 现象 - 关键信息

👍 后车低速编码器跳变(duty < 5% 时偶发 ±2)
👍 [front] 环岛识别在反向出环时误判为十字
👍 添加根目录 README
👎 bug (太空)
👎 这里有问题 (没说哪里)
👎 急 急 急 (没信息)

8.1.4 Issue 与 PR 联动(关键技巧!)#

GitHub 内置了一套关键字魔法:在 commit 信息或 PR 描述里写这些关键字,合并时会自动关闭对应 Issue

关键字含义
close / closes / closed关闭 Issue
fix / fixes / fixed修复 Issue(同样关闭)
resolve / resolves / resolved解决 Issue(同样关闭)

用法示例:

docs: 添加项目根目录 README
GitHub 仓库主页之前是空的,本 PR 添加 README 作为门面入口。
closes #2

当这个 PR 合并到 main 时,Issue #2 会自动从 Open 变成 Closed

也支持跨仓库引用:closes user/repo#3

一次关多个 Issue#

fixes #5, fixes #7, fixes #9

⚠️ 注意: 必须每个 Issue 前都写关键字。fixes #5, #7, #9 ❌ 这样只会关 #5。

8.1.5 Issue 模板(让仓库专业起来)#

如果你的仓库有人提 Issue,模板能让对方按你预期的格式提交,避免”问题描述很模糊”。

创建模板#

  1. 在仓库根目录创建 .github/ISSUE_TEMPLATE/ 目录
  2. 添加模板文件,比如 bug_report.md
---
name: Bug 报告
about: 反馈一个发现的 bug
title: '[BUG] '
labels: bug
assignees: ''
---
## 现象
描述实际看到的现象
## 期望行为
描述应该是怎样的
## 复现步骤
1. ...
2. ...
3. ...
## 环境
- 硬件: TC264D 主控板 vX.X
- 编译器: TASKING vX.X
- 摄像头: MT9V03X
- 是否能稳定复现: 是 / 偶发 1/X 次
## 相关日志/截图
(贴 logic analyzer 波形、串口输出、屏幕截图等)

下次有人点 New issue,会先弹出”选择模板”页面,选择后预填这些字段。

也能写功能请求模板#

.github/ISSUE_TEMPLATE/feature_request.md

---
name: 功能请求
about: 提议一个新功能
title: '[FEAT] '
labels: enhancement
---
## 想解决什么问题
## 期望的解决方案
## 替代方案
## 影响哪些模块
- [ ] front_car
- [ ] back_car
- [ ] 共享库

8.1.6 Labels、Milestones、Assignees#

Labels(标签)#

GitHub 默认给了几个:bugdocumentationenhancementgood first issuehelp wantedquestion

给本项目设计一套合适的标签(按维度分类):

类型 (type) 模块 (scope) 优先级 (priority)
bug front-car priority/critical
enhancement back-car priority/high
documentation common priority/medium
question drivers priority/low
refactor docs
状态 (status) 领域 (area)
status/blocked area/perception
status/in-progress area/control
status/needs-review area/persistence
area/hardware

设置位置:Issues 标签页 → Labels 按钮 → New label

颜色按维度配——比如所有 priority/* 用红/橙/黄/绿渐变,看一眼就知道紧急程度。

Milestones(里程碑)#

把多个 Issue 打包成”v1.1 大目标”。比如:

Milestone: v1.1 - 后车闭环加固
Due date: 2026-06-01
Description: 后车跟随稳态精度提升 + 速度匹配收敛性问题
Issues 列表:
#5 后车低速编码器跳变 [closed]
#7 速度匹配 SMC 抖振抑制 [open]
#9 卡尔曼初值收敛慢 [open]
Progress: ▓▓░░░ 33% (1/3)

设置位置:Issues 标签页 → Milestones → New milestone

Assignees(指派人)#

谁负责处理这个 Issue。点 Issue 右侧 Assignees 选人。一个 Issue 可以多人指派。

8.1.7 实战:在 double_car 创建一个 Issue 看看#

练习任务(自己操作,不在终端跑):

  1. 打开 https://github.com/forest-wang-sunshine/double_car/issues
  2. New issue
  3. 标题:docs: 添加 GitHub 进阶教程笔记
  4. 描述:
    ## 内容
    整理 GitHub 平台进阶功能的学习笔记,包括:
    - Issues
    - Actions
    - Releases
    - 分支保护规则
    ## 目的
    作为日常协作和发布流程的参考资料
    完成后将提交一个 PR 添加 `GitHub进阶教程.md` 文件。
  5. 创建后记下 Issue 编号(比如 #3
  6. 后面发 PR 时在描述里写 closes #3,合并时 Issue 自动关闭

8.2 Actions —— CI/CD 自动化#

8.2.1 什么是 CI/CD#

  • CI = Continuous Integration(持续集成)—— 每次 push/PR,自动跑测试和检查
  • CD = Continuous Deployment/Delivery(持续部署/交付)—— 测试通过后自动发布
开发者 push 代码 ───→ GitHub 检测到事件
┌──────────────┐
│ 触发 CI │
│ │
│ 跑 lint │
│ 跑测试 │
│ 跑构建 │
└──────┬───────┘
┌───────┴───────┐
▼ ▼
全绿 ✅ 有红 ❌
│ │
允许合并 PR 阻止合并 + 通知开发者

CI/CD 的价值: 把”跑测试”这种重复劳动从人脑挪到机器,并且每次都跑完整套,不会漏。

8.2.2 GitHub Actions 的核心概念#

Workflow(工作流) 一个完整的自动化流程
├── Trigger 什么时候触发(on)
└── Job(s) 一个或多个 job
├── runs-on 在什么环境运行
└── Step(s) 具体的步骤
├── uses 用别人写好的 action
└── run 跑一段 shell 命令

对应中文: 工作流 → 作业 → 步骤。一个仓库可以有多个工作流,每个工作流可以有多个作业,每个作业可以有多个步骤。

8.2.3 workflow 文件结构详解#

Workflow 文件必须放在 .github/workflows/ 目录下,扩展名 .yml

最小可运行模板#

.github/workflows/hello.yml
name: Hello CI # 工作流名字(在 Actions 页面显示)
on: # 触发条件
push: # push 时触发
branches: [main] # 仅 main 分支
pull_request: # PR 时触发
branches: [main] # 目标是 main 的 PR
jobs: # 作业列表
greet: # 作业 ID
runs-on: ubuntu-latest # 在 Ubuntu 容器里跑
steps: # 步骤列表
- name: Say hello
run: echo "Hello from GitHub Actions!"
- name: Print environment
run: |
uname -a
pwd
ls -la

把这个文件 commit 推上去,下一次 push 就会自动跑。

8.2.4 常用触发条件(on#

on:
push: # push 时
branches: [main, develop] # 限定分支
paths: # 限定路径
- 'src/**'
- '!**.md' # ! 表示排除
pull_request: # PR 时(推荐 CI 都监听这个)
branches: [main]
types: [opened, synchronize, reopened] # PR 的子事件
schedule: # 定时触发(cron 语法)
- cron: '0 8 * * 1' # 每周一上午 8 点
workflow_dispatch: # 允许手动触发(Actions 页面有按钮)
inputs:
version:
description: '要发布的版本'
required: true
default: 'v1.0.0'
release: # 发 release 时
types: [published]
issue_comment: # 有人评论 Issue 时
types: [created]

8.2.5 常用步骤(steps#

steps:
# 1. 拉取代码(几乎每个 workflow 第一步都是它)
- uses: actions/checkout@v4
# 2. 设置语言环境
- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.12'
# 3. 缓存(加速后续构建)
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
# 4. 跑命令
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
# 5. 多行命令
- name: Build and check
run: |
make build
ls -la build/
du -sh build/
# 6. 设置环境变量
- name: Set env
run: echo "MY_VAR=hello" >> $GITHUB_ENV
# 7. 用环境变量
- run: echo "Var is $MY_VAR"
# 8. 上传产物(让别的 job 或人下载)
- uses: actions/upload-artifact@v4
with:
name: firmware-hex
path: Debug/*.hex

8.2.6 实战 1:检查 commit 信息格式(Conventional Commits)#

本项目 CLAUDE.md 规定 commit 必须遵循 Conventional Commits。手动 review 容易漏,让 Actions 自动检查:

.github/workflows/commitlint.yml
name: Lint commit messages
on:
pull_request:
branches: [main]
jobs:
commitlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 拉取完整历史,否则比对不了
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install commitlint
run: |
npm install --save-dev @commitlint/cli @commitlint/config-conventional
- name: Configure commitlint
run: |
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style',
'refactor', 'test', 'chore', 'perf'
]]
}
};
EOF
- name: Validate PR commits
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

效果:以后任何人发 PR,commit 信息不符合 feat: xxx / fix(scope): xxx 格式,CI 直接红,不能合并。

8.2.7 实战 2:检查不能提交编译产物#

防止有人误把 .elf / .hex / Debug/ 提交进仓库(虽然 .gitignore 有,但保险起见):

.github/workflows/no-binary.yml
name: Forbid binary artifacts
on:
pull_request:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for forbidden files
run: |
forbidden_patterns=(
"*.elf" "*.hex" "*.bin" "*.map" "*.o"
"Debug/*" "Release/*" "*.zip"
)
found=0
for pattern in "${forbidden_patterns[@]}"; do
if find . -path './.git' -prune -o -type f -name "$pattern" -print | grep -q .; then
echo "❌ 发现禁止提交的文件类型: $pattern"
find . -path './.git' -prune -o -type f -name "$pattern" -print
found=1
fi
done
if [ $found -eq 1 ]; then
echo ""
echo "请检查 .gitignore 并删除上述文件后重新提交"
exit 1
fi
echo "✅ 没有发现违规文件"

8.2.8 实战 3:markdown 文档格式检查#

.github/workflows/markdown-lint.yml
name: Markdown Lint
on:
pull_request:
paths:
- '**.md'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DavidAnson/markdownlint-cli2-action@v15
with:
globs: '**/*.md'
config: |
{
"MD013": false,
"MD041": false
}

8.2.9 实战 4:自动给 PR 打标签#

PR 改了哪些文件,自动加对应标签:

.github/workflows/labeler.yml
name: PR Labeler
on:
pull_request_target:
types: [opened, synchronize]
jobs:
label:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@v5

配套的规则文件 .github/labeler.yml

front-car:
- changed-files:
- any-glob-to-any-file: 'Front_Car-main/**'
back-car:
- changed-files:
- any-glob-to-any-file: 'back_car-main/**'
documentation:
- changed-files:
- any-glob-to-any-file: ['**/*.md', 'docs/**']
ci:
- changed-files:
- any-glob-to-any-file: '.github/**'

效果:以后 PR 改了 Front_Car-main/code/PID.c,自动加上 front-car 标签,一眼能看出来 PR 影响范围。

8.2.10 Secrets(密钥管理)—— 别把密码塞进 yml!#

如果你的 workflow 需要 API 密钥(比如调云服务),绝对不要写在 yml 里(会被全世界看到)。

设置 Secret#

  1. 仓库 Settings → 左侧 Secrets and variablesActions
  2. New repository secret
  3. 填 Name(如 MY_API_KEY)和 Value
  4. 保存后这个值永远只能引用,不能再查看

在 workflow 里用#

- name: Call API
env:
API_KEY: ${{ secrets.MY_API_KEY }}
run: |
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/...

GitHub 会自动把 secret 在日志里 mask 成 ***,避免泄漏。

8.2.11 关于 AURIX 项目的特殊情况#

⚠️ TASKING 编译器不能在 GitHub-hosted runner 上运行

  1. License 是商业的,不能装在公共 runner 上
  2. AURIX Studio 是 Windows GUI,不适合 headless CI

折中方案#

方案 A:纯 lint,不编译

  • 跑 commit message 检查、文档拼写、引脚冲突检查、文件结构验证等
  • 依然能拦住 80% 的低级错误

方案 B:self-hosted runner(自建 runner)

把你装了 TASKING 的 Windows 电脑配置成 GitHub 的 self-hosted runner,让 Actions 在你的电脑上跑。

设置位置:Settings → Actions → Runners → New self-hosted runner

按 GitHub 给的 PowerShell 脚本一步步装好,然后 workflow 里写:

jobs:
build:
runs-on: self-hosted # ← 不再用 ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
# 这里就能用 TASKING 命令了
cd Front_Car-main/Debug
mingw32-make

⚠️ self-hosted runner 的安全问题:仓库公开时不要用 self-hosted runner(fork 提 PR 能在你电脑上跑任意代码)。私有仓库或团队成员可信时再用。

适合本项目的简易方案#

写一个只检查不编译的 CI,先把质量门槛立起来:

.github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
lint:
name: Format & Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check no binary files
run: |
if find . -path './.git' -prune -o \
\( -name '*.elf' -o -name '*.hex' -o -name '*.map' \) \
-print | grep -q .; then
echo "::error::发现编译产物"
exit 1
fi
- name: Check both projects exist
run: |
test -d Front_Car-main/code || (echo "Front_Car-main/code 缺失"; exit 1)
test -d back_car-main/code || (echo "back_car-main/code 缺失"; exit 1)
- name: Validate zf_common_headfile.h discipline
run: |
# 检查没有 .h 文件违反"不能 #include zf_common_headfile.h"的规则
if grep -r --include='*.h' '#include "zf_common_headfile.h"' \
Front_Car-main/code back_car-main/code 2>/dev/null; then
echo "::error::用户层 .h 不应该包含 zf_common_headfile.h(会循环包含)"
exit 1
fi

注意 ::error:: 是 GitHub Actions 的特殊语法,会让这条信息变红色错误并定位到 PR。


8.3 Releases —— 版本发布#

8.3.1 Release 与 Tag 的关系#

先搞清楚两个相关概念:

Tag Release
─────────── ──────────────
Git 原生概念 GitHub 平台功能
是某个 commit 的"别名标签" 基于 Tag 包装的"发布页面"
轻量、纯本地能创建 带描述、附件、下载统计
git tag v1.0.0 必须先有 Tag,再创建 Release
网页操作或 API 创建
关系图:
●────●────●────●────● ← main
↑ ↑
v1.0.0 v1.1.0
│ │
│ │
│ (Release 页面)
│ 含描述、Release Notes
│ 含附件 .hex / .elf
│ 含下载统计
(Tag,纯指针)

8.3.2 语义化版本(SemVer)#

行业标准的版本号格式:

v <主版本>.<次版本>.<修订版本>
v MAJOR . MINOR . PATCH
数字含义什么时候 +1
MAJOR主版本不向前兼容的大改动
MINOR次版本添加新功能,向前兼容
PATCH修订版本修 bug,向前兼容

例子:

  • v1.0.0v1.0.1:修了一个 bug
  • v1.0.1v1.1.0:加了一个新功能(如新增超声波避障)
  • v1.1.0v2.0.0:重构了整个控制框架,老代码不兼容

预发布版本: v2.0.0-alpha.1v2.0.0-rc.1(rc = release candidate)

8.3.3 通过命令行创建 Tag#

# 1. 轻量 tag(仅指针,没 message)
git tag v1.0.0
# 2. 带注解 tag(推荐,包含作者、时间、message)
git tag -a v1.0.0 -m "v1.0.0 - 首个稳定版
主要功能:
- 前车循迹(环岛/十字/斑马线)
- 后车跟随(卡尔曼+SMC)
- 双车通信(红外)"
# 3. 给历史某个 commit 打 tag
git tag -a v0.9.0 95ac857 -m "v0.9.0 - 比赛前最后一个版本"
# 4. 推送 tag 到远程(默认 push 不推 tag)
git push origin v1.0.0
# 5. 一次推所有本地 tag
git push origin --tags
# 6. 查看所有 tag
git tag # 列表
git tag -l "v1.*" # 通配符过滤
git show v1.0.0 # 看某 tag 的详情
# 7. 删除 tag
git tag -d v1.0.0 # 删本地
git push origin --delete v1.0.0 # 删远程

8.3.4 在 GitHub 网页创建 Release#

方式 A:从已有 Tag 创建#

  1. 仓库主页右侧 Releases → 点进入
  2. Draft a new release
  3. Choose a tag 下拉选已有 tag(或填新名让它自动建)
  4. Target 选基于哪个分支(默认 main)
  5. Release titlev1.0.0 - 首个稳定版
  6. Description:详细的 Release Notes(看下面 8.3.5)
  7. Attach binaries:拖拽 .hex/.elf 等文件到这里(可选)
  8. 选项:
    • Set as a pre-release:alpha/beta/rc 时勾上
    • Set as the latest release:标记为”最新版”
    • Create a discussion for this release:自动开一个讨论区
  9. Publish release

方式 B:从命令行(用 gh CLI)#

如果你装了 GitHub CLI(gh),可以一行搞定:

gh release create v1.0.0 \
--title "v1.0.0 - 首个稳定版" \
--notes-file RELEASE_NOTES.md \
Front_Car-main/Debug/Front_Car.hex \
back_car-main/Debug/Back_Car.hex

8.3.5 Release Notes 写法#

推荐格式#

## 🎯 主要内容
首个比赛稳定版本,覆盖完整的前车循迹和后车跟随能力。
## ✨ 新功能
- 前车环岛识别状态机(左/右环岛)
- 前车十字识别与十字穿越
- 前车斑马线识别(终点判停)
- 后车双目标连通域追踪
- 后车 SMC + 卡尔曼速度匹配
## 🐞 修复
- 修复后车低速时编码器读数跳变(#5)
- 修复前车出环误判十字(#7)
## 🔧 改进
- PID 改用 LADRC 提升抗扰动
- 电压补偿前移,避免 ADC 噪声直接调制 PWM
## 📚 文档
- 添加 README、Git使用教程、Git进阶教程
- 完善 Project_Interview_Mastery.md 的算法推导
## 💔 不兼容变更
无(首个版本)
## 📦 下载
- `Front_Car.hex` —— 前车固件,烧到前车 TC264D
- `Back_Car.hex` —— 后车固件,烧到后车 TC264D
## 🧪 测试
- ✅ 前车单车跑完赛道(5/5)
- ✅ 后车单车跟前车跑完赛道(5/5)
- ✅ 双车协作完整赛道(3/3)
## 👥 贡献者
@forest-wang-sunshine

自动生成 Release Notes#

GitHub 网页创建 Release 时,Generate release notes 按钮,GitHub 会自动从上次 Release 到当前 tag 之间的所有 PR 列出来,按 label 分类,生成一份初稿。

可以配置自定义模板:.github/release.yml

changelog:
exclude:
labels:
- ignore-for-release
categories:
- title: ✨ 新功能
labels: [enhancement, feat]
- title: 🐞 Bug 修复
labels: [bug, fix]
- title: 📚 文档
labels: [documentation]
- title: 🔧 维护
labels: [chore, refactor]

8.3.6 实战:Tag 触发 Actions 自动构建并附 .hex#

最强工作流:开发完成 → 打 tag → push → GitHub Actions 自动编译 → 自动创建 Release 并附固件。

.github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*' # 只在打 v 开头的 tag 时触发
jobs:
build:
runs-on: self-hosted # 需要本机 TASKING(见 8.2.11)
steps:
- uses: actions/checkout@v4
- name: Build front car
run: mingw32-make -C "Front_Car-main/Debug"
- name: Build back car
run: mingw32-make -C "back_car-main/Debug"
- name: Collect artifacts
run: |
mkdir release-files
cp "Front_Car-main/Debug/Front_Car.hex" release-files/
cp "back_car-main/Debug/Back_Car.hex" release-files/
cp "Front_Car-main/Debug/Front_Car.elf" release-files/
cp "back_car-main/Debug/Back_Car.elf" release-files/
- name: Create Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true # 自动生成 release notes
files: |
release-files/*.hex
release-files/*.elf

效果:

# 你的工作流变成只需要:
git tag -a v1.0.0 -m "v1.0.0 - 首个稳定版"
git push origin v1.0.0
# GitHub 自动:
# 1. 检测到 v1.0.0 tag
# 2. 触发 release.yml workflow
# 3. 在 self-hosted runner 上编译两个项目
# 4. 创建 v1.0.0 Release 页面
# 5. 自动生成 release notes(从上次 release 到这个 tag 的所有 PR)
# 6. 附上 4 个二进制文件
# 7. 通知所有 watchers

8.3.7 删除/修改 Release#

  • 改 release notes:去 Release 页面点 Edit
  • 删除 release:Release 页面 → ...Delete ⚠️ 删除 release 不会删 tag,要单独 git push origin --delete v1.0.0
  • 取消 latest 标记:Edit release → 取消 Set as the latest release

8.4 分支保护规则 —— 让 main 真正安全#

8.4.1 为什么需要保护规则#

到目前为止,你或任何 collaborator 都可以直接 git push origin main,绕过 PR 流程。这在团队里是大问题:

  • 实习生手滑 force push,main 历史被改写
  • 没 review 的烂代码直接进 main
  • 没跑 CI 的代码进 main,触发线上故障
  • 不该 merge 的实验代码进 main

分支保护规则 = 让 GitHub 帮你强制执行规矩。设置后即使是仓库 owner 也得遵守(除非显式给 owner 豁免)。

8.4.2 在哪里设置#

仓库主页 → Settings → 左侧 Branches → 右侧 Add branch protection rule

或者用新版的 Rulesets(GitHub 在 2023 年后推荐用这个):

仓库主页 → Settings → Rules → Rulesets → New ruleset

两者功能类似,Rulesets 更灵活,能批量管理多分支。新手先用 Branch protection rules 也完全没问题。

8.4.3 关键开关详解#

打开 Add branch protection ruleBranch name patternmain(或用通配符 release/*main 同时保护)。然后看下面这些开关:

Require a pull request before merging(必开)#

强制:所有改动必须通过 PR,不能直接 push 到 main。

子选项:

  • Require approvals —— 至少需要几个人 review 同意。个人项目可填 0,团队建议 1+
  • Dismiss stale pull request approvals when new commits are pushed —— 有新 commit 时,旧的 approve 自动失效(防止”批了又改”)
  • Require review from Code Owners —— 见 8.4.4

Require status checks to pass before merging(强烈建议开)#

强制:CI 必须全绿才能合并。

设置后会出现一个搜索框,让你勾选必须通过的 check

☑ commitlint ← 必须通过
☑ markdown-lint ← 必须通过
☑ no-binary ← 必须通过
☑ ci / lint ← 必须通过

子选项:

  • Require branches to be up to date before merging —— 强制 PR 分支必须是基于最新的 main(防止过时分支引入兼容性问题)

Require conversation resolution before merging#

PR 评论里所有”未解决”的对话必须点 Resolve 才能合并。防止 reviewer 提的问题被忽略。

Require signed commits#

要求 commit 有 GPG 签名(证明真的是你的)。安全要求高的项目开。

Require linear history#

禁止合并提交,只允许 squash merge 或 rebase merge。让历史保持一条直线。

Require deployments to succeed before merging#

如果你用 GitHub 的 Environments(如 staging),强制部署到 staging 成功才能合并。

Lock branch#

完全锁住,任何人都不能改。适合归档已结束的项目。

Do not allow bypassing the above settings#

最严格——连 admin 都不能绕过。强烈建议开,否则规则等于摆设。

Restrict who can push to matching branches#

限定特定的人/团队才能 push。即使开了上面的所有规则,可能还想精确控制谁能 merge。

危险操作禁止#

  • Allow force pushes ⚠️ —— 务必关掉!force push 能改写历史
  • Allow deletions ⚠️ —— 务必关掉!防止有人删 main 分支

8.4.4 Code Owners 文件#

CODEOWNERS 文件让 GitHub 自动给 PR 指定 reviewer

创建 CODEOWNERS#

文件路径:.github/CODEOWNERS(推荐位置)

内容示例:

# 默认所有改动都要 owner review
* @forest-wang-sunshine
# 前车代码归 forest 管
/Front_Car-main/ @forest-wang-sunshine
# 后车代码归后车小组
/back_car-main/ @backcar-team-member
# 文档归文档维护者管
*.md @docs-maintainer
/docs/ @docs-maintainer
# CI 配置归 DevOps
/.github/ @devops-lead

效果:

  • PR 改了 Front_Car-main/code/PID.c,自动 @ forest-wang-sunshine 来 review
  • PR 改了 README.md,自动 @ docs-maintainer
  • 一个 PR 改了多个区域,会 @ 所有相关 owner

如果保护规则开了 Require review from Code Owners,这个 review 还是必须的。

8.4.5 实战配置建议#

个人项目(如本项目)#

Branch name pattern: main
☑ Require a pull request before merging
☐ Require approvals (0 个,因为只有一个人)
☑ Require status checks to pass
☑ Require branches to be up to date
勾选: 你的 CI workflow 名字
☑ Require conversation resolution
☑ Do not allow bypassing the above settings
☐ Allow force pushes
☐ Allow deletions

效果:仍然能强制走 PR 流程,CI 必须通过,但因为只有自己一个人,不需要别人 approve。

小团队项目#

Branch name pattern: main
☑ Require a pull request before merging
☑ Require approvals: 1
☑ Dismiss stale pull request approvals when new commits are pushed
☑ Require review from Code Owners
☑ Require status checks to pass
☑ Require branches to be up to date
勾选: 所有关键 CI workflow
☑ Require conversation resolution
☑ Do not allow bypassing the above settings
☐ Allow force pushes
☐ Allow deletions

大型/严肃项目#

在小团队基础上加:

☑ Require approvals: 2
☑ Require signed commits
☑ Require linear history
☑ Require deployments to succeed before merging
☑ Restrict who can push → 限定特定团队

8.4.6 Rulesets(GitHub 2023+ 新功能)#

Rulesets 是 Branch protection rules 的升级版,主要优势:

  • Bypass list —— 精确指定谁能绕过(按用户、团队、role)
  • 多分支模式 —— 一个 ruleset 同时保护 mainrelease/*production
  • 可启用/禁用切换 —— 临时关闭整套规则比删了重建方便
  • 审计日志 —— 谁绕过了规则、什么时候,都有记录

设置入口:Settings → Rules → Rulesets → New ruleset → New branch ruleset

填表:

Name: Protect main and releases
Enforcement status: Active
Targets:
Branches: main, release/*
Rules:
☑ Restrict creations
☑ Restrict updates → 必须通过 PR
☑ Restrict deletions
☑ Require linear history
☑ Require pull request
- Required approvals: 1
- Require Code Owner review
☑ Require status checks to pass
- commitlint
- ci/lint
☐ Block force pushes

如果将来你的项目变大了,迁移到 Rulesets 体验更好。


综合实战:从 Issue 到 Release 的完整生命周期#

把今天学的所有功能串起来,看一个真实场景如何流转:

场景#

某天你测试时发现:后车在过弯时偶尔丢失目标,导致追丢前车

第 1 步:开 Issue#

去仓库 Issues 页面,New issue

Title: 后车过弯时偶发丢失目标,追丢前车
Description:
## 现象
后车在大弯道(半径 < 1.2m)时,连通域追踪偶尔丢失双目标,
导致 error[0]/error[1] 异常,后车失控停车或冲出赛道。
## 复现步骤
1. 双车正常跟随直道
2. 进入第 3 圈的大左弯
3. 大约 30% 概率丢目标
## 猜测原因
弯道时前车从摄像头视野的一侧滑到中间,连通域算法
可能把前车的车标和阴影分成两个独立连通域。
## 影响
比赛 3 圈中至少出现 1 次,致命问题
Labels: bug, back-car, priority/critical
Assignees: @forest-wang-sunshine
Milestone: v1.0.1

提交后得到 Issue 编号 #5

第 2 步:基于 Issue 开发#

git switch main && git pull
git switch -c fix/back-car-target-loss

back_car-main/code/image_deal.c 修复问题,commit:

git add back_car-main/code/image_deal.c
git commit -m "fix(back): 修正过弯时连通域分裂导致目标丢失
加入连通域间距阈值,距离小于 5px 的合并为同一目标。
解决在大弯道时车标和阴影被识别为独立目标的问题。
fixes #5"
git push -u origin fix/back-car-target-loss

注意 fixes #5 —— 合并时会自动关闭 Issue #5。

第 3 步:发起 PR#

GitHub 网页发 PR:

Title: fix(back): 修正过弯时连通域分裂导致目标丢失
Description:
## 改动
在 image_deal.c 的连通域后处理阶段加入间距阈值合并。
## 解决问题
fixes #5
## 测试
- ✅ 室内圆形测试场连续 10 圈无丢失
- ✅ 模拟弯道阴影场景 50 次 0 丢失(之前 30%)
## 风险
新增的合并逻辑会让"两辆很近的车"也被识别为一个,
但本赛规则下不会出现两辆车同时在一辆后车前 1m 内。

第 4 步:CI 跑通#

✅ commitlint 通过
✅ no-binary 通过
✅ markdown-lint 通过
✅ ci / lint 通过

第 5 步:Code review + 合并#

队友看完代码,点 Approve。你点 Squash and merge(小 PR 用 squash 让 main 历史干净)。

合并后:

  • ✅ Issue #5 自动从 Open 变 Closed(因为 PR 描述里写了 fixes #5
  • ✅ main 多了一个 squash commit
  • ✅ 远程分支自动删除(设置过 Auto-delete head branches)

第 6 步:本地清理#

git switch main && git pull
git branch -d fix/back-car-target-loss

第 7 步:发 Release#

修复积累到一定程度,准备发 v1.0.1:

git tag -a v1.0.1 -m "v1.0.1 - 后车过弯稳定性修复"
git push origin v1.0.1

如果配了 8.3.6 的 release.yml,接下来全自动

  1. GitHub Actions 检测到 v1.0.1 tag
  2. 在 self-hosted runner 编译两个项目
  3. 自动创建 Release 页面,标题 v1.0.1
  4. 自动生成 release notes(包含上面的 PR)
  5. 附上 Front_Car.hexBack_Car.hex 等文件
  6. 标记为 Latest release

第 8 步:通知队友#

只需要把 Release 页面 URL 发给队友:

https://github.com/forest-wang-sunshine/double_car/releases/tag/v1.0.1

队友点进去能看到:完整改动列表、固件下载、关联的 Issue 和 PR。


GitHub 其他实用功能(速览)#

Discussions#

仓库 → Settings → Features → 勾 Discussions

适合:开放性讨论、Q&A、想法征集(不像 Issue 那样必须有”要做的事”)。

格式比 Issue 更灵活,支持点赞、置顶、标记最佳回答。

Projects(任务面板)#

仓库 → Projects → New project。

类似 Trello/Jira 的看板,把 Issues 和 PR 拖到不同列(Todo / In Progress / Done)。

适合:可视化追踪 milestone 进展、规划 sprint。

Wiki#

仓库 → 顶部 Wiki 标签。

适合:长文档、用户手册、设计文档。

但实践中很多人推荐直接用 docs/ 目录 + markdown —— 因为:

  • Wiki 是独立的 git repo,不能在主仓库 PR 流程里 review
  • docs/ 在主仓库里能跟代码一起版本化
  • 本项目的 docs/{requirements,plans}/ 已经是这种做法

Pages#

仓库 → Settings → Pages。

把仓库里的 markdown/HTML 自动发布成网站,URL 类似 https://<用户名>.github.io/<仓库>/

适合:项目主页、文档站点。配合 Jekyll/Hugo/MkDocs 等静态生成器更专业。

Insights#

仓库顶部 Insights 标签:

  • Pulse —— 最近一周活跃度
  • Contributors —— 谁贡献了多少
  • Traffic —— 谁访问过、从哪里来
  • Commits —— 提交频率图
  • Code frequency —— 增删行数趋势
  • Network —— fork 关系图
  • Forks —— 谁 fork 了你的项目

Security#

仓库 → Security 标签:

  • Dependabot —— 自动检测依赖漏洞并发 PR 更新(npm/pip 项目用,AURIX 项目不太适用)
  • Code scanning —— 自动扫描代码安全问题
  • Secret scanning —— 自动检测是否有人误把密钥提交进来

速查表#

Issues 关键字(在 commit / PR / 评论里写)#

close #N closes #N closed #N → 关闭 Issue
fix #N fixes #N fixed #N → 关闭 Issue
resolve #N resolves #N resolved #N → 关闭 Issue
#N → 引用 Issue(不关闭)
@user → 提及某人
@team-name → 提及团队

常用 Markdown 在 Issue/PR 里的妙用#

- [ ] 待办事项 1
- [x] 已完成事项 2
```c
// 代码块(带语法高亮)
float kp = 1.5;
```
> 引用别人的话
| 表头 | 表头 |
|------|------|
| 表格 | 内容 |
[链接文本](https://example.com)
![图片描述](image.png)
<details>
<summary>折叠区域标题</summary>
折叠的详细内容
</details>

Actions 常用 actions#

- uses: actions/checkout@v4 # 拉代码
- uses: actions/setup-node@v4 # Node.js 环境
- uses: actions/setup-python@v5 # Python 环境
- uses: actions/cache@v4 # 缓存
- uses: actions/upload-artifact@v4 # 上传产物
- uses: actions/download-artifact@v4 # 下载产物
- uses: softprops/action-gh-release@v2 # 创建 Release
- uses: peter-evans/create-pull-request@v6 # 创建 PR
- uses: actions/labeler@v5 # 自动打标签

Tag 与 Release 命令#

git tag # 列出所有 tag
git tag -l "v1.*" # 通配符过滤
git tag -a v1.0.0 -m "说明" # 创建带注解的 tag
git tag -a v1.0.0 <哈希> -m "..." # 给历史 commit 打 tag
git tag -d v1.0.0 # 删本地 tag
git push origin v1.0.0 # 推一个 tag
git push origin --tags # 推所有 tag
git push origin --delete v1.0.0 # 删远程 tag
git show v1.0.0 # 看 tag 详情
# 用 gh CLI
gh release create v1.0.0 --notes "..." file.hex # 创建 release 并附文件
gh release list # 列表
gh release view v1.0.0 # 查看
gh release delete v1.0.0 # 删除

分支保护规则配置位置#

仓库 → Settings → Branches → Add branch protection rule
仓库 → Settings → Rules → Rulesets → New ruleset (新版)

文件位置约定#

.github/
├── CODEOWNERS 自动指定 reviewer
├── ISSUE_TEMPLATE/ Issue 模板
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md PR 模板
├── workflows/ Actions 工作流
│ ├── ci.yml
│ ├── release.yml
│ └── labeler.yml
├── labeler.yml labeler action 的规则
├── release.yml release notes 自动生成配置
└── dependabot.yml Dependabot 配置

一页纸总结#

┌────────────────────────────────────────────────────────────────────┐
│ GitHub 平台四大进阶功能 │
├────────────────────────────────────────────────────────────────────┤
│ │
│ Issues 工单系统 │
│ ────── PR 描述里写 "closes #N" 自动关单 │
│ 用 Labels / Milestones / Assignees 组织 │
│ .github/ISSUE_TEMPLATE/ 加模板 │
│ │
│ Actions 自动化工作流 │
│ ────── .github/workflows/*.yml │
│ on: 触发, jobs: 作业, steps: 步骤 │
│ 用 secrets.* 引用密钥 │
│ TASKING 编译要 self-hosted runner │
│ │
│ Releases 版本发布 │
│ ────── 基于 Tag (vMAJOR.MINOR.PATCH) │
│ git tag -a vX.Y.Z -m "..." && git push --tags │
│ 配合 release.yml 工作流自动构建+发布 │
│ │
│ Branch 分支保护 │
│ Protection Settings → Branches → Add rule │
│ ────── 必勾:Require PR / Require status checks / │
│ Do not allow bypassing │
│ 必关:Allow force pushes / Allow deletions │
│ │
├────────────────────────────────────────────────────────────────────┤
│ │
│ 完整生命周期: │
│ │
│ 开 Issue → 创建分支 → 写代码 → PR → CI 通过 → review → │
│ 合并(自动 close Issue)→ 累积改动 → 打 Tag → │
│ Actions 自动构建 → 自动创建 Release → 通知用户 │
│ │
└────────────────────────────────────────────────────────────────────┘
semver: v MAJOR . MINOR . PATCH
↑ ↑ ↑
不兼容 新功能 修 bug

本教程在 2026-05-04 整理,基于 double_car 项目的协作场景。可作为团队 GitHub 工作流的参考标准。

GitHub 进阶教程:Issues、Actions、Releases、分支保护
https://mizuki.mysqil.com/posts/git使用/github进阶教程/
作者
风过无痕
发布于
2026-05-04
许可协议
CC BY 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00