1、本地Git命令
1.1、Git Commit
Git Commit = 项目快照(Snapshot)
每次 git commit 并不是粗暴地复制整个目录,而是对已跟踪文件当前状态的轻量级快照记录。Git 通过对比当前版本与上一次提交的差异(diff),将变更打包存储,因此提交记录非常轻量。

1.2、Git Branch
Git Branch = 可移动的标签指针
分支本质上只是一个指向某个提交记录的可移动指针,仅此而已。它不复制任何文件,不占用额外存储空间。

为什么"早建分支!多用分支!"
| 优势 | 说明 |
|---|---|
| 零成本创建 | 分支只是 41 字节的引用文件,创建再多也没有存储或内存开销 |
| 逻辑隔离 | 按功能/bug/实验拆分工作,避免单分支臃肿混乱 |
| 并行开发 | 多人或多任务同时进行,互不干扰 |
| 安全实验 | 新想法随便试,搞砸了删掉分支即可,不影响主线 |
关键命令
bash
# 创建分支(但停留在当前分支)
git branch newImage
# 切换分支
git checkout newImage
⚠️ 常见误区:创建 ≠ 切换
bash
git branch newImage # 创建了 newImage 分支
# 但 HEAD 仍然指向 main!
git commit # ❌ 提交会跑到 main 上,newImage 原地不动
如何理解 "提交记录"、"分支"和 HEAD?
- 提交记录(Commit)= 项目的快照
每个提交保存了那一刻所有已跟踪文件的完整状态
每个提交(除第一个外)都有一个 parent 指针,指向上一个提交
这样一条一条连起来,就是项目的历史链 - 分支(Branch)= 可移动的标签指针
分支本身不存代码,它只是指向某个提交的引用
当你在这个分支上提交时,这个指针会自动向前移动,指向最新的提交
其他分支如果不切换过去,就原地不动 - HEAD = 你在哪
HEAD 是一个特殊指针,指向当前所在的分支
HEAD 决定了:你的下一次提交,会让哪个分支跟着走
1.3、Git Merge
git merge = 整合两条历史线
当你想把一个分支的修改合并到另一个分支时,git merge 会创建一个新的提交记录,这个提交的特殊之处在于它有两个 parent 节点。它相当于在说:
"我要把这两个分支的所有历史提交,以及它们各自的祖先,全部包含进来。"

⚠️ 关键注意点
- 合并方向很重要:git merge bugFix 是把 bugFix 合并到当前分支,不是反过来
- 合并提交不可少:它是两条分支历史的交汇点,没有它,其中一条分支的历史会被"隐藏"
1.4、Git Rebase
git rebase = "变基":把提交记录连根拔起,重新栽种到另一棵树的顶端
Rebase 会取出当前分支上的一系列提交,复制 它们,然后在目标分支的最新提交之后逐个重新应用。原提交并不会被删除(只是不再被引用),新产生的是内容相同但哈希不同的副本。
效果:让并行开发的两条分支,看起来像是按顺序串行开发的一样。

Rebase vs Merge 对比
| 维度 | git merge |
git rebase |
|---|---|---|
| 历史形状 | 保留分支结构,产生分叉和合并提交 | 线性历史,无分叉 |
| 提交记录 | 保留原提交,新增一个合并提交 | 复制提交,原提交"悬空",哈希改变 |
| 可读性 | 能看清"什么时候合并的" | 像一条直线,非常干净 |
| 安全性 | 安全,不改变已有提交 | 改写历史,需谨慎使用 |
| 适用场景 | 公共分支合并、保留完整协作痕迹 | 本地分支整理、特性分支上线前清理 |
2、远程Git命令
2.1、Git Clone
git clone = 把远程仓库完整复制到本地
远程仓库本质上就是你本地仓库在另一台计算机上的拷贝,通过互联网进行通信。git clone 不只是下载代码,而是把远程仓库的完整历史、所有分支、所有提交都复制到本地。

克隆后本地得到什么
| 内容 | 说明 |
|---|---|
| 完整提交历史 | 从第一个提交到最新提交,全部在本地 |
| 所有分支 | 远程分支映射为 origin/<分支名>,如 origin/main |
| 默认检出分支 | 通常自动切换到 main(或仓库默认分支) |
| 远程别名 | 远程仓库被命名为 origin,后续用这个名字引用 |
远程仓库的三大价值
- 备份:即使本地硬盘损坏,代码还在远程
- 协作:团队成员可以共享代码、审查变更
- 托管:GitHub/GitLab 等平台基于此提供 CI/CD、Issue、PR 等功能
2.2、远程分支
远程分支 = 远程仓库状态的"本地镜像"
远程分支的命名格式为 /,例如 origin/main(教程简写为 o/main)。它反映的是你上次与远程通信时,远程仓库对应分支的状态。

远程分支的三大特性
| 特性 | 说明 |
|---|---|
| 只读快照 | 它是远程状态的本地缓存,不能直接在上面提交 |
| 通信才更新 | 只有执行 fetch/pull/push 时才会刷新 |
| 切换即分离 HEAD | 切到远程分支会自动进入 detached HEAD,防止误操作 |
2.3、git fetch
git fetch = 纯下载操作
它只做两件事,且只做这两件事:
- 下载远程仓库中本地缺失的提交记录
- 更新本地远程分支指针(如 origin/main)
git fetch 做了什么 vs 没做什么
| ✅ 做了 | ❌ 没做 |
|---|---|
| 下载远程的新提交到本地 | 修改你的本地 main 分支 |
更新 origin/main 等远程分支指针 |
合并代码到当前分支 |
| 让你能看到远程的最新状态 | 改动你工作目录里的任何文件 |
为什么需要 git fetch?
远程分支(如 origin/main)是你上次和远程通信时的快照。当同事推送了新代码,你的 origin/main 还是旧的。git fetch 就是"去远程看一眼,把新东西下载下来,更新快照"。
常见误区
"我 git fetch 了,为什么代码没变?"
因为 fetch 不是 pull 。fetch 只是把远程的数据"拿进家门",但还没"摆到桌上"。你的本地分支、工作目录完全不受影响。

2.4、git pull
git pull = git fetch + git merge 的简写
它是 Git 中最常用的"同步远程代码"命令,把"下载远程更新"和"合并到本地分支"两步合为一步。

2.5、git push
git push = 发布你的成果
它是 git pull 的反向操作:把本地仓库的新提交上传到远程仓库,让远程分支跟上你的本地分支。一旦 push 成功,团队成员就能从远程拉取你的代码。
三件事同步发生:
- 上传本地缺失的提交到远程仓库
- 更新远程仓库的对应分支指针(如远程的 main)
- 更新本地的远程跟踪分支(如 origin/main)
2.6、远程历史分叉与解决方案
问题场景
你周一 clone 了仓库,在本地开发了一周。周五准备 push 时,发现同事已经推送了新代码------远程历史和你本地的基准已经分叉了。
bash
远程:C0 → C1 → C2(同事的新提交)
本地:C0 → C1 → C3(你的提交,基于旧 C1)
此时直接 git push 会被拒绝:
! rejected main -> main (non-fast-forward)
Git 拒绝的原因:你的 C3 基于旧的 C1,而远程已经前进到 C2。Git 不会猜测"是回退远程还是强行合并",它强制你先处理这个分歧。
两种解决方案
核心思路都一样:先把远程最新变更拿进来,让你的工作基于最新的代码,再 push。
方案一:Rebase(线性历史)
bash
git fetch origin
git rebase origin/main (把远程最新代码拉下来,然后把我的本地工作挪到它头顶上)
git push origin main
效果:你的 C3 被复制到 C2 后面,历史变成一条直线。
结果:C0 → C1 → C2 → C3'
优点:历史干净、线性,便于回溯。
缺点:改写本地提交的哈希(如果已推送到其他远程需注意)。
方案二:Merge(保留分叉)
bash
git fetch origin
git merge origin/main
git push origin main
效果:产生一个合并提交 M,把两条历史连在一起。
bash
结果:C0 → C1 → C2 → M(合并提交)
↘ C3 ↗
优点:保留完整协作痕迹,不改动已有提交。
缺点:历史图会出现分叉和合并节点。
简写命令
| 完整流程 | 简写 |
|---|---|
fetch + rebase + push |
git pull --rebase → git push |
fetch + merge + push |
git pull → git push |