Git: Git添加文件到暂存区详解
暂存区(Staging Area)是Git的独特概念,它位于工作区和版本库之间,让你精确控制每次提交的内容。git add命令将修改添加到暂存区。
1. git add概述
(1) 什么是暂存区?
暂存区是Git三区模型中的关键部分:
graph TB
subgraph Git三区模型
W[工作区<br/>Working Directory<br/>实际编辑的文件]
S[暂存区<br/>Staging Area<br/>准备提交的修改]
R[版本库<br/>Repository<br/>所有提交历史]
end
W -->|git add| S
S -->|git commit| R
R -->|git checkout| W
style W fill:#fff3cd
style S fill:#d4edda
style R fill:#c3e6cb
(2) 为什么需要暂存区?
暂存区提供了精细的提交控制:
| 优势 | 说明 | 示例 |
|---|---|---|
| 选择性提交 | 不是所有修改都要提交 | 只提交修复bug的文件,不提交实验代码 |
| 分批提交 | 不同修改分开提交 | 功能A和功能B分别提交 |
| 修改检查 | 提交前检查内容 | 确认暂存的修改无误 |
| 撤销修改 | 撤销暂存不影响工作区 | 暂存了错误文件可以撤销 |
(3) git add的作用
git add命令将工作区的修改复制到暂存区:
- 新文件:添加到暂存区,标记为待提交的新文件
- 修改文件:将修改后的版本添加到暂存区
- 删除文件:将删除操作添加到暂存区
2. 添加流程
(1) 基本语法
BASH
# 添加单个文件
git add <文件名>
# 添加多个文件
git add <文件1> <文件2> <文件3>
# 添加目录下所有文件
git add <目录名>
# 添加当前目录所有文件
git add .
(2) 添加流程详解
sequenceDiagram
participant W as 工作区
participant S as 暂存区
participant R as 版本库
Note over W: 文件状态: Modified/Untracked
W->>S: git add <file>
Note over S: 复制文件到暂存区<br/>计算SHA-1哈希<br/>更新索引
Note over S: 文件状态: Staged
S->>R: git commit
Note over R: 文件状态: Committed
(3) 添加后的变化
添加文件到暂存区后:
- 工作区:文件保持不变,可以继续编辑
- 暂存区:保存添加时的文件快照
- 状态变化:文件从Untracked/Modified变为Staged
▶ 示例:添加单个文件
BASH
# 创建新文件
echo "# My Project" > README.md
# 查看状态(未跟踪)
git status
# Untracked files:
# README.md
# 添加到暂存区
git add README.md
# 查看状态(已暂存)
git status
# Changes to be committed:
# new file: README.md
# 查看暂存区内容
git diff --staged
# diff --git a/README.md b/README.md
# new file mode 100644
# index 0000000..e69de29
# --- /dev/null
# +++ b/README.md
# @@ -0,0 +1 @@
# +# My Project
▶ 示例:添加多个文件
BASH
# 创建多个文件
echo "console.log('app');" > app.js
echo "console.log('test');" > test.js
echo "node_modules/" > .gitignore
# 添加多个文件
git add app.js test.js .gitignore
# 查看状态
git status -s
# A .gitignore
# A app.js
# A test.js
# 或者分步添加
git add app.js
git add test.js
git add .gitignore
# 结果相同
3. 添加选项
(1) 批量添加方式
Git提供多种批量添加方式:
BASH
# 添加当前目录所有文件(不包括删除)
git add .
# 添加所有已跟踪文件的修改和删除
git add -u
# 添加所有文件(包括新文件、修改、删除)
git add -A
# 或
git add --all
# 交互式添加(逐个确认)
git add -p
(2) 选项对比
| 命令 | 新文件 | 已修改 | 已删除 | 作用范围 |
|---|---|---|---|---|
git add <文件> |
✅ | ✅ | ✅ | 指定文件 |
git add . |
✅ | ✅ | ❌ | 当前目录 |
git add -u |
❌ | ✅ | ✅ | 整个仓库 |
git add -A |
✅ | ✅ | ✅ | 整个仓库 |
(3) 交互式添加
git add -p(patch模式)让你逐个确认每个修改块:
BASH
git add -p
# 显示修改块,询问是否暂存
# Stage this hunk [y,n,q,a,d,e,?]?
# y - yes,暂存这个块
# n - no,不暂存
# q - quit,退出
# a - all,暂存这个文件的所有块
# d - discard,不暂存这个文件的所有块
# e - edit,手动编辑这个块
# ? - help,显示帮助
▶ 示例:批量添加对比
BASH
# 创建场景
echo "new file" > new.txt # 新文件
echo "content" > tracked.txt
git add tracked.txt
git commit -m "Add tracked"
echo "modified" >> tracked.txt # 已修改
git rm tracked.txt # 删除(模拟)
# 使用 git add .
git add .
git status -s
# A new.txt
# (不处理删除)
# 重置
git reset
# 使用 git add -u
git add -u
git status -s
# D tracked.txt
# (只处理已跟踪文件的修改和删除)
# 重置
git reset
# 使用 git add -A
git add -A
git status -s
# A new.txt
# D tracked.txt
# (处理所有)
4. 暂存区管理
(1) 查看暂存区内容
BASH
# 查看暂存的修改
git diff --staged
# 或
git diff --cached
# 查看暂存区和版本库的差异
git diff --staged HEAD
# 查看暂存区文件列表
git status
(2) 暂存区的特点
暂存区的重要特性:
graph TB
A[工作区文件] -->|git add| B[暂存区快照]
B -->|git commit| C[版本库提交]
A -->|继续编辑| D[工作区新版本]
D -->|git add| E[更新暂存区]
B -.->|不同版本| D
style B fill:#d4edda
style D fill:#fff3cd
关键理解:
- 暂存区保存的是添加时的快照,不是引用
- 添加后继续编辑,工作区和暂存区会有不同版本
- 需要再次
git add才能更新暂存区
(3) 暂存区覆盖
重复git add会覆盖暂存区内容:
BASH
# 第一次添加
echo "version 1" > file.txt
git add file.txt
# 暂存区:version 1
# 修改文件
echo "version 2" > file.txt
# 工作区:version 2
# 暂存区:version 1(未变)
# 再次添加
git add file.txt
# 暂存区:version 2(已更新)
▶ 示例:暂存区与工作区分离
BASH
# 创建并添加文件
echo "Line 1" > file.txt
git add file.txt
# 查看暂存区内容
git diff --staged
# +Line 1
# 继续编辑文件
echo "Line 2" >> file.txt
# 查看工作区与暂存区的差异
git diff
# +Line 2
# 查看状态
git status -s
# AM file.txt
# A:暂存区有内容(Line 1)
# M:工作区有新修改(Line 2)
# 更新暂存区
git add file.txt
# 现在暂存区包含所有修改
git diff --staged
# +Line 1
# +Line 2
5. 撤销添加
(1) 撤销暂存
如果暂存了错误的文件,可以撤销暂存:
BASH
# 撤销单个文件的暂存(新语法)
git restore --staged <文件名>
# 撤销单个文件的暂存(旧语法)
git reset HEAD <文件名>
# 撤销所有暂存
git restore --staged .
# 或
git reset
(2) 撤销后的状态
撤销暂存后:
- 暂存区:文件被移除
- 工作区:文件保持不变
- 状态变化:
- 新文件:从Staged变为Untracked
- 已修改:从Staged变为Modified
(3) 撤销vs丢弃
注意区分两个操作:
graph TB
A[已暂存的文件] -->|git restore --staged| B[撤销暂存<br/>工作区保留]
A -->|git restore| C[丢弃修改<br/>恢复到暂存区版本]
B --> D[状态: Untracked/Modified]
C --> E[状态: Staged]
style B fill:#d4edda
style C fill:#f8d7da
▶ 示例:撤销暂存操作
BASH
# 创建并添加文件
echo "test content" > test.txt
git add test.txt
git status -s
# A test.txt
# 撤销暂存
git restore --staged test.txt
git status -s
# ?? test.txt
# 文件变回未跟踪状态
# 已跟踪文件的撤销
echo "# Project" > README.md
git add README.md
git commit -m "Add README"
echo "new content" >> README.md
git add README.md
git status -s
# M README.md
# 撤销暂存
git restore --staged README.md
git status -s
# M README.md
# 文件变回已修改状态,修改内容保留
▶ 示例:交互式添加场景
BASH
# 创建包含多个修改的文件
cat > app.js << 'EOF'
function oldFunction() {
console.log('old');
}
function newFeature() {
console.log('new feature');
}
function debugCode() {
console.log('debug'); // 临时调试代码
}
EOF
git add app.js
git commit -m "Add app"
# 修改文件:包含功能改进和调试代码
cat > app.js << 'EOF'
function oldFunction() {
console.log('old');
console.log('improved'); // 功能改进
}
function newFeature() {
console.log('new feature');
console.log('enhanced'); // 功能增强
}
function debugCode() {
console.log('debug'); // 临时调试代码
}
EOF
# 使用交互式添加,只暂存功能改进
git add -p
# 逐个确认每个修改块
# y - 暂存功能改进
# n - 不暂存调试代码
# 提交功能改进
git commit -m "Improve features"
# 调试代码还在工作区,未提交
❓ 常见问题
Q git add . 和 git add -A 有什么区别?
A
git add .只处理当前目录及子目录的文件,不包括其他目录的删除。git add -A处理整个仓库的所有文件,包括所有目录的新增、修改和删除。在仓库根目录下两者效果相同,但在子目录中会有差异。Q 暂存后继续编辑文件会怎样?
A 文件会同时出现在暂存区和工作区,但内容不同。暂存区保存的是添加时的版本,工作区是编辑后的新版本。状态显示为AM或MM。需要再次
git add更新暂存区,或者提交暂存区内容后再添加新修改。Q 如何查看暂存区的内容?
A 使用
git diff --staged或git diff --cached查看暂存的修改内容。这会显示暂存区与上次提交的差异。如果想看具体文件内容,可以用git show :filename查看暂存区的文件。Q git add会覆盖已暂存的内容吗?
A 是的。对同一文件再次执行
git add会更新暂存区的内容为最新版本。这是更新暂存区的正常方式,不是问题而是特性。Q 如何只添加文件的部分修改?
A 使用
git add -p进入交互模式,Git会逐个显示修改块(hunk),你可以选择y暂存、n跳过、e手动编辑。这样可以精确控制哪些修改进入暂存区,实现一个文件的不同修改分开提交。📖 小节
- 暂存区是工作区和版本库之间的缓冲区,提供精确的提交控制
git add <文件>添加指定文件,支持添加多个文件和目录- 批量添加有三种方式:
.当前目录、-u已跟踪文件、-A所有文件 - 交互式添加
git add -p可以逐块确认修改,实现部分提交 - 暂存区保存的是添加时的快照,添加后编辑需要再次添加
- 撤销暂存用
git restore --staged,工作区文件保持不变 - 理解暂存区的工作方式是掌握Git工作流的关键
📝 作业
-
基础题:创建一个Git仓库,添加多个文件到暂存区,使用
git diff --staged查看暂存内容,然后提交。观察每一步的状态变化。 -
进阶题:创建一个文件,添加到暂存区后继续编辑,观察工作区和暂存区的差异。尝试使用
git add -p交互式添加,只暂存部分修改。 -
挑战题:模拟一个真实场景:修复了两个bug,添加了新功能,还有临时调试代码。使用交互式添加和多次提交,将不同修改分开提交,保持提交历史的清晰性。