搜索 K
主题
分支是 Git 最核心的功能之一。git branch、git switch、git checkout 三个命令构成了分支管理的完整工具集。Git 2.23 之后,官方推荐使用 switch 切换分支、restore 恢复文件,替代万能但容易混淆的 checkout。
分支本质上只是一个指向提交的可移动指针,创建和切换分支几乎是零成本操作。
# 分支在磁盘上只是一个文件,内容是 40 字符的 SHA
cat .git/refs/heads/main
# abc1234def5678901234567890abcdef12345678
# HEAD 文件记录「当前在哪个分支」
cat .git/HEAD
# ref: refs/heads/feature| 概念 | 说明 |
|---|---|
| HEAD | 指向当前所在分支(或直接指向提交 = detached) |
| 分支 | 指向某个提交的可移动指针 |
| 提交 | 不可变的快照,包含父提交指针 |
| 远程分支 | origin/main 等,记录远程仓库分支的最新已知状态 |
checkout vs switch vs restore Git 2.23(2019)将 checkout 的两大职责拆分为独立命令:
| 旧命令 | 新命令 | 用途 |
|---|---|---|
git checkout <branch> | git switch <branch> | 切换分支 |
git checkout -b <branch> | git switch -c <branch> | 创建并切换 |
git checkout -- <file> | git restore <file> | 恢复文件 |
git checkout <sha> -- <file> | git restore -s <sha> <file> | 从提交恢复文件 |
switch + restorecheckout 仍然可用且不会被移除,但新命令语义更清晰,不容易误操作。例如 git checkout main 可能是切换到 main 分支,也可能是恢复名为 main 的文件——switch 和 restore 消除了这种歧义。
# 创建分支(不切换)
git branch feature/payment
# 创建并切换到新分支
git switch -c feature/payment
# 旧写法
git checkout -b feature/payment
# 从指定提交创建分支
git branch feature/payment abc1234
git switch -c feature/payment abc1234
# 从远程分支创建本地追踪分支
git switch -c feature/payment origin/feature/payment
# 简写(自动追踪同名远程分支)
git switch feature/payment
# 如果本地没有但 origin 有,Git 会自动创建追踪分支
# 从标签创建分支
git switch -c hotfix/from-v2 v2.0.0# 切换到已有分支
git switch main
# 旧写法
git checkout main
# 切换到上一个分支(类似 cd -)
git switch -
# 旧写法
git checkout -
# 切换并丢弃本地修改(危险!)
git switch -f main
# 旧写法
git checkout -f main
# 切换时自动合并本地修改
git switch --merge main-f 强制)commit 或 stash# 安全的切换流程
git stash push -m "WIP: 当前功能"
git switch main
# ... 做完事情 ...
git switch feature
git stash pop# 列出本地分支
git branch
# * main
# feature/payment
# hotfix/login
# 列出远程分支
git branch -r
# origin/main
# origin/feature/payment
# 列出所有分支(本地 + 远程)
git branch -a
# 显示每个分支的最后提交
git branch -v
# * main abc1234 feat: 最新提交
# feature/payment def5678 fix: 修复支付
# 显示详细信息(含追踪关系)
git branch -vv
# * main abc1234 [origin/main] feat: 最新提交
# feature/payment def5678 [origin/feature/payment: ahead 2] fix: 修复支付
# 按合并状态过滤
git branch --merged main # 已合并到 main 的分支
git branch --no-merged main # 未合并到 main 的分支
# 按最后提交时间排序
git branch --sort=-committerdate
# 最近修改的分支排在最前面
# 按模式过滤
git branch --list "feature/*"
git branch --list "hotfix/*"# 重命名当前分支
git branch -m new-name
# 重命名指定分支
git branch -m old-name new-name
# 同步到远程(删除旧的 + 推送新的)
git push origin --delete old-name
git push origin new-name
git push origin -u new-name # 设置追踪# 删除已合并的本地分支
git branch -d feature/payment
# 如果分支未合并,Git 会阻止删除
# 强制删除(即使未合并)
git branch -D feature/payment
# 删除远程分支
git push origin --delete feature/payment
# 或
git push origin :feature/payment
# 批量删除已合并的分支
git branch --merged main | grep -v "main\|develop" | xargs git branch -d
# 清理远程已删除但本地还有的追踪引用
git fetch --prune
# 或
git remote prune origin# 创建分支时自动追踪
git switch -c feature origin/feature
# Branch 'feature' set up to track remote branch 'feature' from 'origin'.
# 为已有分支设置追踪
git branch --set-upstream-to=origin/feature feature
# 简写
git branch -u origin/feature
# 查看追踪关系
git branch -vv
# 取消追踪
git branch --unset-upstream featuregit branch -vv
# feature abc1234 [origin/feature: ahead 3, behind 2] WIP| 状态 | 含义 |
|---|---|
ahead N | 本地比远程多 N 个提交(需要 push) |
behind N | 远程比本地多 N 个提交(需要 pull) |
ahead N, behind M | 两边都有独有提交(需要 merge/rebase) |
gone | 远程分支已被删除 |
# 功能分支
feature/payment-module
feature/user-auth
feat/JIRA-1234-add-search
# 修复分支
fix/login-timeout
bugfix/null-pointer
hotfix/critical-payment-error
# 发布分支
release/v3.0
release/2026-q1
# 其他
chore/update-dependencies
docs/api-documentation
refactor/payment-service
test/add-e2e-tests# ✅ 好的分支名
feature/user-registration # 描述性、使用连字符
fix/PROJ-456-login-crash # 包含 issue 编号
hotfix/v2.3.1-payment-fix # 包含版本信息
# ❌ 不好的分支名
my-branch # 无意义
temp # 不描述目的
Feature/Payment # 大写(不同 OS 大小写敏感不同)
feature/add new feature # 包含空格
feature/payment_module_v2_final_final # 太长Windows 和 macOS 的文件系统默认不区分大小写,但 Git 的引用区分大小写。这意味着 Feature/test 和 feature/test 在 Linux 上是两个不同的分支,但在 Windows/macOS 上会冲突。建议:统一使用小写。
# 长期分支
main # 只有正式发布的代码
develop # 开发主线,feature 合并到这里
# 短期分支
feature/* # 从 develop 创建,合并回 develop
release/* # 从 develop 创建,合并到 main + develop
hotfix/* # 从 main 创建,合并到 main + develop适用场景:有明确版本发布周期的项目(桌面软件、移动 App、大型 SaaS)
# 只有一个长期分支
main # 始终处于可部署状态
# 所有开发都在 feature 分支
# 通过 Pull Request 合并到 main
# 合并后立即部署适用场景:持续部署的 Web 应用、SaaS 服务
# 所有人直接在 main(trunk)上开发
# 使用 feature flag 控制未完成的功能
# 分支生命周期极短(< 1 天)
# 规则:
# 1. 分支最多存活 1-2 天
# 2. 小步提交,频繁集成
# 3. 使用 feature flag 隔离未完成功能
# 4. CI/CD 流水线必须在几分钟内完成适用场景:大型团队、微服务架构、Google/Facebook 等公司
# 1. 从 main 创建 feature 分支
git switch main
git pull origin main
git switch -c feature/user-profile
# 2. 开发功能(多次提交)
git add .
git commit -m "feat: 添加用户头像上传"
git add .
git commit -m "feat: 添加个人信息编辑"
# 3. 定期同步 main 的更新
git switch main
git pull origin main
git switch feature/user-profile
git rebase main
# 或
git merge main
# 4. 推送到远程
git push -u origin feature/user-profile
# 5. 创建 Pull Request → 代码审查 → 合并
# 6. 合并后清理
git switch main
git pull origin main
git branch -d feature/user-profile
git push origin --delete feature/user-profile# 1. 从 main 创建 hotfix 分支
git switch main
git pull origin main
git switch -c hotfix/fix-payment-crash
# 2. 修复 bug
git add .
git commit -m "fix: 修复支付金额精度丢失导致的崩溃"
# 3. 推送并创建 PR(或直接合并)
git push -u origin hotfix/fix-payment-crash
# 如果紧急需要直接合并:
git switch main
git merge --no-ff hotfix/fix-payment-crash
git tag -a v2.3.1 -m "Hotfix v2.3.1"
git push origin main --follow-tags
# 4. 同步到 develop(如果使用 Git Flow)
git switch develop
git merge --no-ff hotfix/fix-payment-crash
git push origin develop
# 5. 清理
git branch -d hotfix/fix-payment-crash
git push origin --delete hotfix/fix-payment-crash# 同时开发支付和通知两个功能
git switch -c feature/payment main
git switch -c feature/notification main
# 在两个功能间切换
git switch feature/payment
# 做一些工作...
git commit -m "feat: 支付逻辑"
git switch feature/notification
# 做另一些工作...
git commit -m "feat: 通知系统"
# 或使用 worktree 避免频繁切换
git worktree add ../project-payment feature/payment
git worktree add ../project-notification feature/notification详见 Git worktree
# 1. 获取别人的 PR 分支进行本地审查
git fetch origin pull/456/head:pr-456
git switch pr-456
# 2. 本地运行测试
npm test
# 3. 审查完毕切回
git switch main
git branch -D pr-456
# 或者直接 checkout 远程分支(不创建本地分支)
git switch --detach origin/feature/payment
# 审查完毕
git switch main# 查看远程已删除但本地还在的追踪引用
git fetch --prune
# 查看本地分支中哪些的远程分支已被删除
git branch -vv | grep ": gone]"
# feature/old-stuff abc1234 [origin/feature/old-stuff: gone] WIP
# 自动清理(删除远程已经 gone 的本地分支)
git branch -vv | grep ": gone]" | awk '{print $1}' | xargs git branch -d
# 查看超过 30 天没有更新的分支
git for-each-ref --sort=committerdate --format='%(committerdate:short) %(refname:short)' refs/heads/ | \
awk -v cutoff=$(date -d "30 days ago" +%Y-%m-%d) '$1 < cutoff {print $1, $2}'# GitHub 分支保护规则设置(Settings → Branches)
# 1. 禁止直接推送到 main
# 2. 要求 PR 审查(至少 1-2 人)
# 3. 要求 CI 通过
# 4. 禁止 force push
# 5. 要求签名提交
# 本地 pre-push hook 防止误推送到 main
#!/bin/bash
# .git/hooks/pre-push
PROTECTED_BRANCHES="main master develop"
CURRENT=$(git rev-parse --abbrev-ref HEAD)
for branch in $PROTECTED_BRANCHES; do
if [ "$CURRENT" = "$branch" ]; then
echo "❌ 禁止直接推送到 $branch!请使用 Pull Request。"
exit 1
fi
done# 以下操作会进入 detached HEAD
git checkout abc1234 # 检出特定提交
git checkout v2.0.0 # 检出标签
git switch --detach main # 显式 detach
# Git 会警告你
# You are in 'detached HEAD' state...# ✅ 安全操作:查看代码、运行测试
git log --oneline -5
npm test
git diff HEAD main
# ⚠️ 危险操作:提交会成为「悬空提交」
git commit -m "在 detached HEAD 上提交"
# 切换到其他分支后,这个提交可能被 gc 回收!
# 挽救 detached HEAD 上的提交
git switch -c rescue-branch # 创建分支来保存提交
# 或
git switch main
git cherry-pick abc1234 # 摘取到 main# 哪些分支包含了这个提交
git branch --contains abc1234
# main
# release/v3.0
# 哪些远程分支包含了这个提交
git branch -r --contains abc1234
# 哪些分支的 HEAD 指向这个提交
git branch --points-at abc1234# 查看 feature 有但 main 没有的提交
git log main..feature --oneline
# 查看两个分支的差异统计
git diff main...feature --stat
# 查看两个分支各自独有的提交
git log main...feature --oneline --left-right
# < abc1234 main 独有
# > def5678 feature 独有
# 查看两个分支的共同祖先
git merge-base main feature# 将当前分支强制移动到指定提交(危险!)
git branch -f main abc1234
# 将当前分支重置到远程状态
git reset --hard origin/main详见 Git reset
[alias]
# 分支列表(按最近修改排序)
br = branch --sort=-committerdate --format='%(color:green)%(committerdate:relative)%(color:reset) %(color:yellow)%(refname:short)%(color:reset) %(subject)'
# 创建并切换分支
cb = switch -c
# 切换到上一个分支
sw = switch -
# 删除已合并的分支
cleanup = "!git branch --merged main | grep -v 'main\\|develop' | xargs -r git branch -d"
# 查看所有分支的追踪状态
bv = branch -vv
# 查看远程已删除的分支
gone = "!git branch -vv | grep ': gone]' | awk '{print $1}'"# 创建带时间戳的临时实验分支
git switch -c experiment/$(date +%Y%m%d-%H%M)
# 实验完毕后清理所有实验分支
git branch --list "experiment/*" | xargs git branch -D# 使用 fzf 模糊搜索并切换分支
git switch $(git branch --sort=-committerdate | fzf --height 40% | tr -d ' *')
# 配置为 alias
[alias]
sw-fzf = "!git switch $(git branch --sort=-committerdate | fzf --height 40% | tr -d ' *')"# GitHub PR 设置:合并后自动删除分支
# Settings → General → Pull Requests → Automatically delete head branches ✅
# 本地同步清理
git fetch --prune
git branch -vv | grep ": gone]" | awk '{print $1}' | xargs git branch -d# Git Flow 中的 release 分支完整流程
# 1. 从 develop 创建 release 分支
git switch develop
git pull origin develop
git switch -c release/v3.0.0
# 2. 在 release 分支上只做 bug 修复和版本号更新
vim package.json # 更新版本号
git commit -am "chore: bump version to 3.0.0"
# 3. 修复发现的 bug
git commit -am "fix: 修复注册表单验证"
# 4. 合并到 main 并打标签
git switch main
git merge --no-ff release/v3.0.0
git tag -a v3.0.0 -m "Release v3.0.0"
# 5. 合并回 develop(同步修复)
git switch develop
git merge --no-ff release/v3.0.0
# 6. 删除 release 分支
git branch -d release/v3.0.0
git push origin --delete release/v3.0.0
# 7. 推送
git push origin main --follow-tags
git push origin develop# 同时维护 v1.x、v2.x、v3.x 三个大版本
# main ← 最新开发
# release/v3 ← v3.x 维护分支
# release/v2 ← v2.x 维护分支(LTS)
# release/v1 ← v1.x 维护分支(仅安全修复)
# 安全漏洞修复需要应用到所有维护版本
git switch main
git commit -am "fix: 修复 XSS 漏洞"
# cherry-pick 到各维护分支
git switch release/v3
git cherry-pick -x <fix-sha>
git tag -a v3.2.1 -m "v3.2.1: 安全修复"
git switch release/v2
git cherry-pick -x <fix-sha>
git tag -a v2.8.5 -m "v2.8.5: 安全修复"
git switch release/v1
git cherry-pick -x <fix-sha>
git tag -a v1.12.3 -m "v1.12.3: 安全修复"# 功能拆分为多个相互依赖的 PR
# main → feature/auth-base → feature/auth-ui → feature/auth-tests
# 创建依赖链
git switch -c feature/auth-base main
# 实现认证基础...
git push -u origin feature/auth-base
git switch -c feature/auth-ui feature/auth-base
# 实现认证 UI...
git push -u origin feature/auth-ui
git switch -c feature/auth-tests feature/auth-ui
# 编写测试...
git push -u origin feature/auth-tests
# 当 auth-base 合并到 main 后,更新依赖链
git switch feature/auth-ui
git rebase main # 现在基于 main(包含了 auth-base)
git push --force-with-lease
git switch feature/auth-tests
git rebase feature/auth-ui
git push --force-with-lease# 创建没有历史记录的孤立分支
git switch --orphan gh-pages
# 或
git checkout --orphan gh-pages
# 清空工作区
git rm -rf .
# 添加文档站点内容
echo "<h1>Docs</h1>" > index.html
git add index.html
git commit -m "docs: 初始化文档站点"
git push origin gh-pages
# 常见用途:
# - gh-pages:GitHub Pages 静态站点
# - docs:独立的文档分支
# - assets:存放大型二进制资源
# - config:存放环境配置#!/bin/bash
# branch-report.sh — 分支健康报告
echo "📊 分支健康报告"
echo "================="
echo ""
# 统计
TOTAL=$(git branch -a | wc -l)
LOCAL=$(git branch | wc -l)
REMOTE=$(git branch -r | wc -l)
MERGED=$(git branch --merged main | grep -v "main\|develop" | wc -l)
STALE=$(git for-each-ref --sort=committerdate --format='%(committerdate:short) %(refname:short)' refs/heads/ | \
awk -v cutoff=$(date -d "30 days ago" +%Y-%m-%d 2>/dev/null || date -v-30d +%Y-%m-%d) '$1 < cutoff' | wc -l)
echo "本地分支: $LOCAL"
echo "远程分支: $REMOTE"
echo "已合并未删除: $MERGED"
echo "超过 30 天未更新: $STALE"
echo ""
# 已合并可清理的分支
if [ "$MERGED" -gt 0 ]; then
echo "🗑️ 可清理的已合并分支:"
git branch --merged main | grep -v "main\|develop" | sed 's/^/ /'
echo ""
fi
# 最近活跃的分支
echo "🔥 最近活跃的分支(前 5):"
git for-each-ref --sort=-committerdate --count=5 --format=' %(committerdate:relative) %(refname:short)' refs/heads/
echo ""
# 远程已删除的分支
GONE=$(git branch -vv | grep ": gone]" | awk '{print $1}')
if [ -n "$GONE" ]; then
echo "👻 远程已删除的本地分支:"
echo "$GONE" | sed 's/^/ /'
fi# 分支就是一个 40 字符的文件
cat .git/refs/heads/main
# abc1234def5678901234567890abcdef12345678
# 创建分支 = 创建一个文件
echo "abc1234def5678901234567890abcdef12345678" > .git/refs/heads/test
# 等价于 git branch test
# packed-refs:当分支太多时,Git 将它们压缩到一个文件中
cat .git/packed-refs
# abc1234... refs/heads/main
# def5678... refs/heads/feature
# ghi9012... refs/tags/v1.0.0
# HEAD 文件记录当前分支
cat .git/HEAD
# ref: refs/heads/main ← 正常状态(指向分支名)
# abc1234def5678... ← detached HEAD(直接指向 SHA)# 分支切换的性能:
# - 创建分支:写一个 41 字节的文件 → 几乎瞬间
# - 切换分支:对比并更新变更的文件 → 取决于差异大小
# - 大型 monorepo 中切换可能较慢(文件数量巨大)
# 加速大仓库的分支切换
git config core.fsmonitor true # 使用文件系统监视器(Git 2.37+)
git config core.untrackedcache true # 缓存未跟踪文件信息
git sparse-checkout init # 只检出需要的目录# ❌ 基于过时的 main 创建
git switch -c feature/new main # main 可能不是最新的!
# ✅ 先更新 main
git switch main
git pull origin main
git switch -c feature/new# 如果有文件叫 main
git checkout main # 歧义!是切换分支还是恢复文件?
# ✅ 使用 switch/restore 消除歧义
git switch main # 明确:切换分支
git restore main # 明确:恢复文件
# 如果必须用 checkout
git checkout main -- # -- 表示后面是路径# -d 会阻止删除未合并的分支(安全)
git branch -d feature
# error: The branch 'feature' is not fully merged.
# -D 强制删除(不可逆!)
git branch -D feature
# 如果误删了,可以通过 reflog 恢复
git reflog | grep feature
git switch -c feature abc1234# ❌ 在 Windows/macOS 上创建了大小写不同的分支
git branch Feature/test
git branch feature/test
# 在大小写不敏感的文件系统上会冲突!
# ✅ 统一使用小写
git branch feature/test# ❌ 在 detached HEAD 上提交后直接切换
git checkout v2.0.0
vim fix.ts
git commit -am "fix"
git switch main # 刚才的提交变成「悬空提交」!
# ✅ 在 detached HEAD 上提交后创建分支保存
git switch -c hotfix/from-v2.0git switch 和 git checkout 到底用哪个?switch(切换分支)+ restore(恢复文件)checkoutcheckout 不会被移除,团队中可以根据 Git 版本统一选择checkoutgit fetch --prune
git branch -vv | grep ": gone]" | awk '{print $1}' | xargs git branch -dGit 不直接记录分支的「父分支」,但可以通过以下方式推断:
# 查看 feature 和 main 的分叉点
git merge-base feature main
# 查看 feature 分支创建时的 reflog
git reflog show feature | tail -1feature/、fix/、release/ 前缀)git branch --sort=-committerdate 查看最近活跃的分支# 管道和 xargs 不可用,用 PowerShell 方式
# 删除已合并的分支
git branch --merged main | Where-Object { $_ -notmatch 'main|develop' } | ForEach-Object { git branch -d $_.Trim() }
# 清理远程已删除的分支
git branch -vv | Select-String ": gone]" | ForEach-Object { ($_ -split '\s+')[1] } | ForEach-Object { git branch -d $_ }| 目标 | 命令 |
|---|---|
| 创建分支 | git branch <name> |
| 创建并切换 | git switch -c <name> |
| 切换分支 | git switch <name> |
| 切换到上一个分支 | git switch - |
| 查看本地分支 | git branch |
| 查看所有分支 | git branch -a |
| 查看分支详情 | git branch -vv |
| 按时间排序 | git branch --sort=-committerdate |
| 查看已合并分支 | git branch --merged main |
| 查看未合并分支 | git branch --no-merged main |
| 重命名分支 | git branch -m <old> <new> |
| 删除本地分支 | git branch -d <name> |
| 强制删除 | git branch -D <name> |
| 删除远程分支 | git push origin --delete <name> |
| 设置追踪 | git branch -u origin/<name> |
| 查看包含某提交的分支 | git branch --contains <sha> |
| 清理远程追踪引用 | git fetch --prune |
| 从标签创建分支 | git switch -c <name> <tag> |
| 进入 detached HEAD | git switch --detach <sha> |