搜索 K
主题
git log 和 git diff 是 Git 中最常用的查看和分析命令。log 用于浏览提交历史,diff 用于对比代码差异。熟练掌握这两个命令的各种参数,可以极大提高代码审查和调试效率。
git log 回答「发生了什么」,git diff 回答「改了什么」。
git log [<options>] [<revision range>] [-- <path>...]git log
# 显示完整的提交历史(SHA、作者、日期、提交信息)
# 按时间倒序排列# 单行显示(最常用)
git log --oneline
# abc1234 feat: 支付模块
# def5678 fix: 修复登录
# 显示分支图
git log --oneline --graph
# * abc1234 (HEAD -> main) Merge feature
# |\
# | * def5678 feat: 新功能
# |/
# * ghi9012 上一个提交
# 完整的分支图(所有分支)
git log --oneline --graph --all
# 显示修改的文件列表
git log --stat
# 显示每个提交的 diff
git log -p
# 限制显示数量
git log -5 # 最近 5 个提交
git log -n 10 # 最近 10 个提交--format) # 常用 format 占位符
# %H 完整 SHA
# %h 缩短 SHA
# %an 作者名
# %ae 作者邮箱
# %ar 相对日期(3 days ago)
# %ad 绝对日期
# %s 提交信息标题
# %b 提交信息正文
# %d 引用名(分支、标签)
# 紧凑格式
git log --format="%h %ar %an: %s"
# abc1234 3 days ago 张三: feat: 支付模块
# def5678 5 days ago 李四: fix: 修复登录
# 带颜色的自定义格式
git log --format="%C(yellow)%h%C(reset) %C(green)%ar%C(reset) %C(blue)%an%C(reset): %s%C(red)%d%C(reset)"
# 保存为 alias
git config --global alias.lg "log --format='%C(yellow)%h%C(reset) %C(green)%ar%C(reset) %C(blue)%an%C(reset): %s%C(red)%d%C(reset)' --graph"
# 使用:git lg# 最近一周的提交
git log --since="1 week ago"
git log --after="2026-03-01"
# 某个时间之前的提交
git log --until="2026-02-28"
git log --before="1 month ago"
# 时间范围
git log --since="2026-01-01" --until="2026-01-31"
# 相对时间格式
git log --since="3.days"
git log --since="2.weeks"# 按作者名(支持正则)
git log --author="张三"
git log --author="zhang"
# 多个作者(正则 OR)
git log --author="张三\|李四"# 搜索提交信息中包含关键字的提交
git log --grep="支付"
git log --grep="fix:"
git log --grep="bug" --grep="fix" --all-match # AND 关系
# 不区分大小写
git log --grep="payment" -i# -S:pickaxe 搜索 —— 查找「增加或删除了特定字符串」的提交
git log -S "processPayment"
# 找到引入或删除 "processPayment" 字符串的提交
# -G:正则搜索 —— 查找 diff 中匹配正则的提交
git log -G "TODO|FIXME|HACK"
# 查看匹配的具体 diff
git log -S "processPayment" -p-S vs -G 的区别-S "text":查找改变了 "text" 出现次数的提交(新增或删除了这个字符串)-G "regex":查找diff 中包含匹配正则的行的提交(更广泛的匹配)-S 更精准(只找引入/删除),-G 更全面(包括修改了包含该正则的行)。
# 查看特定文件的提交历史
git log -- src/payment/checkout.ts
# 查看目录下所有文件的提交历史
git log -- src/payment/
# 查看多个文件
git log -- src/auth.ts src/config.ts
# 查看文件的重命名历史
git log --follow -- src/new-name.ts# 只显示新增文件的提交
git log --diff-filter=A -- "*.ts"
# 只显示删除文件的提交
git log --diff-filter=D
# 只显示修改文件的提交
git log --diff-filter=M -- src/
# 过滤类型:A(Added) C(Copied) D(Deleted) M(Modified) R(Renamed)# feature 有但 main 没有的提交
git log main..feature --oneline
# main 有但 feature 没有的提交
git log feature..main --oneline
# 两个分支的差异(双向)
git log main...feature --oneline --left-right
# < abc1234 main 独有的提交
# > def5678 feature 独有的提交
# 查看某个分支的所有提交(不含合并提交)
git log main..feature --no-merges.. vs ... 的区别A..B — B 中有但 A 中没有的提交(单向)A...B — A 和 B 各自独有的提交(双向,常配合 --left-right)# 查看某个函数是谁在何时引入的
git log -S "function processPayment" --oneline
# 查看某个函数在文件中的逐行修改历史(结合 blame)
git log -L :processPayment:src/payment.ts
# 显示 processPayment 函数在每次提交中的完整变化
# 查看特定行范围的历史
git log -L 100,150:src/payment.ts# 获取两个版本之间的所有提交(按类型分组)
git log v2.0.0..v3.0.0 --oneline --no-merges
# 只看 feat 提交
git log v2.0.0..v3.0.0 --grep="^feat" --oneline
# 只看 fix 提交
git log v2.0.0..v3.0.0 --grep="^fix" --oneline
# 生成简易 CHANGELOG
echo "# Changelog v3.0.0"
echo ""
echo "## Features"
git log v2.0.0..v3.0.0 --grep="^feat" --format="- %s" --no-merges
echo ""
echo "## Bug Fixes"
git log v2.0.0..v3.0.0 --grep="^fix" --format="- %s" --no-merges# 按作者统计提交数
git shortlog -sn
# 142 张三
# 89 李四
# 45 王五
# 按作者统计某段时间的提交
git shortlog -sn --since="2026-01-01"
# 统计每个作者修改的行数
git log --format='%an' | sort -u | while read author; do
echo "$author:"
git log --author="$author" --numstat --format="" | awk '{add+=$1; del+=$2} END {printf " +%d -%d\n", add, del}'
done# 查看上次部署标签之后的所有提交
git log v2.5.0..HEAD --oneline --no-merges
# 只看影响了特定目录的提交
git log v2.5.0..HEAD --oneline -- src/api/
# 查看谁的提交可能引入了问题
git log v2.5.0..HEAD --format="%h %an: %s" --no-merges# 查找删除了特定代码的提交
git log -S "deletedFunction" --diff-filter=D -p
# 查找某个文件被删除的提交
git log --diff-filter=D -- src/old-file.ts
git log --all --full-history -- src/old-file.ts
# 恢复被删除的文件
git show <sha>:src/old-file.ts > src/old-file.ts[alias]
# 漂亮的单行图形日志(最常用)
lg = log --graph --oneline --decorate --all
# 带作者和日期
lga = log --graph --format='%C(yellow)%h%C(reset) %C(green)%ar%C(reset) %C(blue)%an%C(reset): %s%C(red)%d%C(reset)' --all
# 最近 N 个提交
l5 = log --oneline -5
l10 = log --oneline -10
# 查看某个文件的提交历史
lf = log --oneline --follow --
# 今天的提交
today = log --since='midnight' --oneline --no-merges
# 我的提交
my = log --author='<你的名字>' --oneline--first-parent 简化合并历史 # 在使用 merge commit 的项目中,log 可能非常杂乱
# --first-parent 只沿着第一个父提交(即 main 分支)走
git log --first-parent --oneline main
# 只显示直接在 main 上的提交和合并提交
# 不显示被合并进来的分支的内部提交# 找到合并提交
git log --merges --grep="Merge pull request #456" --oneline
# 查看合并提交引入的所有提交
git log <merge-sha>^1..<merge-sha>^2 --oneline
# ^1 是 main 的父提交,^2 是 feature 的最后提交git diff [<options>] [<commit>] [-- <path>...]
git diff [<options>] <commit> <commit> [-- <path>...]
git diff [<options>] --cached [<commit>] [-- <path>...]理解 git diff 的关键是理解 Git 的三棵树:
| 命令 | 对比对象 |
|---|---|
git diff | 工作目录 vs 暂存区 |
git diff --cached | 暂存区 vs HEAD(即将提交的内容) |
git diff HEAD | 工作目录 vs HEAD |
git diff <commit> | 工作目录 vs 指定提交 |
git diff <A> <B> | 提交 A vs 提交 B |
git diff <A>...<B> | merge-base(A,B) vs B |
# 查看工作目录中未 git add 的修改
git diff
# 查看特定文件
git diff src/main.ts
# 查看特定目录
git diff src/payment/# 查看已 git add 但未 commit 的修改
git diff --cached
# 同义命令
git diff --staged# 对比两个提交
git diff abc1234 def5678
# 对比两个分支
git diff main feature
# 对比当前分支和 main 的 merge-base(PR 审查常用)
git diff main...feature
# 显示 feature 相对于「分叉点」的修改,而非相对于 main 最新状态.. vs ... 在 diff 中的含义在 diff 中(与 log 不同!):
git diff A B 或 git diff A..B — 对比 A 和 B 的当前状态git diff A...B — 对比 merge-base(A,B) 和 B(即 B 分支自分叉以来的修改)代码审查通常用 A...B(查看 PR 引入了什么变更)。
# 只显示修改的文件列表和统计
git diff --stat
# src/main.ts | 15 +++++++++------
# src/config.ts | 3 +++
# 2 files changed, 12 insertions(+), 6 deletions(-)
# 只显示文件名
git diff --name-only
# 显示文件名和修改状态
git diff --name-status
# M src/main.ts (Modified)
# A src/new-file.ts (Added)
# D src/old-file.ts (Deleted)
# 显示简短统计
git diff --shortstat
# 2 files changed, 12 insertions(+), 6 deletions(-)# 忽略行尾空白差异
git diff --ignore-space-at-eol
# 忽略所有空白差异
git diff -w
# 同义
git diff --ignore-all-space
# 忽略空白数量变化(但不忽略新增/删除空白)
git diff -b
# 同义
git diff --ignore-space-change
# 忽略空行变化
git diff --ignore-blank-lines-w很多时候代码格式化工具(Prettier、Black)会修改空白,导致 diff 中充满无意义的差异。使用 -w 可以过滤掉这些噪音,只看真正的代码修改。
# 按单词对比(适合散文/文档/注释的修改)
git diff --word-diff
# 输出:This is [-old-]{+new+} text
# 按字符对比
git diff --word-diff-regex=.
# 彩色单词对比
git diff --color-words# 显示每个修改块所在的函数名
git diff -p --function-context
# 对比特定函数的变化
git diff -L :functionName:file.ts# 默认二进制文件只显示 "Binary files differ"
# 使用 textconv 配置自定义对比方式
# 对比图片文件的 EXIF 信息
# 在 .gitattributes 中配置
# *.png diff=exif
# 在 .gitconfig 中配置
# [diff "exif"]
# textconv = exiftool# 查看 PR 引入的完整修改
git diff main...feature
# 只看某种类型的文件
git diff main...feature -- "*.ts" "*.tsx"
# 排除特定文件
git diff main...feature -- . ":(exclude)package-lock.json"
git diff main...feature -- . ":(exclude)*.lock"
# 统计修改量
git diff main...feature --stat# 查看从上次部署到现在的所有修改
git diff v2.5.0..HEAD --stat
# 只看后端代码的修改
git diff v2.5.0..HEAD -- src/api/ src/services/
# 确认没有调试代码遗留
git diff v2.5.0..HEAD | grep -n "console.log\|debugger\|TODO"# 对比两个版本的配置文件
git diff v1.0.0 v2.0.0 -- config/
# 对比两个分支的 package.json 依赖变化
git diff main feature -- package.json
# 查看依赖变化的详情(忽略锁文件)
git diff main feature -- package.json | grep "^\+\|^-" | grep -v "^---\|^+++"# 检查暂存区中即将提交的修改
git diff --cached
# 确认没有敏感信息
git diff --cached | grep -i "password\|secret\|api_key\|token"
# 确认没有调试代码
git diff --cached | grep -n "console.log\|debugger\|print("
# 查看修改摘要
git diff --cached --stat# 将 diff 输出保存为 patch 文件
git diff main..feature > feature.patch
# 应用 patch
git apply feature.patch
# 检查 patch 是否可以应用
git apply --check feature.patch
# 生成带提交信息的 patch(推荐)
git format-patch main..feature
# 每个提交一个 patch 文件
# 应用 format-patch 的 patch
git am *.patch# 对比两个文件(不需要是 Git 管理的文件)
git diff --no-index file1.ts file2.ts
# 对比两个目录
git diff --no-index dir1/ dir2/# 使用 VS Code 作为 diff 工具
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# 使用
git difftool main..feature
# 其他常用工具
# - Beyond Compare
# - Meld
# - WinMerge(Windows)
# - Kaleidoscope(macOS)# 排除 lock 文件和生成的代码
git diff -- . ":(exclude)package-lock.json" ":(exclude)yarn.lock" ":(exclude)*.generated.ts"
# 配置全局排除(在 .gitattributes 中)
# package-lock.json diff=nodiff
# 在 .gitconfig 中
# [diff "nodiff"]
# command = true[alias]
# 查看未暂存修改
d = diff
# 查看已暂存修改
dc = diff --cached
# 查看修改统计
ds = diff --stat
# 查看修改文件列表
dn = diff --name-only
# 忽略空白的 diff
dw = diff -w
# PR 审查式 diff
dr = "!f() { git diff ${1:-main}...HEAD; }; f"
# 上次提交的修改
dl = diff HEAD~1 HEAD# 1. 先用 log 定位可疑提交
git log --oneline --since="1 week ago" -- src/payment/
# 2. 用 diff 查看具体修改
git diff abc1234~1 abc1234
# 3. 用 show 查看完整提交(log + diff 的结合)
git show abc1234
# 4. 用 blame 定位具体代码行
git blame src/payment/checkout.tsgit bisect 使用 # bisect 找到问题提交后
# 1. 查看该提交修改了什么
git show <bad-sha> --stat
# 2. 对比该提交前后的完整差异
git diff <bad-sha>~1 <bad-sha>
# 3. 查看该提交前后的函数级别变化
git diff <bad-sha>~1 <bad-sha> -p --function-context详见 Git bisect
git show —— log + diff 的快捷方式 # 查看最新提交的详情
git show
# 查看指定提交
git show abc1234
# 只看文件列表
git show --stat abc1234
# 只看特定文件的修改
git show abc1234 -- src/main.ts
# 查看某个提交时的文件内容(不是 diff)
git show abc1234:src/main.ts# 1. 确认上次部署时间对应的提交
git log --oneline --until="2026-03-07 18:00" -1
# abc1234 最后一次部署的提交
# 2. 查看部署后到现在的所有提交
git log abc1234..HEAD --oneline --no-merges
# 3. 只看影响了关键路径的提交
git log abc1234..HEAD --oneline -- src/api/payment/ src/services/order/
# 4. 搜索可疑的代码修改
git log abc1234..HEAD -S "setTimeout" -p # 谁加了 setTimeout?
git log abc1234..HEAD -G "catch\s*\(\s*\)" -p # 谁吞了异常?# 谁在什么时候修改了敏感文件
git log --format="%H %ai %an: %s" -- src/auth/ src/security/ config/secrets/
# 查看所有 force push(通过 reflog)
git reflog --format="%h %gd %gs" | grep "forced-update"
# 统计某段时间内的提交频率(用于评估开发节奏)
git log --format="%ad" --date=short --since="2026-01-01" | sort | uniq -c
# 5 2026-01-02
# 12 2026-01-03
# 8 2026-01-04# 步骤 1:找到可疑的代码行
git blame src/payment/checkout.ts -L 45,60
# 步骤 2:查看该行的完整修改历史
git log -L 45,60:src/payment/checkout.ts
# 步骤 3:结合 bisect 自动定位
git bisect start HEAD v2.0.0
git bisect run npm test详见 Git bisect
# 对比 staging 和 production 的配置差异
git diff origin/staging origin/production -- config/
# 只看 .env 模板的差异
git diff origin/staging origin/production -- .env.example
# 对比 Dockerfile 差异
git diff origin/staging origin/production -- Dockerfile docker-compose.yml# 只看新增的文件
git diff main...feature --diff-filter=A --name-only
# 只看删除的文件
git diff main...feature --diff-filter=D --name-only
# 只看重命名的文件
git diff main...feature --diff-filter=R --name-only
# 排除测试文件,只看业务代码
git diff main...feature -- . ":(exclude)__tests__" ":(exclude)*.test.ts" ":(exclude)*.spec.ts"
# 只看新增行数超过 50 行的文件(检测大文件修改)
git diff main...feature --numstat | awk '$1 > 50 {print $3}'# 只看迁移文件的变更
git diff main...feature -- migrations/ db/migrate/
# 确认没有破坏性的迁移操作
git diff main...feature -- migrations/ | grep -i "DROP\|DELETE\|TRUNCATE\|ALTER.*DROP"
# 查看 schema 文件的变更
git diff main...feature -- prisma/schema.prisma db/schema.rbgit log 的可视化输出 # 终端中最漂亮的 git log 配置
git config --global alias.lg "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all"
# 按日期分组显示
git log --format="%ad %s" --date=short | awk -F' ' '{date=$1; $1=""; if(date!=prev){print date; prev=date} print " "$0}'
# 显示提交的影响范围(哪些目录)
git log --oneline --name-only -5 | awk '/^[a-f0-9]/{commit=$0;next} /\//{dir=$0; sub(/\/[^/]*$/,"",dir); dirs[commit][dir]=1} END{for(c in dirs){print c; for(d in dirs[c]) print " "d}}'git diff 与 CI/CD 集成 # CI 中检测是否有代码修改(用于条件构建)
if git diff --quiet HEAD~1 -- src/; then
echo "src/ 无修改,跳过构建"
else
echo "src/ 有修改,执行构建"
npm run build
fi
# 只在特定目录有变更时运行对应的测试
CHANGED_DIRS=$(git diff --name-only HEAD~1 | cut -d'/' -f1-2 | sort -u)
if echo "$CHANGED_DIRS" | grep -q "src/api"; then
npm run test:api
fi
if echo "$CHANGED_DIRS" | grep -q "src/ui"; then
npm run test:ui
figit log 生成发布报告 #!/bin/bash
# release-report.sh — 自动生成发布报告
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "HEAD~50")
CURR_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD")
echo "# 发布报告: $CURR_TAG"
echo ""
echo "## 概要"
echo "- 提交数: $(git log $PREV_TAG..$CURR_TAG --oneline --no-merges | wc -l)"
echo "- 贡献者: $(git log $PREV_TAG..$CURR_TAG --format='%an' | sort -u | wc -l)"
echo "- 修改文件数: $(git diff $PREV_TAG $CURR_TAG --name-only | wc -l)"
echo ""
echo "## 新功能"
git log $PREV_TAG..$CURR_TAG --grep="^feat" --format="- %s (%h)" --no-merges
echo ""
echo "## Bug 修复"
git log $PREV_TAG..$CURR_TAG --grep="^fix" --format="- %s (%h)" --no-merges
echo ""
echo "## 贡献者"
git log $PREV_TAG..$CURR_TAG --format='%an' | sort | uniq -c | sort -rn | awk '{print "- "$2" ("$1" 次提交)"}'git blame 深度使用 # 查看某行代码的最后修改者
git blame src/payment.ts -L 45,60
# 忽略空白变更的 blame(更准确地找到真正修改者)
git blame -w src/payment.ts
# 跟踪代码从另一个文件移过来的历史
git blame -C src/new-file.ts
# -C:检测从其他文件复制/移动的代码
# 更深层的代码移动检测
git blame -C -C -C src/file.ts
# 三个 -C:检测任何文件间的代码移动git log 输出太多怎么办?使用过滤参数缩小范围:
git log -10 # 最近 10 条
git log --since="1 week ago" # 最近一周
git log -- src/specific-dir/ # 特定目录
git log --author="张三" # 特定作者
git log --no-merges # 排除合并提交git diff 输出中的 @@ 行是什么意思?@@ -10,7 +10,8 @@ function processPayment() {-10,7:旧文件从第 10 行开始,显示 7 行+10,8:新文件从第 10 行开始,显示 8 行function processPayment():这个修改块所在的函数# 先获取最新的远程信息
git fetch origin
# 对比本地和远程
git diff main origin/main
git log main..origin/main --oneline^ 的问题?# PowerShell 中 ^ 是特殊字符
# ❌
git diff HEAD^1
# ✅ 使用引号或 ~
git diff "HEAD^1"
git diff HEAD~1git log --all --oneline -- src/file.ts| 目标 | 命令 |
|---|---|
| 单行图形日志 | git log --oneline --graph --all |
| 最近 N 个提交 | git log -N |
| 按作者过滤 | git log --author="名字" |
| 按信息过滤 | git log --grep="关键字" |
| 按代码内容过滤 | git log -S "代码" |
| 按文件过滤 | git log -- <path> |
| 按时间过滤 | git log --since="1 week ago" |
| 分支差异 | git log main..feature |
| 修改统计 | git log --stat |
| 显示 diff | git log -p |
| 贡献者统计 | git shortlog -sn |
| 函数历史 | git log -L :func:file |
| 跟踪文件重命名 | git log --follow -- <file> |
| 排除合并提交 | git log --no-merges |
| 目标 | 命令 |
|---|---|
| 未暂存的修改 | git diff |
| 已暂存的修改 | git diff --cached |
| 所有修改(vs HEAD) | git diff HEAD |
| 两个提交间的差异 | git diff <A> <B> |
| 分支分叉后的差异 | git diff main...feature |
| 只看文件列表 | git diff --name-only |
| 修改统计 | git diff --stat |
| 忽略空白 | git diff -w |
| 按单词对比 | git diff --word-diff |
| 排除文件 | git diff -- . ":(exclude)*.lock" |
| 生成 patch | git diff > file.patch |
| 对比非 Git 文件 | git diff --no-index file1 file2 |
| 检查冲突标记残留 | git diff --check |
stash show -p 查看 stash 的 diffgit blame — 查看每行代码的最后修改者git show — 查看单个提交的详情(log + diff)