当前位置: 首页 > news >正文

git diff 从入门到精通

从三个区域模型出发,拆解 git diff 的默认行为、区间语义、输出格式,以及那些让人困惑的设计选择。


前置知识:三个区域

理解git diff之前,必须先理解 Git 的三个状态区域:

工作区 暂存区 本地仓库 (Working Directory) (Staging / Index) (HEAD) ↓ ↓ ↓ 你编辑文件的地方 git add 进来的地方 git commit 进来的地方
区域是什么怎么进怎么出
工作区磁盘上的实际文件你保存编辑器git add复制到暂存区
暂存区下次提交的"待提交清单"git addgit commit变成新 HEAD
HEAD当前分支最后一次提交的快照git commit只能被下一次 commit 覆盖

有了这个模型,三个核心 diff 命令就一目了然:

gitdiff# 工作区 ←→ 暂存区gitdiff--staged# 暂存区 ←→ HEADgitdiffHEAD# 工作区 ←→ HEAD

为什么git diff默认比较工作区和暂存区

这个默认行为让很多人困惑。直觉上你会觉得默认应该比较「工作区和上一次提交」,因为那才是"我改了什么"。

但 Git 的设计哲学不同:Git 假设你git add时已经检查过那些改动了,“确认没问题,准备提交”。所以git diff默认展示的是"你还确认的那部分"——add 之后又改了什么,帮你决定要不要再 add 一次。

真正常用的提交预览其实是git diff --staged

# "看看我即将提交什么"——这才是你最常用的gitdiff--staged# 设个别名省事gitconfig--globalalias.ds'diff --staged'

一句话git add= 勾选,git diff= 还没勾的,git diff --staged= 已经勾了的。习惯了这个心理模型就不别扭了。


工作区、暂存区、HEAD 状态演练

假设你创建一个新文件333.txt,内容333,然后git add

# 修改文件 333.txt → git add 333.txtgitdiff# 空:工作区和暂存区内容一致gitdiff--staged# 有输出:暂存区有 333.txt,HEAD 没有gitdiffHEAD# 有输出:工作区有这个文件,HEAD 没有

三步的状态图:

工作区 暂存区 HEAD 333.txt ──(相同)──▶ 333.txt ──(有差异)──▶ 无此文件

git diff为空是因为 add 之后你没再改过文件——工作区和暂存区完全一致。git diff --staged展示的是「暂存了但还没提交」,这才是你下一步的动作预览。


未跟踪文件:diff 看不到

git diff只比较已跟踪内容,未跟踪文件不会出现在任何 diff 输出中。想看未跟踪的文件只能用git status

如果一定要让 diff 包含未跟踪文件,可以用--intent-to-add假装暂存一个空版本:

gitadd-Nuntracked-file.txt# 暂存一个空占位gitdiff# 现在能看到差异了

这不是日常操作——只是让你知道有这条路。


区间比较:两点 vs 三点

基础语法

gitdiffA..B# 从 A 到 B(A 之后的变化)gitdiffA...B# 从共同祖先到 B(B 分支独有的变化)gitdiffA# 省略第二个参数,默认对比工作区:A vs 当前工作区

闭区间还是开区间

A..B左开右闭(A, B]:以 A 为基准线,A 自己的改动不包含,A 之后到 B 的改动包含

A 的改动 commit C commit D B 的改动 ✗ ✓ ✓ ✓

想包含 A 的改动,基准线往前挪一位:

gitdiffA~1..B# A 的改动也被算进去了

两点 vs 三点在有分支时才有区别

线性历史上.....结果相同。分支场景下...才有特殊含义:

# 从 main 分叉出去后,feature 分支上独有的变化gitdiffmain...feature-branch# feature 分支从分叉点到现在的全部变化(含 main 合进来的)gitdiffmain..feature-branch

...常用于 PR review:“别人在这个分支上到底改了啥,去掉 main 上混入的”。


实用输出格式

快速浏览

# 只看改了哪些文件、改了多少行gitdiff--stat# 额外标注新增/删除/重命名gitdiff--stat--compact-summary# 只看文件名gitdiff--name-only

控制上下文行数

# 默认 3 行上下文gitdiff# 精简到 1 行gitdiff--unified=1# 或 -U1# 只显示改动行,完全不要上下文gitdiff-U0

其他有用选项

# 只看新增的行(过滤掉整个 diff 的元信息)gitdiff|grep'^+'|grep-v'^+++'# 忽略空白变化gitdiff-w# 单词级别的 diff(改动浓缩到一行内)gitdiff--word-diff=plain# 按文件类型过滤gitdiff--'*.py'gitdiff-- src/

高级用法

查看最近 N 个提交的累计差异

# 最近 3 个提交 + 当前未暂存修改gitdiffHEAD~3# 只看最近 3 个提交(不含未暂存)gitdiffHEAD~3..HEAD

指定文件在某区间内的变化

gitdiffmain..HEAD -- path/to/file.py

查看某次提交本身做了什么

gitshow<commit-hash># 等价于gitdiff<commit-hash>~1..<commit-hash>

查看暂存区中某个文件的改动

gitdiff--staged-- path/to/file.py

分支合并前的预览

# 合入 main 会带进去什么gitdiffmain...feature-branch# 如果有冲突,只看冲突文件gitdiff--name-only --diff-filter=U

比较两个分支的文件差异(不看内容)

gitdiff--name-status main..feature# 输出每行:A/M/D + 文件名

检查是否有改动(脚本中常用)

gitdiff--quiet# 工作区干净 → exit 0;有改动 → exit 1gitdiff--quiet--staged# 同上但检查暂存区

常见场景速查

你想看什么命令
改了还没 add 的git diff
add 了还没 commit 的git diff --staged
所有还没 commit 的git diff HEAD
上一次 commit 改了什么git show HEAD
最近 3 个 commit 总共改了啥git diff HEAD~3
某两个 commit 之间的差异git diff A..B
PR 里这个分支独有改动git diff main...feature
只列文件名和统计git diff --stat --compact-summary
只看 .py 文件的改动git diff -- '*.py'

总结

git diff的复杂性来自 Git 的三区域模型——工作区、暂存区、HEAD 各司其职。一旦理解了这个模型,各种 diff 变体只是"选两个点做比较"而已。

日常只用三个命令就够了:

gitdiff--staged# 提交前最后看一眼gitdiffHEAD~3# 回顾最近的改动gitdiffmain...HEAD# 分支合并前确认

剩下的--stat-U0--word-diff是调味料,按需加。

http://www.jsqmd.com/news/855689/

相关文章:

  • 为什么选择snnTorch?5个理由让你爱上这个脉冲神经网络框架
  • 别再瞎调PID了!手把手教你用STM32 HAL库搞定电机速度闭环(附完整代码)
  • Tere跨平台部署指南:在Linux、Windows和macOS上的终极安装配置教程
  • 3步实战Windows风扇控制:FanControl深度配置指南
  • 《Windows Sysinternals实战指南》PsTools 学习笔记(7.5):PsExec 的备用凭据与安全基线
  • 2026番茄罐头供应商怎么选?番茄酱供应厂家-恒钧隆实力解析 - 栗子测评
  • 现在怎么去学习AI,在哪里去学习?
  • PyTorch-FCN扩展开发指南:添加新数据集和网络架构的完整流程
  • torchtitan-npu:在昇腾集群上训练大模型
  • Lumia设备深度定制突破:Windows Phone Internals核心技术解密与实战指南
  • 避坑指南:VirtualBox中CentOS虚拟机网络配置的5个常见错误(附ifcfg-enp0s8文件详解)
  • 2026水果罐头源头厂家指南必看!甜玉米罐头批发厂家全梳理 - 栗子测评
  • 基于ssm的支教志愿者招聘系统(10069)
  • CANN AscendC反量化缓冲区API
  • 如何在Windows系统上免费恢复WannaCry加密文件?内存密钥恢复工具实战指南
  • 基于ssm框架的博客系统(10070)
  • MODBUS调试助手开发全解析:从协议原理到实战避坑指南
  • 告别臃肿PDF!用Ghostscript命令行批量压缩/拆分/合并的保姆级教程
  • rebar3与Hex.pm集成指南:Erlang包管理的完整解决方案
  • 《Windows Sysinternals实战指南》PsTools 学习笔记(7.7):进程性能选项——优先级、CPU 亲和性与稳定落地
  • HTML会代替Markdown吗?为什么?
  • 2026年口碑好的南京报警腕表/社区矫正腕表批量采购厂家推荐 - 品牌宣传支持者
  • 终极GTA5游戏增强菜单:YimMenu全方位安全防护指南
  • 别再死记命令了!用eNSP模拟真实办公室,手把手带你搞定华为AC+AP无线组网
  • 新能源充电桩厂家有哪些?2026新能源充电桩厂家优选:权威电动汽车充电桩厂家+电动汽车充电桩品牌榜单 - 栗子测评
  • 3分钟掌握UnityPackage Extractor:无需Unity轻松提取资源包
  • OpencvSharp 算子学习教案之 - Cv2.GetWindowHandle
  • Wallaby测试覆盖率分析:确保Web应用质量的最佳实践
  • FFXIV ACT插件开发指南:基于内存操作实现副本动画跳过功能
  • 《Sysinternals实战指南》进程和诊断工具学习笔记(8.17):LiveKd 实战——运行方式、常用参数、现场采集套路