# Git 历史查看与撤销

## 查看提交历史（git log）

### 基本使用

`$ git log`
输出示例：
```text
commit 5de18d5... (SHA-1 40位哈希值)
Author: ...
Date: ...
    提交说明
```
SHA-1哈希值：对内容和头信息的校验和，保证数据完整性，确保任何时候checkout都能得到完全一致的状态。

### 常用选项


|选项|说明|
|---|---|
| `--pretty=oneline` |简化输出，每行显示一个提交|
| `--pretty=format:"%h - %s"` |自定义输出格式|
| `--graph` |用 ASCII 图展示分支/合并历史|
| `--no-merges` |不显示合并提交|
| `-S <字符串>` |查找内容新增/删除的提交|
| `-p` |显示每个提交的差异|
组合使用

```bash
# 美化显示分支结构
$ git log --pretty=oneline --graph

# 查看特定内容的提交历史
$ git log -S "function_name"
```

### git reflog
记录所有HEAD的变更历史，可用于恢复丢失的提交：
`$ git reflog`
## 查看提交历史与回溯

```bash
git log --oneline -5                     # 最近5条提交
git log --since="2 weeks ago"            # 两周内的提交
git log --author="someone"               # 某作者的提交
git log -S "function_name"               # 包含特定字符串增删的提交
git reflog                               # 本地所有 HEAD 移动历史
git reset --hard HEAD^                   # 回退到上一个版本（丢弃工作区修改）
git reset --soft HEAD^                   # 回退版本但保留工作区和暂存区修改
git reset --mixed HEAD^                  # 回退版本并取消暂存（保留工作区修改）
```

> 谨慎使用 `git reset --hard`，它会丢弃所有未提交的更改。

## 查看提交内容（git show）

```bash
# 查看某次提交的详细信息
$ git show <commit-hash>

# 查看最近一次提交
$ git show HEAD
```

## reset 与 checkout 的区别

**重置reset**

**多次修改并多次提交**

**前进或者后退**

**Git reset --hard 同步移动本地库、暂存区和工作区**

**Git reset --mixed 工作区不动，保留修改，本地库、暂存区移动**

**Git reset --soft 本地库移动，暂存区和工作区不动**

**1. git checkout HEAD^**

- **行为**：切换到上一个提交（HEAD^），但不会改变当前分支的指针。
- **效果**：
  - 你的工作目录会更新为上一个提交的状态。
  - 你处于“分离头指针”（detached      HEAD）状态，即当前不在任何分支上。
  - 你可以查看或测试上一个提交的内容，但不会影响当前分支的历史。
  - 如果你在分离头指针状态下做了修改并提交，这些提交不会属于任何分支，除非你显式地创建一个新分支来保存它们。
- **适用场景**：查看历史版本的内容，而不改变当前分支的状态。

**2. git reset --hard HEAD^**

- **行为**：将当前分支的指针移动到上一个提交（HEAD^），并强制更新工作目录和暂存区以匹配该提交。
- **效果**：
  - 当前分支的指针会回退到上一个提交。
  - 工作目录和暂存区会被重置为上一个提交的状态。
  - 所有未提交的更改（包括未暂存的和已暂存的）都会被丢弃。
- **适用场景**：彻底回退到上一个版本，丢弃当前的所有更改。

创建一个新文件，add commit，然后删除了这个文件,然后又add commit如何恢复？

Git reset --hard

重置状态到文件没有删除的本地库版本即可

## 撤销操作

### 1. 修正最后一次提交（`git commit --amend`）

**用途**：修改提交信息或补充遗漏的文件。

**工作原理**：用**新的提交**替换旧的提交，而非修复旧提交本身。

```bash
# 修改提交信息
$ git commit --amend -m "新的提交信息"
# 补充遗漏的文件
$ git add 遗漏的文件
$ git commit --amend
```

> 💡 典型场景：提交后发现漏掉了几个文件，或者提交信息写错了。

---

### 2. 取消暂存（`git reset HEAD`）

**用途**：将文件从暂存区移出，但**保留工作区的修改**。

```bash
$ git reset HEAD <文件名>
```

> 💡 典型场景：误用 `git add *` 暂存了所有文件，想取消部分文件的暂存。

> 📌 提示：`git status` 会提示你 `use "git reset HEAD <file>..." to unstage`。

---

### 3. 撤销工作区修改（`git checkout --`）

**用途**：丢弃工作区的修改，恢复到最后提交的版本。

```bash
$ git checkout -- <文件名>
```

> ⚠️ **危险警告**：此操作会**永久丢失**本地修改，无法恢复！除非你确定不需要这些修改，否则**不要使用**。

> 📌 提示：`git status` 会提示你 `use "git checkout -- <file>..." to discard changes in working directory`。

---

### 4. 安全的替代方案（`git stash`）

如果你仍想保留当前修改，但暂时需要撤消，可以使用 `git stash` 暂存起来，稍后再恢复：

```bash
# 临时保存工作区的修改
$ git stash save "备注信息"
# 恢复最近一次暂存的修改
$ git stash pop
```

> 💡 `git stash` 的详细用法将在 **Git 分支** 章节中进一步介绍。

---

### 完整撤销操作速查表

| 场景         | 命令                                    | 安全性      |
| ---------- | ------------------------------------- | -------- |
| 修改上一次提交信息  | `git commit --amend -m "新信息"`         | ✅ 安全     |
| 补充文件到上一次提交 | `git add <文件>` → `git commit --amend` | ✅ 安全     |
| 取消暂存       | `git reset HEAD <文件>`                 | ✅ 安全     |
| 撤销工作区修改    | `git checkout -- <文件>`                | ❌ **危险** |
| 安全保存工作区修改  | `git stash save "备注"`                 | ✅ 安全     |
---

[[版本控制系统]] · [[Git学习顺序]] · 上一章：[[Git 暂存与提交]] · 下一章：[[Git 分支管理]]
