Skip to content

Git History

理解和查看项目历史是使用 Git 的重要技能。本章将详细介绍如何查看、分析和理解 Git 的提交历史。

基本历史查看

git log 基础用法

bash
# 查看完整的提交历史
git log

# 查看简洁的单行历史
git log --oneline

# 限制显示的提交数量
git log -n 5
git log --oneline -10

# 查看图形化的分支历史
git log --graph

# 组合使用
git log --oneline --graph -10

创建演示历史

让我们先创建一个有丰富历史的项目来演示:

bash
# 创建演示项目
mkdir git-history-demo
cd git-history-demo
git init

# 创建初始提交
echo "# Git 历史演示项目" > README.md
git add README.md
git commit -m "初始提交: 添加 README"

# 添加更多提交
echo "项目描述" >> README.md
git add README.md
git commit -m "更新 README: 添加项目描述"

echo "console.log('Hello World');" > app.js
git add app.js
git commit -m "添加主应用文件"

echo "body { margin: 0; }" > style.css
git add style.css
git commit -m "添加样式文件"

详细的 log 选项

格式化输出

bash
# 自定义格式
git log --pretty=format:"%h - %an, %ar : %s"

# 常用格式选项
git log --pretty=format:"%H"     # 完整哈希
git log --pretty=format:"%h"     # 简短哈希
git log --pretty=format:"%an"    # 作者名字
git log --pretty=format:"%ae"    # 作者邮箱
git log --pretty=format:"%ad"    # 作者日期
git log --pretty=format:"%ar"    # 相对日期
git log --pretty=format:"%s"     # 提交信息
git log --pretty=format:"%b"     # 提交正文

# 美化的日志格式
git log --pretty=format:"%C(yellow)%h%C(reset) - %C(green)%an%C(reset), %C(blue)%ar%C(reset) : %s"

时间和日期过滤

bash
# 查看特定时间段的提交
git log --since="2 weeks ago"
git log --until="2023-12-01"
git log --since="2023-01-01" --until="2023-12-31"

# 相对时间
git log --since="yesterday"
git log --since="1 week ago"
git log --since="2 months ago"

# 具体日期格式
git log --since="2023-01-01 00:00:00"
git log --after="Jan 1 2023" --before="Dec 31 2023"

作者和提交者过滤

bash
# 按作者过滤
git log --author="张三"
git log --author="zhangsan@example.com"

# 支持正则表达式
git log --author="张.*"
git log --author=".*@company.com"

# 按提交者过滤
git log --committer="李四"

# 排除特定作者
git log --author="^(?!.*张三).*$" --perl-regexp

内容搜索

bash
# 搜索提交信息
git log --grep="修复"
git log --grep="bug" --grep="fix" --all-match

# 搜索代码变更
git log -S "function_name"
git log -G "正则表达式"

# 搜索文件内容变更
git log -p -S "console.log"

# 忽略大小写
git log --grep="BUG" -i

文件和路径过滤

bash
# 查看特定文件的历史
git log README.md
git log -- README.md  # 更安全的写法

# 查看多个文件
git log file1.txt file2.txt

# 查看目录的历史
git log src/
git log -- src/

# 查看已删除文件的历史
git log --all --full-history -- deleted_file.txt

高级历史查看

图形化历史

bash
# 基本分支图
git log --graph --oneline

# 详细分支图
git log --graph --pretty=format:"%C(red)%h%C(reset) -%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(bold blue)<%an>%C(reset)"

# 查看所有分支
git log --graph --oneline --all

# 简化的分支图
git log --graph --simplify-by-decoration --oneline --all

统计信息

bash
# 显示修改统计
git log --stat

# 显示简短统计
git log --shortstat

# 显示文件名统计
git log --name-only

# 显示文件状态
git log --name-status

# 显示数字统计
git log --numstat

差异显示

bash
# 显示每个提交的差异
git log -p

# 限制差异上下文行数
git log -p -U1

# 只显示特定文件的差异
git log -p -- file.txt

# 显示单词级别的差异
git log -p --word-diff

特殊的历史查看

查看合并历史

bash
# 只显示合并提交
git log --merges

# 不显示合并提交
git log --no-merges

# 显示第一父提交
git log --first-parent

# 查看合并的详细信息
git log --merges -p

查看分支历史

bash
# 查看两个分支的差异
git log main..feature-branch

# 查看在 feature-branch 但不在 main 的提交
git log main..feature-branch

# 查看在 main 但不在 feature-branch 的提交
git log feature-branch..main

# 查看两个分支的对称差异
git log main...feature-branch

查看标签历史

bash
# 查看标签之间的历史
git log v1.0..v2.0

# 查看从标签到现在的历史
git log v1.0..HEAD

# 查看包含特定标签的提交
git log --contains v1.0

实用的历史别名

设置常用别名

bash
# 美化的日志
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

# 简洁的历史
git config --global alias.hist "log --oneline --graph --decorate --all"

# 详细的历史
git config --global alias.ll "log --oneline --graph --decorate --stat"

# 查看最近的提交
git config --global alias.last "log -1 HEAD --stat"

# 查看今天的提交
git config --global alias.today "log --since='midnight' --oneline"

使用别名

bash
# 使用设置的别名
git lg
git hist
git ll
git last
git today

历史分析工具

gitk 图形界面

bash
# 启动 gitk
gitk

# 查看所有分支
gitk --all

# 查看特定文件的历史
gitk README.md

# 查看特定时间段
gitk --since="1 week ago"

git show 命令

bash
# 查看最新提交
git show

# 查看特定提交
git show commit_hash

# 查看特定提交的特定文件
git show commit_hash:file.txt

# 只显示提交信息,不显示差异
git show --name-only commit_hash

# 显示统计信息
git show --stat commit_hash

git blame 追踪代码

bash
# 查看文件每行的最后修改者
git blame file.txt

# 查看特定行范围
git blame -L 10,20 file.txt

# 忽略空白字符变化
git blame -w file.txt

# 显示邮箱而不是用户名
git blame -e file.txt

# 显示原始行号
git blame -n file.txt

历史搜索技巧

使用 git bisect 查找问题

bash
# 开始二分查找
git bisect start

# 标记当前提交为坏的
git bisect bad

# 标记已知好的提交
git bisect good commit_hash

# Git 会自动切换到中间的提交
# 测试后标记结果
git bisect good  # 或 git bisect bad

# 继续直到找到问题提交
# 结束二分查找
git bisect reset

查找引入特定代码的提交

bash
# 查找添加特定代码的提交
git log -S "function_name" --source --all

# 查找修改特定代码的提交
git log -G "regex_pattern" --source --all

# 查找文件重命名
git log --follow -- new_filename.txt

查找丢失的提交

bash
# 查看引用日志
git reflog

# 查看所有分支的引用日志
git reflog --all

# 查看特定分支的引用日志
git reflog show branch_name

# 恢复丢失的提交
git checkout commit_hash
git branch recovered-branch

历史可视化

创建历史图表

bash
# 生成简单的 ASCII 图
git log --graph --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit --all

# 生成更详细的图表
git log --graph --full-history --all --color --pretty=format:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s"

导出历史数据

bash
# 导出为 CSV 格式
git log --pretty=format:'"%h","%an","%ae","%ad","%s"' --date=iso > commits.csv

# 导出为 JSON 格式(需要 jq 工具)
git log --pretty=format:'{"hash":"%H","author":"%an","email":"%ae","date":"%ad","message":"%s"}' --date=iso

# 生成统计报告
git shortlog -sn  # 按作者统计提交数
git shortlog -sne # 包含邮箱

历史清理和重写

修改历史(谨慎使用)

bash
# 修改最后一次提交
git commit --amend

# 交互式重写历史
git rebase -i HEAD~3

# 压缩提交
git rebase -i HEAD~3
# 在编辑器中将 pick 改为 squash

# 分割提交
git rebase -i HEAD~3
# 在编辑器中将 pick 改为 edit
# 然后使用 git reset HEAD^ 和重新提交

过滤历史

bash
# 从历史中移除文件
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD

# 移除敏感信息(推荐使用 git-filter-repo)
git filter-repo --path passwords.txt --invert-paths

# 重写作者信息
git filter-branch --env-filter '
if [ "$GIT_COMMITTER_EMAIL" = "old@example.com" ]
then
    export GIT_COMMITTER_NAME="New Name"
    export GIT_COMMITTER_EMAIL="new@example.com"
fi
if [ "$GIT_AUTHOR_EMAIL" = "old@example.com" ]
then
    export GIT_AUTHOR_NAME="New Name"
    export GIT_AUTHOR_EMAIL="new@example.com"
fi
' HEAD

历史分析脚本

提交统计脚本

bash
#!/bin/bash
# 生成提交统计报告

echo "=== Git 历史分析报告 ==="
echo "生成时间: $(date)"
echo ""

echo "=== 基本统计 ==="
echo "总提交数: $(git rev-list --all --count)"
echo "总分支数: $(git branch -a | wc -l)"
echo "总标签数: $(git tag | wc -l)"
echo ""

echo "=== 作者统计 ==="
git shortlog -sn | head -10
echo ""

echo "=== 最近活动 ==="
echo "最近 10 次提交:"
git log --oneline -10
echo ""

echo "=== 文件统计 ==="
echo "修改最频繁的文件:"
git log --name-only --pretty=format: | sort | uniq -c | sort -rn | head -10

代码贡献分析

bash
#!/bin/bash
# 分析代码贡献

echo "=== 代码贡献分析 ==="

# 按作者统计代码行数
git log --shortstat --pretty="%cE" | sed 's/\(.*\)@.*/\1/' | grep -v "^$" | awk 'BEGIN { line=""; } !/^ / { if (line=="" || !match(line, $0)) {line = $0 "," line }} /^ / { print line " # " $0; line=""}' | sort | sed -E 's/# //;s/ files? changed,//;s/([0-9]+) ([0-9]+ deletion)/\1 0 insertions, \2/;s/\(\+\)//;s/\(\-\)//' | awk 'BEGIN {name=""; files=0; insertions=0; deletions=0;} {if ($1 != name && name != "") { print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net"; files=0; insertions=0; deletions=0; name=$1; } name=$1; files+=$2; insertions+=$3; deletions+=$4} END {print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net";}'

echo ""
echo "=== 月度提交趋势 ==="
git log --date=format:'%Y-%m' --pretty=format:'%ad' | sort | uniq -c | sort -k2

历史最佳实践

1. 保持清晰的提交历史

bash
# ✅ 好的提交信息
git commit -m "feat: 添加用户登录功能"
git commit -m "fix: 修复登录页面样式问题"
git commit -m "docs: 更新 API 文档"

# ❌ 避免的提交信息
git commit -m "修改"
git commit -m "更新代码"
git commit -m "临时提交"

2. 使用语义化提交

bash
# 提交类型
feat:     # 新功能
fix:      # 修复 bug
docs:     # 文档更新
style:    # 代码格式化
refactor: # 重构
test:     # 测试相关
chore:    # 构建过程或辅助工具的变动

# 示例
git commit -m "feat(auth): 添加 OAuth 登录支持"
git commit -m "fix(ui): 修复移动端布局问题"

3. 定期清理历史

bash
# 压缩功能分支的提交
git rebase -i main

# 清理合并后的分支
git branch -d feature/completed-feature

# 清理远程分支引用
git remote prune origin

故障排除

常见问题

bash
# 问题1: 找不到特定提交
# 解决: 使用 reflog 查找
git reflog | grep "关键词"

# 问题2: 历史太长,查看缓慢
# 解决: 使用分页或限制数量
git log --oneline -20
git log | less

# 问题3: 中文显示问题
# 解决: 配置编码
git config --global core.quotepath false
git config --global gui.encoding utf-8

性能优化

bash
# 对于大型仓库,使用浅克隆
git clone --depth 1 <url>

# 获取更多历史
git fetch --unshallow

# 清理不必要的对象
git gc --aggressive --prune=now

总结

Git 历史查看的核心要点:

基本命令

bash
git log                 # 查看历史
git log --oneline      # 简洁视图
git log --graph        # 图形视图
git show commit_hash   # 查看特定提交
git blame file.txt     # 追踪代码变更

高级技巧

  • 🔍 使用过滤器精确查找
  • 📊 生成统计和分析报告
  • 🎨 自定义格式和别名
  • 🔧 使用图形工具辅助

最佳实践

  • ✅ 保持清晰的提交信息
  • ✅ 使用语义化提交规范
  • ✅ 定期清理和整理历史
  • ✅ 善用别名提高效率

掌握 Git 历史查看后,你就能够:

  • 📈 分析项目发展趋势
  • 🐛 快速定位问题来源
  • 👥 了解团队贡献情况
  • 📚 学习代码演进过程

在下一章中,我们将学习 Git 的合并操作。

本站内容仅供学习和研究使用。