Git中文社区

核心概念

Git 的大部分命令,都是在工作区、暂存区和仓库这三个地方之间搬运数据。先把这几个概念弄清楚,后面的命令会好理解很多。

三个区域

一个 Git 项目包含三个主要区域:

  工作区                暂存区               本地仓库
(Working Directory)   (Staging Area)       (Repository)
      │                    │                    │
      │ ── git add ──────▶ │                    │
      │                    │ ── git commit ───▶ │
      │ ◀──────────────── git restore / checkout ── │

工作区(Working Directory)

工作区就是你在电脑上能看到的项目目录,是你编辑文件的地方。它是从仓库中取出的某个版本的文件。

暂存区(Staging Area / Index)

暂存区是一个文件(位于 .git/index),保存了下次将要提交的文件列表信息。可以把它理解为"提交前的购物车":你把想提交的修改放进去,确认无误后一起结账(提交)。

暂存区的存在,让你可以精细地控制每次提交包含哪些修改。例如你同时修改了三个文件,但只想先提交其中两个,就可以只把那两个加入暂存区。

本地仓库(Repository)

项目根目录下的 .git 目录就是本地仓库,Git 用它来保存项目的元数据和对象数据库。这是 Git 中最重要的部分,从其他计算机克隆仓库时,复制的就是这里的数据。

警告

不要手动修改或删除 .git 目录中的内容,否则可能导致仓库损坏、历史丢失。

文件的状态

工作区中的每个文件只有两种大状态:已跟踪(tracked) 或 未跟踪(untracked)。已跟踪的文件是指已经被纳入版本控制的文件,它们又可以处于以下三种状态之一:

状态含义
未修改(unmodified)文件与最近一次提交的内容相同
已修改(modified)修改了文件,但还没保存到暂存区
已暂存(staged)对已修改文件的当前版本做了标记,将包含在下次提交中

一个文件的典型生命周期是:

未跟踪 ──add──▶ 已暂存 ──commit──▶ 未修改 ──编辑──▶ 已修改 ──add──▶ 已暂存 ...

基本的 Git 工作流程

  1. 在工作区中修改文件;
  2. 将你想要下次提交的更改选择性地暂存(git add);
  3. 提交更新,将暂存区的文件快照永久存储到 Git 仓库(git commit)。

提交(Commit)

提交是 Git 中最基本的单元。每个提交包含:

  • 项目在那一刻的完整快照;
  • 作者、提交者和时间;
  • 提交说明(commit message);
  • 指向父提交的指针(第一个提交没有父提交,合并提交有多个父提交)。

每个提交都有一个唯一的 SHA-1 哈希值作为 ID,通常只需使用前 7 位即可引用,例如 a1b2c3d。

所有提交通过父指针连接起来,形成一条(或多条)历史链:

A ◀── B ◀── C ◀── D   (main)

分支(Branch)

Git 中的分支本质上只是一个指向某个提交的可移动指针。创建分支就是创建一个新指针,所以非常轻量,几乎瞬间完成。

              E ◀── F   (feature)
             /
A ◀── B ◀── C ◀── D     (main)

HEAD 是一个特殊的指针,指向你当前所在的分支(或提交)。当你切换分支时,HEAD 就会指向新的分支。每次提交后,HEAD 所指向的分支会自动前移到新提交。

# 查看 HEAD 当前指向
cat .git/HEAD
# ref: refs/heads/main

当 HEAD 直接指向某个提交而不是分支时,称为**分离头指针(detached HEAD)**状态,此时的新提交不属于任何分支,切换走后容易"丢失"。

远程仓库(Remote)

远程仓库是托管在网络上(或其他位置)的项目版本库,例如 GitHub 上的仓库。你可以从远程拉取别人的提交,也可以把自己的提交推送上去。克隆的仓库默认有一个名为 origin 的远程仓库。

小结

  • 工作区 是你编辑的地方,暂存区 是准备提交的内容,仓库 保存所有历史;
  • git add 把修改从工作区放入暂存区,git commit 把暂存区保存为一个新提交;
  • 分支 是指向提交的指针,HEAD 指向当前分支。

记住这张图,后面几乎所有命令都是在这三个区域之间移动数据。下一章我们来创建第一个仓库。