head是一个指向当前工作分支(或提交)的独立指针,而非分支本身;分支是指向特定提交的指针,head则“登记”用户当前所在分支,其文件内容为ref: refs/heads/main或直接为commit哈希。

HEAD 是什么,它和分支到底谁指谁
HEAD 不是分支,而是一个独立的指针,它始终指向「当前你正在工作的那个分支(或提交)」。分支(比如 main、dev)本身也是指针,但它只负责固定指向某个 commit;而 HEAD 的作用是告诉 Git:「我现在在哪儿干活」。
执行 git branch 时看到的 * 号所在分支,就是 HEAD 当前所指——不是分支在控制 HEAD,而是 HEAD 在「登记」你此刻归属的分支。
关键点:
-
HEAD文件内容是ref: refs/heads/main,说明它正软链接到main分支;如果内容是纯哈希(如abc123...),就进入了「分离头指针(detached HEAD)」状态 - 分支名本身存放在
.git/refs/heads/<name></name>,里面只有一行 commit ID;HEAD 不存储代码,也不复制文件,只做路由 - 切换分支本质是两步:更新 HEAD 指向新分支 + 让工作目录文件匹配该分支最新 commit 的快照
git switch 和 git checkout 切分支时,HEAD 怎么动
git switch(Git 2.23+ 推荐)和 git checkout <branch></branch> 都会移动 HEAD,但行为细节有差异:
以从 main 切到 feature/login 为例:
- 两者都会把
HEAD文件内容改成ref: refs/heads/feature/login - 两者都会重置暂存区(index)和工作目录(working tree)为
feature/login所指 commit 的状态 -
git checkout <commit-id></commit-id>会直接让 HEAD 指向该 commit(脱离分支),而git switch --detach <commit-id></commit-id>才是等效写法;不加--detach的git switch拒绝切换到裸 commit - 如果目标分支不存在,
git switch -c <new></new>会先创建再切换;git checkout -b <new></new>同理,但语义稍隐晦
为什么切分支后文件变了,但没运行 git pull
因为 Git 分支切换不是「拉代码」,而是「换视角」:HEAD 移动 → 分支指针被读取 → Git 找到它指向的 commit → 把该 commit 对应的全部文件快照还原进工作目录。
这解释了常见困惑:
- 没网络也能切换分支:所有数据都在本地
.git目录里,不依赖远程 “切换慢” 通常是因为工作目录有未提交修改,Git 拒绝覆盖(报错 - 如果刚切过去发现某些文件没变,检查是否处于分离 HEAD 状态(
git status显示HEAD detached at abc123),此时你不在任何分支上,自然不会关联分支的命名指针 - 切换后
git log只显示当前分支的提交历史,不是全部历史;想看所有分支交汇点,得用git log --all --graph
error: Your local changes to the following files would be overwritten)
分离 HEAD 状态下 commit,会发生什么
当你执行 git checkout abc123 或 git switch --detach abc123 后,HEAD 就不再指向分支名,而是直连某个 commit ID。这时做 git commit:
- 新提交会被创建,父节点是 abc123
- HEAD 会自动前进指向这个新 commit(仍是分离状态)
- 但没有任何分支引用它 —— 下次切换分支,这个提交就「不可达」,可能被
git gc清理掉 - 补救方式只有立刻建分支:切换前运行
git switch -c temp-fix,或者切回去后用git branch fix-on-abc abc123再git merge fix-on-abc
真正容易被忽略的是:分离 HEAD 不是错误状态,而是 Git 提供的「临时沙盒」能力;但它的不可持续性,要求你每次 commit 后必须手动绑定分支,否则劳动成果随时蒸发。











