Skip to content

文件状态与暂存

概述

Git 通过文件状态来追踪项目中的文件变化。理解文件状态生命周期是掌握 Git 的关键,它能帮助你准确控制哪些修改应该被提交,哪些应该被忽略。

Git 的文件状态分为:未跟踪(Untracked)、未修改(Unmodified)、已修改(Modified)、已暂存(Staged)。文件在这些状态之间流转,最终形成提交历史。

文件状态生命周期

状态流转图

┌─────────────────────────────────────────────────────────────┐
│                    Git 文件状态生命周期                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                     ┌──────────────┐                        │
│                     │   未跟踪      │                        │
│                     │ (Untracked)  │                        │
│                     └──────┬───────┘                        │
│                            │                                 │
│                  git add   │                                 │
│                            ▼                                 │
│  ┌──────────────┐    ┌──────────────┐                       │
│  │   未修改      │◄───│    已暂存     │                       │
│  │ (Unmodified) │    │  (Staged)    │                       │
│  └──────┬───────┘    └──────┬───────┘                       │
│         │                   │                                │
│  编辑文件 │            git commit                            │
│         │                   │                                │
│         ▼                   ▼                                │
│  ┌──────────────┐    ┌──────────────┐                       │
│  │   已修改      │    │    已提交     │                       │
│  │  (Modified)  │    │ (Committed)  │                       │
│  └──────┬───────┘    └──────────────┘                       │
│         │                                                    │
│   git add │                                                  │
│         │                                                    │
│         ▼                                                    │
│  ┌──────────────┐                                           │
│  │    已暂存     │                                           │
│  │  (Staged)    │                                           │
│  └──────────────┘                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四种状态详解

未跟踪(Untracked)

bash
# 新创建的文件处于未跟踪状态
echo "new file" > new.txt

# 查看状态
git status
# On branch main
# Untracked files:
#   new.txt

# 特点:
# - Git 不知道这个文件的存在
# - 不会被纳入版本控制
# - 需要手动添加到暂存区

未修改(Unmodified)

bash
# 已提交且未修改的文件处于未修改状态
git status
# On branch main
# nothing to commit, working tree clean

# 特点:
# - 文件内容与仓库中一致
# - 工作目录干净
# - 不需要任何操作

已修改(Modified)

bash
# 修改已跟踪的文件
echo "modified content" >> tracked.txt

# 查看状态
git status
# On branch main
# Changes not staged for commit:
#   modified:   tracked.txt

# 特点:
# - 文件内容与仓库中不同
# - 修改在工作目录中
# - 需要添加到暂存区

已暂存(Staged)

bash
# 将修改添加到暂存区
git add tracked.txt

# 查看状态
git status
# On branch main
# Changes to be committed:
#   modified:   tracked.txt

# 特点:
# - 文件修改已暂存
# - 准备好提交
# - 下次提交会包含这些修改

git add 添加文件

基本用法

bash
# 添加单个文件
git add filename.txt

# 添加多个文件
git add file1.txt file2.txt file3.txt

# 添加当前目录下所有文件
git add .

# 添加所有文件(包括删除的文件)
git add --all
# 或
git add -A

# 添加所有修改和删除的文件(不包括新文件)
git add -u

# 添加所有文件(包括未跟踪的文件)
git add *

添加指定类型文件

bash
# 添加所有 .php 文件
git add *.php

# 添加所有 .js 文件
git add *.js

# 添加 src 目录下所有文件
git add src/

# 添加多个目录
git add src/ tests/ docs/

# 添加特定模式的文件
git add src/**/*.php

交互式添加

bash
# 交互式添加
git add -i

# 输出示例
#           staged     unstaged path
#   1:    unchanged        +0/-1 TODO
#   2:    unchanged        +1/-1 index.html
#   3:    unchanged        +5/-1 lib/simplegit.rb
#
# *** Commands ***
#   1: status   2: update   3: revert   4: add untracked
#   5: patch    6: diff     7: quit     8: help
# What now>

部分暂存(Patch 模式)

bash
# 交互式部分暂存
git add -p filename.txt

# 输出示例
diff --git a/filename.txt b/filename.txt
index abc1234..def5678 100644
--- a/filename.txt
+++ b/filename.txt
@@ -1,5 +1,8 @@
 line 1
 line 2
+new line 1
+new line 2
 line 3
 line 4
+new line 3

(1/1) Stage this hunk [y,n,q,a,d,e,?]?

# 选项说明:
# y - 暂存此块
# n - 不暂存此块
# q - 退出
# a - 暂存此文件所有剩余块
# d - 不暂存此文件所有剩余块
# s - 分割成更小的块
# e - 手动编辑
# ? - 帮助

添加时设置权限

bash
# 添加文件并设置可执行权限
git add --chmod=+x script.sh

# 添加文件并取消可执行权限
git add --chmod=-x script.sh

# 查看权限变化
git diff --cached

添加的注意事项

bash
# 注意:git add 是幂等的
# 多次添加同一个文件不会产生问题

# 添加后继续修改
git add file.txt
echo "more content" >> file.txt

# 此时文件同时处于已暂存和已修改状态
git status
# Changes to be committed:
#   modified:   file.txt
#
# Changes not staged for commit:
#   modified:   file.txt

# 需要再次添加
git add file.txt

git status 查看状态

基本用法

bash
# 查看完整状态
git status

# 输出示例
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   src/App.php

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   src/Controller.php

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    src/NewClass.php

no changes added to commit but untracked files present

简洁模式

bash
# 简洁输出
git status -s
# 或
git status --short

# 输出示例
 M src/Controller.php    # 已修改(未暂存)
M  src/App.php           # 已修改(已暂存)
MM src/Model.php         # 已修改(部分暂存)
A  src/NewClass.php      # 新文件(已暂存)
?? src/Unknown.php       # 未跟踪
D  src/OldClass.php      # 已删除(已暂存)
 D src/Deleted.php       # 已删除(未暂存)
R  old.txt -> new.txt    # 重命名
C  copy.txt              # 复制

# 状态码说明:
# ?? - 未跟踪
# A  - 新添加到暂存区
# M  - 已修改
# D  - 已删除
# R  - 重命名
# C  - 复制
# 第一列表示暂存区状态
# 第二列表示工作目录状态

分支状态

bash
# 查看分支状态
git status -sb
# 或
git status --short --branch

# 输出示例
## main...origin/main
 M src/Controller.php

# 显示分支差异
git status -v
# 显示暂存区与仓库的差异

git status -vv
# 显示暂存区和工作目录的差异

忽略子模块

bash
# 忽略子模块变化
git status --ignore-submodules

# 忽略脏子模块
git status --ignore-submodules=dirty

# 忽略所有子模块
git status --ignore-submodules=all

显示被忽略的文件

bash
# 显示被忽略的文件
git status --ignored

# 输出示例
On branch main
Ignored files:
  .env
  vendor/
  node_modules/

查看特定文件状态

bash
# 查看特定文件状态
git status src/App.php

# 查看目录状态
git status src/

# 使用通配符
git status "*.php"

.gitignore 忽略文件

基本语法

bash
# .gitignore 文件语法

# 1. 注释
# 这是注释

# 2. 忽略特定文件
.env
config.local.php

# 3. 忽略特定扩展名的文件
*.log
*.tmp
*.swp

# 4. 忽略整个目录
vendor/
node_modules/
build/

# 5. 忽略目录下的所有文件
logs/*
temp/*

# 6. 不忽略特定文件(例外规则)
!important.log
!important/

# 7. 忽略根目录下的文件(不影响子目录)
/README.md
/.env

# 8. 忽略所有目录下的特定文件
**/temp.txt

# 9. 忽略特定目录下的所有文件
src/**/temp/

# 10. 使用方括号匹配
*.[oa]     # 忽略 .o 和 .a 文件
*.[xX][mM][lL]  # 忽略 .xml(不区分大小写)

通配符详解

bash
# * 匹配任意字符(不包括 /)
*.log           # 匹配所有 .log 文件
src/*.log       # 匹配 src 目录下的 .log 文件

# ** 匹配任意字符(包括 /)
**/test         # 匹配任意目录下的 test
src/**/*.php    # 匹配 src 下所有目录的 .php 文件

# ? 匹配单个字符
file?.txt       # 匹配 file1.txt, file2.txt 等

# [] 匹配字符集
file[123].txt   # 匹配 file1.txt, file2.txt, file3.txt
file[a-z].txt   # 匹配 filea.txt 到 filez.txt

# ! 取反
*.log
!important.log  # 不忽略 important.log

# / 目录分隔符
/build/         # 忽略根目录下的 build 目录
build/          # 忽略所有 build 目录

常用 .gitignore 模板

PHP 项目

bash
# .gitignore for PHP project

# 依赖
/vendor/
node_modules/

# 编译输出
/build/
/dist/

# 日志
*.log
/logs/

# 缓存
*.cache
/cache/

# 环境配置
.env
.env.local
.env.*.local

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# 操作系统
.DS_Store
Thumbs.db

# 测试
.phpunit.result.cache
/coverage/

# 临时文件
*.tmp
*.bak
*.backup

前端项目

bash
# .gitignore for Frontend project

# 依赖
node_modules/
bower_components/

# 构建输出
dist/
build/
.next/
out/

# 日志
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# 环境配置
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# 缓存
.cache/
.parcel-cache/

# IDE
.idea/
.vscode/
*.swp
*.swo

# 操作系统
.DS_Store
Thumbs.db

# 测试
coverage/

# 临时文件
*.log
*.tmp

Laravel 项目

bash
# .gitignore for Laravel project

# 依赖
/vendor/
node_modules/

# 构建输出
/public/build
/public/hot

# 存储
/storage/*.key
/storage/logs/*
/storage/framework/cache/*
/storage/framework/sessions/*
/storage/framework/views/*

# 环境配置
.env
.env.backup
.env.production
.phpunit.result.cache

# IDE
.idea/
.vscode/
*.swp

# 操作系统
.DS_Store
Thumbs.db

# 其他
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

创建 .gitignore 文件

bash
# 创建 .gitignore 文件
touch .gitignore

# 使用模板创建
curl -o .gitignore https://www.toptal.com/developers/gitignore/api/php,macos,windows

# 或使用在线生成器
# https://www.toptal.com/developers/gitignore

# 添加到仓库
git add .gitignore
git commit -m "chore: 添加 .gitignore 配置"

检查忽略规则

bash
# 检查文件是否被忽略
git check-ignore -v .env

# 输出示例
.gitignore:18:.env    .env

# 检查多个文件
git check-ignore -v file1.txt file2.txt

# 查看所有被忽略的文件
git status --ignored

清理已跟踪的忽略文件

bash
# 从仓库中删除但保留本地文件
git rm --cached .env

# 从仓库中删除整个目录
git rm --cached -r vendor/

# 从仓库中删除所有被忽略的文件
git rm --cached -r .
git add .

# 提交更改
git commit -m "chore: 从版本控制中移除被忽略的文件"

全局 .gitignore

bash
# 创建全局 .gitignore
touch ~/.gitignore_global

# 配置全局忽略
git config --global core.excludesfile ~/.gitignore_global

# 添加常见忽略规则
cat > ~/.gitignore_global << 'EOF'
# 操作系统
.DS_Store
Thumbs.db

# IDE
.idea/
.vscode/
*.swp
*.swo

# 临时文件
*~
*.log
EOF

文件状态操作

查看文件差异

bash
# 查看工作目录与暂存区的差异
git diff

# 查看暂存区与仓库的差异
git diff --staged
# 或
git diff --cached

# 查看工作目录与仓库的差异
git diff HEAD

# 查看特定文件差异
git diff filename.txt

# 查看两个提交之间的差异
git diff commit1 commit2

# 查看统计信息
git diff --stat

# 查看简要信息
git diff --name-only

撤销修改

bash
# 撤销工作目录的修改(未暂存)
git restore filename.txt
# 或
git checkout -- filename.txt

# 撤销暂存区的修改(取消暂存)
git restore --staged filename.txt
# 或
git reset HEAD filename.txt

# 完全撤销(工作目录和暂存区)
git restore --source=HEAD filename.txt

# 撤销所有修改
git restore .

# 撤销特定目录的修改
git restore src/

删除文件

bash
# 删除文件并暂存删除
git rm filename.txt

# 删除文件但保留本地副本
git rm --cached filename.txt

# 删除整个目录
git rm -r directory/

# 强制删除(包括未提交的修改)
git rm -f filename.txt

# 删除所有被跟踪的文件
git rm -r --cached .

重命名文件

bash
# 重命名文件
git mv oldname.txt newname.txt

# 等价于
mv oldname.txt newname.txt
git rm oldname.txt
git add newname.txt

# 移动文件
git mv file.txt src/

# 移动并重命名
git mv old/path/file.txt new/path/newfile.txt

实用技巧

快速查看修改概览

bash
# 查看修改的文件列表
git status -s

# 查看修改统计
git diff --stat

# 查看修改摘要
git diff --shortstat

# 查看修改的文件数量
git diff --numstat | wc -l

批量操作

bash
# 添加所有修改的文件
git add -u

# 添加所有文件(包括删除)
git add -A

# 撤销所有暂存
git reset HEAD

# 撤销所有修改
git restore .

# 删除所有未跟踪的文件
git clean -f

# 删除所有未跟踪的文件和目录
git clean -fd

# 预览将要删除的文件
git clean -n

使用 Git 别名

bash
# 配置状态别名
git config --global alias.st status
git config --global alias.ss "status -s"
git config --global alias.d diff
git config --global alias.ds "diff --staged"

# 使用别名
git st
git ss
git d
git ds

总结

文件状态速查表

状态说明操作
Untracked未跟踪git add 添加
Unmodified未修改编辑文件
Modified已修改git add 暂存
Staged已暂存git commit 提交

常用命令速查

bash
# 添加文件
git add .                  # 添加所有文件
git add -p                 # 交互式添加

# 查看状态
git status                 # 完整状态
git status -s              # 简洁状态

# 撤销操作
git restore <file>         # 撤销工作目录修改
git restore --staged <file> # 取消暂存

# 删除文件
git rm <file>              # 删除并暂存
git rm --cached <file>     # 只删除仓库中的文件

# 重命名
git mv <old> <new>         # 重命名文件

下一步

掌握文件状态管理后,建议继续学习: