Git 完全指南:入门到精通
📖 本文系统梳理 Git 所有核心知识点,从基础概念到高级技巧,配备大量实战案例,帮助你真正掌握 Git 的精髓。
目录
- [Git 基础概念](#Git 基础概念)
- 安装与初始配置
- 仓库操作
- 文件状态与暂存区
- 提交管理
- 分支管理
- 合并与变基
- 远程仓库
- 撤销与回退
- 标签管理
- 储藏(Stash)
- 高级操作
- [Git 工作流](#Git 工作流)
- 常见问题与解决方案
- 命令速查表
1. Git 基础概念
1.1 什么是 Git?
Git 是一个分布式版本控制系统,由 Linus Torvalds 于 2005 年创建。与集中式版本控制(如 SVN)不同,每个开发者本地都有完整的仓库副本。
集中式(SVN): 分布式(Git):
服务器 服务器
│ ↑↓ ↑↓
┌──┴──┐ 开发者A 开发者B
开发者A 开发者B (完整仓库)(完整仓库)
1.2 三个工作区域
┌─────────────────────────────────────────────────────┐
│ │
│ 工作区 暂存区(Index) 本地仓库 │
│ Working Dir → Staging Area → Repository │
│ │
│ git add ──────────→ │
│ git commit ──────────→ │
│ git checkout ←───────────────────────── │
│ │
└─────────────────────────────────────────────────────┘
工作区:你实际编辑文件的地方
暂存区:准备提交的文件快照(.git/index)
本地仓库:已提交的历史记录(.git/objects)
1.3 文件的四种状态
未跟踪(Untracked) ──git add──→ 已暂存(Staged)
│
已跟踪(Tracked) ←──git commit──────┘
│
├── 未修改(Unmodified)
│
└── 已修改(Modified) ──git add──→ 已暂存(Staged)
1.4 核心对象模型
Git 内部用四种对象存储数据:
blob → 存储文件内容
tree → 存储目录结构(包含blob和tree的引用)
commit → 存储提交信息(包含tree、父commit、作者等)
tag → 存储标签信息
每个对象用 SHA-1 哈希值唯一标识(40位十六进制)
1.5 HEAD 指针
HEAD 是一个特殊指针,指向当前所在的分支(或提交)
正常状态:HEAD → main → commit C3
↑
当前最新提交
分离HEAD状态:HEAD → commit C2(直接指向某个提交)
此时不在任何分支上,新提交不属于任何分支
HEAD 的相对引用:
HEAD^ → 父提交(上一个提交)
HEAD^^ → 祖父提交
HEAD~3 → 往前数3个提交
HEAD~1 = HEAD^
2. 安装与初始配置
2.1 安装
bash
# macOS
brew install git
# Ubuntu/Debian
sudo apt-get install git
# CentOS/RHEL
sudo yum install git
# Windows:下载 Git for Windows
# https://git-scm.com/download/win
2.2 全局配置(必做)
bash
# 设置用户名和邮箱(每次提交都会用到)
git config --global user.name "张三"
git config --global user.email "zhangsan@example.com"
# 设置默认编辑器
git config --global core.editor vim # 使用 vim
git config --global core.editor "code --wait" # 使用 VS Code
# 设置默认分支名(Git 2.28+)
git config --global init.defaultBranch main
# 推荐配置
git config --global pull.rebase true # pull 时默认 rebase
git config --global push.default current # push 自动推到同名远程分支
git config --global fetch.prune true # fetch 时自动清理失效远程分支
git config --global core.autocrlf input # 统一换行符(macOS/Linux)
# 设置常用别名
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"
# 查看所有配置
git config --list
# 查看某项配置
git config user.name
2.3 配置文件层级
系统级:/etc/gitconfig (git config --system)
用户级:~/.gitconfig (git config --global)
仓库级:.git/config (git config --local)
优先级:仓库级 > 用户级 > 系统级
3. 仓库操作
3.1 初始化仓库
bash
# 在当前目录初始化新仓库
git init
# 在指定目录初始化
git init my-project
# 初始化后目录结构
my-project/
├── .git/ ← Git 仓库数据(不要手动修改)
│ ├── HEAD ← 当前分支指针
│ ├── config ← 仓库配置
│ ├── objects/ ← 所有对象(blob/tree/commit/tag)
│ └── refs/ ← 分支和标签引用
└── (你的项目文件)
3.2 克隆仓库
bash
# 克隆远程仓库
git clone https://github.com/user/repo.git
# 克隆到指定目录
git clone https://github.com/user/repo.git my-folder
# 克隆指定分支
git clone -b develop https://github.com/user/repo.git
# 浅克隆(只克隆最近N次提交,节省时间和空间)
git clone --depth 1 https://github.com/user/repo.git
# 克隆并包含子模块
git clone --recurse-submodules https://github.com/user/repo.git
4. 文件状态与暂存区
4.1 查看状态
bash
# 查看工作区状态
git status
# 简洁模式
git status -s
# 输出说明:
# ?? → 未跟踪文件
# A → 新文件已暂存
# M → 已修改(左列=暂存区,右列=工作区)
# D → 已删除
4.2 添加到暂存区
bash
# 添加单个文件
git add README.md
# 添加多个文件
git add src/main.c src/utils.c
# 添加当前目录所有文件
git add .
# 添加所有已跟踪文件的修改(不包含新文件)
git add -u
# 交互式添加(可以选择性暂存文件的某些部分)
git add -p
# 按 y 暂存该块,n 跳过,s 拆分,e 手动编辑,q 退出
案例:只提交部分修改
bash
# 场景:修改了 main.c,但只想提交其中一部分改动
git add -p main.c
# Git 会逐块显示修改,你可以选择哪些块进入暂存区
# 这样可以把一个文件的修改拆分成多个提交
4.3 查看差异
bash
# 查看工作区 vs 暂存区的差异(未暂存的修改)
git diff
# 查看暂存区 vs 最新提交的差异(已暂存但未提交的修改)
git diff --staged
git diff --cached # 同上
# 查看工作区 vs 某次提交的差异
git diff HEAD~2
# 查看两个分支的差异
git diff main feature/login
# 只显示有差异的文件名
git diff --name-only
# 显示文件名和修改统计
git diff --stat
4.4 .gitignore 文件
bash
# .gitignore 示例
# 忽略所有 .log 文件
*.log
# 忽略 build 目录
build/
# 忽略特定文件
config/local.json
# 不忽略某个文件(即使上面的规则匹配)
!important.log
# 忽略根目录下的 TODO 文件(不忽略子目录中的)
/TODO
# 忽略 doc 目录下所有 .txt 文件(不递归)
doc/*.txt
# 忽略 doc 目录下所有 .pdf 文件(递归)
doc/**/*.pdf
bash
# .gitignore 不生效的解决方法
# 原因:文件已经被 Git 跟踪,需要先从缓存中移除
git rm -r --cached . # 清除所有缓存
git add . # 重新添加(此时 .gitignore 生效)
git commit -m "fix: update .gitignore"
5. 提交管理
5.1 创建提交
bash
# 基本提交
git commit -m "feat: 添加用户登录功能"
# 跳过暂存区,直接提交所有已跟踪文件的修改
git commit -am "fix: 修复登录验证bug"
# 打开编辑器写详细提交信息
git commit
# 修改最后一次提交(未push时使用)
git commit --amend -m "新的提交信息"
# 修改最后一次提交(不改信息,只改内容)
git add forgotten-file.txt
git commit --amend --no-edit
5.2 提交信息规范(Conventional Commits)
格式:<类型>(<范围>): <描述>
类型:
feat → 新功能
fix → Bug修复
docs → 文档修改
style → 代码格式(不影响功能)
refactor → 重构(不是新功能也不是修复)
test → 添加测试
chore → 构建过程或辅助工具的变动
perf → 性能优化
ci → CI配置修改
示例:
feat(auth): 添加JWT令牌验证
fix(payment): 修复重复扣款问题
docs(api): 更新接口文档
refactor(user): 重构用户模块代码结构
5.3 查看提交历史
bash
# 基本日志
git log
# 单行显示
git log --oneline
# 图形化显示分支
git log --oneline --graph --all
# 显示最近N次提交
git log -5
# 显示某个文件的提交历史
git log --follow src/main.c
# 搜索提交信息
git log --grep="登录"
# 搜索代码变更(谁改了这行代码)
git log -S "function login"
# 显示某个时间范围的提交
git log --after="2024-01-01" --before="2024-12-31"
# 显示某个作者的提交
git log --author="张三"
# 显示每次提交的文件变更统计
git log --stat
# 显示每次提交的具体改动
git log -p
# 自定义格式
git log --pretty=format:"%h %an %ar %s"
# %h=短哈希 %an=作者名 %ar=相对时间 %s=提交信息
5.4 查看某次提交
bash
# 查看最新提交的详情
git show
# 查看指定提交
git show abc1234
# 查看某次提交修改了哪些文件
git show --stat abc1234
# 查看某次提交中某个文件的内容
git show abc1234:src/main.c
6. 分支管理
6.1 分支基本操作
bash
# 查看所有本地分支
git branch
# 查看所有分支(包含远程)
git branch -a
# 查看分支详情(含最新提交)
git branch -v
# 查看已合并到当前分支的分支
git branch --merged
# 查看未合并到当前分支的分支
git branch --no-merged
# 创建分支
git branch feature/login
# 切换分支
git checkout feature/login
git switch feature/login # Git 2.23+ 推荐
# 创建并切换(一步到位)
git checkout -b feature/login
git switch -c feature/login # Git 2.23+ 推荐
# 基于某个提交/标签创建分支
git checkout -b hotfix/v1.2 v1.2.0
# 重命名分支
git branch -m old-name new-name
# 删除已合并的分支
git branch -d feature/login
# 强制删除分支(未合并也删)
git branch -D feature/login
6.2 分支工作流案例
bash
# 典型功能开发流程
git checkout main
git pull origin main # 确保本地是最新的
git checkout -b feature/user-auth # 创建功能分支
# ... 开发代码 ...
git add .
git commit -m "feat: 添加用户认证模块"
git commit -m "test: 添加认证单元测试"
git push origin feature/user-auth # 推送到远程
# 在 GitHub/GitLab 上创建 Pull Request / Merge Request
# 代码审查通过后合并到 main
# 合并后清理
git checkout main
git pull origin main
git branch -d feature/user-auth # 删除本地分支
git push origin --delete feature/user-auth # 删除远程分支
6.3 HEAD 与分支指针
bash
# 查看 HEAD 指向
cat .git/HEAD
# 输出:ref: refs/heads/main
# 分离 HEAD(直接指向某个提交)
git checkout abc1234
# 警告:You are in 'detached HEAD' state
# 从分离 HEAD 状态创建新分支(保存工作)
git checkout -b new-branch
# 切回分支(放弃分离HEAD状态的提交)
git checkout main
7. 合并与变基
7.1 Merge(合并)
bash
# 将 feature 分支合并到当前分支
git merge feature/login
# 强制生成合并提交(即使可以快进)
git merge --no-ff feature/login
# 快进合并(不生成合并提交,默认行为)
git merge --ff-only feature/login
# 合并但不提交(先查看合并结果)
git merge --no-commit feature/login
# 压缩合并(将feature的所有提交压缩为一个)
git merge --squash feature/login
git commit -m "feat: 合并用户登录功能"
Merge 的两种模式图解:
快进合并(Fast-forward):
main: A → B
feature: → C → D
合并后:
main: A → B → C → D
(没有合并提交,历史是线性的)
非快进合并(--no-ff):
main: A → B
feature: → C → D
合并后:
main: A → B ────────→ M(合并提交)
↗
feature: C → D
(保留了分支信息)
7.2 Rebase(变基)
bash
# 将当前分支变基到 main
git rebase main
# 变基到远程 main
git rebase origin/main
# 交互式变基(整理最近4个提交)
git rebase -i HEAD~4
# 变基过程中的操作
git rebase --continue # 解决冲突后继续
git rebase --skip # 跳过当前提交
git rebase --abort # 放弃变基,恢复原状
交互式变基(rebase -i)的操作指令:
pick → 保留该提交(默认)
reword → 保留提交,但修改提交信息
edit → 保留提交,但暂停以便修改
squash → 将该提交合并到前一个提交(合并提交信息)
fixup → 将该提交合并到前一个提交(丢弃提交信息)
drop → 删除该提交
案例:整理提交历史
bash
# 场景:开发过程中产生了很多零碎提交,推送前想整理
git log --oneline
# abc1234 fix typo
# def5678 fix another typo
# ghi9012 add login feature
# jkl3456 WIP: login
# 整理最近4个提交
git rebase -i HEAD~4
# 编辑器中修改为:
# pick jkl3456 WIP: login
# squash ghi9012 add login feature
# squash def5678 fix another typo
# squash abc1234 fix typo
# 保存后,Git 会将4个提交合并为1个
# 并让你编写新的提交信息
7.3 Merge vs Rebase 选择指南
┌──────────────────┬──────────────────┬──────────────────┐
│ 场景 │ 推荐方式 │ 原因 │
├──────────────────┼──────────────────┼──────────────────┤
│ 同步main到功能分支│ rebase │ 保持线性历史 │
│ 功能分支合入main │ merge --no-ff │ 保留分支信息 │
│ 已push的提交 │ 永远不要rebase │ 会重写远程历史 │
│ 个人分支整理 │ rebase -i │ 推送前清理历史 │
│ 紧急修复 │ merge │ 快速且保留上下文 │
└──────────────────┴──────────────────┴──────────────────┘
黄金法则:
✅ 个人分支(未push)→ 随意使用 rebase
✅ 公共分支(已push)→ 只用 merge,禁止 rebase
7.4 解决合并冲突
bash
# 冲突文件内容示例
<<<<<<< HEAD
const user = { name: 'Alice', age: 25 };
=======
const user = { name: 'Bob', age: 30 };
>>>>>>> feature/update-user
# <<<<<<< HEAD 到 ======= 是当前分支的内容
# ======= 到 >>>>>>> 是要合并进来的内容
# 解决步骤:
# 1. 打开冲突文件,手动编辑保留正确内容
# 2. 删除所有冲突标记(<<<, ===, >>>)
# 3. 暂存已解决的文件
git add src/user.js
# 4. 继续合并/变基
git merge --continue # 或
git rebase --continue
# 查看冲突文件列表
git diff --name-only --diff-filter=U
# 使用工具解决冲突
git mergetool # 使用配置的合并工具
8. 远程仓库
8.1 远程仓库管理
bash
# 查看远程仓库
git remote -v
# 添加远程仓库
git remote add origin https://github.com/user/repo.git
# 添加多个远程仓库
git remote add upstream https://github.com/original/repo.git
# 修改远程仓库地址
git remote set-url origin https://github.com/user/new-repo.git
# 删除远程仓库
git remote remove upstream
# 重命名远程仓库
git remote rename origin upstream
8.2 fetch / pull / push
bash
# ── fetch:只下载,不合并 ──────────────────────────
git fetch origin # 获取所有远程分支的更新
git fetch origin main # 只获取 main 分支的更新
git fetch --all # 获取所有远程仓库的更新
# ── pull:下载并合并 ──────────────────────────────
git pull # = fetch + merge
git pull origin main # 拉取远程 main 并合并
git pull --rebase # = fetch + rebase(推荐)
git pull --rebase origin main
# ── push:推送到远程 ──────────────────────────────
git push origin main # 推送 main 分支
git push origin HEAD # 推送当前分支(推荐写法)
git push -u origin feature # 首次推送并设置跟踪
git push --all # 推送所有分支
git push --tags # 推送所有标签
# 强制推送(rebase后使用,慎用!)
git push --force origin feature
git push --force-with-lease origin feature # 更安全的强制推送
fetch vs pull 的区别:
git fetch:
远程仓库 → origin/main(远程跟踪分支)
本地 main 分支不变,安全!
git pull:
远程仓库 → origin/main → main(自动合并)
相当于 git fetch + git merge origin/main
推荐习惯:
重要分支先 fetch,检查后再手动 merge
个人分支直接 pull --rebase
8.3 远程分支操作
bash
# 查看远程分支
git branch -r
# 跟踪远程分支(创建本地分支并关联)
git checkout -b feature origin/feature
git checkout --track origin/feature # 简写
# 设置已有分支的跟踪关系
git branch -u origin/main main
git branch --set-upstream-to=origin/main main
# 删除远程分支
git push origin --delete feature/old-branch
git push origin :feature/old-branch # 等价写法
# 清理本地失效的远程分支引用
git fetch --prune
git remote prune origin
8.4 SSH 配置
bash
# 生成 SSH 密钥
ssh-keygen -t ed25519 -C "your_email@example.com"
# 查看公钥(复制到 GitHub/GitLab)
cat ~/.ssh/id_ed25519.pub
# 测试 SSH 连接
ssh -T git@github.com
# 使用 SSH 克隆
git clone git@github.com:user/repo.git
# 切换已有仓库的协议(HTTPS → SSH)
git remote set-url origin git@github.com:user/repo.git
9. 撤销与回退
9.1 撤销工作区修改
bash
# 丢弃工作区中某个文件的修改(恢复到暂存区状态)
git checkout -- src/main.c
git restore src/main.c # Git 2.23+ 推荐
# 丢弃工作区所有修改
git checkout -- .
git restore .
# 删除未跟踪的文件(预览)
git clean -nd
# 删除未跟踪的文件(执行)
git clean -fd
# 删除未跟踪的文件和目录(包含 .gitignore 忽略的文件)
git clean -fdx
9.2 撤销暂存区(取消 add)
bash
# 取消暂存某个文件(保留工作区修改)
git reset HEAD src/main.c
git restore --staged src/main.c # Git 2.23+ 推荐
# 取消暂存所有文件
git reset HEAD .
git restore --staged .
9.3 reset(重置提交)
bash
# 三种模式对比
git reset --soft HEAD~1 # 撤销提交,保留暂存区和工作区
git reset HEAD~1 # 撤销提交,清空暂存区,保留工作区(默认)
git reset --hard HEAD~1 # 撤销提交,清空暂存区和工作区(危险!)
# 回退到指定提交
git reset --hard abc1234
# 将本地重置为与远程完全一致
git fetch origin
git reset --hard origin/main
# 后悔了?撤销 reset(ORIG_HEAD 保存了 reset 前的状态)
git reset --hard ORIG_HEAD
reset 三种模式图解:
初始状态:
仓库: A → B → C(HEAD)
暂存区: C的内容
工作区: C的内容(可能有修改)
git reset --soft HEAD~1:
仓库: A → B(HEAD)
暂存区: C的内容(保留!)
工作区: 不变
→ 适合:重新提交(修改提交信息或合并提交)
git reset HEAD~1(--mixed):
仓库: A → B(HEAD)
暂存区: B的内容(清空C的暂存)
工作区: 不变(C的修改还在)
→ 适合:重新整理后提交
git reset --hard HEAD~1:
仓库: A → B(HEAD)
暂存区: B的内容
工作区: B的内容(C的所有修改丢失!)
→ 适合:彻底放弃某次提交
9.4 revert(安全撤销)
bash
# 创建一个新提交来撤销指定提交(安全,不改写历史)
git revert abc1234
# 撤销最近一次提交
git revert HEAD
# 撤销多个提交(不自动提交,手动提交)
git revert --no-commit HEAD~3..HEAD
git commit -m "revert: 撤销最近3次提交"
# 撤销合并提交(需要指定保留哪个父提交)
git revert -m 1 abc1234 # -m 1 表示保留第一个父提交(main分支)
reset vs revert 选择:
git reset:
✅ 本地未push的提交
✅ 个人分支
❌ 已push到公共分支(会导致历史不一致)
git revert:
✅ 已push到公共分支
✅ 需要保留完整历史记录
✅ 团队协作场景
9.5 reflog(后悔药)
bash
# 查看所有操作记录(包括已删除的提交)
git reflog
# 输出示例:
# abc1234 HEAD@{0}: commit: feat: 添加登录
# def5678 HEAD@{1}: reset: moving to HEAD~1
# ghi9012 HEAD@{2}: commit: fix: 修复bug
# 恢复到某个状态
git reset --hard HEAD@{2}
# 恢复误删的分支
git checkout -b recovered-branch abc1234
10. 标签管理
10.1 创建标签
bash
# 轻量标签(只是一个指向提交的指针)
git tag v1.0.0
# 附注标签(包含标签信息、作者、日期)
git tag -a v1.0.0 -m "Release version 1.0.0"
# 给历史提交打标签
git tag -a v0.9.0 abc1234 -m "Beta release"
# 查看所有标签
git tag
# 查看标签详情
git show v1.0.0
10.2 推送和删除标签
bash
# 推送单个标签
git push origin v1.0.0
# 推送所有标签
git push origin --tags
# 删除本地标签
git tag -d v1.0.0
# 删除远程标签
git push origin --delete v1.0.0
git push origin :refs/tags/v1.0.0 # 等价写法
# 检出标签(进入分离HEAD状态)
git checkout v1.0.0
# 基于标签创建分支
git checkout -b hotfix/v1.0 v1.0.0
11. 储藏(Stash)
11.1 基本操作
bash
# 储藏当前工作区修改
git stash
# 储藏并添加描述
git stash push -m "WIP: 用户登录功能"
# 储藏包含未跟踪文件
git stash push -u -m "包含新文件的储藏"
# 查看所有储藏
git stash list
# 输出:
# stash@{0}: WIP on feature: abc1234 WIP: 用户登录功能
# stash@{1}: WIP on main: def5678 fix: 修复bug
# 恢复最新储藏(并从列表删除)
git stash pop
# 恢复指定储藏(不删除)
git stash apply stash@{1}
# 删除指定储藏
git stash drop stash@{0}
# 清空所有储藏
git stash clear
11.2 实战案例
bash
# 场景:正在开发功能,突然需要切换分支修复紧急bug
# 1. 储藏当前工作
git stash push -m "WIP: 用户登录功能开发中"
# 2. 切换到 main 分支修复 bug
git checkout main
git checkout -b hotfix/payment-bug
# ... 修复 bug ...
git commit -m "fix: 修复支付重复扣款问题"
git push origin hotfix/payment-bug
# 3. 回到功能分支,恢复工作
git checkout feature/user-login
git stash pop
# 如果恢复时有冲突,解决后手动删除 stash
git stash drop
12. 高级操作
12.1 Cherry-pick(精选提交)
bash
# 将某个提交应用到当前分支
git cherry-pick abc1234
# 应用多个提交
git cherry-pick abc1234 def5678
# 应用一个范围的提交(不含起点)
git cherry-pick abc1234..def5678
# 应用但不自动提交
git cherry-pick --no-commit abc1234
# 冲突后继续
git cherry-pick --continue
# 放弃 cherry-pick
git cherry-pick --abort
案例:从其他分支摘取特定修复
bash
# 场景:同事在 develop 分支修复了一个 bug(提交 abc1234)
# 你需要把这个修复应用到 release 分支,但不想合并整个 develop
git checkout release/v1.2
git cherry-pick abc1234
# 只把那一个 bugfix 提交应用到 release 分支
12.2 Bisect(二分查找 Bug)
bash
# 场景:某个功能在某次提交后出现了 bug,需要找到是哪次提交引入的
# 开始二分查找
git bisect start
# 标记当前版本是坏的
git bisect bad
# 标记某个已知正常的版本
git bisect good v1.0.0
# Git 会自动切换到中间的提交,你测试后标记
git bisect good # 这个版本正常
git bisect bad # 这个版本有问题
# Git 会不断缩小范围,最终找到引入 bug 的提交
# 找到后重置
git bisect reset
# 自动化二分查找(用脚本判断好坏)
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test.sh # 脚本返回0=good,非0=bad
12.3 Worktree(多工作区)
bash
# 场景:在 feature 分支开发时,需要同时查看/修改 main 分支
# 创建新工作区(检出 hotfix 分支)
git worktree add ../project-hotfix hotfix/login-bug
# 创建新工作区并新建分支
git worktree add -b emergency-fix ../project-fix main
# 查看所有工作区
git worktree list
# 删除工作区
git worktree remove ../project-hotfix
# 清理失效的工作区引用
git worktree prune
12.4 Submodule(子模块)
bash
# 添加子模块
git submodule add https://github.com/user/lib.git libs/mylib
# 克隆含子模块的仓库
git clone --recurse-submodules https://github.com/user/repo.git
# 初始化子模块(克隆后忘记加 --recurse-submodules)
git submodule init
git submodule update
# 更新所有子模块到最新
git submodule update --remote
# 删除子模块
git submodule deinit libs/mylib
git rm libs/mylib
rm -rf .git/modules/libs/mylib
12.5 Git Hooks(钩子)
bash
# 钩子存放在 .git/hooks/ 目录
# 常用钩子:
# pre-commit → 提交前执行(代码检查、格式化)
# commit-msg → 验证提交信息格式
# pre-push → 推送前执行(运行测试)
# post-merge → 合并后执行(安装依赖)
# 示例:pre-commit 钩子(代码格式检查)
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
# 运行代码格式检查
npm run lint
if [ $? -ne 0 ]; then
echo "❌ 代码格式检查失败,请修复后再提交"
exit 1
fi
echo "✅ 代码格式检查通过"
EOF
chmod +x .git/hooks/pre-commit
# 示例:commit-msg 钩子(验证提交信息格式)
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/sh
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore|perf|ci)(\(.+\))?: .{1,72}$"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "❌ 提交信息格式错误!"
echo "正确格式:feat(scope): 描述"
exit 1
fi
EOF
chmod +x .git/hooks/commit-msg
12.6 Blame(追责)
bash
# 查看文件每一行的最后修改者
git blame src/main.c
# 只查看某几行
git blame -L 10,20 src/main.c
# 忽略空白字符变化
git blame -w src/main.c
# 显示原始提交(追踪代码移动)
git blame -C src/main.c
12.7 Archive(打包)
bash
# 将当前版本打包为 zip
git archive --format=zip HEAD > release.zip
# 打包指定标签
git archive --format=tar.gz v1.0.0 > v1.0.0.tar.gz
# 只打包某个目录
git archive HEAD src/ | tar -x -C /tmp/
13. Git 工作流
13.1 GitFlow 工作流
适合:有明确版本发布周期的项目
分支结构:
main → 生产环境,只接受 hotfix 和 release 合并
develop → 开发主干,功能分支的集成点
feature/* → 功能开发分支(从 develop 创建)
release/* → 发布准备分支(从 develop 创建)
hotfix/* → 紧急修复分支(从 main 创建)
流程:
1. 从 develop 创建 feature 分支开发
2. 完成后合并回 develop
3. 从 develop 创建 release 分支
4. release 分支只做 bug 修复和文档
5. release 合并到 main(打标签)和 develop
6. 线上 bug 从 main 创建 hotfix 分支
7. hotfix 合并到 main 和 develop
bash
# GitFlow 实践
# 开始新功能
git checkout develop
git checkout -b feature/user-auth
# 完成功能
git checkout develop
git merge --no-ff feature/user-auth
git branch -d feature/user-auth
# 准备发布
git checkout -b release/v1.2.0 develop
# 修复发布相关问题...
git checkout main
git merge --no-ff release/v1.2.0
git tag -a v1.2.0 -m "Release v1.2.0"
git checkout develop
git merge --no-ff release/v1.2.0
git branch -d release/v1.2.0
# 紧急修复
git checkout -b hotfix/v1.2.1 main
# 修复...
git checkout main
git merge --no-ff hotfix/v1.2.1
git tag -a v1.2.1 -m "Hotfix v1.2.1"
git checkout develop
git merge --no-ff hotfix/v1.2.1
git branch -d hotfix/v1.2.1
13.2 GitHub Flow(简化工作流)
适合:持续部署、小团队、Web 应用
规则:
1. main 分支始终可部署
2. 从 main 创建描述性分支名
3. 频繁推送到远程同名分支
4. 随时创建 Pull Request 讨论
5. 审查通过后合并到 main
6. 合并后立即部署
bash
# GitHub Flow 实践
git checkout main
git pull origin main
git checkout -b feature/add-payment
# 开发...
git add .
git commit -m "feat: 添加支付功能"
git push origin feature/add-payment
# 在 GitHub 创建 Pull Request
# 团队审查代码
# 审查通过后合并到 main
# 自动触发 CI/CD 部署
# 清理
git checkout main
git pull origin main
git branch -d feature/add-payment
13.3 Trunk-Based Development
适合:高频发布、大型团队、DevOps 成熟的团队
规则:
1. 所有开发者频繁合并到 main(每天至少一次)
2. 功能分支生命周期不超过 2 天
3. 使用 Feature Flag 控制未完成功能
4. 强大的 CI/CD 保障质量
14. 常见问题与解决方案
14.1 误操作恢复
bash
# 问题1:误删分支,如何恢复?
git reflog # 找到分支最后的提交哈希
git checkout -b recovered abc1234 # 基于该提交重建分支
# 问题2:reset --hard 后想恢复
git reflog # 找到 reset 前的状态
git reset --hard HEAD@{1} # 恢复到 reset 前
# 问题3:误提交了敏感信息(密码/密钥)
# 方法1:修改最后一次提交(未push)
git commit --amend # 删除敏感信息后重新提交
# 方法2:已push,需要重写历史(危险!需通知团队)
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch config/secrets.json' \
--prune-empty --tag-name-filter cat -- --all
git push --force --all
# 更好的方法:使用 git-filter-repo 工具
pip install git-filter-repo
git filter-repo --path config/secrets.json --invert-paths
14.2 常见错误处理
bash
# 错误:push 被拒绝(远程有新提交)
# ! [rejected] main -> main (fetch first)
git pull --rebase origin main # 先拉取再推送
git push origin main
# 错误:合并冲突无法解决,想放弃
git merge --abort # 放弃合并
git rebase --abort # 放弃变基
# 错误:.gitignore 不生效
git rm -r --cached . # 清除缓存
git add .
git commit -m "fix: update .gitignore"
# 错误:提交到了错误的分支
# 场景:本应提交到 feature,却提交到了 main
git log --oneline -3 # 找到误提交的哈希
git checkout feature
git cherry-pick abc1234 # 把提交移到正确分支
git checkout main
git reset --hard HEAD~1 # 从 main 删除该提交
# 错误:大文件提交导致 push 失败
# 使用 Git LFS(Large File Storage)
git lfs install
git lfs track "*.psd"
git lfs track "*.zip"
git add .gitattributes
git add large-file.psd
git commit -m "add large file via LFS"
14.3 性能优化
bash
# 清理仓库(删除无用对象)
git gc
# 深度清理
git gc --aggressive --prune=now
# 查看仓库大小
git count-objects -vH
# 找出大文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sort -k3 -n -r | head -20
15. 命令速查表
基础操作
bash
git init # 初始化仓库
git clone <url> # 克隆仓库
git status # 查看状态
git add <file> # 暂存文件
git add . # 暂存所有
git commit -m "msg" # 提交
git log --oneline --graph # 查看历史
git diff # 查看未暂存的修改
git diff --staged # 查看已暂存的修改
分支操作
bash
git branch # 查看分支
git branch <name> # 创建分支
git checkout <name> # 切换分支
git checkout -b <name> # 创建并切换
git merge <branch> # 合并分支
git branch -d <name> # 删除分支
git branch -D <name> # 强制删除
远程操作
bash
git remote -v # 查看远程
git remote add origin <url> # 添加远程
git fetch origin # 获取远程更新
git pull origin main # 拉取并合并
git push origin main # 推送
git push -u origin HEAD # 首次推送并跟踪
git push --force-with-lease # 安全强制推送
撤销操作
bash
git restore <file> # 丢弃工作区修改
git restore --staged <file> # 取消暂存
git reset --soft HEAD~1 # 撤销提交(保留暂存)
git reset HEAD~1 # 撤销提交(保留工作区)
git reset --hard HEAD~1 # 彻底撤销提交
git revert HEAD # 安全撤销(创建新提交)
git reflog # 查看操作历史(后悔药)
高级操作
bash
git stash # 储藏修改
git stash pop # 恢复储藏
git cherry-pick <hash> # 精选提交
git rebase main # 变基
git rebase -i HEAD~3 # 交互式变基
git bisect start/good/bad # 二分查找bug
git blame <file> # 查看行修改者
git tag -a v1.0 -m "msg" # 创建标签
git worktree add <path> # 添加工作区
实用别名配置
bash
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.undo "reset HEAD~1 --mixed"
git config --global alias.unstage "restore --staged"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.aliases "config --get-regexp alias"
附录:Git 学习路线
入门阶段:
✅ git init / clone
✅ git add / commit / push / pull
✅ git status / log / diff
✅ 基本分支操作(branch / checkout / merge)
进阶阶段:
✅ rebase(变基)
✅ reset / revert(撤销)
✅ stash(储藏)
✅ cherry-pick(精选)
✅ 远程仓库管理
✅ 解决合并冲突
高级阶段:
✅ 交互式 rebase(rebase -i)
✅ bisect(二分查找)
✅ worktree(多工作区)
✅ submodule(子模块)
✅ hooks(钩子)
✅ reflog(操作历史)
✅ Git 工作流设计
精通阶段:
✅ Git 内部原理(对象模型)
✅ 自定义 Git 命令
✅ Git LFS(大文件管理)
✅ 历史重写(filter-branch / filter-repo)
✅ 团队 Git 规范制定
💡 核心原则总结:
- 频繁提交,小步前进 --- 每个提交只做一件事
- 个人分支随意折腾,公共分支只做加法 --- 已push的不要rebase
- 用 rebase 同步,用 merge 合并 --- 保持历史整洁
- 危险操作前先备份 ---
git checkout -b backup_$(date +%Y%m%d)- reflog 是最后的救命稻草 --- 几乎所有误操作都能恢复