1. 引言

Git 是目前最流行的版本控制系统之一。它通过三种结构之间的数据流转最终形成提交树(commit tree)。为了方便标识,一些关键的提交会通过 ref(引用)来标记,比如分支名和标签名。

本文将重点解析 Git 中两个核心概念:HEAD主分支(master/main),并对比它们的功能和差异。我们会从提交树的结构讲起,逐步介绍 HEAD 的作用、主分支的特性,最后总结它们之间的区别。

文中所有示例命令均在 Debian 12(Bookworm)环境下测试通过,使用 GNU Bash 5.2.15 和 Git 2.39.2,适用于大多数 POSIX 兼容环境。


2. 提交树概览

Git 的核心是提交树,它记录了所有历史提交的状态。每次提交都代表一个工作目录的快照。

在提交树中,有两个始终存在的引用(ref):

  • 主分支名称(master 或 main)
  • HEAD

早期 Git 默认主分支名为 master,较新版本通常使用 main。主分支通常被视为仓库的“根”,其他分支都可追溯到它。但注意,主分支不一定是提交树的“主干”。

HEAD 是一个指向当前提交的动态指针,它反映了当前工作目录的状态。可以理解为:主分支是仓库的起点,HEAD 是当前所在的位置。

来看一个提交树的示例:

$ git log --all --decorate --oneline --graph
* 8a62fcb (branch1) branch feature
| * 94884cd (branch2) secondary feature WIP
| * 89da3cd secondary branch modifications
|/
| * 02d0395 (branch3) experimental
|/
* 37929d5 branch modifications
| * f5262a4 (HEAD -> master) new structure
| * a403ae7 wipeout
| * bf9d913 major modifications
| * baf6427 minor modifications
|/
* 7340bc4 restructuring
* ef49b0f structuring
* d0c4fb9 init commit

在这个例子中,master 分支是最长的分支,但 branch1 却是图中的“主干”。这说明主分支不一定就是树的主干。

同时,HEAD 指向了 master 的最新提交,这容易让人混淆 HEAD 与主分支之间的关系。


3. HEAD 是什么?

HEAD 是 Git 中一个指向当前提交的动态指针。

它会随着以下操作而改变:

会改变 HEAD 的操作:

  • checkout:切换分支或恢复文件
  • commit:创建新提交
  • fetch:获取远程对象和引用
  • merge:合并分支
  • rebase:变基操作
  • reset:重置 HEAD
  • pull:拉取并合并
  • revert:撤销提交
  • switch:切换分支

⚠️ 注意:HEAD 本身并不直接指向提交,而是指向一个引用(ref),再由该引用指向具体的提交。

也就是说,HEAD 是一个“双重间接”指针:

HEAD → ref → commit

因此,只要这两个关系中的任何一个发生变化,HEAD 的指向也会发生变化。


4. 主分支(master/main)

主分支是 Git 初始化仓库时自动创建的分支。

4.1 基本概念

每个分支本质上是一个指向某个提交的指针。每当该分支有新的提交时,这个指针就会更新。因此,分支可以看作是一个从创建点开始、到最新提交结束的线性结构。

来看一个例子:

$ git log --all --decorate --oneline --graph
* 8a62fcb (branch1) branch feature
| * 94884cd (branch2) secondary feature WIP
| * 89da3cd secondary branch modifications
|/
| * 02d0395 (branch3) experimental
|/
* 37929d5 branch modifications
| * f5262a4 (HEAD -> master) new structure
| * a403ae7 wipeout
| * bf9d913 major modifications
| * baf6427 minor modifications
|/
* 7340bc4 restructuring
* ef49b0f structuring
* d0c4fb9 init commit

在这个例子中:

  • branch1 起始于 37929d5,包含一个提交:8a62fcb
  • master 起始于 d0c4fb9,结束于 f5262a4,也就是当前 HEAD 所在的位置

但请注意:HEAD 指向的分支是可变的,它并不总是指向主分支。

4.2 切换分支时的变化

我们来看一个切换分支的例子:

$ git checkout branch1
Switched to branch 'branch1'
$ git log --all --decorate --oneline --graph
* 8a62fcb (HEAD -> branch1) branch feature
| * 94884cd (branch2) secondary feature WIP
| * 89da3cd secondary branch modifications
|/
| * 02d0395 (branch3) experimental
|/
* 37929d5 branch modifications
| * f5262a4 (master) new structure
| * a403ae7 wipeout
| * bf9d913 major modifications
| * baf6427 minor modifications
|/
* 7340bc4 restructuring
* ef49b0f structuring
* d0c4fb9 init commit

此时 HEAD 已经指向 branch1 的最新提交,而 master 保持不变。这清楚地展示了 HEAD 与主分支之间的区别。

4.3 修改默认主分支名

Git 默认主分支名为 master,但在新版本中可以改为 main

✅ 修改单个仓库的主分支名:

$ git branch --move master main

⚠️ 注意:如果远程仓库存在(如 GitHub),还需同步远程分支:

$ git push --set-upstream origin main
$ git push origin --delete master

不过,GitHub 等平台默认保护主分支,不能直接删除。你需要先解除保护,再切换默认分支。

✅ 全局设置默认主分支名:

$ git config --global init.defaultBranch main

之后所有新仓库的主分支将默认为 main

注意:不能将分支命名为 HEAD,因为这是保留关键字

$ git branch --move master HEAD
fatal: 'HEAD' is not a valid branch name

5. HEAD 与主分支的区别总结

特性 HEAD 主分支(master/main)
名称 固定为 HEAD 通常是 master 或 main
类型 提交指针 提交指针
间接层级 双重(HEAD → ref → commit) 单层(ref → commit)
功能 跟踪当前工作目录状态 跟踪主分支的最新提交
触发变化的操作 checkout、commit、merge 等 checkout、commit、merge 等

虽然两者在某些行为上有交集,但本质上它们是两个不同概念:HEAD 是动态的当前指针,主分支是静态的默认分支


6. 小结

HEAD 是 Git 中一个指向当前提交的动态指针,而主分支(master/main)是仓库初始化时创建的默认分支。

虽然在很多情况下 HEAD 指向主分支的最新提交,但这只是一个临时状态。HEAD 的变化远比主分支频繁,尤其是在切换分支、提交、重置等操作时。

理解 HEAD 与主分支的区别,有助于更清晰地掌握 Git 的工作原理,避免在多人协作或分支切换时踩坑。


原始标题:Difference Between Git HEAD and Primary master or main Branch