1. Git 提交树简介
Git 作为版本控制系统,其核心在于其树状结构,其中最核心的是提交树(Commit Tree)。提交树记录了项目的所有历史变更,构成了 Git 的版本控制基础。
在 Git 中,我们常见的操作如创建分支、合并、回滚等,本质上都是在操作提交树。理解提交树的结构和导航方式,有助于我们更高效地使用 Git。
2. Git 的三棵树
Git 在设计上基于三种“树”结构:
- HEAD 树(提交树):当前分支的最新提交快照
- 暂存区(Staging Area):待提交的文件变更
- 工作树(Working Tree):当前工作目录中的文件
这三棵树构成了 Git 的工作流程。我们通常在工作树中修改文件,将变更添加到暂存区,最后通过 git commit
提交到提交树。
示例查看状态:
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file3
new file: file4
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file1
Untracked files:
(use "git add <file>..." to include in what will be committed)
file2
3. 提交树结构
提交树由一系列的提交节点组成,每个提交都指向其父节点,从而形成一个树状结构。使用 git log
可以查看提交树的拓扑:
$ git log --all --decorate --oneline --graph
* 7763ee6 (tag: v0.1, branch1) branch feature
| * 24bfcf4 (branch2) secondary feature WIP
| * 1a063ad secondary branch modifications
|/
| * 435ac3e (branch3) experimental
|/
* 0ad45b6 branch modifications
| * 9369e35 (HEAD -> master) major modifications
| * 1724387 minor modifications
|/
* 84cbf13 restructuring
* ceb18d3 structuring
* 992361a init commit
这个结构展示了多个分支的提交历史,以及它们的合并关系。理解这种结构有助于我们在合并、变基等操作中避免踩坑。
4. 提交树的导航方式
4.1. 使用提交 ID 和引用(Ref)
每个提交都有一个唯一的 ID(SHA-1 哈希),我们也可以通过引用(如分支、标签)来定位提交:
$ git show-ref
7763ee672134e3fb174c72f03f07ae8ddf8ddf24 refs/heads/branch1
24bfcf443f3b17137af5a2422f5a12f56b7e8a4e refs/heads/branch2
...
这些引用可以用于定位特定提交,例如 git checkout branch1
就是切换到指向该提交的引用。
4.2. 相对引用操作符
Git 提供了相对引用操作符,可以方便地导航提交树:
HEAD^
:HEAD 的第一个父提交HEAD~2
:HEAD 的祖父提交HEAD~2^1
:HEAD 的祖父提交的第一个父提交
示例:
$ git show --quiet --oneline HEAD^
1724387 minor modifications
这种方式在查看历史提交时非常有用,尤其是在写脚本或调试时。
4.3. 特殊引用(Special Refs)
Git 还维护了一些特殊的引用,用于记录关键操作:
HEAD
:当前分支的最新提交ORIG_HEAD
:上一次 HEAD 的位置(用于恢复)FETCH_HEAD
:最近一次 fetch 的远程提交MERGE_HEAD
:正在合并的提交CHERRY_PICK_HEAD
:正在 cherry-pick 的提交
这些引用可以避免手动记录提交 ID,尤其在合并、变基等操作中非常有用。
4.4. 查找两个分支的最近共同祖先
使用 git merge-base
可以快速找到两个分支的最近共同祖先:
$ git merge-base branch1 branch2
0ad45b6db8bc17beeece36040392d6690c876162
这在合并冲突、代码审查等场景中非常实用。
4.5. 查找最早共同祖先或其他交汇点
如果想查找两个分支的最早共同祖先,可以使用如下命令组合:
$ diff --unified <(git rev-list --first-parent COMMIT_A) \
<(git rev-list --first-parent COMMIT_B) | \
sed --quiet -e 's/^ //p' | head -1
这个命令利用 diff
找出两个提交历史的差异点,再提取第一个共同提交。
5. 使用 Tig 查看提交树
Tig 是一个终端界面工具,可以更直观地浏览 Git 提交树。
5.1. 安装
$ apt install tig
5.2. 基本使用
$ tig
进入后按 h
可查看帮助,支持多种视图切换:
m
:主视图(main)d
:diff 视图l
:log 视图t
:tree 视图s
:status 视图c
:staging 视图
5.3. 查看完整提交树
$ tig --all
可以显示所有分支的提交历史,结构清晰,便于分析分支合并关系。
6. 使用 GitUI 查看提交树
GitUI 是另一个终端界面工具,支持 Linux、macOS 和 Windows。
6.1. 安装
$ curl --silent https://api.github.com/repos/extrawurst/gitui/releases/latest | grep -wo "https.*linux.*gz" | wget -qi -
$ tar xzvf gitui-linux-musl.tar.gz
$ chmod +x gitui
$ install gitui /usr/local/bin
6.2. 基本使用
$ gitui
支持 Tab 切换视图,使用方向键导航,按 Enter
查看提交详情。
6.3. 查看完整提交树
虽然 GitUI 没有直接显示树状结构的选项,但可以在 Log 视图中查看分支提交历史,并通过按键导航查看详细信息。
7. 使用 Lazygit 查看提交树
Lazygit 是目前最流行的 Git 终端界面工具之一。
7.1. 安装
$ LAZYGIT_VERSION=$(curl --silent 'https://api.github.com/repos/jesseduffield/lazygit/releases/latest' | perl -n0we 'print $1 if /"tag_name": "v(.*?)"/;')
$ curl --location --output lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
$ tar xf lazygit.tar.gz lazygit
$ install lazygit /usr/local/bin
7.2. 基本使用
$ lazygit
界面分为多个面板,支持 Tab 切换、方向键选择、?
查看帮助等。
7.3. 查看完整提交树
在 Status 视图中按 a
键,即可查看所有分支的提交树结构:
$ lazygit status
使用 PageUp
和 PageDown
滚动查看完整提交历史。
8. 总结 ✅
本文介绍了 Git 提交树的基本结构和多种导航方式,包括:
- 提交树的基本构成
- 使用提交 ID 和引用操作提交树
- 使用
git merge-base
查找分支交汇点 - 使用 Tig、GitUI、Lazygit 等 TUI 工具更直观地查看提交树
✅ 建议:对于复杂项目,建议使用 TUI 工具辅助 Git 操作,提升效率并减少出错概率。
❌ 注意:不要依赖 Git 的默认行为,尤其是在合并、变基等操作前,务必确认当前 HEAD 和分支状态。
⚠️ 提醒:某些操作(如 reset
、rebase
)会修改提交历史,谨慎使用。