别背 Git 命令了,先搞懂这张地图

285 阅读6分钟

工作区 → 暂存区 → 本地仓库 → 远程仓库。Git 所有的命令,都是在这四个节点之间搬运变化。

学 Git 最亏的方式,就是把命令当咒语背。git add 是"添加",git commit 是"提交",git push 是"推送"——背了 20 个命令,换个顺序还是不会。

因为你不理解 Git 在底层到底在干什么。

Git 的整个设计,只围绕一个模型:四个节点,三条搬运线。

  工作区         暂存区          本地仓库         远程仓库
(Working)  →   (Stage)   →  (Local Repo)  →  (Remote)
  你写代码       购物车         永久快照        Gitee/GitHub

          git add       git commit      git push
          ───────→     ────────→      ────────→

          ←───────     ←────────      ←────────
          git restore    git reset       git pull

看懂了这张图,后面所有命令都是推论。


一、起点:git init 还是 git clone?

有两种方式获得一个 Git 仓库:

# 方式一:把本地项目升级为仓库
git init

# 方式二:把远程仓库复制到本地
git clone https://gitee.com/xxx/project.git

git init 在你的项目文件夹里创建 .git 目录,工作区从此有了暂存区和仓库。自己的新项目,用它。

git clone 干了三件事:创建文件夹 → 初始化仓库 → 把远程仓库的所有快照和历史拉到本地。参与已有项目,用它。


二、三个区域

工作区

就是你项目文件夹里能看到的文件。你写代码、改代码、删代码,都在这里。

Git 不会自动跟踪工作区的变化。 你改了一行,Git 看见了,但它不动——除非你显式告诉它"这个改动我要了"。

.gitignore:在源头过滤

有些文件你永远不会想让 Git 跟踪:node_modules/.env、编译产物、IDE 配置、日志文件……

创建 .gitignore

# .gitignore
node_modules/
.env
dist/
*.log
.DS_Store

匹配到的文件,Git 就当看不见——git status 不会报 untracked,git add . 不会误加。

.gitignore 是在工作区入口设的一道门。在进入 add → commit 这条流水线之前,先把垃圾筛掉。

暂存区

git add 把改动从工作区搬到暂存区。

暂存区是 Git 设计里最妙的发明。它像一个购物车:可以往里扔东西,可以拿出来,可以分批次结账。只要还没 commit,仓库版本纹丝不动。

仓库

git commit 把暂存区里的内容打包成一张永久快照,存进仓库。

仓库是一串快照的链条——每次 commit 指向它的上一次,形成一条可以随时回退的时间线。

想看这条时间线,用 git log

git log --oneline
# a1b2c3d 完成首页布局和样式
# e4f5g6h 初始化项目结构

--oneline 让每条 commit 只占一行,只显示 id 和说明——这就是你项目的"版本履历表"。


三、为什么 add + commit 必须两步?

不能一步到位,这是故意的。

假设你在做首页功能,涉及三个文件:

git add index.html    # 页面结构
git add common.css    # 样式
git add common.js     # 逻辑

三次 add,暂存区里攒了三样东西,仓库纹丝不动。

然后一次提交:

git commit -m '完成首页布局和样式'

多次 add,一次 commit。 带来的好处:

  1. 逻辑分组——一个 commit 对应一个完整功能,不是零散的"保存"
  2. 提前后悔——add 完了发现不该加?git reset 把文件从购物车拿出来,不影响工作区
  3. 提交历史干净——git log 看到的是一行行有意义的功能节点,不是满屏的"改了一行"

如果 add 和 commit 是一步,那每改一个文件就产生一个快照——三个文件三个快照,每个都是"半成品",回退到任何一个都会坏。


四、git status——任何不确定的时候,先打这个

git status

它告诉你:

  • 工作区里哪些文件改了但没 add(红色)
  • 暂存区里哪些文件等着被 commit(绿色)
  • 哪些文件 Git 根本不认识(untracked)
  • 本地仓库和远程仓库有没有不同步(ahead / behind)

git status 就是把四个节点的状态同时汇报给你。 每次操作前后都打一次,这个习惯比背任何命令都值钱。


五、连接远程仓库

git init 之后,你的仓库只存在于本地。要让队友看到,或者自己换个设备继续开发,需要绑定远程仓库:

git remote add origin https://gitee.com/你的用户名/项目名.git

origin 是远程仓库的别名——可以叫任何名字,但大家约定叫 origin。这条命令只执行一次,之后 Git 就记住了。

第一次推送:

git push -u origin master

-u(--set-upstream)把本地的 master 和远程的 master 绑定。绑定之后,以后只需要敲:

git push    # 本地仓库 → 远程仓库,Git 知道往哪推
git pull    # 远程仓库 → 本地仓库 + 工作区,Git 知道从哪拉

git remote add 只做了一件事:给你的远程仓库 URL 起一个本地别名。 origin 不是一个实物,就是那个 URL 的简称。之后你敲 git push origin master,Git 把 origin 翻译成 URL,往那推。

在此之前,add/commit 都在本地打转,git push 会直接报错——Git 不知道往哪推。有了 remote,搬运线才从本地仓库延伸到远程仓库。


六、用这个模型,理解一切命令

一旦你接受了"四个节点、三条搬运线",所有 Git 命令都是推论:

命令搬运方向干什么
git add工作区 → 暂存区改动加入购物车
git commit暂存区 → 本地仓库结账,生成快照
git push本地仓库 → 远程仓库快照同步给队友
git pull远程仓库 → 本地仓库 + 工作区拉取队友的快照
git clone远程仓库 → 本地(全部)把整个仓库复制到本地
git restore file本地仓库 → 工作区用仓库版本覆盖工作区(撤销修改)
git reset file暂存区 → 工作区从购物车拿出来(取消 add)
git reset --soft HEAD~1本地仓库 → 暂存区撤销 commit,改动回到购物车
git diff对比工作区和暂存区看看哪些改动还没 add
git log --oneline浏览本地仓库查看快照时间线

你不是在学几十个命令。你是在学一个模型,每个命令只是这个模型的一条连线。


七、完整流程

从零到推送:

# 1. 初始化
git init

# 2. 创建 .gitignore(内容见第二节)
# 手动新建文件,写入 node_modules/ 和 .env 等需要忽略的规则

# 3. 绑定远程(只做一次)
git remote add origin https://gitee.com/xxx/project.git

# 4. 日常开发循环
git status          # 看四个节点的状态
git add .           # 工作区 → 暂存区
git commit -m 'xxx' # 暂存区 → 本地仓库
git pull            # 先拉取队友的更新
git push            # 本地仓库 → 远程仓库

每次 push 前先 git pull。因为如果队友在你之前推了新 commit,远程仓库的版本就比你的本地仓库"更新"。Git 会拒绝你的 push——不允许用旧快照覆盖新快照。先 pull 把队友的改动拉到本地合并,再 push 才能通过。


下次遇到新 Git 命令,别搜"XX 命令怎么用"。先问自己:这个命令在哪些节点之间搬运了什么? 回答了这个问题,用法自然出来。