Git相关
Git 版本控制 完整系统学习大纲
本文面向测试工程师,按”概念 → 单人使用 → 分支 → 远程协作 → 撤销回退 → 测试实战”的顺序组织,由浅入深。 Git 不只是开发的工具:测试脚本要版本管理、Bug 要定位是哪次提交引入的、回归范围要靠
git diff确定、CI 流水线靠 Git 事件触发。掌握 Git,是测试工程化的第一步。
一、Git 概述
1.1 什么是 Git?
- 定义:Git 是一个分布式版本控制系统(DVCS),由 Linus Torvalds 于 2005 年为管理 Linux 内核开发而创建。
- 作用:记录文件的每一次变更,支持多人协作、版本回退、分支并行开发。
- 地位:当今事实标准,GitHub / GitLab / Gitee / Bitbucket 都是基于 Git 的平台。
1.2 为什么需要版本控制?
| 没有版本控制 | 有 Git |
|---|---|
代码_v1.java、代码_v2_final.java、代码_最终版.java |
完整历史,随时回退 |
| 改坏了没法恢复 | 一键回退到任意历史版本 |
| 两个人改同一个文件互相覆盖 | 分支并行,合并时冲突可解 |
| 不知道谁改的、为什么改 | 每次提交有作者、时间、说明 |
| 无法定位 Bug 是哪次改动引入 | git bisect 二分定位 |
1.3 集中式 vs 分布式
| 维度 | 集中式(SVN) | 分布式(Git) |
|---|---|---|
| 版本库位置 | 只在中央服务器 | 每个开发者都有完整仓库 |
| 断网能否提交 | ❌ 不能 | ✅ 能(本地提交,联网再推) |
| 速度 | 慢(每次都要联网) | 快(大部分操作在本地) |
| 分支 | 目录拷贝,重 | 指针,极轻量 |
| 单点故障 | 服务器挂了就全瘫 | 任一副本都能恢复 |
1.4 Git vs SVN 对比
| 对比项 | Git | SVN |
|---|---|---|
| 架构 | 分布式 | 集中式 |
| 存储方式 | 快照(每次提交存完整快照) | 增量(存差异) |
| 版本号 | 40 位 SHA-1 哈希 | 递增数字(r1, r2…) |
| 分支成本 | 极低(创建分支就是建指针) | 高(复制目录) |
| 学习曲线 | 较陡 | 平缓 |
| 现状 | 主流,新项目首选 | 老项目维护 |
1.5 三个区域与四种状态(核心概念,务必理解)
┌─────────────┐ git add ┌─────────────┐ git commit ┌─────────────┐
│ 工作区 │ ──────────► │ 暂存区 │ ──────────► │ 版本库 │
│ Working │ ◄────────── │ Staging / │ ◄────────── │ Repository │
│ Directory │ checkout │ Index │ reset │ (.git) │
└─────────────┘ └─────────────┘ └─────────────┘
你编辑文件的地方 临时存放待提交内容 已提交的历史快照
文件的四种状态:
| 状态 | 含义 | 转换命令 |
|---|---|---|
| Untracked 未跟踪 | 新文件,Git 还没管 | git add → Staged |
| Modified 已修改 | 已跟踪文件被改动了 | git add → Staged |
| Staged 已暂存 | 已加入暂存区,待提交 | git commit → Committed |
| Committed 已提交 | 已安全存入版本库 | — |
git status # 看文件处于什么状态(最常用命令,没有之一)
git status -s # 简洁模式
状态简写含义:
?? 未跟踪
A 新加入暂存区
M 已修改(第一列:暂存区中的改动;第二列:工作区的改动)
D 已删除
R 重命名
1.6 测试工程师为什么必须会 Git?
| 场景 | 用途 |
|---|---|
| 管理测试脚本 | 自动化用例、压测脚本纳入版本管理 |
| 定位 Bug 引入点 | git bisect 二分查找哪次提交引入问题 |
| 确定回归范围 | git diff 看改了哪些文件/模块 |
| 代码评审 | 参与 Code Review,提前发现缺陷 |
| 分支与环境对应 | 测试环境部署指定分支 |
| CI/CD | 提交触发流水线(配合 Jenkins) |
| 缺陷复现 | 切到出问题的版本复现 |
二、安装与配置
2.1 安装
# Windows:下载 Git for Windows(自带 Git Bash)
# https://git-scm.com/download/win
# 或用包管理器(PowerShell 管理员权限)
winget install Git.Git
# macOS
brew install git
# Ubuntu/Debian
sudo apt install git
# 验证
git --version
💡 Windows 用户建议用 Git Bash 或 PowerShell(非 cmd),命令提示符习惯与 Linux 一致,教程里的命令可直接用。
2.2 首次配置(必做)
# 配置用户名和邮箱(提交时会记录,务必配置)
git config --global user.name "YourName"
git config --global user.email "your@email.com"
# 查看配置
git config --list
git config user.name
配置三个级别:
| 级别 | 参数 | 作用域 | 文件位置 |
|---|---|---|---|
| 系统 | --system |
所有用户 | /etc/gitconfig |
| 全局 | --global |
当前用户所有仓库 | ~/.gitconfig |
| 本地 | --local(默认) |
仅当前仓库 | .git/config |
优先级:local > global > system
2.3 常用配置项
# 默认编辑器(改 VSCode)
git config --global core.editor "code --wait"
# 换行符处理(跨平台协作必配!)
# Windows:
git config --global core.autocrlf true # 检出转 CRLF,提交转 LF
# macOS / Linux:
git config --global core.autocrlf input # 提交转 LF,检出不变
# 中文文件名不转义显示(默认会显示成 \344\275\240 这种八进制)
git config --global core.quotepath false
# 默认分支名
git config --global init.defaultBranch main
# 开启命令行着色
git config --global color.ui auto
# 记住密码(避免每次推送都输入)
git config --global credential.helper store # 明文存储
git config --global credential.helper cache --timeout=3600 # 缓存 1 小时
配置别名(强烈建议,能省大量敲字):
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm "commit -m"
git config --global alias.lg "log --oneline --graph --all --decorate"
# 一个好用的日志别名(推荐直接配上)
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# 之后就能用
git st
git lg
2.4 SSH 密钥配置(免密推送)
# 1. 生成密钥(ed25519 算法,比 RSA 更短更安全)
ssh-keygen -t ed25519 -C "your@email.com"
# 一路回车即可(也可设密码)
# 2. 查看公钥并复制
cat ~/.ssh/id_ed25519.pub
# Windows: type C:\Users\你的用户名\.ssh\id_ed25519.pub
# 3. 粘贴到 GitHub / GitLab
# GitHub: Settings → SSH and GPG keys → New SSH key
# 4. 测试连通
ssh -T git@github.com
# 看到 "Hi xxx! You've successfully authenticated..." 即成功
⚠️ 配置 SSH 后,clone 要用 SSH 地址(
git@github.com:user/repo.git)而不是 HTTPS 地址,否则仍会要求输密码。
已有仓库从 HTTPS 切到 SSH:
git remote set-url origin git@github.com:user/repo.git
git remote -v # 确认
2.5 .gitignore(忽略不需要的文件)
# 常见忽略项
*.log # 日志
*.tmp
.DS_Store # macOS
Thumbs.db # Windows
node_modules/ # 依赖目录
target/ # Java 构建产物
dist/ build/ # 前端构建产物
__pycache__/ # Python 缓存
*.pyc
.env # 环境变量(含密码,绝不能提交!)
*.iml
.idea/ .vscode/ # IDE 配置(一般忽略)
语法规则:
# 开头 注释
/ 目录
* 通配多个字符
? 通配单个字符
! 取反(不忽略)
** 多级目录
/xxx 只忽略根目录下的 xxx
# 已提交的文件想忽略,需要先从版本库移除
git rm --cached <file> # 从暂存区删除,保留本地文件
git rm -r --cached . # 全部移除(然后重新 add)
💡 各语言的
.gitignore模板可以在 gitignore.io 直接生成。
三、基础操作(单人使用)
3.1 创建仓库
# 方式一:本地新建
mkdir my-project && cd my-project
git init # 生成 .git 目录
git init -b main # 指定初始分支名
# 方式二:克隆远程仓库(更常见)
git clone https://github.com/user/repo.git
git clone https://github.com/user/repo.git mydir # 指定目录名
git clone -b dev https://github.com/user/repo.git # 克隆指定分支
git clone --depth 1 https://github.com/user/repo.git # 浅克隆,只要最后一次提交(大仓库提速)
3.2 添加与提交
git add <file> # 添加指定文件
git add . # 添加当前目录所有变更(最常用)
git add -A # 添加所有变更(含删除,等价于 git add --all)
git add -p # 交互式分块添加(一次提交拆成多个,很实用)
git commit -m "提交说明" # 提交
git commit -am "说明" # add + commit(仅对已跟踪文件有效,新文件不行)
git commit --amend # 修改最后一次提交(见 6.4)
# 标准提交流程
git status # 1. 看改了什么
git diff # 2. 看具体改动内容
git add . # 3. 加入暂存区
git commit -m "feat: 新增登录接口测试" # 4. 提交
3.3 查看差异
git diff # 工作区 vs 暂存区(未 add 的改动)
git diff --staged # 暂存区 vs 版本库(已 add 未 commit 的改动)
git diff HEAD # 工作区 vs 最新版本库
git diff <commit1> <commit2> # 两次提交之间
git diff main..dev # 两个分支之间
git diff --stat # 只看统计(改了几个文件、多少行)
git diff --name-only # 只看文件名 ★ 确定回归范围常用
git diff <file> # 只看某文件
💡 测试常用:
git diff --name-only main...HEAD列出本次改动涉及的文件,据此圈定回归测试范围。
3.4 查看历史
git log # 完整日志
git log --oneline # 一行一条(最常用)
git log --oneline -5 # 最近 5 条
git log --graph # 图形化显示分支
git log --all --decorate --oneline --graph # 全部分支的图形化日志
git log --author="张三" # 按作者过滤
git log --since="2026-10-01" --until="2026-10-31" # 按时间
git log --grep="登录" # 按提交信息关键字搜索
git log -S "keyword" # 按代码内容变更搜索(找某行代码是什么时候加的)
git log -- <file> # 某文件的变更历史
git log -p <file> # 某文件的变更历史 + 具体 diff
git show <commit> # 查看某次提交的详细信息
git show <commit>:<file> # 查看某次提交中该文件的内容
3.5 撤销修改(分场景,务必看清)
| 场景 | 命令 |
|---|---|
| 撤销工作区未 add 的修改 | git restore <file> 或 git checkout -- <file> |
| 撤销已 add 但未 commit | git restore --staged <file> 或 git reset HEAD <file> |
| 撤销已 commit(未推送) | git reset --soft HEAD~1(保留改动) |
| 撤销已 commit(已推送) | git revert <commit>(推荐,不改历史) |
# 丢弃工作区某个文件的改动(危险,不可恢复)
git restore <file>
# 把文件从暂存区撤回来(保留工作区改动)
git restore --staged <file>
# 恢复到某个提交的某个文件
git restore --source=<commit> <file>
⚠️
git checkout -- <file>会直接丢弃工作区改动,无法恢复。执行前先确认git diff看过内容。
3.6 删除与重命名
git rm <file> # 删除文件(同时从版本库移除)
git rm --cached <file> # 只从版本库移除,保留本地文件(配 .gitignore 用)
git mv old.txt new.txt # 重命名
# 也可以直接删除文件后 git add -A,Git 会自动识别为删除
3.7 标签 Tag(版本发布用)
git tag # 查看所有标签
git tag v1.0.0 # 给当前提交打轻量标签
git tag -a v1.0.0 -m "发布1.0" # 附注标签(带说明,推荐)
git tag -a v0.9.0 <commit> # 给历史提交补打标签
git show v1.0.0 # 查看标签详情
git push origin v1.0.0 # 推送单个标签(标签默认不会随 push 推送!)
git push origin --tags # 推送所有标签
git tag -d v1.0.0 # 删除本地标签
git push origin --delete v1.0.0 # 删除远程标签
💡 测试价值:用 Tag 标记每个提测版本(如
v2.3.0-test1),随时能切回该版本复现问题。
四、分支管理(核心)
4.1 分支的本质
Git 的分支只是一个指向某次提交的可变指针——极其轻量,创建分支瞬间完成。
main: A ── B ── C
│
└── dev: C ── D ── E
HEAD 指向当前所在分支
git branch # 查看本地分支(* 标记当前分支)
git branch -a # 查看全部分支(含远程)
git branch -v # 查看分支最后一次提交
4.2 分支操作
# 创建
git branch dev # 创建分支(不切换)
git switch dev # 切换分支(Git 2.23+ 推荐)
git checkout dev # 切换分支(老写法)
git switch -c dev # 创建并切换 ★ 最常用
git checkout -b dev # 同上(老写法)
# 从远程分支创建本地分支
git switch -c dev origin/dev
git checkout --track origin/dev
# 删除
git branch -d dev # 删除已合并的分支(安全)
git branch -D dev # 强制删除未合并分支
# 重命名
git branch -m old new
4.3 合并分支
# 合并 dev 到当前分支(先切到 main)
git switch main
git merge dev
两种合并方式:
| 类型 | 条件 | 结果 |
|---|---|---|
| Fast-forward 快进合并 | main 没有新提交,dev 只是领先 | 直接把 main 指针前移,不产生新提交 |
| 三方合并 | 两边都有新提交 | 产生一个新的”合并提交” |
git merge --no-ff dev # 强制生成合并提交(保留分支历史,推荐用于功能分支)
git merge --ff-only dev # 只允许快进,否则失败
4.4 冲突解决(重点)
冲突何时发生:两个分支修改了同一个文件的同一部分,Git 无法自动合并。
冲突文件中的标记:
<<<<<<< HEAD
这是当前分支(main)的内容
=======
这是要合并进来的分支(dev)的内容
>>>>>>> dev
解决步骤:
# 1. 合并时提示冲突
git merge dev
# Auto-merging app.py
# CONFLICT (content): Merge conflict in app.py
# Automatic merge failed; fix conflicts and then commit the result.
# 2. 查看冲突文件
git status # 显示 "both modified"
# 3. 手动编辑文件,删除 <<<<<<< ======= >>>>>>> 标记,
# 保留正确的内容(或合并两边的内容)
# 4. 标记为已解决
git add app.py
# 5. 完成合并提交
git commit # 会自动带合并说明,直接保存即可
# 6. 放弃合并(搞不定了想重来)
git merge --abort
💡 建议:冲突涉及业务逻辑时,不要自己拍脑袋决定保留哪边,找相关开发一起确认。测试同学最容易在合并测试脚本分支时遇到冲突。
4.5 rebase 变基(merge 的替代方案)
# 把当前分支的提交"接"到目标分支的后面
git switch feature
git rebase main
# 等价于:把 feature 的改动重新在 main 最新提交上放一遍
# 结果:历史变成一条直线,没有合并提交
merge vs rebase:
| 维度 | merge | rebase |
|---|---|---|
| 历史 | 保留分支结构,有合并提交 | 变直线,更清爽 |
| 提交历史 | 不改写 | 改写(产生新的 commit hash) |
| 冲突处理 | 一次解决 | 可能需要多次(每个提交一次) |
| 安全性 | 安全 | ⚠️ 不要对已推送的公共分支 rebase |
黄金法则:
✅ 对自己本地未推送的分支随便 rebase
❌ 绝不要对已推送到远程、别人也在用的分支 rebase(会打乱别人的历史)
4.6 cherry-pick(摘樱桃)
只把某一次提交应用到当前分支(不想合并整个分支时用)。
git switch main
git cherry-pick <commit-hash> # 摘取某次提交
git cherry-pick <commit1> <commit2> # 多个
git cherry-pick <commit1>^..<commit3> # 连续区间
git cherry-pick --abort # 取消
💡 测试场景:修复 Bug 的提交在 dev 分支上,需要单独拎到发布分支 → cherry-pick。
4.7 stash 暂存(临时切换分支用)
git stash # 把未提交的改动"藏起来",工作区变干净
git stash push -m "说明" # 带说明
git stash -u # 连同未跟踪文件一起暂存
git stash list # 查看暂存列表
git stash pop # 恢复最近一次并删除记录 ★
git stash apply # 恢复但保留记录
git stash apply stash@{1} # 恢复指定那次
git stash drop # 删除最近一次暂存
git stash clear # 清空所有
典型场景:正在改 A 功能,突然要切到 main 看个东西 →
git stash→ 切走 → 回来git stash pop。
4.8 分支策略(团队协作规范)
| 策略 | 分支构成 | 适用 |
|---|---|---|
| Git Flow | main / develop / feature / release / hotfix | 传统、版本节奏明确的项目 |
| GitHub Flow | main + 临时 feature 分支 | 持续交付,互联网团队常用 |
| Trunk-Based | 主干 + 短期分支 | 高频发布,需强 CI 支撑 |
Git Flow 典型分支:
main 生产环境代码,只能从 release/hotfix 合并
develop 开发主线
feature/* 功能分支,从 develop 切,完成后合回 develop
release/* 发布分支,从 develop 切,测试在此分支进行
hotfix/* 线上紧急修复,从 main 切,修完合回 main 和 develop
💡 测试要知道:测试通常在
release/*分支上进行,测完合入main发布。所以提 Bug 时要说清楚是哪个分支,否则开发可能找错地方。
五、远程仓库协作
5.1 远程仓库管理
git remote -v # 查看远程仓库
git remote add origin <url> # 添加远程仓库
git remote set-url origin <new-url> # 修改地址
git remote remove origin # 删除
git remote show origin # 查看远程详情
5.2 拉取与推送
git clone <url> # 首次:克隆
git fetch # 拉取远程更新到本地(**不自动合并**,安全)
git pull # = fetch + merge(自动合并)
git pull --rebase # = fetch + rebase(推荐,历史更清爽)
git push origin main # 推送到远程 main
git push -u origin main # 首次推送并设置上游跟踪(-u 只需一次)
git push # 之后直接 git push
fetch vs pull(重要区别):
| 命令 | 行为 | 安全性 |
|---|---|---|
git fetch |
只下载远程更新到本地的 origin/main,不改你的工作区 |
✅ 安全,可先 diff 再决定 |
git pull |
下载 + 立即合并到当前分支 | ⚠️ 可能产生冲突或意外改动 |
# 推荐的安全流程
git fetch origin
git diff main origin/main # 先看看别人改了什么
git merge origin/main # 确认无误再合并
5.3 跟踪分支与 upstream
git branch -vv # 查看本地分支与远程的对应关系
git push -u origin feature # 首次推送时建立跟踪
git branch --set-upstream-to=origin/main main # 手动设置
5.4 多人协作标准流程
# 1. 开始工作前,先同步最新代码(重要!)
git switch main
git pull
# 2. 创建自己的分支
git switch -c feature/login
# 3. 开发/编写,阶段性提交
git add .
git commit -m "feat: 登录接口用例"
# 4. 推送到远程
git push -u origin feature/login
# 5. 提 Pull Request / Merge Request,等待评审
# 6. 评审通过后合并到 main,删除自己的分支
git switch main
git pull
git branch -d feature/login
5.5 Fork 工作流(开源项目)
1. 在 GitHub 上 Fork 别人的仓库到自己账号
2. clone 自己账号下的仓库
3. 添加上游仓库,便于同步
git remote add upstream https://github.com/原作者/repo.git
4. 改动提交到自己仓库,推送
5. 在 GitHub 上发起 Pull Request 给原作者
6. 原作者合并
同步上游更新:
git fetch upstream
git merge upstream/main
5.6 PR / MR 评审要点(测试参与)
| 检查项 | 说明 |
|---|---|
| 改动范围 | Files changed 是否超出本次需求范围 |
| 逻辑正确性 | 边界条件、异常处理 |
| 是否影响其他模块 | 公共方法、配置改动 |
| 是否有测试覆盖 | 新增功能是否带用例 |
| 命名与规范 | 变量命名、注释 |
| 安全问题 | 硬编码密码、SQL 拼接 |
六、撤销与回退(危险操作,重点)
6.1 三个命令的区别(易混淆)
| 命令 | 作用对象 | 是否改历史 | 适用 |
|---|---|---|---|
git reset |
移动分支指针 | ✅ 改写历史 | 本地未推送的提交 |
git revert |
新建一个”反向提交” | ❌ 不改历史 | 已推送的提交(推荐) |
git restore / checkout |
恢复文件内容 | — | 撤销文件改动 |
6.2 reset 三种模式
git reset --soft <commit> # 只移动 HEAD,暂存区和工作区都不变
git reset --mixed <commit> # 移动 HEAD + 重置暂存区(默认),工作区不变
git reset --hard <commit> # 移动 HEAD + 重置暂存区 + 重置工作区 ⚠️
| 模式 | HEAD | 暂存区 | 工作区 | 后果 |
|---|---|---|---|---|
--soft |
移动 | 不变 | 不变 | 改动还在暂存区,可重新提交 |
--mixed(默认) |
移动 | 重置 | 不变 | 改动回到工作区,未 add |
--hard |
移动 | 重置 | 重置 | ⚠️ 改动全部丢失 |
git reset --hard HEAD~1 # 回退到上一次提交,丢弃最后那次提交的所有改动 ⚠️
git reset --hard HEAD~3 # 回退 3 次提交
git reset --hard <commit> # 回退到指定提交
git reset --hard origin/main # 丢弃所有本地改动,与远程完全一致
⚠️
--hard是 Git 里最危险的操作之一,工作区未提交的改动会永久丢失。执行前务必确认git status干净,或先git stash。
6.3 revert(安全撤销,推荐)
git revert <commit> # 创建一个新提交,内容与该提交相反
git revert HEAD # 撤销最后一次提交
git revert --no-edit <commit> # 不打开编辑器,直接提交
git revert <c1>..<c2> # 撤销一段提交
git revert -m 1 <merge-commit> # 撤销合并提交(-m 1 表示保留主线)
原来:A ── B ── C ── D
revert C 后:A ── B ── C ── D ── C'(撤销C的改动)
历史保留完整,别人拉代码不会出问题 → 已推送的提交一律用 revert
6.4 修改提交
# 修改最后一次提交的说明
git commit --amend -m "新的提交说明"
# 补充文件到最后一次提交(不产生新提交)
git add forgotten.txt
git commit --amend --no-edit
# 修改作者
git commit --amend --author="Name <email>"
⚠️
--amend会改写历史,只用于未推送的提交。已推送的提交 amend 后再 push 需要--force,会影响他人。
6.5 reflog:找回”丢掉”的提交(救命命令)
Git 会记录 HEAD 的每一次移动,即使你 reset –hard 了,提交对象通常还在(直到 GC)。
git reflog # 查看 HEAD 的移动历史
git reflog --all # 全部
# 找到误删的提交 hash 后,恢复
git reset --hard <找到的hash>
# 或
git cherry-pick <hash>
实操:
1. git reflog 找到 "commit: xxx" 那行的 hash(如 a1b2c3d)
2. git show a1b2c3d 确认是不是要找的内容
3. git reset --hard a1b2c3d 恢复
💡 只要提交过(commit 过),基本都救得回来。真正救不回来的是从未 commit 的工作区改动。
6.6 安全准则
- 已推送的公共提交 → 用
revert,不用reset - 不确定时先
git stash或git branch backup建个备份分支 reset --hard前必看git status- 强制推送(
--force)前,先确认没人基于你的分支工作;团队建议用--force-with-lease(更安全)
git push --force-with-lease # 只在远程没有别人新提交时才强制推送(推荐)
git push --force # 无条件强制推送 ⚠️
七、高级技巧
7.1 bisect:二分查找引入 Bug 的提交(测试利器)
# 场景:某功能现在是坏的,但之前是好的,想知道是哪次提交搞坏的
git bisect start
git bisect bad # 标记当前版本是坏的
git bisect good <已知正常的commit或tag> # 标记一个已知正常的版本
# Git 会自动切换到中间的提交,你测试后标记:
git bisect bad # 这个版本有问题
git bisect good # 这个版本正常
# 反复几次后,Git 会告诉你第一个坏提交:
# xxxxxxx is the first bad commit
git bisect reset # 结束,回到原分支
自动化 bisect(有测试脚本时更高效):
git bisect start HEAD v1.0.0
git bisect run python test_login.py # 脚本退出码 0 = good,非 0 = bad
git bisect reset
7.2 blame:查看每行代码是谁改的
git blame <file> # 每行显示作者、时间、提交
git blame -L 10,20 <file> # 只看 10-20 行
git blame -w <file> # 忽略空白改动
git blame -C <file> # 追踪代码移动
7.3 其他实用命令
# 查看某行代码的变更历史
git log -L 10,20:<file>
# 清理未跟踪文件(小心)
git clean -n # 先预览会删什么
git clean -fd # 删除未跟踪的文件和目录
git clean -fdx # 连 .gitignore 里的也删(谨慎)
# 压缩历史(交互式 rebase)
git rebase -i HEAD~3 # 合并/修改最近 3 次提交
# 编辑界面里:
# pick 保留
# squash 合并到上一个
# reword 修改提交信息
# drop 删除该提交
# 查看某个提交的改动文件
git show --stat <commit>
git show --name-only <commit>
# 归档导出(打包某版本的代码)
git archive --format=zip --output=v1.0.zip v1.0.0
7.4 子模块与工作树(了解)
# submodule:仓库里引用另一个仓库
git submodule add <url> path/
git submodule update --init --recursive
# worktree:同一个仓库同时检出多个分支到不同目录(避免来回切换)
git worktree add ../hotfix-dir hotfix
git worktree list
git worktree remove ../hotfix-dir
# Git LFS:管理大文件(如测试用的大视频、模型文件)
git lfs install
git lfs track "*.mp4"
git add .gitattributes
八、团队规范
8.1 Commit Message 规范(Conventional Commits)
格式:<type>(<scope>): <subject>
type 取值:
feat 新功能
fix 修复 bug
docs 文档
style 格式(不影响代码逻辑)
refactor 重构
perf 性能优化
test 增加/修改测试 ★
chore 构建/工具/依赖
ci CI 配置
示例:
feat(login): 新增短信验证码登录
fix(order): 修复金额为 0 时下单失败
test(order): 补充订单取消的边界用例
写好提交信息的原则:
✅ 一行说清"做了什么"(50 字内)
✅ 正文说明"为什么做"(不是怎么做)
✅ 关联需求/Bug 单号:fix(order): 修复重复下单 #BUG-1234
❌ 避免:"修改"、"更新"、"fix"、"aaa" 这种无信息量的说明
8.2 Git Hooks(自动化钩子)
.git/hooks/ 目录下有各种钩子脚本,在特定时机自动触发。
| 钩子 | 触发时机 | 常见用途 |
|---|---|---|
pre-commit |
提交前 | 跑 lint、单元测试 ★ |
commit-msg |
提交信息写入前 | 校验 commit 格式 |
pre-push |
推送前 | 跑完整测试 |
post-merge |
合并后 | 自动安装依赖 |
# 示例:pre-commit 钩子(.git/hooks/pre-commit,需 chmod +x)
#!/bin/sh
echo "提交前检查:运行单元测试..."
python -m pytest tests/ -q
if [ $? -ne 0 ]; then
echo "❌ 测试未通过,提交被拒绝"
exit 1
fi
💡 测试价值:用
pre-commit强制跑 lint 和冒烟测试,能拦住大量低级错误。推荐用 pre-commit 框架 统一管理(配置在.pre-commit-config.yaml,可随仓库共享)。
8.3 分支保护(平台侧配置)
GitHub / GitLab 都支持对分支设置保护规则:
- 禁止直接 push 到 main,必须走 PR
- PR 必须有 N 个评审通过
- CI 流水线必须通过才能合并
- 要求分支是最新的
九、测试视角:Git 在测试工作中的应用(重点)
9.1 测试代码也要版本管理
测试仓库建议结构:
test-repo/
├── api/ 接口自动化用例
├── web/ Web 自动化(Selenium/Playwright)
├── app/ App 自动化
├── performance/ 压测脚本(JMeter/Locust)
├── data/ 测试数据
├── config/ 环境配置(不含密码!)
├── conftest.py pytest 公共 fixture
├── pytest.ini
├── requirements.txt
└── .gitignore
⚠️ 安全红线:测试脚本里绝不能硬编码密码、token、AK/SK。用环境变量或配置中心,并把
.env加入.gitignore。
9.2 用 Git 确定回归测试范围(高频实战)
# 场景:开发说"本次改动不大",但你想知道到底改了哪些模块
# 1. 查看本次发布改了哪些文件
git diff --name-only v2.2.0...v2.3.0
# 2. 只看某个模块的改动
git diff --stat v2.2.0...v2.3.0 -- src/order/
# 3. 查看具体业务逻辑改动
git diff v2.2.0...v2.3.0 -- src/order/service.py
# 4. 找出改动涉及的所有提交(便于逐个确认)
git log --oneline v2.2.0...v2.3.0
# analysis_change.py —— 自动分析变更范围,辅助确定回归用例
import subprocess
def changed_files(base: str, target: str = "HEAD") -> list:
"""获取两个版本之间的变更文件"""
out = subprocess.run(
["git", "diff", "--name-only", f"{base}...{target}"],
capture_output=True, text=True, encoding="utf-8"
).stdout
return [f for f in out.splitlines() if f.strip()]
def classify(files: list) -> dict:
"""按目录归类,映射到测试模块"""
mapping = {
"src/order/": "订单模块",
"src/user/": "用户模块",
"src/pay/": "支付模块",
"src/product/": "商品模块",
"api/": "接口层",
"web/": "前端页面",
}
result = {}
for f in files:
hit = "其他"
for prefix, module in mapping.items():
if f.startswith(prefix):
hit = module
break
result.setdefault(hit, []).append(f)
return result
if __name__ == "__main__":
files = changed_files("v2.2.0", "v2.3.0")
print(f"共变更 {len(files)} 个文件")
for module, fs in classify(files).items():
print(f"\n【{module}】{len(fs)} 个文件")
for f in fs[:10]:
print(f" - {f}")
# 输出示例:→ 订单模块 12 个文件 → 本轮回归重点:订单
9.3 定位 Bug 引入点(bisect 实战)
# 场景:登录功能昨天还好好的,今天挂了,中间有 30 次提交
git bisect start
git bisect bad HEAD
git bisect good v2.2.0
# 如果有自动化测试脚本,全自动定位:
git bisect run pytest tests/test_login.py::test_login_success
# Git 自动二分,最终输出:
# a1b2c3d4 is the first bad commit
# commit a1b2c3d4
# Author: 张三
# Date: ...
# refactor(auth): 重构鉴权逻辑
# 拿到这个提交,直接定位到"重构鉴权"引入的问题
git bisect reset
💡 给开发的 Bug 描述:”该问题由提交
a1b2c3d4(refactor(auth): 重构鉴权逻辑)引入,bisect 已确认”——这种 Bug 单质量极高,开发会立刻信服并快速修复。
9.4 复现历史版本的问题
# 切到出问题的版本
git switch -c reproduce v2.1.0 # 从 tag 创建分支
# 部署/运行,复现问题
# 或者只检出某个历史版本的配置文件
git show v2.1.0:config/app.yml > app_v2.1.0.yml
# 复现完记得切回去
git switch main
9.5 分支与测试环境对应
| 分支 | 环境 | 测试内容 |
|---|---|---|
feature/* |
开发自测环境 | 开发自测、冒烟 |
develop |
集成测试环境 | 接口测试、集成测试 |
release/* |
预发布/Staging | 系统测试、回归、验收 |
main |
生产 | 灰度验证、线上监控 |
💡 提 Bug 时务必注明分支名 + commit hash + 环境,避免”我这里好的”这类扯皮。
9.6 与 CI/CD 集成
典型流水线(配合 Jenkins / GitLab CI / GitHub Actions):
代码 push / PR
↓ 触发
1. 拉取代码(git clone)
2. 安装依赖
3. 静态检查(lint)
4. 单元测试
5. 接口自动化(pytest)
6. 构建打包
7. 部署到测试环境
8. UI 自动化 / 冒烟
↓
结果回写到 PR(通过才允许合并)
git commit触发构建 → 见 Jenkins- 自动化测试脚本本身也在 Git 仓库中,CI 拉取后执行
- 测试报告可归档为 CI 产物
9.7 测试团队的 Git 建议
- 测试脚本与开发代码同仓库或独立仓库均可,但要保证版本可追溯
- 用例分支跟随需求分支,需求合入主干时用例一起合入
- 每个提测版本打 Tag,便于回溯
- 提交信息规范统一,方便追溯(如
test(order): 补充取消订单用例 #BUG-123) - 敏感信息绝不入库(密码、token、生产数据)
- 定期同步主干,避免分支长期偏离导致合并困难
十、图形化工具
| 工具 | 平台 | 特点 |
|---|---|---|
| VSCode 内置 Git | 跨平台 | 轻量,够用,推荐日常 |
| IntelliJ IDEA / PyCharm | 跨平台 | Java/Python 开发者首选,冲突解决体验好 |
| SourceTree | Win/mac | 免费,可视化分支图清晰 |
| GitKraken | 跨平台 | 漂亮,功能强(部分收费) |
| TortoiseGit | Windows | 资源管理器右键集成,老牌 |
| GitHub Desktop | Win/mac | 简单,适合新手 |
💡 建议:图形化工具用来”看”(分支图、diff 对比),命令行用来”做”(rebase、reset、bisect 等复杂操作)。两者结合效率最高。图形化工具能帮你直观理解分支结构,但复杂操作还是命令行更可控。
十一、常见问题速查
| 问题 | 原因 | 解决 |
|---|---|---|
not a git repository |
不在 Git 仓库里 | cd 到仓库目录或先 git init |
| 提交时提示配用户名邮箱 | 没配置 | git config --global user.name/email |
failed to push... rejected |
远程有新提交,本地落后 | 先 git pull(或 git pull --rebase)再 push |
| push 要输密码 | 用的 HTTPS 地址 | 改 SSH 地址或配 credential helper |
Permission denied (publickey) |
SSH 密钥没配好 | 检查 ~/.ssh/id_ed25519.pub 是否加到平台 |
中文文件名显示 \344\275\240 |
默认转义 | git config --global core.quotepath false |
换行符冲突(^M / 整个文件都被改) |
CRLF/LF 不一致 | 配 core.autocrlf |
| 误删分支 | — | git reflog 找回最后一个提交,再 git branch <name> <commit> |
reset --hard 后想恢复 |
— | git reflog 找回(前提是 commit 过) |
| 提交了大文件导致 push 很慢 | 仓库有二进制大文件 | 用 git lfs,或 git filter-branch 清理历史(谨慎) |
| 合并冲突不知道怎么选 | — | 别自己猜,找相关开发确认;或 git merge --abort 重来 |
| 工作区乱了想重来 | — | git stash(有改动要留)或 git reset --hard origin/main(确认无重要改动) |
常用命令速查:
# 日常
git status / git add . / git commit -m "xxx" / git push / git pull
git log --oneline / git diff / git diff --name-only
# 分支
git branch -a / git switch -c <name> / git switch <name> / git merge <name>
git branch -d <name> / git cherry-pick <commit>
# 撤销
git restore <file> # 丢工作区改动
git restore --staged <file> # 撤出暂存区
git reset --soft HEAD~1 # 撤提交,保留改动
git revert <commit> # 安全撤销(推荐)
git reflog # 找回丢失的提交
# 临时
git stash / git stash pop / git stash list
# 排查
git bisect start/bad/good/reset # 定位引入 Bug 的提交
git blame <file> # 谁改的这行
git log -S "keyword" # 搜代码变更
十二、学习资源
| 资源 | 说明 |
|---|---|
| Pro Git 中文版 | 最权威的免费教程,强烈推荐 |
| Git 官方文档 | 命令完整参考 |
| Learn Git Branching | 交互式可视化练习,理解分支最佳工具 |
| GitHub Skills | GitHub 官方互动课程 |
| gitignore.io | 生成 .gitignore 模板 |
| Conventional Commits | 提交信息规范 |
| Oh Shit, Git!?! | 救急:Git 搞砸了怎么办 |
| Git Flight Rules | 常见问题的应对手册 |