开发者必看的 15 个困惑的 Git 术语(以及它们的真正含义)

PHP 开发者必看的 15 个困惑的 Git 术语(以及它们的真正含义)

做了多年开发, 自 2015 年开始使用 Git, 我审过数百个 Pull Request,收拾过无数混乱的代码仓库,也带过不少在 Git 命令里打转的新人。

老实说,我完全理解他们的困惑。Git 确实强大,但它的术语系统就像一个迷宫------很多词看着相似,实际用法却天差地别。

今天就来聊聊这些连老手都可能搞混的 Git 术语。如果你是新手,这篇文章能帮你少走很多弯路。

原文 开发者必看的 15 个困惑的 Git 术语(以及它们的真正含义)

HEAD vs head vs Detached HEAD

开发者常犯的错误:

把 HEAD 当成又一个分支名。

它的真实身份:

HEAD 是一个指针,指向你当前所在的 commit ------ 通常是你所在分支的最新提交。

每次你提交代码,HEAD 就会移动到那个新 commit 上。

bash 复制代码
# 查看 HEAD 指向哪里
git log --oneline --decorate -n 3

# --oneline 把每个 commit 压缩成一行显示:
# commit hash 的前 7 个字符 + commit 信息

# --decorate
# 在 commit 旁边显示分支和标签引用
# 这样你就能看到 HEAD、main、origin/main 或 v1.0.0 这些指针当前在哪

# -n 3
# 只显示最近 3 个 commit

你会看到类似这样的输出:

复制代码
a3c4d5e (HEAD -> main, origin/main) Add user API

如果你直接 checkout 到某个旧 commit:

bash 复制代码
git checkout a3c4d5e

你会看到这样的提示:You are in 'detached HEAD' state.

这只是说你现在不在任何分支上------你在查看历史快照。没什么坏事发生。

如果你想保存在这里做的工作:

bash 复制代码
git switch -c hotfix/legacy-bug

至于 head(小写),它不是 Git 的关键字------通常只是非正式用法或复数形式,比如"分支的 heads"。

Git 把分支的最新提交存在 .git/refs/heads/ 下,所以你可能会在内部引用中看到这个词。

比如:

复制代码
.git/refs/heads/main
.git/refs/heads/feature/login

所以当你看到"所有 heads"时,意思是"每个分支的最新 commit",而不是那个特殊的 HEAD 指针。

后缀的含义:

Git 提供了一些方式让你从 HEAD 开始往回追溯历史。

HEAD~1

表示"HEAD 之前的一个 commit"。

HEAD~2 表示"之前的两个 commit",以此类推。

bash 复制代码
git show HEAD~1

显示你当前 commit 的上一个。

HEAD^1 和 HEAD^2

这些是父指针。它们在处理 merge commit 时最有用。

一个 merge commit 有两个父节点------一个来自你所在的分支,另一个来自你合并进来的分支。

bash 复制代码
git diff HEAD^1 HEAD^2

对比合并时两边各自贡献了什么。

^1 表示"第一个父节点",^2 表示"第二个父节点"。

经验法则:

  • ~ 线性地往回走
  • ^ 处理 merge commit 的父节点

如下图演示

把 feature 合并到 main 后,merge commit (M) 有两个父节点:

  • HEAD^1 → commit C(合并前的 main)
  • HEAD^2 → commit E(feature 分支的末端)

一旦你把 HEAD 想象成"你在这里",Git 的导航模型就瞬间清晰了。

Commit vs Changeset

很多开发者以为 commit 就是 diff------其实不是。

  • commit = 仓库的完整快照 + 元数据 + 父节点链接
  • changeset = 两个 commit 之间的差异
bash 复制代码
git show HEAD          # 显示 commit 及其 diff(changeset 视图)
git diff HEAD~1 HEAD   # 只显示两个 commit 之间的原始 diff
git add -p             # 选择性暂存变更(构建你的 changeset)
git commit -m "Fix NPE in user lookup"

理解这个区别能帮你打造原子化 commit------每个 commit 只包含一个逻辑变更------而不是一股脑全扔进去。

Branch ≠ Copy

创建分支不会克隆代码库。

它只是创建一个指向 commit 的新指针。

bash 复制代码
git branch feature/login
git switch feature/login

现在你有了一个从 main 分叉出去的轻量级指针。没有额外文件,没有复制。

Tags

Tags 标记特定的 commit------通常用于发布版本,而且不会移动。

bash 复制代码
git tag v1.0.0
git push origin v1.0.0

和分支不同,tags 是不可变的。一旦设置,它们永远指向同一个 commit。

Fast-Forward Merge

Fast-forward 不是什么特殊操作------它只是没有分叉的合并。

无分叉 -> 可以 Fast-forward

mainB 之后就没动过。

bash 复制代码
git switch main
git merge --ff-only feature

结果:

没有创建 merge commit -> Git 只是把 main 的指针往前移了。

分支已分叉 -> 无法 Fast-forward

两边都在 B 之后有了新提交。

bash 复制代码
git switch main
git merge feature

现在 Git 必须创建一个 merge commit 来合并 ED

如果你坚持要 fast-forward:

bash 复制代码
git merge --ff-only feature
# error: Not possible to fast-forward

规则:

如果双方在分叉后都有新 commit,就无法 fast-forward。

Squash

Squash 在合并前把多个 commit 压扁成一个------适合清理混乱的 feature 分支历史。

bash 复制代码
git merge --squash feature/login
git commit -m "Add login feature"

你的分支历史保持干净,同时在 PR 里不会丢失工作上下文。

origin vs upstream

这个挺有意思的......我几天前在处理一个 fork 项目时才搞清楚区别。之前我一直以为它俩是一回事 😃

origin 是你克隆仓库时默认的远程仓库名称。

如果你 fork 了一个仓库,原始仓库叫做 upstream

bash 复制代码
git remote -v

你可能会看到:

复制代码
origin   git@github.com:yourname/project.git
upstream git@github.com:org/project.git

用 upstream 从原始源拉取变更:

bash 复制代码
git fetch upstream

Remote-Tracking Branches

origin/mainmain 不是一回事。

  • main = 你的本地分支
  • origin/main = Git 对远程 main 的最后已知快照
bash 复制代码
git fetch
git diff main origin/main

这能告诉你上游有什么变化,而不用立即合并。

Fetch vs Pull

git fetch 只更新你对远程仓库的本地认知。

git pull 做了这个,然后自动合并(或 rebase)。

bash 复制代码
git fetch origin
git merge origin/main

这比盲目 git pull 更安全、更明确。

The Staging Area (Index)

暂存区是 Git 的"候车室"。

你决定哪些变更进入下一个 commit。

bash 复制代码
git add src/App.java
git status
git commit -m "Fix null check"

你可以暂存特定的代码块:

bash 复制代码
git add -p

就像在结账前往购物车里放东西。

Working Directory

你的工作目录就是你正在编辑的文件------不是仓库本身。

真正的仓库在 .git/ 里。

bash 复制代码
git status
# "working tree clean" 意思是你的文件和 HEAD 一致

Tracked vs Untracked Files

你添加过一次的文件是"已跟踪"的。

新文件在你暂存它们之前不会被跟踪。

bash 复制代码
git status
# Untracked files: (use "git add <file>")

提交前一定要检查这个------未跟踪的文件不会出现在 commit 里。

Dirty Tree

"Dirty tree" 只是说你的工作目录有未提交的变更。

bash 复制代码
git status
# modified: src/App.java

切换分支前先提交或 stash 它们,避免冲突。

Reset vs Revert

Git 里最容易被误解的两个命令。

  • reset 移动 HEAD,可能会丢弃 commit(危险)
  • revert 创建一个新 commit 来撤销之前的变更(安全)
bash 复制代码
git reset --hard HEAD~1   # 删除最后一个 commit
git revert HEAD           # 通过添加新 commit 安全地撤销

如果你在共享分支上工作,永远用 revert

总结

从本质上讲,Git 就是一个由 commit指针 组成的图。

一旦你理解了 HEAD分支快照 的工作原理,其他一切都会变得合乎逻辑。

相关推荐
shencz20001 小时前
在windows10里的apache2.4加php7.2的环境下上安装Laravel5.8框架
php·laravel
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
用户298698530141 小时前
Python 实现 Excel 与 Markdown 互转的实用指南
后端·python·excel
用户77283104908401 小时前
krono-job:零侵入、单二进制交付的分布式任务调度平台(开源)
后端
Conan在掘金1 小时前
鸿蒙报错速查:Function lacks ending return statement,返回路径漏 return 就炸,根因 + 真解法
后端
人间凡尔赛2 小时前
AI-Native 云原生架构:2026 年从容器编排到智能体编排的范式革命
后端·云原生·架构
IT_陈寒2 小时前
Vue的响应式让我加班到凌晨3点,原来问题出在这
前端·人工智能·后端