

























适用场景:3 人共用 1 个 GitHub 仓库,每人独立分支开发,通过 PR 合入 main
策略:GitHub Flow | 主线main+ 功能分支feat/xxx
把 Git 仓库想象成 一本可以无限回溯的日记本。
Git 把一次保存分成两步,就像 超市购物:
| Git 概念 | 比喻 | 实际操作 |
|---|---|---|
| 工作区 | 你把商品从货架扔进购物车 | 你在 IDE 里改了代码文件 |
| 暂存区 | 你把购物车推到收银台,准备结账 | git add |
| 仓库 | 你刷卡付钱,商品正式归你 | git commit |
为什么不一步到位? 因为你可以一次逛超市买 10 样东西,但分两次结账——先把生鲜结了放进冰箱,再把日用品慢慢逛。git add 给了你选择权:你可以只把一部分修改放进这次提交,剩下的下次再提交。
每次 git commit 就像在 RPG 游戏中存了个档:
a3f2b1c)所以当你搞砸了,你可以读档回到上一个存档点。这就是 Git 最核心的价值——允许你犯错,也允许你回头。
分支是 Git 最强大的概念,把它想象成 科幻片里的平行宇宙:
main ────●────●────●────●────● (主线宇宙:已经上线运行的版本)
\
feat/workorder──●────● (分支宇宙:你在里面疯狂实验工单功能)
在 feat/workorder 这个平行宇宙里:
这就是为什么你们三个人可以同时开发不同功能而互不干扰——因为你们各自在自己的平行宇宙里干活。
git clone https://github.com/yourteam/ccms_training.git
比喻:就像你去图书馆借了一本书(仓库)的完整复印本。
origin(远程仓库),你手上这本叫 local(本地仓库)git branch feat/workorder-backend # 创建分支
git checkout feat/workorder-backend # 切换过去
# 或一步到位:
git checkout -b feat/workorder-backend
比喻:你在高速公路 main 上开着车,突然看到一个出口:"工单开发专用道"。你拐下去,这条专用道上只有你一辆车,你可以随便开快开慢、停下来修车、甚至掉头——完全不影响主路上的车流。
命名规范(重要):
| 前缀 | 用途 | 示例 |
|---|---|---|
feat/ |
新功能 | feat/workorder-list-page |
fix/ |
修 bug | fix/workorder-date-format |
refactor/ |
重构(不改功能) | refactor/workorder-service |
git status
比喻:在收银台前看一眼你的购物车——"哪些东西要结账?哪些还在货架上?"
Git 会告诉你三件事:
git add src/main/java/controller/WorkOrderController.java # 只加一个文件
git add src/main/java/controller/ # 加整个目录
git add . # 全加
比喻:你要结账了,把要买的商品一件一件放到收银台上。你可以选择:
git add xxx.java),service 呢?下次再说git add .)推荐做法:先 git status 看一眼改了哪些文件,然后用 git add 逐个确认。这就跟你结账前把商品过一遍是一个道理——"等等,这个薯片我什么时候拿的?不要了。"
git commit -m "feat: 新增工单列表查询接口"
比喻:收银员扫完码,你刷卡付钱,打印机吐出一张小票。这个小票就是 commit message。
小票(commit message)要写清楚买了什么:
好例子 ✅:
feat: 新增工单列表分页查询接口,支持按状态和类型筛选
差例子 ❌:
改了点东西
update
fix bug
你们项目用的是约定式提交格式:
feat: 新增工单管理后台列表页
fix: 修复工单日期格式化时区问题
refactor: 抽取工单查询公共方法到基类
就像超市小票要写清楚商品名一样,commit message 要写清楚改了什么 + 为什么改。
知识点:commit 就像一个游戏存档点。聪明的玩家会在"刚打完一个 BOSS"之后存个档,而不是"在 BOSS 房间里残血时"存档。同理:
git push origin feat/workorder-backend
比喻:你在自己的复印本上写了好多笔记,现在你把笔记上传到图书馆的云端系统,这样别人也能看到你的最新版本了。
第一次 push 新分支时:
git push -u origin feat/workorder-backend
-u 的意思是"绑定关系"——你告诉 Git:"以后 git push 默认就推到 origin/feat/workorder-backend"。相当于把门禁卡和你的工号绑定,以后刷卡自动识别。
git pull origin main
比喻:图书馆的 main 书被张三更新了几页,你需要把最新版拿过来。
⚠️ 重要习惯:每天开始工作前,先:
git checkout main
git pull origin main # 把主线最新版拉下来
git checkout feat/你的分支
git merge main # 把主线的更新合入你的分支
这就像每天早上先看一眼公告栏——"今天有没有新的通知?我的代码和最新的主线兼容吗?" 如果几天不 pull,到合入时你会发现冲突堆积成山,处理起来头都大了。
这是 Git 里最容易让人晕的两个概念,我们用小说来比喻。
main: A──B──C
\
feat: D──E
merge 后:
main: A──B──C────M (M 是一个"合并提交")
\ /
feat: D──E
比喻:两本小说,一个是"主线剧情"(main),一个是"外传"(feat)。merge 就是把外传的剧情作为一个新章节插入到主线中,并保留"这里插入了外传"的记录。
merge 的优点:诚实,历史完整记录了谁在什么时候做了什么。
merge 的缺点:如果频繁 merge,历史图会像蜘蛛网。
rebase 前: A──B──C (main)
\
D──E (feat)
rebase 后: A──B──C──D'──E' (feat)
(main)
比喻:rebase 就像你写小说写到一半,发现主线剧情更新了,于是你把你的外传章节撕下来,重新贴在主线最新一页的后面,然后把原来的撕痕擦掉——看起来好像你一开始就是接着最新主线写的。
rebase 的优点:历史干净整洁,一条直线。
rebase 的缺点:篡改历史(commit hash 会变),如果你已经 push 过了再 rebase,会让别人疯掉。
给你们的建议:用 merge,不要用 rebase。rebase 的学习曲线陡,用不好会丢失代码。对于你们的场景,merge 足够简单清晰。
你的分支上开发完成
│
▼
git push 推到 GitHub
│
▼
在 GitHub 网页上创建 Pull Request
│
▼
另一个人 Review(看一眼,点 Approve)
│
▼
Merge 到 main
│
▼
删除你的功能分支(已经用完,可以扔了)
比喻:PR 就像你在公司写了一份方案,提交给同事审批:
git push在项目根目录创建 .github/pull_request_template.md:
## 变更说明
<!-- 简述这个 PR 做了什么 -->
## 变更类型
- [ ] 新功能 (feat)
- [ ] 修 Bug (fix)
- [ ] 重构 (refactor)
- [ ] 文档 (docs)
## 测试说明
<!-- 如何验证这个 PR 的改动是正确的? -->
## 截图(如涉及前端页面)
<!-- 拖入截图 -->
这样每个人提 PR 时自动填入模板,不会遗漏关键信息。
比喻:写完代码就像写完一篇文章,自己读总觉得没问题。第二个人一看:
a1 是什么意思?" → 命名的可读性Review 不是找茬,是双保险。你们的 Review 标准可以很简单:
对三人团队,Review 控制在 5-10 分钟,不要过度审查。
比喻:GitHub Issue 就像把便利贴贴在冰箱上——"今天要买牛奶"、"周末要修水管"。
建议你们创建三个 Issue 来跟踪工作:
Issue #1: [后端] 工单管理后台 CRUD 接口 → assign 张三
Issue #2: [前端] 工单列表页 + 详情/编辑页 → assign 李四
Issue #3: [联调] 前后端联调测试 → assign 两人
然后在你 commit 时引用 Issue:
git commit -m "feat: 新增工单列表查询接口 #1"
GitHub 会自动在 Issue #1 下显示这个 commit,就像给便利贴打了个勾:"牛奶已买 ✅"。
你们目前没有 CI/CD。如果以后想加,最简单的用法是:
# .github/workflows/ci.yml
# 效果:每次 push 或提 PR 时,自动跑一遍编译检查
比喻:就像商场门口有一个自动测温机器人。你每次推代码,它自动跑一遍"能不能编译通过?",如果通不过,它就在 PR 上打一个大红叉——"你体温过高,不能进去"。
这个可以考虑以后再配,现在不用配,降低学习曲线。
# 第 1 步:确认自己在正确的分支上
git branch
# 输出:* feat/workorder-backend ← 前面有 * 说明当前在此分支
# 第 2 步:拉取主线最新代码
git checkout main
git pull origin main
# 第 3 步:回到自己的分支,合并主线更新
git checkout feat/workorder-backend
git merge main
# 如果提示 conflict,参考 4.3 节处理
比喻:这就像每天早上上班先泡杯咖啡、打开邮箱看一眼新邮件、确认今天的工作清单。花 1 分钟就能避免 1 小时的 merge 痛苦。
改代码 → git status → git add → git commit → 继续改 → ...
│
每完成一个小功能点
│
git push(备份到云端)
比喻:就像写文章——不是写完 5000 字才保存一次,而是每写完一段就 Ctrl+S。commit 就是这个"保存"。
建议的 commit 节奏:
| 情况 | 频率 |
|---|---|
| 新增一个方法/类 | 即时 commit |
| 修完一个 bug | 即时 commit |
| 删除不需要的代码 | 即时 commit |
| 改了一半中途被打断 | git stash(暂存) |
比喻:张三和李四都去超市买菜。张三在李四的购物清单上把"白菜"改成了"生菜",李四自己把"白菜"改成了"菠菜"。超市系统不知道该听谁的——这就是冲突。
Git 的表现:merge 时提示 CONFLICT,文件里出现这种标记:
<<<<<<< HEAD
生菜 ← 这行是张三改的
=======
菠菜 ← 这行是李四改的
>>>>>>> feat/workorder-backend
解决方法(手动裁决):
<<<<<<< / ======= / >>>>>>> 标记git add . → git commit -m "merge: 解决与 feat/workorder-backend 的冲突"⚠️ 最重要的一条:遇到冲突不要慌,不要乱删文件,不要强行 git push -f(强制推送会覆盖别人的代码)。叫上另一个人,一起看,一起决定——这本身就是协作的一部分。
# 1. 确保所有代码已提交
git status # 应该显示 "nothing to commit, working tree clean"
# 2. 推送到 GitHub
git push origin feat/workorder-backend
# 3. 去 GitHub 网页上创建 Pull Request
# base: main ← compare: feat/workorder-backend
# 4. 填好 PR 描述,点 "Create Pull Request"
# 5. 通知另一个人 Review
# 6. Review 通过后,点 "Merge pull request"
# 7. 删除分支(本地 + 远程)
git branch -d feat/workorder-backend
git push origin --delete feat/workorder-backend
比喻:就像你写完了一份方案,打印出来、装订好、放到领导桌上、等领导签字,签字通过后归档,原来的草稿纸就可以扔了。分支就是那张草稿纸——任务完成了,它就完成了历史使命。
基于你们工单模块的开发任务,建议的分工:
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 张三 │ │ 李四 │ │ 你(协调) │
│ feat/work- │ │ feat/work- │ │ │
│ order-back │ │ order-front │ │ GitHub Issue │
│ end │ │ │ │ 管理 + Review │
├──────────────┤ ├──────────────────┤ ├──────────────────┤
│ Controller │ │ list.vue │ │ 最终 Merge │
│ Service │ │ edit.vue │ │ 数据库变更 │
│ API 测试 │ │ 页面联调 │ │ 环境搭建 │
└──────────────┘ └──────────────────┘ └──────────────────┘
为什么这样拆?
| 场景 | 命令 | 比喻 |
|---|---|---|
| 看当前状态 | git status |
看一眼购物车里有什么 |
| 加文件到暂存 | git add . 或 git add xxx |
把商品放到收银台 |
| 提交 | git commit -m "feat: xxx" |
刷卡结账,留小票 |
| 推送到 GitHub | git push origin 分支名 |
上传笔记到云端 |
| 拉取最新 | git pull origin main |
下载别人的更新 |
| 创建分支 | git checkout -b feat/xxx |
从高速路拐到专用道 |
| 切换分支 | git checkout 分支名 |
换一条道开 |
| 看所有分支 | git branch |
看看地图上有几条道 |
| 合并分支 | git merge 分支名 |
把专用道合回主路 |
| 暂存当前修改 | git stash |
把手头的活先放进抽屉 |
| 取出暂存 | git stash pop |
从抽屉里拿出来继续干 |
| 撤销未 add 的修改 | git checkout -- 文件名 |
购物车里的东西不要了,放回货架 |
| 撤销已 add 未 commit | git reset HEAD 文件名 |
从收银台拿回来,放回购物车 |
| 撤销已 commit(未 push) | git reset --soft HEAD~1 |
把刚付的钱退了,商品回到收银台 |
| 看提交历史 | git log --oneline |
翻看日记本的目录页 |
| 看某次提交改了啥 | git show commit的hash |
翻到日记某页细看 |
| 删除分支 | git branch -d 分支名 |
专用道到终点了,拆除 |
症状:git branch 显示 * main,然后你就开始改代码了。
后果:张三在 main 上写了 500 行,李四也在 main 上写了 300 行,王五 push 了 200 行——三条河流撞在一起,冲突大到想辞职。
正确做法:永远在自己的功能分支上干活。main 只用来 pull 最新代码,然后 merge 到自己的分支。
症状:push 失败了,提示 "rejected",然后搜到一个命令 git push -f,试了一下,成功了!
后果:你开心了,因为你把代码推上去了。但张三的代码被你覆盖了——他的 3 天工作消失了。
比喻:就像你在图书馆的书上直接涂改,然后把原版撕了换成你的涂改版。后面来借书的人看到的就是你的版本,原来的内容永远丢失了。
正确做法:先 git pull,处理冲突,再 git push。永远不要 -f,除非你 100% 确定你知道自己在干什么。
症状:git commit -m "1" 或 git commit -m "update"
后果:两周后你自己都不记得这次提交干了什么。git log 变成了一本无字天书。
正确做法:用约定式提交格式,写清楚改了什么。
症状:一下午改了工单列表、修了登录 bug、删了两个废弃文件、改了一下 CSS 颜色……然后一个 git commit -m "更新"。
比喻:就像你去超市买了牛奶、灯泡、拖把、薯片、洗衣液,全塞在一个袋子里。一周后你想找"什么时候买的牛奶",只能把整个袋子倒出来翻。
正确做法:一个 commit 做一件事。改工单列表 → commit,修登录 bug → commit,删废弃文件 → commit。这样将来你想"回退工单列表的改动",一行命令就搞定。
症状:在你的分支上开发了两周,从来没 git pull origin main 过。两周后准备合入,git merge main——蹦出 15 个 conflict。
比喻:就像你出差两周,回来发现办公室的布局全变了——你的桌子被移到了窗边,饮水机被搬走了,墙上多了一台电视。你站在原地不知所措。
正确做法:每天开始工作前 git pull origin main + git merge main。冲突如果每天处理,也就一两行;如果两周处理一次,那是 15 个文件满地找牙。
| 你想干什么 | 你做的操作 | 一句话比喻 |
|---|---|---|
| 开始干活 | checkout -b feat/xxx |
从主路拐进专用道 |
| 干活中保存 | add + commit |
存个游戏档 |
| 干到一半被打断 | stash |
把手头的活锁进抽屉 |
| 干完了上传 | push |
把作业交到云端 |
| 每天更新同步 | pull origin main + merge main |
看一眼公告栏,保证自己没掉队 |
| 干完了请人审核 | 在 GitHub 上创建 PR | 把方案提交审批 |
| 审核通过合入 | 点 Merge | 方案生效,并入正式版 |
| 分支用完删除 | branch -d |
草稿纸扔了 |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。