PHP 开发者必看的 15 个困惑的 Git 术语(以及它们的真正含义) 
 
做了多年开发, 自 2015 年开始使用 Git, 我审过数百个 Pull Request,收拾过无数混乱的代码仓库,也带过不少在 Git 命令里打转的新人。 
老实说,我完全理解他们的困惑。Git 确实强大,但它的术语系统就像一个迷宫——很多词看着相似,实际用法却天差地别。 
今天就来聊聊这些连老手都可能搞混的 Git 术语。如果你是新手,这篇文章能帮你少走很多弯路。 
原文 开发者必看的 15 个困惑的 Git 术语(以及它们的真正含义) 
HEAD vs head vs Detached HEAD 
 
开发者常犯的错误: 
 
把 HEAD 当成又一个分支名。 
它的真实身份: 
 
HEAD 是一个指针,指向你当前所在的 commit —— 通常是你所在分支的最新提交。 
每次你提交代码,HEAD 就会移动到那个新 commit 上。- # 查看 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:你会看到这样的提示:You are in 'detached HEAD' state. 
这只是说你现在不在任何分支上——你在查看历史快照。没什么坏事发生。 
如果你想保存在这里做的工作:- 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",以此类推。显示你当前 commit 的上一个。 
HEAD^1 和 HEAD^2 
这些是父指针。它们在处理 merge commit 时最有用。 
一个 merge commit 有两个父节点——一个来自你所在的分支,另一个来自你合并进来的分支。对比合并时两边各自贡献了什么。 
^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 之间的差异
 
 
 - 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 的新指针。- git branch feature/login
 - git switch feature/login
 
  复制代码 现在你有了一个从 main 分叉出去的轻量级指针。没有额外文件,没有复制。 
Tags 
 
Tags 标记特定的 commit——通常用于发布版本,而且不会移动。- git tag v1.0.0
 - git push origin v1.0.0
 
  复制代码 和分支不同,tags 是不可变的。一旦设置,它们永远指向同一个 commit。 
Fast-Forward Merge 
 
Fast-forward 不是什么特殊操作——它只是没有分叉的合并。 
无分叉 -> 可以 Fast-forward 
 
 
main 从 B 之后就没动过。- git switch main
 - git merge --ff-only feature
 
  复制代码 结果: 
 
没有创建 merge commit -> Git 只是把 main 的指针往前移了。 
分支已分叉 -> 无法 Fast-forward 
 
 
两边都在 B 之后有了新提交。- git switch main
 - git merge feature
 
  复制代码 现在 Git 必须创建一个 merge commit 来合并 E 和 D。 
如果你坚持要 fast-forward:- git merge --ff-only feature
 - # error: Not possible to fast-forward
 
  复制代码 规则: 
 
如果双方在分叉后都有新 commit,就无法 fast-forward。 
Squash 
 
Squash 在合并前把多个 commit 压扁成一个——适合清理混乱的 feature 分支历史。- git merge --squash feature/login
 - git commit -m "Add login feature"
 
  复制代码 你的分支历史保持干净,同时在 PR 里不会丢失工作上下文。 
origin vs upstream 
 
 
这个挺有意思的……我几天前在处理一个 fork 项目时才搞清楚区别。之前我一直以为它俩是一回事  
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除 
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |