git diff 命令
简介
git diff 是 Git 中一个非常重要的命令,用于显示文件之间的差异。它可以比较工作区、暂存区、不同提交之间的差异,帮助开发者了解代码的变化。
基本概念
Git 中有三个主要区域:
- 工作区(Working Directory):当前正在编辑的文件
- 暂存区(Staging Area / Index):已使用
git add 添加的文件
- 仓库(Repository):已提交的版本
git diff 可以比较这些区域之间的差异。
命令语法
1 2 3 4 5 6
| git diff [选项] [--] [<路径名>...] git diff [选项] --cached [<提交>] [--] [<路径名>...] git diff [选项] <提交> [--] [<路径名>...] git diff [选项] <提交1> <提交2> [--] [<路径名>...] git diff [选项] <提交1>..<提交2> [--] [<路径名>...] git diff [选项] <提交1>...<提交2> [--] [<路径名>...]
|
查看帮助文档
常用选项
| 选项 |
说明 |
--cached, --staged |
比较暂存区和最后一次提交 |
-p, -u, --unified=<n> |
显示统一格式的差异,n 为上下文行数 |
--stat |
显示统计信息(修改的文件和行数) |
--name-only |
只显示文件名 |
--name-status |
显示文件名和状态(M/A/D/R) |
-w, --ignore-all-space |
忽略所有空白字符的差异 |
-b, --ignore-space-change |
忽略空白字符数量的变化 |
--ignore-blank-lines |
忽略空白行的差异 |
-S<string> |
显示包含指定字符串的更改 |
-G<regex> |
显示匹配正则表达式的更改 |
--color[=<when>] |
使用颜色高亮显示差异 |
--no-color |
不使用颜色 |
-R |
反向显示差异(新文件在前) |
--word-diff |
按单词显示差异 |
--word-diff-regex=<regex> |
使用正则表达式定义单词边界 |
--ignore-submodules |
忽略子模块的更改 |
--submodule=<format> |
指定子模块差异的格式 |
--ext-diff |
允许执行外部 diff 工具 |
--no-ext-diff |
禁止执行外部 diff 工具 |
--no-index |
比较两个路径,即使它们不在 Git 仓库中 |
基本使用
1. 比较工作区和暂存区
显示工作区中已修改但未暂存的文件差异(默认行为)。
1 2 3 4 5 6 7 8
| $ git diff
$ git diff README.md
$ git diff src/
|
示例输出:
1 2 3 4 5 6 7 8 9 10
|
@@ -10,7 +10,7 @@ int main() { printf("Hello, World!\n"); - printf("Old message\n"); + printf("New message\n"); return 0; }
|
2. 比较暂存区和最后一次提交
使用 --cached 或 --staged 选项。
1 2 3 4 5 6 7 8
| $ git diff --cached
$ git diff --staged
$ git diff --cached README.md
|
3. 比较工作区和最后一次提交
1 2 3 4 5
| $ git diff HEAD
$ git diff HEAD README.md
|
4. 比较两次提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $ git diff commit1 commit2
$ git diff abc1234 def5678
$ git diff HEAD~1 HEAD
$ git diff commit1..commit2
$ git diff commit1...commit2
|
5. 比较分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $ git diff branch1 branch2
$ git diff main develop
$ git diff main origin/main
$ git diff main..develop
$ git diff main...develop
|
6. 比较提交和文件
1 2 3 4 5 6 7 8
| $ git diff HEAD src/main.c
$ git diff commit1 commit2 -- README.md
$ git diff --cached HEAD~1
|
输出格式说明
Git 默认使用统一格式显示差异:
1 2 3 4 5 6 7 8 9
|
@@ -1,3 +1,3 @@ line 1 -line 2 (old) +line 2 (new) line 3
|
格式说明:
--- a/file.txt:原始文件
+++ b/file.txt:修改后的文件
@@ -1,3 +1,3 @@:块头,表示从第1行开始,共3行
-:删除的行
+:添加的行
- 没有符号:未修改的行
上下文行数
1 2 3 4 5 6 7 8
| $ git diff
$ git diff -U5
$ git diff --unified=10
|
常用选项详解
–stat:显示统计信息
1 2 3 4 5 6 7 8
| $ git diff --stat README.md | 2 +- src/main.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-)
$ git diff --stat --summary
|
–name-only:只显示文件名
1 2 3 4 5
| $ git diff --name-only README.md src/main.c src/utils.h
|
–name-status:显示文件名和状态
1 2 3 4 5 6 7
| $ git diff --name-status M README.md M src/main.c A src/utils.h D oldfile.txt R100 oldname.txt newname.txt
|
状态码说明:
M:修改(Modified)
A:添加(Added)
D:删除(Deleted)
R:重命名(Renamed)
C:复制(Copied)
忽略空白字符
1 2 3 4 5 6 7 8 9 10 11
| $ git diff -w
$ git diff -b
$ git diff --ignore-blank-lines
$ git diff -w -b --ignore-blank-lines
|
颜色输出
1 2 3 4 5 6 7 8 9 10 11
| $ git diff --color
$ git diff --no-color
$ git diff --color=always
$ git diff --color=auto
|
搜索特定更改
1 2 3 4 5 6 7 8
| $ git diff -S"function_name"
$ git diff -G"^import"
$ git diff -S"TODO" --stat
|
单词级别差异
1 2 3 4 5
| $ git diff --word-diff
$ git diff --word-diff-regex='[A-Za-z0-9]+'
|
示例输出:
1 2 3 4 5 6
|
@@ -1 +1 @@ This is [-old-]{+new+} text.
|
高级用法
比较特定路径
1 2 3 4 5 6 7 8 9 10 11
| $ git diff HEAD -- README.md
$ git diff HEAD -- src/
$ git diff HEAD -- file1.txt file2.txt
$ git diff HEAD -- "*.py"
|
限制上下文行数
1 2 3 4 5 6 7 8
| $ git diff -U0
$ git diff -U1
$ git diff -U20
|
反向显示
1 2 3 4 5
| $ git diff -R
$ git diff -R commit1 commit2
|
比较非 Git 文件
1 2 3 4 5
| $ git diff --no-index file1.txt file2.txt
$ git diff --no-index dir1/ dir2/
|
使用外部 diff 工具
1 2 3 4 5 6 7 8
| $ git config --global diff.tool vimdiff
$ git difftool
$ git difftool --tool=vimdiff
|
实际应用场景
场景1:查看未暂存的更改
1 2 3 4 5
| $ git diff
$ git diff src/main.c
|
场景2:查看已暂存的更改
1 2 3 4 5
| $ git diff --cached
$ git diff --cached README.md
|
场景3:查看所有更改(工作区 + 暂存区)
1 2 3 4 5 6
| $ git diff HEAD
$ git diff $ git diff --cached
|
场景4:代码审查
1 2 3 4 5 6 7 8
| $ git diff main..feature-branch
$ git diff --stat main..feature-branch
$ git diff main..feature-branch -- src/main.c
|
场景5:查看提交历史中的更改
1 2 3 4 5 6 7 8
| $ git diff HEAD~1 HEAD
$ git diff HEAD~3 HEAD
$ git diff abc1234^..abc1234
|
场景6:查找特定更改
1 2 3 4 5 6 7 8
| $ git diff -S"TODO"
$ git diff -G"function.*\(\)"
$ git diff commit1..commit2 -S"bug"
|
场景7:忽略空白字符差异
1 2 3 4 5
| $ git diff -w
$ git diff -b --ignore-blank-lines
|
场景8:生成补丁文件
1 2 3 4 5 6 7 8
| $ git diff > changes.patch
$ git diff commit1 commit2 > feature.patch
$ git apply changes.patch
|
场景9:比较远程分支
1 2 3 4 5 6
| $ git diff main origin/main
$ git fetch origin $ git diff main origin/main
|
场景10:查看文件重命名
1 2 3 4 5
| $ git diff --name-status HEAD~1 HEAD
$ git diff -M HEAD~1 HEAD
|
与其他命令的组合
git diff + git log
1 2 3 4 5 6
| $ git log --oneline $ git diff commit1 commit2
$ git log -p
|
git diff + git show
1 2 3 4 5
| $ git show commit1
$ git diff commit1^..commit1
|
git diff + git stash
1 2 3 4 5
| $ git stash show -p
$ git diff stash@{0}
|
git diff + grep
1 2 3 4 5
| $ git diff | grep "function_name"
$ git diff -G"pattern" | grep "file"
|
常见问题和技巧
问题1:diff 输出太长
解决方案:
1 2 3 4 5 6 7 8
| $ git diff --name-only
$ git diff --stat
$ git diff -U3
|
问题2:只想看特定类型的更改
解决方案:
1 2 3 4 5 6 7 8 9 10 11
| $ git diff --diff-filter=A
$ git diff --diff-filter=D
$ git diff --diff-filter=M
$ git diff --diff-filter=AM
|
问题3:忽略某些文件的差异
解决方案:
1 2 3 4 5
| $ git diff -- ':!*.log' ':!*.tmp'
$ git diff -- ':!.gitignore'
|
问题4:查看二进制文件的差异
解决方案:
1 2 3 4 5 6
|
$ git config diff.pdf.textconv pdftotext
$ git difftool binary-file.pdf
|
问题5:比较时包含未跟踪的文件
解决方案:
1 2 3 4 5 6 7
| $ git status
$ git add untracked-file.txt $ git diff --cached
|
技巧1:使用别名简化命令
1 2 3 4 5 6 7 8 9
| $ git config --global alias.d 'diff' $ git config --global alias.dc 'diff --cached' $ git config --global alias.ds 'diff --stat'
$ git d $ git dc $ git ds
|
技巧2:使用颜色主题
1 2 3 4 5 6
| $ git config --global color.diff auto $ git config --global color.diff.meta "yellow bold" $ git config --global color.diff.frag "magenta bold" $ git config --global color.diff.old "red bold" $ git config --global color.diff.new "green bold"
|
技巧3:保存差异到文件
1 2 3 4 5 6 7 8
| $ git diff > diff.txt
$ git diff commit1 commit2 > feature-diff.txt
$ git diff >> all-diffs.txt
|
技巧4:在编辑器中使用
1 2 3 4 5
| $ git diff | vim -
$ git diff | less
|
最佳实践
1. 提交前检查
1 2 3 4 5
| $ git diff --cached
$ git diff HEAD
|
2. 代码审查
1 2 3 4 5
| $ git diff main..feature-branch --stat
$ git diff main..feature-branch
|
3. 调试问题
1 2 3 4 5
| $ git diff commit1..commit2
$ git diff -S"bug" commit1..commit2
|
4. 文档化更改
1 2 3 4 5
| $ git diff > CHANGES.patch
$ git diff --stat > CHANGES.txt
|
5. 使用合适的上下文
1 2 3 4 5
| $ git diff -U10
$ git diff -U3
|
6. 忽略无关差异
1 2 3 4 5
| $ git diff -w
$ git diff -b --ignore-blank-lines
|
输出格式说明
格式:@@ -起始行,行数 +起始行,行数 @@
-10,7:原始文件从第10行开始,共7行
+10,7:新文件从第10行开始,共7行
行标记
(空格):未修改的行
-:删除的行(红色)
+:添加的行(绿色)
\:行尾没有换行符
文件头
--git:Git 格式
a/file.txt:原始文件路径
b/file.txt:新文件路径
index:文件的 blob 对象哈希
100644:文件模式(普通文件)
总结
git diff 是 Git 中最重要的命令之一,掌握它可以帮助你:
- 查看更改:了解工作区、暂存区和提交之间的差异
- 代码审查:比较分支和提交,进行代码审查
- 调试问题:查找引入问题的更改
- 生成补丁:创建补丁文件用于分享或备份
- 统计分析:查看代码更改的统计信息
通过合理使用 git diff 的各种选项,可以更高效地查看和理解代码的变化。