Developer Handbook
Git & GitHub
完整场景化指南
从零开始构建本地仓库,理解分支与合并的原理,掌握团队协作的完整流程。每一步操作都有原因,每一个概念都有类比。
Git 原理
Branch & Merge
团队协作
VS Code 集成
回滚操作
在使用任何 Git 命令之前,先建立这个最重要的心智模型:Git 把你的代码分布在四个"空间"里,所有命令本质上都是在这四个空间之间搬移数据。
工作区
Working Directory
你直接编辑的文件,磁盘上的真实内容
add →
⇄
← restore
暂存区
Staging Area
准备提交的快照,commit 前的缓冲层
commit →
⇄
← reset
本地仓库
Local Repo (.git)
完整历史提交链,所有分支都在这里
push →
⇄
← pull
远程仓库
Remote (GitHub)
云端备份 + 协作中心,团队共享的真相来源
核心心智模型
每次 commit 不是保存"变化",而是保存整个项目的一张快照。Git 用 SHA-1 哈希唯一标识每张快照,快照之间形成父子链条,这就是历史。分支只是一个指向某个 commit 的"指针标签",创建、删除分支几乎是零成本操作。
在执行 git init 之前,你的项目只是一堆普通文件夹。这条命令会在项目根目录创建 .git 隐藏目录,里面存放整个仓库的数据库 —— 所有快照、所有分支、所有历史,全部在这里。
cd ~/Projects/my-app
git init
git status
推荐:先配置 .gitignore
node_modules/
dist/
.env
.env.local
.DS_Store
.vscode/
.idea/
*.log
coverage/
从工作区到仓库,必须经过两道门。这是最重要的操作流程:
git add .
git status
git commit -m "初始提交"
为什么要有暂存区这个中间层?
你可能同时改了 10 个文件,但只想把其中 3 个作为一次有意义的提交。暂存区让你精确控制每次 commit 的内容范围,是一种让提交历史保持清晰的设计。
Commit 信息规范
| 前缀 | 含义 | 示例 |
| feat | 新功能 | feat: 用户头像上传 |
| fix | Bug 修复 | fix: 修正登录校验逻辑 |
| docs | 文档更新 | docs: 更新 README |
| refactor | 重构 | refactor: 提取公共工具函数 |
| chore | 杂项 | chore: 升级依赖版本 |
| revert | 回滚 | revert: 撤销误合并的分支 |
在 GitHub 创建好仓库后(不勾选任何初始化选项),把本地和远程关联起来:
git remote add origin git@github.com:用户名/仓库名.git
git push -u origin main
git remote -v
情况 B
git remote add origin ...
已有 .git 但无远程,直接添加即可
情况 C
git remote set-url origin ...
远程地址填错了,用 set-url 修正
分支的本质是让你在不污染主线的情况下做实验。想象你有一本书的稿件,想尝试一个新的写法但不确定,分支就是给你开一个"平行草稿",满意了再合并回来。
git checkout -b feature/login
git branch
git branch -a
git checkout main
git branch -d feature/login
git push origin --delete feature/login
场景一:Fast-forward(最简单)
如果 main 自从分叉后没有任何新提交,Git 直接把 main 指针往前移,不产生 merge commit,历史依然是直线。
git checkout main
git merge feature/login
场景二:三方合并(正常协作)
git checkout main
git pull
git merge feature/login
git push
场景三:发生冲突
<<<<<<< HEAD(当前分支 main)
const port = 3000;
const port = 8080;
>>>>>>> feature/login
git merge feature/login
git status
git add src/config.ts
git commit
VS Code 冲突视图
VS Code 会在冲突区域上方显示 Accept Current / Incoming / Both 按钮,比手动删除标记更直观。
Rebase 把你分支上的提交"剪切"下来,重新"粘贴"到目标分支的最新位置之后。结果是提交历史变成一条直线,没有 merge commit。
git checkout feature/login
git rebase main
git add .
git rebase --continue
git rebase --abort
铁律:已推送的分支禁止 rebase
rebase 会改写 commit 哈希值,等于重写历史。已经 push 的分支只用 merge,永远不 rebase。
Merge vs Rebase 场景对照
| 场景 | 推荐操作 | 理由 |
| 功能分支 → main 合并 | merge | 保留完整历史 |
| 同步 main 最新变更到功能分支 | rebase | 保��线性历史 |
| 已推送到远程的分支 | 禁止 rebase | 改写历史会破坏他人仓库 |
| 整理本地未推送的提交 | rebase -i | 交互式变基,合并/编辑提交 |
| 面板区域 | 对应命令 | 说明 |
| 右上角分支名 badge | git checkout | 点击可切换 / 创建分支 |
| 输入框 + Commit 按钮 | git commit -m "..." | 填写信息后点击提交 |
| 文件旁的 + 号 | git add <file> | 把单个文件放入暂存区 |
| 文件旁的 - 号 | git restore --staged | 从暂存区移回工作区 |
| ... 菜单(三点) | Pull / Push / Fetch / Merge / Rebase / Stash | 所有高级操作的入口 |
推荐安装 GitLens 扩展
GitLens 在每行代码旁显示最后一次 commit 的作者和时间(blame 信息),还提供可视化的分支历史图。
每个功能在独立分支上开发,通过 Pull Request 审查后合并到 main。
-
1
同步主干,确保基于最新代码
为什么:开始前获取别人的最新改动,减少后续冲突概率
git checkout main && git pull
-
2
创建功能分支,隔离开发
为什么:main 始终保持可发布状态,功能开发互不干扰
git checkout -b feature/user-profile
-
3
开发、小步提交
为什么:每个有意义的改动单独提交,方便追溯、回滚,也方便 code review
git add . && git commit -m "feat: 用户头像上传"
-
4
推送分支到远程
为什么:备份本地工作;让团队能看到你在做什么;为 PR 做准备
git push -u origin feature/user-profile
-
5
在 GitHub 上创建 Pull Request
为什么:PR 是代码进入主干的审查门,团队可以评论、讨论、要求修改
-
6
合并 PR 并本地同步清理
为什么:远程已合并,本地 main 要跟上;删除完成的功能分支
git checkout main && git pull
git branch -d feature/user-profile
策略一:merge main(安全)
git merge main
历史完整但有交叉点。适合已推送的分支,希望保留完整历史。
策略二:rebase main(整洁)
git rebase main
历史变成直线,无 merge commit。仅适合未推送的本地分支。
git pull
git pull --rebase
git fetch
git log HEAD..origin/main
git merge origin/main
| 场景 | 命令 | 影响历史 | 影响远程 |
| 丢弃工作区改动(未 add) | git restore <file> | 否 | 否 |
| 撤销暂存(已 add 未 commit) | git restore --staged <file> | 否 | 否 |
| 撤销最近一次 commit(保留改动) | git reset --soft HEAD~1 | 本地 | 否 |
| 完全丢弃到某次 commit | git reset --hard <hash> | 危险 | 否 |
| 安全回滚已推送的 commit | git revert <hash> | 追加新提交 | 需要 push |
## 场景1:改了文件,还没 add,想放弃
git restore src/config.ts
git restore .
## 场景2:已经 add,想退回工作区
git restore --staged src/config.ts
## 场景3:commit 了但没 push,想撤销(改动回到暂存区)
git reset --soft HEAD~1
## 场景4:完全丢弃(危险!改动不可恢复)
git reset --hard HEAD~1
## 场景5:已 push,需要安全回滚
git log --oneline
git revert <commit-hash>
git push
## 救命:reset --hard 后找回代码
git reflog
git reset --hard <reflog-hash>
reset --hard 是不可逆操作
绝大多数"代码删没了"的情况都能通过 git reflog 找回,但前提是没有执行 git gc。
01
三个空间
工作区 → 暂存区 → 本地仓库 → 远程仓库。所有命令都是在这四个空间之间移动数据。
02
commit 是快照
不是记录"哪里变了",而是拍下整个项目当时的样子。哈希值唯一标识每张快照,快照之间的父子关系形成历史链。
03
分支是指针
分支名只是贴在某个 commit 上的标签。创建、删除、切换分支都是在操作这个指针,不会改动任何文件内容。
04
merge vs rebase
merge 把两条线汇合,历史完整但有交叉;rebase 把提交搬到另一条线末尾,历史整洁但改写了哈希。已推送的提交只能 merge。