跳转到内容

记录更新到仓库

你现在已经拥有了一个真正的 Git 仓库,并从其中检出了文件的某个版本。接下来,你需要对这些文件做些修改,在完成一个阶段的目标后,提交本次更新到仓库。

在开始操作之前,彻底理解 Git 如何管理文件的状态是至关重要的。这是 Git 学习曲线中最陡峭的一段,但一旦掌握,你将如鱼得水。

工作目录下的每一个文件都不外乎这两种状态:已跟踪(Tracked) 或 未跟踪(Untracked)。

  • 已跟踪(Tracked):指那些 Git 已经知道的文件(已提交或已暂存)。它们又可以分为三种子状态:
    • 未修改(Unmodified):自上次提交后未曾改动。
    • 已修改(Modified):自上次提交后被修改了,但还没放到暂存区。
    • 已暂存(Staged):修改已放入暂存区,准备下次提交。
  • 未跟踪(Untracked):Git 尚未管理的任何文件(既没有在上次提交中,也没有在暂存区中)。

下图展示了文件的生命周期流转:

graph LR
Untracked((未跟踪)) -- "git add" --> Staged
Unmodified((未修改)) -- 编辑文件 --> Modified((已修改))
Modified -- "git add" --> Staged((已暂存))
Staged -- "git commit" --> Unmodified
Unmodified -- "git rm" --> StagedDel((已暂存删除))
%% 定义适配亮/暗模式的样式类
classDef untrackedNode fill:#718096,stroke:#4a5568,color:#fff,stroke-width:2px
classDef unmodifiedNode fill:#4a5568,stroke:#2d3748,color:#fff,stroke-width:2px
classDef modifiedNode fill:#e53e3e,stroke:#c53030,color:#fff,stroke-width:2px
classDef stagedNode fill:#3182ce,stroke:#2c5282,color:#fff,stroke-width:2px
class Untracked untrackedNode
class Unmodified unmodifiedNode
class Modified modifiedNode
class Staged stagedNode

理解了状态,我们再来看看这些状态对应的物理/逻辑区域。这是 Git 最核心的设计之一。

  1. 工作区 (Working Directory): 就是你在电脑文件资源管理器里能看到的目录。你在这里编辑代码、修改文件。这里是“现实世界”。

  2. 暂存区 (Staging Area / Index): 这是一个逻辑区域(实际上是 .git 目录下的一个文件)。这是 Git 最让新手困惑的地方。

    或者用照相来比喻:

    • 工作区:大家在自由活动。
    • 暂存区:摄影师说“来,大家站好位置,整理表情”,大家走上舞台摆好姿势(Stage 也有舞台的意思)。
    • 仓库:摄影师按下快门,照片(Snapshot)生成并存入相册。
  3. 仓库 (Repository): .git 目录,用于存储项目的元数据和对象数据库。

要查看哪些文件处于什么状态,主要的工具是 git status 命令。

如果你的工作区所有文件都已提交,且没有新文件,运行 git status 会看到:

Terminal window
$ git status
Terminal window
On branch main
nothing to commit, working tree clean

这意味着目前很“干净”,没有东西需要 Git 操心。

如果你创建了一个新文件 README.md,它首先是未跟踪的:

Terminal window
$ echo "My Project" > README.md
$ git status
Terminal window
On branch main
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)

Git 明确告诉你 README.md 是 Untracked files。除非你显式告诉 Git,否则它不会把这个文件纳入版本控制。

如果你运行 git add README.md,此时文件就进入了暂存区:

Terminal window
$ git add README.md
$ git status
Terminal window
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: README.md

Changes to be committed 下的文件,就是如果你现在运行 git commit,会被记录到历史中的内容。

假设你还有一个叫 CONTRIBUTING.md 的文件之前已经被跟踪了,现在你修改了它:

Terminal window
$ git status
Terminal window
On branch main
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: CONTRIBUTING.md

Changes not staged for commit 说明文件被修改了,但还没有放入暂存区(还没有上舞台/放入购物车)。如果现在提交,这个修改不会被记录。

当文件变多时,git status 的输出会非常长。Git 提供了一个紧凑的格式:

Terminal window
$ git status -s
Terminal window
M README.md
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt

这里的输出分为两列(左列和右列),含义如下:

符号含义
??新文件,未跟踪 (Untracked)
A 新文件,已暂存 (Added to Staging)
M已修改,未暂存 (Modified in Working Dir)
M 已修改,已暂存 (Modified in Staging)
MM由你来猜?

关于 MM 的解释: 这意味着该文件在工作区被修改并暂存了(左边的 M),然后又在工作区被修改了(右边的 M)。 这在实际开发中很常见:你写了一半代码觉得不错,先 git add 了一下(存个档),然后继续写,还没再次 add。此时这个文件既有已暂存的内容,也有未暂存的内容。