团队协作的核心 - 分支管理与工作流程
# 工作区 → 暂存区
git add file.txt
git add .
# 暂存区 → 本地仓库
git commit -m "提交说明"
# 工作区 → 本地仓库(跳过暂存区)
git commit -am "提交说明"
# 本地仓库 → 远程仓库
git push origin main
# 撤销工作区修改
git checkout -- file.txt
git restore file.txt
# 撤销暂存区
git reset HEAD file.txt
git restore --staged file.txt
# 撤销提交
git reset --soft HEAD~1 # 保留工作区和暂存区
git reset --mixed HEAD~1 # 保留工作区
git reset --hard HEAD~1 # 全部撤销| 分支类型 | 命名规范 | 用途 | 示例 |
|---|---|---|---|
| 主分支 | main / master | 生产环境代码 | main |
| 开发分支 | develop | 开发主线 | develop |
| 功能分支 | feature/* | 新功能开发 | feature/user-login |
| 修复分支 | bugfix/* | 修复 bug | bugfix/fix-null-pointer |
| 热修复分支 | hotfix/* | 紧急修复生产 bug | hotfix/fix-payment |
| 发布分支 | release/* | 准备发布 | release/v1.2.0 |
feature/PROJ-123-user-login# 创建并切换分支
git checkout -b feature/user-login
git switch -c feature/user-login
# 查看所有分支
git branch -a
# 删除分支
git branch -d feature/user-login
git push origin --delete feature/user-login一套基于 Git 的分支管理规范,适合有明确发布周期的项目。
# 1. 开发新功能
git checkout develop
git checkout -b feature/user-profile
# ... 开发代码 ...
git add .
git commit -m "feat: add user profile page"
git checkout develop
git merge --no-ff feature/user-profile
git branch -d feature/user-profile
# 2. 准备发布
git checkout develop
git checkout -b release/v1.2.0
# ... 修复 bug、更新版本号 ...
git commit -m "chore: bump version to 1.2.0"
# 3. 发布到生产
git checkout master
git merge --no-ff release/v1.2.0
git tag -a v1.2.0 -m "Release version 1.2.0"
git checkout develop
git merge --no-ff release/v1.2.0
git branch -d release/v1.2.0
# 4. 紧急修复
git checkout master
git checkout -b hotfix/fix-payment
# ... 修复代码 ...
git commit -m "fix: resolve payment error"
git checkout master
git merge --no-ff hotfix/fix-payment
git tag -a v1.2.1 -m "Hotfix 1.2.1"
git checkout develop
git merge --no-ff hotfix/fix-payment
git branch -d hotfix/fix-payment| 维度 | Git Flow | GitHub Flow |
|---|---|---|
| 主分支 | master + develop | 仅 main |
| 复杂度 | 高(5 种分支) | 低(2 种分支) |
| 发布周期 | 固定周期 | 持续部署 |
| 适用场景 | 传统软件、移动应用 | Web 应用、SaaS |
| 团队规模 | 大型团队 | 中小型团队 |
# 1. 从 main 创建分支
git checkout main
git pull origin main
git checkout -b feature/add-search
# 2. 开发并提交
git add .
git commit -m "feat: implement search"
git push origin feature/add-search
# 3. 创建 Pull Request
# 4. Code Review
# 5. 合并到 main
# 6. 自动部署将两个分支的修改合并,创建一个新的合并提交。
git checkout main
git merge feature/new-feature
git merge --no-ff feature/new-feature # 保留分支历史将当前分支的提交"移动"到目标分支之后,形成线性历史。
git checkout feature/new-feature
git rebase main
# 交互式 rebase
git rebase -i HEAD~3| 维度 | merge | rebase |
|---|---|---|
| 历史记录 | 保留完整分支历史 | 线性历史 |
| 提交记录 | 产生合并提交 | 不产生额外提交 |
| 冲突解决 | 一次性解决 | 可能多次解决 |
| 安全性 | 安全 | 改变历史,需谨慎 |
永远不要 rebase 已推送到远程的公共分支!
将其他分支的特定提交应用到当前分支。
# 挑选单个提交
git cherry-pick
# 挑选多个提交
git cherry-pick
# 挑选连续提交(不包含 start)
git cherry-pick ..
# 挑选连续提交(包含 start)
git cherry-pick ^..
# 只应用修改,不自动提交
git cherry-pick -n
# 继续/放弃
git cherry-pick --continue
git cherry-pick --abort # 场景:将 develop 的 bug 修复应用到 release
git checkout release/v1.2.0
git log develop --oneline | grep "fix"
# 找到:a1b2c3d fix: resolve payment issue
git cherry-pick a1b2c3d
# 如果有冲突
# 1. 手动解决冲突
# 2. git add .
# 3. git cherry-pick --continue可以修改、合并、删除、重新排序历史提交。
# 修改最近 3 个提交
git rebase -i HEAD~3
# 从某个提交开始
git rebase -i pick a1b2c3d feat: add login
pick d4e5f6g fix: typo
pick h7i8j9k feat: add logout
# 命令说明:
# p, pick = 使用该提交
# r, reword = 修改提交信息
# e, edit = 停下来修改
# s, squash = 合并到前一个提交
# f, fixup = 合并但丢弃提交信息
# d, drop = 删除该提交# 场景:合并多个小提交
git log --oneline
# a1b2c3d feat: add login
# d4e5f6g fix: typo
# h7i8j9k feat: add validation
# k1l2m3n fix: another typo
git rebase -i HEAD~4
# 修改为:
pick a1b2c3d feat: add login
fixup d4e5f6g fix: typo
pick h7i8j9k feat: add validation
fixup k1l2m3n fix: another typo
# 保存后历史变为:
# a1b2c3d feat: add login
# h7i8j9k feat: add validation临时保存工作区和暂存区的修改,让工作区变干净。
# 保存当前修改
git stash
git stash save "WIP: feature X"
# 保存包括未跟踪文件
git stash -u
# 查看 stash 列表
git stash list
# 查看 stash 内容
git stash show
git stash show -p stash@{0}
# 恢复 stash
git stash pop # 恢复并删除
git stash apply # 恢复但保留
git stash apply stash@{1} # 恢复指定 stash
# 删除 stash
git stash drop stash@{0}
git stash clear# 场景:正在开发,突然需要修复紧急 bug
git stash save "WIP: user profile"
git checkout main
git checkout -b hotfix/urgent-bug
# ... 修复 bug ...
git checkout feature/user-profile
git stash pop# 创建轻量标签
git tag v1.0.0
# 创建附注标签(推荐)
git tag -a v1.0.0 -m "Release version 1.0.0"
# 为历史提交打标签
git tag -a v0.9.0 -m "Version 0.9.0"
# 查看所有标签
git tag
git tag -l "v1.*"
# 查看标签详情
git show v1.0.0
# 推送标签
git push origin v1.0.0
git push origin --tags
# 删除标签
git tag -d v1.0.0
git push origin --delete v1.0.0 遵循 SemVer:主版本号.次版本号.修订号
记录所有 HEAD 的变动历史,即使提交被删除也能找回。
# 查看所有操作历史
git reflog
# 查看特定分支
git reflog show main
# 输出示例:
# a1b2c3d HEAD@{0}: commit: feat: add feature
# d4e5f6g HEAD@{1}: checkout: moving from main
# h7i8j9k HEAD@{2}: reset: moving to HEAD~1# 场景1:误用 git reset --hard
git reflog
# 找到:a1b2c3d HEAD@{3}: commit: important
git reset --hard a1b2c3d
# 场景2:误删分支
git branch -D feature/important
git reflog
# 找到:d4e5f6g HEAD@{5}: commit: last commit
git checkout -b feature/important d4e5f6g
# 场景3:误用 rebase
git reflog
# 找到 rebase 前:h7i8j9k HEAD@{10}
git reset --hard h7i8j9k# 查看配置
git config --get gc.reflogExpire # 默认 90 天
# 修改过期时间
git config gc.reflogExpire "180 days"允许在一个 Git 仓库中嵌入另一个 Git 仓库。
# 添加子模块
git submodule add
git submodule add https://github.com/user/lib.git libs/mylib
# 初始化和更新
git submodule init
git submodule update
# 克隆包含子模块的项目
git clone --recursive # 更新所有子模块
git submodule update --remote
# 更新特定子模块
git submodule update --remote libs/mylib
# 进入子模块更新
cd libs/mylib
git pull origin main
cd ../..
git add libs/mylib
git commit -m "chore: update submodule"# 1. 删除 .gitmodules 配置
git config -f .gitmodules --remove-section submodule.libs/mylib
# 2. 删除 .git/config 配置
git config -f .git/config --remove-section submodule.libs/mylib
# 3. 删除目录
git rm --cached libs/mylib
rm -rf libs/mylib
# 4. 删除 .git/modules
rm -rf .git/modules/libs/mylib
# 5. 提交
git commit -m "chore: remove submodule"指定 Git 应该忽略的文件和目录。
# 注释
# 忽略所有 .log 文件
*.log
# 忽略特定文件
config.local.js
# 忽略目录
node_modules/
dist/
# 不忽略特定文件
!important.log
# 忽略 doc 目录下所有 .pdf
doc/**/*.pdf
# 只忽略当前目录的 TODO
/TODO
# 忽略任意目录下的 TODO
TODO# Java 项目
*.class
*.jar
*.war
target/
.idea/
*.iml
# Node.js 项目
node_modules/
npm-debug.log
.env
dist/
# Python 项目
__pycache__/
*.py[cod]
venv/
.env# 从 Git 删除但保留本地文件
git rm --cached
git rm -r --cached
# 示例
echo ".env" >> .gitignore
git rm --cached .env
git commit -m "chore: ignore .env" 使用二分查找算法定位引入 bug 的提交,时间复杂度 O(log n)。
# 1. 开始 bisect
git bisect start
# 2. 标记当前版本为坏版本
git bisect bad
# 3. 标记已知的好版本
git bisect good
# 4. Git 自动切换到中间提交,测试后标记
git bisect bad # 如果有 bug
git bisect good # 如果没有 bug
# 5. 重复步骤 4,直到找到第一个坏提交
# 6. 结束 bisect
git bisect reset # 使用脚本自动测试
git bisect start HEAD v1.0.0
git bisect run ./test.sh
# test.sh 示例
#!/bin/bash
npm test
exit $?# 场景:v1.5.0 有 bug,v1.0.0 没有
git bisect start
git bisect bad v1.5.0
git bisect good v1.0.0
# Git 输出:Bisecting: 50 revisions left
# 测试当前版本
npm run test
git bisect bad # 或 good
# 最终输出:
# a1b2c3d is the first bad commit
git show a1b2c3d
git bisect reset在 Git 操作的特定时刻自动执行的脚本。
| Hook | 触发时机 | 用途 |
|---|---|---|
| pre-commit | commit 之前 | 代码检查、格式化 |
| commit-msg | 提交信息编辑后 | 验证提交信息格式 |
| post-commit | 提交完成后 | 通知、统计 |
| pre-push | push 之前 | 运行测试 |
#!/bin/bash
# .git/hooks/pre-commit
# 运行 ESLint
echo "Running ESLint..."
npm run lint
if [ $? -ne 0 ]; then
echo "ESLint failed. Commit aborted."
exit 1
fi
# 运行测试
echo "Running tests..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Commit aborted."
exit 1
fi
exit 0#!/bin/bash
# .git/hooks/commit-msg
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "Error: Commit message format incorrect"
echo "Expected: type(scope): subject"
exit 1
fi
exit 0# 安装 Husky
npm install husky --save-dev
npx husky install
# 添加 pre-commit hook
npx husky add .husky/pre-commit "npm run lint && npm test"
# 跳过 hooks
git commit --no-verify -m "message"格式:():
类型(type):
- feat: 新功能
- fix: 修复 bug
- docs: 文档更新
- style: 代码格式
- refactor: 重构
- test: 测试相关
- chore: 构建/工具更新
- perf: 性能优化
示例:
feat(auth): add JWT authentication
fix(payment): resolve null pointer exception
docs(readme): update installation guide # 1. 创建功能分支
git checkout -b feature/PROJ-123-user-profile
# 2. 开发并提交
git add .
git commit -m "feat(user): add profile page"
# 3. 推送到远程
git push origin feature/PROJ-123-user-profile
# 4. 创建 Pull Request
# 5. 等待 Code Review
# 6. 根据反馈修改
# 7. 通过后合并到 develop