暂存区详解

进阶
视频演示

暂存区详解:暂存区 vs 本地仓库

🤔 你的问题

  1. 暂存区和 Git 本地仓库有什么区别?
  2. 暂存区的数据怎么维护?

📊 Git 的三个区域

完整流程

工作区(Working Directory)
    ↓ git add
暂存区(Staging Area / Index)
    ↓ git commit
本地仓库(Local Repository)
    ↓ git push
远程仓库(Remote Repository)

详细说明

1. 工作区(Working Directory)

位置: 你的项目文件夹(除了 .git 文件夹)

内容: 你正在编辑的文件

特点:

  • 你可以直接修改文件
  • Git 可以追踪这些文件
  • 但修改还没有被 Git 记录

例子:

project/
├── .git/          ← Git 仓库(不包括在工作区)
├── app.py         ← 工作区(你正在编辑)
└── utils.py       ← 工作区(你正在编辑)

2. 暂存区(Staging Area / Index)

位置: .git/index 文件(隐藏文件)

内容: 准备提交的文件快照

特点:

  • 一个中间区域
  • 你可以选择性地添加文件
  • 只有添加到暂存区的文件才会被提交
  • 数据存储在 .git/index 文件中

作用:

  • 让你选择要提交哪些文件
  • 可以分批次提交
  • 可以预览提交内容

3. 本地仓库(Local Repository)

位置: .git/objects/ 文件夹

内容: 已提交的代码历史

特点:

  • 存储所有提交记录
  • 包含完整的版本历史
  • 数据存储在 .git/objects/
  • 一旦提交,就很难修改(需要特殊操作)

🔍 暂存区 vs 本地仓库的区别

核心区别

特性 暂存区(Staging Area) 本地仓库(Local Repository)
位置 .git/index 文件 .git/objects/ 文件夹
作用 准备提交的文件 已提交的代码历史
可修改性 ✅ 容易修改(可以添加/删除) ❌ 不容易修改(已提交)
持久性 ⚠️ 临时(提交后清空) ✅ 永久(除非删除仓库)
选择性 ✅ 可以选择文件 ❌ 提交时包含所有暂存的文件
查看方式 git status(绿色) git log

详细对比

暂存区(Staging Area)

# 添加到暂存区
git add app.py
 
# 状态
git status
# 输出:
# Changes to be committed:
#   modified: app.py  (绿色,表示在暂存区)

特点:

  • ✅ 可以随时添加文件:git add file1.py file2.py
  • ✅ 可以移除文件:git reset file1.py
  • ✅ 可以清空:git reset
  • ⚠️ 提交后自动清空
  • ⚠️ 如果删除 .git 文件夹,暂存区也会丢失

本地仓库(Local Repository)

# 提交到本地仓库
git commit -m "Update app"
 
# 查看提交历史
git log
# 输出:
# commit abc1234...
# Author: Your Name
# Date: ...
#     Update app

特点:

  • ✅ 永久存储(除非删除仓库)
  • ✅ 包含完整的提交历史
  • ✅ 可以查看、回退、分支
  • ❌ 不容易修改(需要 git commit --amendgit reset
  • ❌ 提交后包含所有暂存的文件

🛠️ 暂存区的数据维护

暂存区的存储位置

位置: .git/index 文件

这是一个二进制文件,存储:

  • 文件的路径
  • 文件的内容哈希
  • 文件的时间戳
  • 文件的权限

暂存区的操作

1. 添加文件到暂存区

# 添加单个文件
git add app.py
 
# 添加多个文件
git add app.py utils.py
 
# 添加所有修改的文件
git add .
 
# 添加所有文件(包括新文件)
git add -A

发生了什么:

  1. Git 读取文件内容
  2. 计算文件内容的哈希值
  3. 将文件信息写入 .git/index
  4. 文件内容存储在 .git/objects/ 中(作为对象)

2. 从暂存区移除文件

# 移除单个文件(但保留工作区的修改)
git reset app.py
# 或
git restore --staged app.py
 
# 清空整个暂存区
git reset

发生了什么:

  1. .git/index 中移除文件信息
  2. 文件仍然在工作区(你的修改还在)
  3. 文件对象仍然在 .git/objects/ 中(不会删除)

3. 查看暂存区内容

# 查看暂存区的状态
git status
 
# 查看暂存区和工作区的差异
git diff --staged
# 或
git diff --cached
 
# 查看暂存区的文件列表
git ls-files --stage

4. 修改暂存区的内容

# 修改文件后,需要重新添加到暂存区
vim app.py          # 修改文件
git add app.py      # 重新添加到暂存区(覆盖之前的)
 
# 或者,直接修改暂存区中的文件
git add app.py      # 添加到暂存区
vim app.py          # 修改文件
git add app.py      # 再次添加(更新暂存区)

📝 实际例子

例子 1: 理解暂存区的作用

# 1. 修改了 3 个文件
vim app.py          # 修改
vim utils.py        # 修改
vim config.py       # 修改
 
# 2. 查看状态
git status
# 输出:
# modified: app.py      (红色,工作区)
# modified: utils.py    (红色,工作区)
# modified: config.py   (红色,工作区)
 
# 3. 只添加 app.py 到暂存区
git add app.py
 
# 4. 查看状态
git status
# 输出:
# Changes to be committed:
#   modified: app.py      (绿色,暂存区)
# 
# Changes not staged for commit:
#   modified: utils.py    (红色,工作区)
#   modified: config.py   (红色,工作区)
 
# 5. 提交(只提交 app.py)
git commit -m "Update app.py"
# 只有 app.py 被提交,utils.py 和 config.py 还在工作区
 
# 6. 查看状态
git status
# 输出:
# Changes not staged for commit:
#   modified: utils.py    (红色,工作区)
#   modified: config.py    (红色,工作区)
# 暂存区已清空(因为已提交)

例子 2: 暂存区的维护

# 1. 添加文件到暂存区
git add app.py
# .git/index 文件被更新,包含 app.py 的信息
 
# 2. 修改 app.py
vim app.py
# 工作区的 app.py 已修改
# 但暂存区还是旧版本
 
# 3. 查看差异
git diff              # 工作区 vs 暂存区(显示修改)
git diff --staged     # 暂存区 vs 本地仓库(显示已暂存的内容)
 
# 4. 更新暂存区
git add app.py        # 重新添加,更新暂存区
 
# 5. 或者,移除暂存区的内容
git reset app.py      # 从暂存区移除(但工作区的修改还在)

例子 3: 暂存区的生命周期

# 初始状态
git status
# 输出:nothing to commit, working tree clean
# 暂存区:空
# 本地仓库:有之前的提交
 
# 修改文件
vim app.py
git status
# 输出:
# modified: app.py  (红色,工作区)
# 暂存区:空
# 本地仓库:有之前的提交
 
# 添加到暂存区
git add app.py
git status
# 输出:
# Changes to be committed:
#   modified: app.py  (绿色,暂存区)
# 暂存区:有 app.py
# 本地仓库:有之前的提交
 
# 提交
git commit -m "Update app"
git status
# 输出:nothing to commit, working tree clean
# 暂存区:空(已清空)
# 本地仓库:有新的提交(包含 app.py)

🔧 暂存区的数据维护机制

1. 自动维护

Git 自动维护:

  • 当你执行 git add 时,Git 自动更新 .git/index
  • 当你执行 git commit 时,Git 自动清空暂存区
  • 当你执行 git reset 时,Git 自动更新 .git/index

2. 手动维护

你可以手动操作:

  • git add - 添加文件到暂存区
  • git reset - 从暂存区移除文件
  • git restore --staged - 从暂存区移除文件(新命令)

3. 暂存区的持久性

暂存区的数据:

  • ✅ 存储在 .git/index 文件中
  • ✅ 即使关闭终端,暂存区的内容还在
  • ⚠️ 如果删除 .git 文件夹,暂存区也会丢失
  • ⚠️ 提交后,暂存区自动清空

4. 暂存区的数据结构

.git/index 文件包含:

  • 文件路径
  • 文件内容的 SHA-1 哈希
  • 文件的时间戳
  • 文件的权限信息
  • 指向 .git/objects/ 中实际文件内容的指针

💡 为什么需要暂存区?

1. 选择性提交

# 修改了多个文件,但只想提交部分
vim app.py
vim utils.py
vim test.py
 
# 只提交 app.py
git add app.py
git commit -m "Update app"
# utils.py 和 test.py 还在工作区,可以继续修改

2. 预览提交内容

# 添加到暂存区后,可以预览
git add app.py
git diff --staged    # 查看将要提交的内容
 
# 确认无误后再提交
git commit -m "Update app"

3. 分批次提交

# 修改了多个文件
vim file1.py
vim file2.py
vim file3.py
 
# 分批次提交
git add file1.py
git commit -m "Add feature 1"
 
git add file2.py
git commit -m "Add feature 2"
 
git add file3.py
git commit -m "Add feature 3"

4. 撤销操作

# 添加到暂存区后,发现有问题
git add app.py
 
# 可以轻松移除
git reset app.py
# 文件还在工作区,可以继续修改

🎯 关键理解

暂存区 vs 本地仓库

操作 暂存区 本地仓库
添加 git add git commit
查看 git status(绿色) git log
修改 容易(重新 add) 困难(需要特殊操作)
清空 提交后自动清空 不会清空(永久存储)
作用 准备提交 已提交的历史

数据维护

  • 暂存区:存储在 .git/index,由 Git 自动维护
  • 本地仓库:存储在 .git/objects/,由 Git 自动维护
  • 你可以操作:添加、移除、查看暂存区的内容
  • Git 自动处理:提交时清空暂存区,创建新的提交对象

📋 总结

暂存区的特点

  1. 临时性:提交后自动清空
  2. 选择性:可以选择要提交的文件
  3. 可修改性:可以随时添加/移除文件
  4. 预览性:可以预览将要提交的内容

本地仓库的特点

  1. 永久性:提交后永久存储
  2. 完整性:包含所有提交历史
  3. 不可变性:不容易修改(需要特殊操作)
  4. 历史性:可以查看、回退、分支

记住

  • 暂存区 = 准备提交的文件(临时、可选择)
  • 本地仓库 = 已提交的代码历史(永久、完整)
  • 暂存区的数据 = 存储在 .git/index,由 Git 自动维护

暂存区就像购物车,你可以选择要买什么,确认后再结账(提交)!