Git 查看历史、撤销回退与冲突解决
排错是日常开发中绕不开的一环:查看历史定位问题、选择正确的方式撤销或回退、以及在合并/拉取/变基时解决冲突。本文汇总这三部分内容。
一、查看提交日志(git log)
git log 用于查看项目的提交历史,支持多种过滤和显示格式。
基本用法
git log # 完整日志(按时间倒序)
git log --oneline # 简洁模式:一行显示 commit hash + 提交说明
git log --graph --oneline # 图形化分支结构,非常直观
限制显示条数与时间范围
git log -n 3 # 只显示最近 3 条提交
git log --since="2025-01-01" # 显示指定日期之后的提交
git log --until="2025-03-01" # 显示指定日期之前的提交
git log --since="2 weeks ago" # 支持相对时间
按作者/内容筛选
git log --author="Zhang" # 作者名称包含 "Zhang" 的提交
git log --committer="Li" # 提交者名称包含 "Li" 的提交
git log --grep="fix" # 提交说明中包含 "fix" 的提交
其他常用选项
git log --stat # 显示每个提交修改的文件统计(+/- 行数)
git log -p # 显示每个提交的具体代码差异(patch)
二、查看差异(git diff)
git diff 用于比较不同区域之间的内容差异。
| 比较范围 | 命令 |
|---|---|
| 工作区 vs 暂存区(未暂存的改动) | git diff |
| 暂存区 vs HEAD(即将提交的内容) | git diff --staged(等价 --cached) |
| 工作区 vs HEAD(已暂存+未暂存的全部改动) | git diff HEAD |
| 两个 commit 之间 | git diff commit1 commit2 |
| 两个分支之间 | git diff branch1 branch2 |
| 只看文件名列表 | git diff --name-only / git diff --stat |
综合示例:
# 查看最近 5 条提交的图形化日志
git log --oneline --graph -5
# 查看工作区有哪些改动(还未 add)
git diff
# 查看已暂存的改动
git diff --staged
# 查看当前分支与 main 分支的差异
git diff main
# 查看某个文件在两个 commit 之间的变化
git diff abc123 def456 -- src/index.js
三、撤销提交与回退
1. 修正上一次提交(git commit --amend)
适用于:提交信息写错了,或者漏掉了几个文件。
# 修改最近一次提交的说明
git commit --amend -m "新的提交说明"
# 补充漏掉的文件(先 git add),不修改说明
git add forgotten-file.txt
git commit --amend --no-edit
--amend实际上会创建一个新的提交(新的 commit hash),替换掉上一次提交。- 注意:如果已经推送到远程,
--amend后需要git push --force(谨慎),否则会与远程历史冲突。不建议对公共分支(如 main)使用 force push。
2. 回退版本(git reset)
将当前分支的 HEAD 指针移动到指定的提交,并可选地影响暂存区和工作区。
| 模式 | 命令 | 影响 |
|---|---|---|
--soft | git reset --soft HEAD~1 | 撤销 commit,保留修改在暂存区(git status 显示为 “Changes to be committed”) |
--mixed(默认) | git reset --mixed HEAD~1 | 撤销 commit 和 add,保留修改在工作区(git status 显示为 “Changes not staged”) |
--hard | git reset --hard HEAD~1 | 完全丢弃修改(工作区、暂存区都恢复到目标提交的状态)—— 危险 |
HEAD~1表示前一个提交,也可以写具体的 commit hash(如git reset --soft abc123)。--hard会丢失所有未提交的改动,请确保不需要这些改动或已备份。
场景示例:
- 想重新编辑上一次提交的内容(撤销 commit 后重新 add、commit):用
--soft。 - 想撤销 commit 且取消暂存,但继续编辑:用
--mixed。 - 想彻底丢弃最近几次错误的提交:用
--hard(确认后使用)。
3. 查看历史操作记录(git reflog)——找回丢失的 commit
当你执行 git reset --hard 误删了提交,或者不小心丢弃了分支,reflog 是救命稻草。
git reflog
它会列出所有 HEAD 的移动记录(包括 commit、reset、merge 等)。找到目标 commit 的 hash,然后:
git reset --hard <commit-hash>
- 注意:
reflog只在本地存在,通常保留 90 天。如果你已经进行了git gc或操作时间太长,可能无法恢复。
4. 反向撤销(git revert)——安全地撤销已推送的提交
git revert 会创建一个新的提交,其内容正好抵消指定的提交所做的修改。这是无风险的撤销方式,因为不会重写历史。
git revert <commit-hash>
- 执行后会打开编辑器让你输入新提交的说明,也可以直接
git revert --no-edit。 - 如果需要撤销多个提交,可以指定范围:
git revert HEAD~3..HEAD。 - 适用场景:已经推送到远程分支(尤其是公共分支),希望撤销某个提交但又不影响其他人的历史。
5. 撤销方式对比
| 命令 | 是否改写历史 | 是否适合已推送分支 | 风险 |
|---|---|---|---|
git commit --amend | 是(替换最后一次提交) | 否(需 force push) | 中(可能影响协作者) |
git reset(soft/mixed/hard) | 是(移动 HEAD,丢弃后续提交) | 否(需 force push) | 高(hard 模式会丢失数据) |
git revert | 否(生成新提交来抵消) | 是(推荐) | 低 |
安全建议:
- 对于尚未推送的本地提交,可以使用
reset或amend。 - 对于已经推送到共享仓库的提交,应优先使用
git revert,避免改写公共历史导致团队混乱。 - 使用
git reset --hard前,务必确认没有未保存的工作,或用git stash暂存。
四、冲突解决
1. 冲突产生情况
冲突通常发生在以下场景:
- 合并分支时:两个分支修改了同一文件的同一区域,Git 无法自动决定保留哪个版本。
git pull时:远程分支和本地分支都有新提交,且修改了相同区域(本质也是合并冲突)。git rebase时:变基过程中如果遇到提交冲突也会暂停。
2. 解决步骤
- 查看冲突文件bash
git status
会列出both modified的文件,这些就是存在冲突的文件。 - 编辑冲突文件
打开冲突文件,你会看到类似下面的标记:text<<<<<<< HEAD 当前分支的内容 ======= 被合并分支的内容(如 feature-branch) >>>>>>> feature-branch<<<<<<< HEAD到=======之间的代码是当前分支(通常是HEAD)的版本。=======到>>>>>>> branch之间的代码是另一个分支的版本。
手动保留你需要的内容(可以是其中一边,也可以是两边组合),然后删除所有冲突标记(<<<<<<<、=======、>>>>>>>)。 - 保存文件
保存你对冲突文件的修改。 - 标记为已解决bash
git add <冲突文件>
(可以一次添加多个文件) - 完成合并(提交)
- 如果是
git merge产生的冲突:bashgit commit # 会生成默认的合并提交信息 # 或 git merge --continue - 如果是
git rebase产生的冲突:解决后执行git add <文件>,然后git rebase --continue。 - 如果想放弃本次合并:
git merge --abort或git rebase --abort。
- 如果是
3. 示例流程
# 假设合并时出现冲突
git merge feature-branch
# Auto-merging index.js
# CONFLICT (content): Merge conflict in index.js
# 1. 查看冲突文件
git status
# both modified: index.js
# 2. 编辑 index.js,删除冲突标记,保留正确内容
# 3. 添加已解决的文件
git add index.js
# 4. 完成合并
git commit -m "Merge feature-branch: resolve conflict in index.js"
解决冲突的关键是仔细对比两边的代码,确保最终结果逻辑正确。如果不确定,可以咨询相关开发者。
五、注意事项
git reset --hard、git push --force、git rebase(对已推送提交)都属于高风险操作,操作前确认改动已备份或团队已知悉。- 冲突解决完成后,务必仔细检查代码逻辑,不能只是简单删除冲突标记,还要保证语义正确。
git reflog是本地误操作的最后一道保险,但有效期有限(默认约 90 天),不能作为长期备份手段。
参考文献
相关文章
Git 分支、远程协作与标签管理
涵盖分支的创建、切换、合并与删除,远程仓库的管理、推送与拉取,以及标签(Tag)的创建、查看、推送与删除,是团队协作的核心内容。
Git 基础概念与命令速查
Git 是目前最流行的分布式版本控制系统。本文介绍工作区/暂存区/仓库等核心概念、文件状态流转,并附上日常开发最常用的命令速查表,适合入门学习与日常查阅。
Git 安装、配置与仓库初始化
涵盖 Windows / macOS / Linux 下 Git 的安装方式、首次使用的全局配置(用户名、邮箱、别名等)、创建或克隆仓库的方式,以及 .gitignore 忽略规则的编写方法。
Git 基础工作流与协作场景
涵盖日常文件级操作(状态查看、暂存、提交、撤销、删除、重命名)与团队协作中的常见场景示例(个人提交、功能分支开发、同步主分支、误提交撤销等)。
运维与协作导读
本目录覆盖日常开发运维中的 Git 版本控制、Docker 容器化与 Nginx 服务网关,与 工程化 · Git、部署相关 等章节互补,提供完整的十阶段学习路径。
Git 配置
版本控制常用 .gitignore(忽略不需纳入仓库的文件)与 .gitattributes(统一换行、diff、合并策略等)。见 工程化概览。
Series
git
2 / 5