← 返回面试总览

🌱 Git 工作流与分支策略面试题

团队协作的核心 - 分支管理与工作流程

📚 Git 工作流与分支策略

1. Git 的三个工作区域是什么?它们之间如何转换?简单

三个工作区域

  • 工作区(Working Directory):你实际编辑文件的目录
  • 暂存区(Staging Area / Index):临时存放即将提交的修改
  • 本地仓库(Repository):Git 保存的完整历史记录

转换命令

# 工作区 → 暂存区
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   # 全部撤销
2. 常见的 Git 分支命名规范有哪些?简单

分支类型

分支类型命名规范用途示例
主分支main / master生产环境代码main
开发分支develop开发主线develop
功能分支feature/*新功能开发feature/user-login
修复分支bugfix/*修复 bugbugfix/fix-null-pointer
热修复分支hotfix/*紧急修复生产 bughotfix/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
3. 什么是 Git Flow 工作流?核心流程是什么?中等

Git Flow 定义

一套基于 Git 的分支管理规范,适合有明确发布周期的项目。

分支结构

  • master:生产环境,每个提交都是一个发布版本
  • develop:开发主线
  • feature/*:功能分支
  • release/*:发布分支
  • hotfix/*:热修复分支

完整流程示例

# 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
4. GitHub Flow 和 Git Flow 有什么区别?中等

GitHub Flow 原则

  • 只有一个长期分支:main
  • 所有开发从 main 创建功能分支
  • 通过 Pull Request 合并
  • 合并后立即部署

对比表格

维度Git FlowGitHub Flow
主分支master + develop仅 main
复杂度高(5 种分支)低(2 种分支)
发布周期固定周期持续部署
适用场景传统软件、移动应用Web 应用、SaaS
团队规模大型团队中小型团队

GitHub Flow 流程

# 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. 自动部署
5. git merge 和 git rebase 有什么区别?中等

git merge

将两个分支的修改合并,创建一个新的合并提交。

git checkout main
git merge feature/new-feature
git merge --no-ff feature/new-feature  # 保留分支历史

git rebase

将当前分支的提交"移动"到目标分支之后,形成线性历史。

git checkout feature/new-feature
git rebase main

# 交互式 rebase
git rebase -i HEAD~3

区别对比

维度mergerebase
历史记录保留完整分支历史线性历史
提交记录产生合并提交不产生额外提交
冲突解决一次性解决可能多次解决
安全性安全改变历史,需谨慎

黄金法则

永远不要 rebase 已推送到远程的公共分支!

6. 如何使用 git cherry-pick 挑选特定提交?中等

cherry-pick 作用

将其他分支的特定提交应用到当前分支。

基本用法

# 挑选单个提交
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
7. 如何使用 git rebase -i 整理提交历史?困难

交互式 rebase

可以修改、合并、删除、重新排序历史提交。

基本用法

# 修改最近 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
8. 什么是 git stash?如何使用?中等

stash 作用

临时保存工作区和暂存区的修改,让工作区变干净。

基本用法

# 保存当前修改
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
9. 如何使用 git tag 管理版本标签?中等

标签类型

  • 轻量标签:只是一个指向提交的引用
  • 附注标签:包含标签信息、创建者、日期(推荐)

创建标签

# 创建轻量标签
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:主版本号.次版本号.修订号

  • 主版本号:不兼容的 API 修改
  • 次版本号:向下兼容的功能新增
  • 修订号:向下兼容的问题修正
10. 如何使用 git reflog 恢复误删的提交?困难

reflog 作用

记录所有 HEAD 的变动历史,即使提交被删除也能找回。

查看 reflog

# 查看所有操作历史
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

reflog 过期时间

# 查看配置
git config --get gc.reflogExpire  # 默认 90 天

# 修改过期时间
git config gc.reflogExpire "180 days"
11. 什么是 git submodule?如何管理?中等

submodule 定义

允许在一个 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"
12. 如何配置 .gitignore 文件?中等

.gitignore 作用

指定 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"
13. 如何使用 git bisect 快速定位 bug?困难

bisect 原理

使用二分查找算法定位引入 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

自动化 bisect

# 使用脚本自动测试
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
14. 如何使用 git hooks 实现自动化?中等

Git Hooks 定义

在 Git 操作的特定时刻自动执行的脚本。

常用 Hooks

Hook触发时机用途
pre-commitcommit 之前代码检查、格式化
commit-msg提交信息编辑后验证提交信息格式
post-commit提交完成后通知、统计
pre-pushpush 之前运行测试

pre-commit 示例

#!/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

commit-msg 示例

#!/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

# 安装 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"
15. 在团队协作中如何制定 Git 规范?困难

提交信息规范(Conventional Commits)

格式:(): 

类型(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

分支管理规范

  • 保护主分支:main 和 develop 设置为受保护分支
  • 强制 Code Review:所有合并必须通过 PR
  • 自动化检查:CI/CD 自动运行测试
  • 定期清理:删除已合并的功能分支

Code Review 流程

# 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

团队协作最佳实践

  • 小步提交:每个提交只做一件事
  • 频繁同步:每天至少一次拉取主分支
  • 及时推送:完成功能后尽快推送
  • 清晰命名:分支名和提交信息要清晰
  • 文档先行:重要变更先更新文档

冲突预防

  • 模块化开发,减少多人修改同一文件
  • 使用代码格式化工具统一风格
  • 大型重构提前沟通
  • 定期 rebase 主分支