在编程开发中,无论是使用 GoC++ 还是 Python 进行项目协作,版本控制都是不可或缺的一环。本文将带你深入理解 Git 的三大核心区域——工作区、暂存区和版本库,并通过实战案例掌握文件修改与提交的精髓。

认识 Git 的三大区域

Git 的管理机制围绕三个独立区域展开,理解它们是掌握 Git 的关键。

  • 工作区(Working Directory):这是你电脑上直接操作的项目文件夹。你在这里新建、修改代码,就像在办公桌上处理文件。所有对 JavaScriptJava 代码的编辑,都首先发生在工作区。
  • 暂存区(Staging Area / Index):这是一个看不见的中间区域,类似于“打包盒”。当你觉得工作区中的改动准备就绪,可以使用 git add 将其放入暂存区。暂存区的信息存储在 .git/index 文件中,因此也被称为索引(Index)。
  • 版本库(Repository):这是 Git 永久存储项目历史版本的地方,位于隐藏的 .git 文件夹内。所有经过 git commit 保存的版本都安全地存放在这里,随时可追溯或恢复。

三大区域的关系与流程

这三者的协作关系可以用一个简单的流程来概括:

+--------------+       +--------------+       +--------------+
|   工作区     | ----> |    暂存区    | ----> |    版本库    |
| (Working Dir)|       | (Staging Area)|       | (Repository) |
+--------------+       +--------------+       +--------------+
    (你的办公桌)       (准备提交的区域)    (历史版本仓库)
         ^                     ^                     |
         |                     |                     |
         +---------------------+---------------------+
               (可以从版本库或暂存区恢复到工作区)

你所有的文件修改都首先发生在 工作区。当你觉得某部分修改完成,需要先用 git add 将其从工作区添加到 暂存区。当暂存区的内容准备好作为一个完整版本保存时,再用 git commit 将其提交到 版本库

⚠️ 重点:仅仅在工作区新建或修改文件,Git 的版本库是不知道的!你必须完成“工作区 → 暂存区 → 版本库”的流程,才能让 Git 真正管理这些改动。

第一次添加文件到仓库

假设你已经在初始化过的项目文件夹中新建了一个 ReadMe 文件,并写入了内容。

# 确保你在 Git 仓库目录下
zz@139-159-150-152:~/gitcode$ pwd
/home/zz/gitcode
# 使用 vim 或其他编辑器创建并编辑 ReadMe 文件
# 比如输入两行内容:
# hello bit
# hello git
zz@139-159-150-152:~/gitcode$ vim ReadMe
# 查看 ReadMe 的内容(确认修改已完成)
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git

现在,ReadMe 文件仅存在于工作区。要让 Git 跟踪它,需要执行两步操作:

  1. 添加到暂存区:使用 git add 命令。常用方式包括:
    • git add 文件名:添加指定文件。
    • git add .:添加当前目录下所有改动(最常用)。
# 将 ReadMe 文件添加到暂存区
zz@139-159-150-152:~/gitcode$ git add ReadMe
  1. 提交到版本库:使用 git commit 命令,并附上清晰的日志消息。
# 提交暂存区的所有内容到版本库
# -m 后面跟着的是本次提交的“说明信息”
zz@139-159-150-152:~/gitcode$ git commit -m "commit my first file"

执行后,Git 会生成一个唯一的版本号(Commit ID),并给出成功反馈:

[master (root-commit) c614289] commit my first file  # [分支信息] commit id 的前几位] 提交信息
1 file changed, 2 insertions(+)                       # 本次提交涉及1个文件,新增了2行内容
create mode 100644 ReadMe                            # ReadMe 文件被创建,权限模式是 100644

理解多次 add,一次 commit:你可以多次使用 git add 将不同文件陆续加入暂存区,然后只需一次 git commit,暂存区中的所有内容就会被作为一个完整版本提交。例如,创建并添加三个空文件:

# 在工作区创建三个新文件
zz@139-159-150-152:~/gitcode$ touch file1 file2 file3
# 逐个或批量添加到暂存区
zz@139-159-150-152:~/gitcode$ git add file1
zz@139-159-150-152:~/gitcode$ git add file2
zz@139-159-150-152:~/gitcode$ git add file3
# 或者直接 git add . 把当前目录下的所有新增文件都加进去
# 一次性提交暂存区里所有待提交的内容(file1, file2, file3)
zz@139-159-150-152:~/gitcode$ git commit -m "add 3 files"
[master 23807c5] add 3 files         # Git 生成了新的 commit id
3 files changed, 0 insertions(+), 0 deletions(-) # 本次提交涉及 3 个文件,没有增删行(因为是空文件)
create mode 100644 file1             # file1 被创建
create mode 100644 file2             # file2 被创建
create mode 100644 file3             # file3 被创建

查看提交历史与 .git 目录变化

每次 git commit 都会留下永久记录。使用 git log 命令可以查看这些历史记录:

zz@139-159-150-152:~/gitcode$ git log
commit 23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) # 最新提交的 commit id,以及 HEAD 和 master 分支的指向
Author: zz91 <2689241679@qq.com>                          # 作者信息
  Date:   Sat May 6 11:27:32 2023 +0800                     # 提交日期和时间
  add 3 files                                         # 提交时填写的消息(message)
  commit c61428926f3853d4ec6dde904415b0e6c1dabcc6           # 上一个提交的 commit id
  Author: zz91 <2689241679@qq.com>
    Date:   Sat May 6 11:25:50 2023 +0800
    commit my first file

如果觉得输出信息太多,可以加上 --oneline 参数简化显示:

zz@139-159-150-152:~/gitcode$ git log --pretty=oneline
23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) add 3 files      # commit id 和提交信息
c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file             # 上一个 commit id 和提交信息

理解 Commit ID:这是 Git 使用 SHA1 算法根据提交内容计算出的唯一哈希值,相当于每个版本的“身份证号”。

(进阶理解)提交后,.git 目录会发生明显变化:

zz@139-159-150-152:~/gitcode$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG       # 最近一次 commit 的消息
├── config               # 仓库配置文件
├── description
├── HEAD                 # 指向当前分支(如 master/main)
├── hooks                # 钩子脚本目录
├── index                # **就是暂存区的文件!git add 会修改它!**
├── info
│   └── exclude          # Git 忽略文件配置
├── logs                 # 记录 HEAD 和分支的移动历史
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects              # **Git 存放所有对象的地方(文件内容、目录树、提交等)!**
│   ├── 23               # 根据对象 ID 前两位命名的文件夹
│   │   └── 807c536969cd886c4fb624b997ca575756eed6  # 最新 commit 对象
│   ├── 83
│   │   └── 0a8c9feefbdc098bbae2cdc25e5034ce1920d7  # 一个 tree 对象 (目录树快照)
│   ├── 8f
│   │   └── add50161b6fafa53ce7e79d278dc490240c946  # 可能是一个 blob 或 tree 对象
│   ├── 9c
│   │   └── 9e1f0f6bff3015df71a0963004476f5e6cfd54  # ReadMe 文件的 blob 对象 (内容)
│   ├── c6
│   │   └── 1428926f3853d4ec6dde904415b0e6c1dabcc6  # 第一个 commit 对象
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391  # file1/file2/file3 的 blob 对象 (内容)
│   ├── info
│   └── pack              # 优化存储的对象打包文件
└── refs                 # 存放指向 commit 的引用,如分支和标签
├── heads            # 分支引用存放处
│   └── master       # master 分支引用,里面存着 master 分支最新提交的 commit id
└── tags             # 标签引用存放处
# 注意:你的 objects 目录下的文件夹和文件可能不同,因为它们是根据你的具体提交内容生成的。
  • index:暂存区的实际文件。
  • HEAD:指向当前所在分支的指针。
  • refs/heads/master:存储 master 分支最新提交的 Commit ID。
  • objects:Git 的对象数据库,存放所有版本数据。

使用 git cat-file 命令可以查看对象内容:

zz@139-159-150-152:~/gitcode$ git cat-file -p 23807c536969cd886c4fb624b997ca575756eed6
tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7  # 这个 commit 对应的目录树对象 ID
parent c61428926f3853d4ec6dde904415b0e6c1dabcc6 # 这个 commit 的父提交 ID(上一个版本)
author zz91 <2689241679@qq.com> 1683343652 +0800 # 作者信息
  committer zz91 <2689241679@qq.com> 1683343652 +0800 # 提交者信息
    # 这是本次提交的消息
    add 3 files
zz@139-15 Confusion - git diff vs git diff --staged? (added, modified, deleted files) - Stack Overflow https://stackoverflow.com/questions/3878338/git-diff-vs-git-diff-staged-added-modified-deleted-files
```git diff` shows the difference between the *working directory* and the *staging area*.
`git diff --staged` shows the differences between the *staging area* and the *last commit*.`
The provided text *only* mentions `git diff [file]` (which compares working dir to staging) and `git diff HEAD -- [file]` (which compares working dir to last commit). It *doesn't* mention `git diff --staged`.
To stick strictly to the text, I should *only* explain `git diff [file]` (WD vs Stage) and `git diff HEAD -- [file]` (WD vs HEAD/Repo). However, for beginner understanding, clearly explaining the three comparisons (`WD vs Stage`, `Stage vs Repo`, `WD vs Repo`) is very helpful.
Let's clarify based on standard Git usage and the provided text:
* `git diff` (without file): By default, compares Working Dir and Staging Area.
* `git diff [file]`: Compares the *specific file* in the Working Dir and Staging Area. (This matches the text's example).
* `git diff --staged` (or `--cached`): Compares Staging Area and the last commit. (Not in text, but a crucial comparison).
* `git diff HEAD` (without file): Compares Working Dir and the last commit.
* `git diff HEAD -- [file]`: Compares the *specific file* in the Working Dir and the last commit. (This matches the text).
Okay, I will explain `git diff [file]` as comparing Working Dir and Staging Area (as the text implies by the context of needing `git add` afterwards). I will also explain `git diff HEAD -- [file]` as comparing Working Dir and the last commit (as the text states). I will *not* introduce `git diff --staged` as it's not in the provided content, even if it's conceptually useful. I need to explain what the diff output format means simply.
Let's refine the "修改文件" section based on this.
**Refined Drafting - Modifying Files:**
* Start with modifying ReadMe.
* Introduce `git status` - explain it shows the state relative to Staging and Repository. Show output "Changes not staged for commit". Explain this means "Working Dir has changes compared to Staging Area".
* Introduce `git diff [file]` - explain it shows *what* those unstaged changes are. Show output. Explain the `+` (added lines) and `-` (removed lines). State it compares Working Dir and Staging Area.
* Mention `git diff HEAD -- [file]` as another diff command, comparing Working Dir and the *last commit* in the Repository. Explain why you might use it (see differences since the *last saved version*).
* Show `git add ReadMe` - explain it moves the *modified* `ReadMe` from Working Dir to Staging Area.
* Show `git status` again - output should be "Changes to be committed". Explain this means "Staging Area has changes ready to be committed".
* Show `git commit -m "..."` - explain it saves the Staging Area to the Repository.
* Show final `git status` - output "nothing to commit, working tree clean". Explain this means Working Dir and Staging Area match the last commit.
This flow directly uses the provided commands and explanations while clearly linking them back to the three areas and the state changes.
Let's integrate this refined section into the overall structure.
59-150-152:~/gitcode$ git cat-file -p 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
100644 blob 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ReadMe   # ReadMe 文件,类型是 blob,这是它的对象 ID
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1   # file1 文件,类型是 blob,这是它的对象 ID
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2   # file2 文件
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3   # file3 文件
zz@139-159-150-152:~/gitcode$ git cat-file -p 9c9e1f0f6bff3015df71a0963004476f5e6cfd54
hello bit
hello git
# 这就是 ReadMe 文件在那个提交时的实际内容!

️ 修改文件并提交:git status 与 git diff

在日常开发中,修改文件是常态。以 Python 项目为例,修改 app.py 后,可以使用以下命令跟踪改动:

  • 查看工作区状态git status 命令会告诉你哪些文件被修改、哪些已暂存。
  • 查看具体修改内容git diff 命令显示工作区与暂存区之间的差异。
# 查看 ReadMe 的当前内容
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
# 修改 ReadMe 文件,比如增加一行
# hello bit
# hello git
# hello world
zz@139-159-150-152:~/gitcode$ vim ReadMe
# 再次查看修改后的内容
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
# 查看 Git 仓库状态
zz@139-159-150-152:~/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")

确认无误后,执行 git addgit commit 提交修改:

# 查看 ReadMe 文件在工作区和暂存区之间的差异
zz@139-159-150-152:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe
index 9c9e1f0..4a97140 100644
--- a/ReadMe         # Diff 比较的“旧”文件(暂存区或最新提交的版本)
+++ b/ReadMe         # Diff 比较的“新”文件(工作区的文件)
@@ -1,2 +1,3 @@     # 表示在原文件的第1行开始的2行,和新文件的第1行开始的3行之间有差异
hello bit
-hello git           # 减号开头的行表示在旧版本有,在新版本被删除了
+hello git           # 加号开头的行表示在旧版本没有,在新版本被增加了
+hello world         # 加号开头的行表示在新版本被增加了

总结 Git 基本操作流程

通过本文的学习,你已经掌握了 Git 的核心工作流程:

  1. 在工作区:创建或修改文件(如 Go、Java 代码)。
  2. 使用 git add:将改动添加到暂存区。
  3. 使用 git commit:将暂存区内容提交到版本库。
  4. 使用 git status 和 git diff:随时查看工作区和暂存区状态。

无论你是在编写 C++ 后端服务,还是用 JavaScript 构建前端应用,掌握这套流程都能让你的版本控制更加高效、可靠。

[AFFILIATE_SLOT_1]

[AFFILIATE_SLOT_2]