跳到主要内容
Git 基础:认识三大区域与文件修改提交流程 | 极客日志
Shell / Bash
Git 基础:认识三大区域与文件修改提交流程 综述由AI生成 Git 工作区、暂存区和版本库的概念及关系,详细演示了使用 git add 和 git commit 将文件纳入管理的流程。通过实际操作展示了如何查看提交历史、理解.git 目录结构,以及利用 git status 和 git diff 监控文件修改状态并正确提交变更。
GRACE Grace 发布于 2026/3/30 更新于 2026/5/23 31 浏览
认识 Git 的三大区域:工作区、暂存区、版本库
要理解 Git 的工作流程,必须先搞清楚它在哪几个地方'存放'和'处理'你的文件。Git 主要涉及以下三个区域:
工作区(Working Directory)
是什么? 就是你在电脑里,能直接看到、直接操作的那个项目文件夹。比如你在里面新建文件、修改代码,这些操作都是在工作区进行的。简单来说,这就是你正在工作的地方 ,你的'办公桌'。
暂存区(Staging Area / Index)
是什么? 这是 Git 中一个非常核心且独特的概念。它不像工作区那样是一个看得见的文件夹,它更像一个目录清单 或者一个中间'打包区' 。当你觉得工作区里的某个文件修改好了,或者某个新文件要纳入 Git 管理了,你就可以用一个命令把这些改动'放'到暂存区里,表明'我这些改动已经准备好了,待会儿要一起保存'。
在哪儿? 暂存区的信息通常存放在 Git 仓库目录(那个隐藏的 .git 文件夹)下的 index 文件里(路径是 .git/index)。所以,有时候人们也把暂存区叫做'索引'(Index)。可以想象成你的'打包盒子',你把准备好一起提交的文件放进去。
版本库(Repository)
是什么? 这就是 Git 用来永久存储 你的项目历史版本的地方。它包含了所有提交过的版本数据,分支信息,以及 Git 管理项目所需的一切数据。
在哪儿? 就是你项目文件夹里那个隐藏的 .git 文件夹 。注意,这个 .git 文件夹不属于 工作区!它是独立于工作区的版本库本身。版本库就像你的'仓库'或'档案室',所有经过 commit 保存的版本都安全地存放在这里,随时可以追溯或恢复。
工作区、暂存区、版本库的关系流程图解 (概念)
想象一下,它们之间的关系就像这样:
+
| 工作区 |
| (Working Dir)| | (Staging Area)| | (Repository) |
+
(你的办公桌) (准备提交的区域) (历史版本仓库)
^ ^
|
|
+
(可以从版本库或暂存区恢复到工作区)
你所有的文件修改都首先发生在工作区 。
当你觉得某一部分修改完成了,需要先 git add 把这些改动从工作区添加到暂存区 。
当你觉得暂存区里的内容(也就是你通过 git add 累积起来的所有改动)都准备好作为一个完整的历史版本保存时,需要 git commit 把暂存区 的内容提交 到版本库 。
你仅仅在工作区新建了一个文件,或者修改了工作区里的文件,对于 Git 的版本库来说,它是不知道 的!这些改动没有 被 Git 跟踪起来。
通过新建或粘贴进目录的文件,并不能称之为向仓库中新增文件,而只是在工作区新增了文件 。必须要通过使用 git add 和 git commit 命令才能将文件添加到仓库中进行管理!!
要让 Git 开始管理这些文件和改动,你必须 完成从工作区 -> 暂存区 -> 版本库 的这个流程,也就是依次使用 git add 命令和 git commit 命令!
将文件添加到仓库进行管理:git add 和 git commit 理解了'三区'的概念,我们就知道 Git 跟踪和保存文件的基本步骤是:
在工作区对文件进行修改或新增。
使用 git add 命令将工作区的改动添加到暂存区 。
使用 git commit 命令将暂存区 的改动提交 到版本库,形成一个新的历史版本。
场景一:第一次添加文件到仓库 假设我们已经在 git init 过的项目文件夹里(也就是工作区),新建了一个 ReadMe 文件,并写了一些内容。
user@host:~/gitcode$ pwd
/home/user/gitcode
user@host:~/gitcode$ vim ReadMe
user@host:~/gitcode$ cat ReadMe
hello bit
hello git
现在,ReadMe 文件在我们的工作区 里。要让 Git 跟踪它,我们需要先把它加到暂存区 。
user@host:~/gitcode$ git add ReadMe
git add [文件名]:将指定文件的工作区改动添加到暂存区。
git add [目录名]:将指定目录(包括子目录)下的所有改动都添加到暂存区。
git add .:将当前目录下的所有 改动(包括新增、修改、删除,但删除需要单独处理或使用特定命令)都添加到暂存区。这是最常用的方式,表示'把我当前目录下所有 Git 知道有变化的文件的改动都放进暂存区'。
执行 git add ReadMe 后,ReadMe 文件的当前状态(包括内容和存在)就被放进了暂存区 ,它现在正安静地躺在你的'打包盒子'里,等待被提交。
第二步:将暂存区内容提交到版本库 (git commit)
现在暂存区里有了 ReadMe 文件。我们可以用 git commit 命令把暂存区里的所有内容作为一个新的版本提交到版本库。
user@host:~/gitcode$ git commit -m "commit my first file"
git commit -m "你的提交信息":提交暂存区中的所有内容到版本库。-m 参数非常重要,后面跟着的是本次提交的日志消息(message) 。这个消息是给你自己和未来的协作者看的,要清晰地说明这次提交'做了什么'。这部分内容绝不能省略,也务必好好描述!
git commit [文件名 1] [文件名 2] ... -m "你的提交信息":提交暂存区中指定 文件的内容到版本库(但通常我们是提交暂存区的全部内容,所以第一个命令更常用)。
执行 git commit -m "commit my first file" 后,Git 会把你暂存区里所有的改动(这里就是新增的 ReadMe 文件内容)打包,生成一个唯一的版本号(commit id),然后永久地存储到版本库里。
[master (root-commit) c614289] commit my first file
1file changed, 2 insertions(+)
create mode 100644 ReadMe
这说明你的 ReadMe 文件已经成功地作为你的第一个版本,被 Git 永久保存起来了。
你可能会想,如果我改了好几个文件,是不是要 add 一次就 commit 一次?不是的!
你可以多次使用 git add 命令,将不同时间修改好的、准备一起提交的文件或改动,陆续地添加到暂存区 。当你觉得所有这次要一起保存的改动都进了暂存区后,最后只需执行一次 git commit 命令 ,Git 就会把暂存区里的所有内容,作为一个完整 的、单一 的版本提交到版本库。
例如,我们再创建并添加三个空文件 file1, file2, file3:
user@host:~/gitcode$ touch file1 file2 file3
user@host:~/gitcode$ git add file1
user@host:~/gitcode$ git add file2
user@host:~/gitcode$ git add file3
user@host:~/gitcode$ git commit -m "add 3 files"
[master 23807c5] add 3 files
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2
create mode 100644 file3
这次提交就包含了这三个文件。这再次印证了 commit 提交的是暂存区 的内容。
查看提交历史:git log 每次 git commit 都会在版本库中留下一个永久的历史记录。我们可以使用 git log 命令来查看这些记录。
user@host:~/gitcode$ git log
commit 23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master)
Author: User <[email protected] >
Date: Sat May 6 11:27:32 2023 +0800
add 3 files
commit c61428926f3853d4ec6dde904415b0e6c1dabcc6
Author: User <[email protected] >
Date: Sat May 6 11:25:50 2023 +0800
commit my first file
git log 命令会按照提交时间的倒序(最近的提交在最上面)显示所有的提交记录。你可以看到每个提交的唯一 ID、作者、时间以及提交时填写的消息。
如果觉得输出信息太多,可以加上 --pretty=oneline 参数,让信息更简洁:
user@host:~/gitcode$ git log --pretty=oneline
23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) add 3 files
c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file
git log 中看到的那一长串字母和数字组合(比如 23807c5... 和 c614289...),就是每次提交的 Commit ID(版本号) 。
它不是简单的 1, 2, 3 递增序号,而是 Git 使用 SHA1 这种加密算法,根据本次提交的内容(包括文件的改动、提交者、时间、父提交等信息)计算出来的一个唯一 的哈希值。即使你在不同的电脑上提交相同的内容,生成的 Commit ID 也会是一样的。它是 Git 用来引用某个特定版本的'身份证号'。通常我们只需要使用它的前几位(一般是 7-8 位)就可以唯一标识一个提交了。
(进阶理解)提交后的 .git 目录变化 为了帮助你更深刻地理解 Git 是如何工作的,我们可以再次 peek 一下 .git 目录里的变化。在我们执行了几次 add 和 commit 后,.git 目录会变得更'丰满'。
user@host:~/gitcode$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 23# 根据对象 ID 前两位命名的文件夹
│ │ └── 807c536969cd886c4fb624b997ca575756eed6
│ ├── 83
│ │ └── 0a8c9feefbdc098bbae2cdc25e5034ce1920d7
│ ├── 8f
│ │ └── add50161b6fafa53ce7e79d278dc490240c946
│ ├── 9c
│ │ └── 9e1f0f6bff3015df71a0963004476f5e6cfd54
│ ├── c6
│ │ └── 142892626f3853d4ec6dde904415b0e6c1dabcc6
│ ├── e6
│ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
这里面有几个关键文件/目录,和我们的操作密切相关:
.git/index: 这就是暂存区 !每次执行 git add 命令,Git 都会更新这个文件,记录下当前暂存区的文件状态和对应的对象信息。
.git/HEAD: 这是一个指针 ,默认情况下,它指向你当前所在的分支(比如 master 或 main)。
user@host:~/gitcode$ cat .git/HEAD
ref: refs/heads/master
.git/refs/heads/master: 这是一个文件,它里面保存着 master 分支最新一次提交的 commit id 。
user@host:~/gitcode$ cat .git/refs/heads/master
23807c536969cd886c4fb624b997ca575756eed6
.git/objects/: 这是 Git 的对象数据库 ,Git 存储所有版本数据的核心区域!每次 git add,Git 会把工作区的文件内容压缩并存入这里,生成一个 blob 对象;每次 git commit,Git 会根据暂存区的内容,生成一个 tree 对象(代表当时的目录结构)和一个 commit 对象(包含作者、时间、message,以及指向 tree 对象和父 commit 对象)。你看到的 objects 目录下以 commit id 前两位命名的文件夹里,就存放着这些对象。
所以上图实际上还有一个文件夹作为逻辑上的中间层:对象库
Git 使用 SHA1 哈希值作为对象的 ID。你可以使用 git cat-file -p [对象 ID] 命令来查看 Git 对象库中某个对象的内容。
例如,查看最新的 commit 对象(使用上面 git log 或 .git/refs/heads/master 看到的 commit id):
user@host:~/gitcode$ git cat-file -p 23807c536969cd886c4fb624b997ca575756eed6
tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
parent c61428926f3853d4ec6dde904415b0e6c1dabcc6
author User <[email protected] > 1683343652 +0800
committer User <[email protected] > 1683343652 +0800
add 3 files
再查看上面 commit 对象里指向的 tree 对象(使用 tree 后面的 ID):
user@host:~/gitcode$ git cat-file -p 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
100644 blob 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ReadMe
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3
这个 tree 对象记录了在 23807c5... 那个提交时,项目根目录下有哪些文件和文件夹,以及它们各自对应的对象 ID。这里可以看到 ReadMe, file1, file2, file3 都指向了各自的内容对象。
最后,我们查看 ReadMe 文件对应的 blob 对象(使用上面看到的 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ID):
user@host:~/gitcode$ git cat-file -p 9c9e1f0f6bff3015df71a0963004476f5e6cfd54
hello bit
hello git
通过这个探索,我们可以看到 Git 如何在 objects 目录下存储文件的实际内容(blob 对象)、目录结构(tree 对象)以及提交信息(commit 对象),并且通过 Commit ID 将它们关联起来。每次 git add 和 git commit 都会在这个对象库中创建新的对象。这有助于我们理解 Git 是如何保存项目历史的。
index: 暂存区 的实际文件,git add 的结果保存在这里。
HEAD: 指向当前所在分支(默认是 master 或 main)的指针 。
refs/heads/master: 一个文件,里面存储着 master 分支最新提交的 commit id 。
objects: Git 的对象数据库 ,存放所有 Git 管理的对象(文件内容、目录树、提交等)。
在今后的学习中,试着将常用的 Git 命令和 .git 目录内部的变化联系起来,每次操作后都进行回想'这时候目录内部的操作',可以帮助你更深刻地理解 Git 的工作原理。
场景二:再次理解 add 和 commit 的配合 为了加深对工作区、暂存区、版本库以及 add 和 commit 命令关系的理解,我们再看一个例子:
user@host:~/gitcode$ touch file4
user@host:~/gitcode$ git add file4
user@host:~/gitcode$ touch file5
user@host:~/gitcode$ git commit -m "add file"
[master 3d406c0] add file
1file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
看提交结果,Git 告诉我们只有 1 file changed (file4)!这是怎么回事?我们明明新增了两个文件 (file4 和 file5) 啊?
原因: 回忆一下我们前面说的,git commit 提交的是暂存区 里的内容。在执行 git commit 命令时:
file4 已经通过 git add file4 被添加到了暂存区。
file5 虽然在工作区被创建了,但我们没有 对它执行 git add file5,所以它还在工作区 ,没有进入暂存区。
因此,git commit 时只看到了暂存区里的 file4,就把 file4 提交了,而完全忽略了还在工作区的 file5。
如何提交 file5 呢? 非常简单,按照流程来:先 git add file5 把 file5 加到暂存区,然后再 git commit 一次。
这个例子再次强调用 commit 提交的是暂存区 ,而不是工作区!在你 commit 之前,一定要确保所有想提交的改动都已经通过 git add 进入了暂存区。
修改文件并提交:git status 和 git diff 除了新增文件,修改已有文件是更常见的操作。Git 在这方面设计得非常高效,因为它跟踪并管理的是文件的修改 ,而不是整个文件。
'修改'可以有很多种:在你文件中新增一行、删除一行、更改几个字符、甚至改变文件名等等,Git 都能识别为'修改'。
user@host:~/gitcode$ cat ReadMe
hello bit
hello git
user@host:~/gitcode$ vim ReadMe
user@host:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
现在,工作区里的 ReadMe 文件内容和版本库中最新提交的 ReadMe 内容已经不一样了。Git 怎么知道哪些文件被修改了呢?
查看工作区状态:git status git status 命令是使用 Git 过程中最最常用的命令之一!它用于查看你当前工作区 和暂存区 的状态,告诉你哪些文件有改动,这些改动处于哪个阶段(在工作区还是暂存区)。
user@host:~/gitcode$ git status
On branch master
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: ReadMe
no changes added to commit
(use "git add" and/or "git commit -a" )
On branch master: 你当前在 master 分支上(分支概念后面会讲)。
Changes not staged for commit:: 工作区有改动,但这些改动还没有添加到暂存区 (还没有 add)。
modified: ReadMe: ReadMe 文件被修改了。
no changes added to commit: 暂存区是空的,没有任何准备要提交的内容。
这个状态说明:你修改了 ReadMe 文件,但 Git 只是知道它被改了,还没有把这个改动记录到暂存区,更没有提交到版本库。它还在你的'办公桌'上。
查看具体修改内容:git diff git status 告诉我们文件被修改了,但具体改了哪些地方呢?这就需要用到 git diff 命令。
git diff 命令默认情况下,是用来查看工作区 与暂存区 之间文件差异的。
user@host:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe
index 9c9e1f0..4a97140 100644
--- a/ReadMe
+++ b/ReadMe
@@ -1,2 +1,3 @@
hello bit
-hellogit
+hello git
+hello world
git diff 的输出使用了标准的 diff 格式:
以 --- a/ 开头表示比较的'旧'文件(通常是暂存区或上一个版本的)。
以 +++ b/ 开头表示比较的'新'文件(通常是工作区当前的)。
@@ ... @@ 之间的信息表示差异发生的位置。
以 - 开头的行表示这行在旧版本有,但在新版本被删除了 。
以 + 开头的行表示这行在旧版本没有,但在新版本被新增了 。
通过 git diff ReadMe,我们清楚地看到在工作区,我们在 hello git 后面新增了一行 hello world,并且虽然 hello git 本身内容没变,但因为上面的行删除了,这里显示好像是删了又加了(Git 认为行号变了也算改动,或者这里的 diff 算法是按行匹配)。但重点是,你能清晰地看到 hello world 是新增的。
另一个常用的 diff 比较:工作区与版本库最新提交的差异
如果你想直接看工作区的文件和版本库里最新提交的版本 有什么不同,可以使用 git diff HEAD -- [文件名] 命令:
user@host:~/gitcode$ git diff HEAD -- ReadMe
这个命令会比较你当前工作区的状态和 HEAD 指针指向的那个提交(也就是当前分支的最新版本)的文件状态。了解这个有助于你区分工作区和暂存区在 diff 命令中的不同作用。
提交修改后的文件 现在我们知道了 ReadMe 被修改了,并且通过 git diff 确认了修改内容。接下来,按照流程,把这个修改也保存到版本库中。
虽然文件是修改,不是新增,但流程一样,还是要先 add 到暂存区:
user@host:~/gitcode$ git add ReadMe
执行 git add ReadMe 后,ReadMe 文件在工作区里的修改就被添加到了暂存区。暂存区里现在包含了 ReadMe 文件修改后的新内容。
现在 ReadMe 的修改已经在暂存区了,我们再看看状态:
user@host:~/gitcode$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: ReadMe
这次的输出变了!ReadMe 文件出现在了 Changes to be committed: 这个区域下,并且前面显示 modified: ReadMe。这表明 ReadMe 文件在暂存区 里有改动,这些改动已经准备好被提交 到版本库了。
第二步:将暂存区内容提交到版本库 (git commit)
暂存区里有内容了,我们就可以执行 commit 命令来保存这个修改版本了:
user@host:~/gitcode$ git commit -m "add modify ReadMe file"
[master 94da695] add modify ReadMe file
1file changed, 2 insertions(+), 1 deletion(-)
提交成功!ReadMe 文件的这次修改已经被作为一个新的版本永久保存在版本库里了。
提交完成后,工作区和暂存区都应该是干净的(和版本库最新提交的状态一致)。
user@host:~/gitcode$ git status
On branch master
nothing to commit, working tree clean
nothing to commit, working tree clean:这说明当前工作区和暂存区都没有任何需要提交的改动,它们的状态是干净的,和版本库里最新的版本是同步的。这是一个很好的状态!
总结一下 Git 的基本操作流程 通过上面的学习,我们现在对 Git 的基本操作流程有了清晰的认识:
在工作区里工作: 新建、编辑、删除文件。
查看状态: 经常使用 git status 查看工作区和暂存区的状态,了解哪些文件有改动,它们处于哪个阶段。
查看具体改动: 使用 git diff [文件名] 查看工作区里的文件相对于暂存区的具体修改内容。
将改动添加到暂存区: 使用 git add [文件名] 或 git add . 将工作区中准备提交的改动放入暂存区。
提交暂存区的改动: 使用 git commit -m "有意义的提交信息" 将暂存区的内容作为一个新版本提交到版本库。
查看历史: 使用 git log 查看已经提交的版本历史。
理解工作区 -> 暂存区 -> 版本库 这个流程,以及 git add 和 git commit 在其中扮演的角色,是掌握 Git 的关键。每次改动都需要经过 add 和 commit 两步(或类似操作)才能真正被 Git 永久记录下来。
接下来,我们将继续学习 Git 的其他常用操作,比如如何回退版本,如何忽略文件等等。
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online