本教程将介绍以下内容:Git 的核心概念(工作区/暂存区/提交历史/Stash)、版本存档与回滚、分支合并与冲突处理、进阶工具(Rebase/Stash/Worktree),以及 GitHub 远程仓库的使用。
教程路线
基础篇:存档
- 让 Git 管理项目(
git init) - 核心模型:工作区、暂存区、提交历史
- 存档流程:
git add→git commit - 查看状态:
git status、git log
基础篇:回滚与忽略
- 回滚的 3 种场景(工作区、暂存区、提交历史)
- 撤销操作:
git restore、git reset、git revert - 忽略文件:
.gitignore
进阶篇:分支与合并
- 分支概念与操作(
git branch、git switch) - 合并分支与冲突处理(
git merge、快进合并、三方合并) - 进阶工具:Rebase、Stash、Worktree
工具篇:GitHub 远程仓库
- GitHub 使用场景与作用
- 配置 SSH Key(
ssh-keygen) - 创建 GitHub 仓库、关联远程仓库(
git remote add) - 推送代码(
git push)、克隆代码(git clone)
第 0 章 基础概念:Git 与 GitHub
(1)Git 是什么?为什么我们要使用 Git?
Git 是一款安装在你电脑上的本地软件,它负责记录并备份代码的各个版本,能够高效管理你的项目。它解决的是项目更新过程中的版本管理问题,并支持我们回退错误的修改。如果你不想变成这样:- 
请使用 Git。
更具体地说,Git 会在项目目录下维护一个本地仓库,把每一次提交的代码状态记录下来。你可以查看历史、比较差异、回退到某个版本,也可以在不同的分支上并行开发。它不依赖网络,本地就能完成版本管理。
(2)什么是 GitHub?与 Git 的关系是什么样的?
既然有了 Git,我们又为什么使用 GitHub?
GitHub 是一个远程网站,用于备份代码和 Git 记录。Git 只是将代码和版本记录备份存储在本地;如果我们的电脑遭遇不测,本地仓库也可能一起丢失,所以对代码进行多重备份是有必要的。GitHub 就担任这个角色。我们可以使用 Git 连接 GitHub 的远程仓库(你可以把 GitHub 理解为存储代码的云盘),代码便可以通过 Git 推送到 GitHub 的服务器中,实现本地一份、云端一份的双重备份。
当然,GitHub 的功能远不止备份,例如协作、共享开源等。不过本篇是 Git 的使用教程,所以这部分不多赘述。
一句话总结:我们用 Git 进行本地的代码版本管理,然后用 Git 连接 GitHub 进行远程的云端备份。
(3)Git 的基础知识:三个区域
那么 Git 是如何运作的?可以先记住三个区域。
假设我们有一个项目,项目所在的目录名为 todo-app,该目录下有两个文件,分别为 index.html 和 readme.md。
工作区是你当前正在编辑的文件所在的目录。你打开 todo-app,看到 index.html、readme.md,这些文件就处在工作区。
暂存区是介于工作区和提交历史之间的一个中间区域,用来存放你准备纳入下一次提交的改动。你用 git add 把工作区里的改动放入暂存区,但这时还没有真正生成提交。
提交历史是已经存档的版本库。你用 git commit 把暂存区里的内容正式存成一个 commit,从此这次改动就进入了提交历史。
一次正常的提交流动是这样的:
工作区 --git add--> 暂存区 --git commit--> 提交历史
为什么要有暂存区,不能直接 commit 吗?暂存区的意义在于,它可以让你一点一点挑出下一次要提交的内容。比如你重构了 todo-app 的代码,多出了 JS 和 CSS 文件,你可以先挑 index.html,再挑对应的 JS 和 CSS,确认无误后再统一提交。如果没有暂存区,你只能把当前所有改动一次性打包提交,很难精确控制一次 commit 到底包含什么。
再往前看一步:提交历史里的每一个 commit 并不是孤立的。分支本质上是一个指向某个 commit 的可移动指针,HEAD 通常指向当前分支,再由当前分支间接指向最新提交。后面讲分支、合并、Rebase 时,都会围绕这张“提交图”展开。另外,Git 除了工作区、暂存区、提交历史之外,还有一个用来临时存放未提交改动的地方,叫 Stash;它更像一个栈,后面会单独讲。
现在你只需要形成初步印象:工作区是正在修改的文件;暂存区存放准备提交的改动;提交历史是已经存档的 commit。git add 把改动放入暂存区,git commit 把暂存区内容写入提交历史。下面从第一次存档开始。
小结: Git 负责本地版本管理,GitHub 负责远程备份;工作区、暂存区、提交历史构成一次提交的基本路径,暂存区让你精确控制一次提交的内容;分支是指向 commit 的可移动指针,Stash 是临时保存未提交改动的栈。先建立这个模型,后面的命令都是围绕它展开的。
阅读前说明:几个容易误解的点
有几个表述如果直接照搬,容易在面试或团队协作中产生误解,先在这里说清楚。
- 分支不是“标签”,而是可移动指针。更准确地说:分支是指向某个 commit 的可移动指针;
HEAD通常指向当前分支,再由当前分支间接指向最新提交。把分支叫“贴在 commit 上的标签”是教学化表达,理解方向没问题,但严格表述应校正。 git restore默认不是“直接从上次提交恢复”。git restore <文件>默认是从暂存区恢复工作区。只是在“改动还没git add”的场景里,暂存区内容和HEAD一致,所以效果看起来像“恢复到上一次提交”。这个区别很重要。- Stash 的“第四空间”是教学类比。Git 的核心模型常讲工作区、暂存区、提交历史;Stash 是
refs/stash下保存的栈,用来临时存放未提交改动。把它叫“第四个区域”方便理解,但不要理解成和前三者完全并列的物理区域。 .gitignore只对未跟踪文件生效。已经被git add或commit跟踪的文件,写进.gitignore不会自动失效,需要git rm --cached <文件>取消跟踪后再提交。git stash默认不包含未跟踪文件。如果需要连未跟踪文件一起收走,要用git stash -u。git branch -d只能删除已合并分支。未合并分支需要-D强制删除,但要谨慎。git push -f不要在公共分支随意使用。强推可能覆盖别人的提交,公共分支回滚优先用git revert。- 快进合并的条件:当前分支没有分叉、且当前分支是目标分支的祖先时,Git 直接把指针前移,不产生新 commit。说“主分支没有新提交”是场景化表达,严格说是“可快进”。
第 1 章 第一次存档:工作区、暂存区、提交历史
你有一个简单的待办项目 todo-app,包含 index.html 和 readme.md,现在还没被 Git 管理。你想给它存档,以免改坏后无法恢复。
终端进入项目目录:
cd todo-app
git init
git init 会创建一个隐藏的 .git 文件夹,里面存放所有版本记录。此时还没有任何存档。
执行:
git status
你会看到 Untracked files(未跟踪的文件),说明 Git 发现了它们但还没开始管理。
把文件加入暂存区:
git add index.html
# 或
git add .
#用 . 来代表当前工作目录下所有文件
git add 只是把改动放入暂存区,并不生成提交。暂存区存在的意义是让你精确控制一次提交的内容:重构代码后多出了 JS 和 CSS 文件,你可以先挑 index.html,再挑对应的 JS 和 CSS,确认无误后再统一提交。
第一次提交前需要设置身份:
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
这不是登录账号,只是告诉 Git 提交记录里记谁的名字。这两行命令只需执行一次,以后在这台电脑上操作任何项目都不用再设置。如果没设置,Git 可能无法让你提交。
提交:
git commit -m "添加待办页面"
-m 后面是提交说明。一个项目可能有几十上百个 commit,写好说明方便以后查阅。必须加 -m 或进入编辑器。
查看历史:
git log --oneline
--oneline 让每个 commit 只占一行。按 Q 退出。
工作区在英文里有时叫 working tree,有时叫 working directory,都是工作区的意思。git status 里的 working tree clean 表示工作区没有未提交改动。
小结: git init 建仓库,git status 看状态,git add 把改动放入暂存区,git commit 生成提交,git log 查看历史;提交前要设置 user.name 和 user.email。记住 add 不等于 commit,暂存区是提交前的中间层。
第 2 章 回滚:改动在哪,就从哪回滚
你改了一下 todo-app 里的 index.html,把页面改成深色主题,但发现改坏了,想要回滚。回滚方法取决于你的改动现在处于哪个区域。
2.1 场景一:改动只在工作区
修改了文件但未 git add,git status 显示 Changes not staged for commit。
git restore .
# 或
git restore index.html
git restore 默认从暂存区恢复工作区。因为本场景还没 git add,暂存区与 HEAD 一致,所以效果就是让工作区文件恢复到上一次提交的状态。
工作区在英文里两种说法,有时叫 working tree,有时叫 working directory,都是工作区的意思。
注意:这会覆盖工作区未保存的改动,慎用。
2.2 场景二:改动已进暂存区
已经执行了 git add,git status 显示 Changes to be committed。
git restore --staged .
git restore .
第一步 git restore --staged . 把改动从暂存区撤回工作区。它仅修改 Git 暂存区记录,文件内容不变。此时 git status 变回 Changes not staged for commit。第二步 git restore . 再把改动从工作区撤销,彻底回滚。
2.3 场景三:改动已提交为 commit
已经 git commit,git log 能看到新提交。
方案 A:删除 commit(危险)
git reset --hard HEAD~1
HEAD 代表当前提交,HEAD~1 代表前一个提交。--hard 会把工作区、暂存区、提交历史全部重置。
--hard 干得很彻底,用的时候一定要小心。如果你的工作区还有没提交的改动,执行后它们也会一起消失。执行前最好先用 git status 看一眼。
其他模式:
git reset --mixed HEAD~1 # 默认模式,可简写 git reset HEAD~1
git reset --soft HEAD~1
git reset --mixed HEAD~1 是默认模式,回滚暂存区和提交历史,保留工作区。适合 commit 后发现小问题想改改再重新提交。git reset --soft HEAD~1 仅回滚提交历史,保留工作区和暂存区。适合你想把几个 commit 合并成一个时使用。
方案 B:追加回滚 commit
git revert HEAD
这会创建一个新的 commit 来抵消原来的改动,历史记录里仍然保留原来的 commit,以后后悔了还能找回来。非常适合公共分支。执行后会弹出 Vim 编辑器,里面是自动生成的回滚说明(以 # 开头的行是注释,会被忽略)。按冒号 :wq 保存退出即可。
工作区坏了用 restore;暂存区进错了先 restore --staged 再 restore;提交历史要删用 reset,公共分支要安全回滚用 revert。--hard 是危险命令,执行前先 git status。
小结: 工作区改动用 git restore;暂存区改动先 git restore --staged 再 git restore;已提交的改动用 git reset 删除提交(--hard 危险),公共分支用 git revert 追加反向提交。回滚前先确认改动在哪个区域。
第 3 章 忽略文件:.gitignore
你在 todo-app 里建了一个 notes.txt 记录个人学习笔记,你不想让 Git 跟踪它们。
创建 .gitignore 文件(在访达里新建,或者用 vim .gitignore),写入要忽略的文件名:
notes.txt
创建后 git status 里 notes.txt 就消失了。
注意:.gitignore 只对未跟踪文件生效。如果文件已经被 git add 或 commit 过,写进 .gitignore 是没用的,需要先用 git rm --cached <文件> 取消跟踪,再提交。
.gitignore 文件本身是需要提交到 Git 的,因为它是项目规则的一部分,换了电脑也需要这些规则。
小结: .gitignore 只对未跟踪文件生效;已跟踪文件要先 git rm --cached 取消跟踪;.gitignore 本身要提交,因为它是项目规则的一部分。
第 4 章 分支:平行开发与合并
4.1 为什么需要分支?
要给 todo-app 增加“截止时间”功能,需要拆成 3 个 commit(界面、保存逻辑、过期提醒)。如果直接在主分支上开发,中间状态主分支会有半成品,用户点到可能会报错。所以需要拉一个新分支专门开发,保证 master 分支随时处于稳定可用状态。
分支本质上是一个指向 commit 的可移动指针,HEAD 指向当前分支,通常间接指向该分支最新提交。不同分支可以各自向前提交,最后再合并。
把分支叫“标签”是教学化说法;严格说分支会随着新提交向前移动,而标签(tag)通常固定指向某个 commit。
4.2 创建并切换分支
git switch -c feature/due-date
-c 是 create 的缩写,相当于 git branch + git switch。老教程里可能会用 git checkout -b,效果一样,但 switch 是新拆出来的命令,更清晰。
分支名里可以带斜杠 /,比如 feature/due-date,这只是命名习惯,Git 并没有严格限制。
4.3 在新分支开发并提交
经历 3 次 git add + git commit。
4.4 切回主分支并合并
git switch master
git merge feature/due-date
为什么合并前要切回 master?因为合并是把别的分支合并到当前所在的分支,所以必须先站在目标分支上。
合并后发生了什么?如果是快进合并(Fast-forward),master 指针直接往前挪,不产生新 commit。如果是三方合并,Git 会自动生成一个新 commit。
合并后分支要删吗?如果分支已经没用了,可以用 git branch -d feature/due-date 删掉。git branch -d 只能删除已合并分支;未合并分支需要 -D 强制删除,慎用。
4.5 快进合并与三方合并
快进合并(Fast-forward):当当前分支没有分叉、且当前分支是目标分支的祖先时,Git 直接把指针前移,不产生新 commit。前面“主分支没有新提交”就是典型可快进情况。
三方合并(Merge Commit):两个分支都有新提交、发生分叉时,Git 新建一个 commit 把两边代码合并起来。
一个功能一个分支;合并前先切回目标分支;能快进就不产生新 commit,有分叉就产生合并 commit;删分支用 -d,未合并分支慎用 -D。
小结: 分支是指向 commit 的可移动指针;git switch -c 创建并切换分支;合并前先切回目标分支;能快进则快进,有分叉则三方合并;删分支用 -d,未合并分支慎用 -D。
第 5 章 合并冲突:Git 停下来让你做决定
你从 master 拉了两个新分支:feature/sort(排序)和 feature/complete-all(全部完成)。两个分支都在 todo-app 的“添加按钮”那一行下面插入了一个新按钮,于是合并时产生了冲突。Git 不知道到底该保留哪一个,也无法决定谁在前谁在后,于是停下来让你决定。
- 执行
git merge feature/complete-all,终端报错CONFLICT,提示Automatic merge failed。 git status查看,提示Unmerged paths(未合并的路径),index.html显示both modified。- 打开
index.html,找到冲突标记:
<<<<<<< HEAD
当前分支的代码
=======
要合并进来的分支的代码
>>>>>>> feature/complete-all
- 删除标记符号,保留你最终需要的代码(这里是两个按钮都保留)。
- 执行:
git add .
git commit
<<<<<<< HEAD 到 ======= 之间是当前分支(master)的代码;======= 到 >>>>>>> feature/complete-all 之间是要合并进来的分支的代码。
冲突发生得越晚,解起来越痛苦。一个功能做一两周,最后合并时冲突可能有一大堆。建议在开发过程中,时不时把分支变基到 master 上,让冲突早点暴露、早点解决。
如果不想解决了,可以用 git merge --abort 放弃本次合并,回到合并前的状态。
冲突不可怕:先看 git status,再找 <<<<<<<、=======、>>>>>>>,改成你要的代码,add 后 commit;不想合并就 merge --abort。
小结: 冲突时 Git 停下来让你决定;先看 git status 找到 Unmerged paths,编辑冲突标记,git add 后 git commit;不想合并用 git merge --abort。冲突越早解决越轻松。
第 6 章 Rebase:给分支重新换一个地基
你的 feature/complete-all 分支是从旧 master 拉出来的,期间 master 已经合入了别人的 feature/sort。如果你直接在 feature/complete-all 上开发完再合并,会有三方合并的冲突。更好的做法是先把分支变基到最新 master 上。
Rebase 是给分支重新换一个“地基”,把当前分支的提交挨个挪到目标分支的最新提交后面。它的本质是把当前分支的每个 commit 挨个挪到目标分支后面重新应用一遍。关键点是:会重写提交历史;冲突时执行 git rebase --continue 而非 git commit。
- 在
feature/complete-all分支上执行:
git rebase master
- 遇到冲突,解决冲突(编辑文件,保留需要的代码)。
- 执行:
git add .
- 关键一步:执行
git rebase --continue
而不是 git commit。在这里用了 commit 会导致 rebase 流程混乱。
- 如果弹出编辑器让你修改 commit 说明,直接保存退出即可。
成功后会显示 successfully rebased。变基后,当前分支就接在了 master 最新的 commit 后面,此时再合并通常就是 Fast-forward,非常干净。
Rebase 是“挪提交、换地基、重写历史”;冲突解决后 add,然后 rebase --continue,不要 commit。
小结: Rebase 把当前分支的提交挪到目标分支最新提交后面,会重写历史;冲突解决后 git add 再 git rebase --continue,不要 git commit;变基后再合并通常就是快进,历史更干净。
第 7 章 Stash:临时保存未提交改动
你正在给 todo-app 写“清空已完成”功能,写了一半。突然用户反馈一个 bug 需要紧急修复。你执行 git switch master 时,Git 报错:
Your local changes would be overwritten by switch
为什么会报错?因为分支切换时,Git 需要改写工作区里的文件。如果你工作区里有未提交的改动,这些改动就会被目标分支的文件覆盖掉,导致你的半成品代码丢失。Git 不敢替你做决定,所以干脆停下来报错。
能不能把改动挪到别的地方放一放?可以。Git 除了工作区、暂存区、提交历史之外,还有一块专门用来临时保存未提交改动的地方,名字叫 Stash(储藏区)。之前它一直是空的,所以没提它。
执行 git stash 后,Git 会把工作区(以及暂存区)里所有还没提交的改动保存到 Stash 里。保存走之后,index.html 就回到了上一次提交时的样子。这个时候再去切分支,就不会覆盖掉任何东西了。
- 执行:
git stash
终端会提示 Saved working directory and index state WIP on ...。
WIP 是 Working Progress 的缩写,意思是“正在做的活”。在 Git 里,就是指那些还没有提交的改动。index 就是暂存区(Staging Area 的另一种叫法)。这说明 Stash 不仅会保存工作区的改动,也会保存暂存区的改动。
-
此时
git status显示working tree clean,工作区干净了。顺利切换到 master,拉取hotfix分支修 bug、合并、删除临时分支。 -
切回原来的分支,执行:
git stash pop
把半成品取回来。pop 是“弹出来”的意思。取回后,工作区又变回修改状态,你可以接着写。当前状态就跟收起来之前一模一样。
stash 适合临时打断一下的情况,先去干点别的,很快就回来。如果你要同时开发多个分支,频繁 stash 和 pop 会非常麻烦。这时候更好的方案是使用 Worktree(见下一章)。
需要补充几点:Stash 不是分支,它是一个栈(Stack),可以存多份,后进先出。取回命令 git stash pop 是弹出最新的一份。Stash 的“第四空间”是教学类比;Git 的核心模型常讲工作区、暂存区、提交历史,Stash 是 refs/stash 下保存的栈。git stash 默认不收未跟踪文件;需要时用 git stash -u。git stash list 可查看栈中保存了哪些记录。
小结: 切分支时工作区不干净会报错;git stash 临时保存未提交改动,修改完后git stash pop 取回;Stash 是栈,默认不含未跟踪文件;频繁切换分支时考虑 Worktree。
第 8 章 Worktree:一个仓库,多个工作目录
你正在给 todo-app 开发“导出”功能,写了一半。产品临时插入一个“统计”功能,并且下周就要上线。你不想频繁 stash 切换分支,想一边保留导出功能的半成品,一边去另一个目录开发统计功能。
- 执行:
git worktree add ../todo-app-stats -b feature/stat master
这行命令的意思是,在上一级目录创建一个 todo-app-stats 文件夹,基于 master 分支创建一个叫 feature/stat 的新分支,并把这个新目录关联到这个新分支。
-
进入新目录,正常开发、
git add、git commit、git merge。 -
功能上线后,删除 worktree:
git worktree remove ../todo-app-stats
不要直接把这个新目录拖进废纸篓!否则 Git 记录会残留。必须用 git worktree remove 命令删除。
核心原理一句话:每一个 Worktree 都有自己独立的工作区和暂存区,但所有的 Worktree 共用同一份提交历史。在任何一个 Worktree 里提交,另一个 Worktree 里都能看到。这跟直接复制粘贴一份文件夹是完全不一样的。
git worktree list 可以查看当前有哪些工作树。加号 + 表示该分支正在另一个 Worktree 中打开。
小结: Worktree 让一个仓库有多个工作目录,各自有独立的工作区和暂存区,但共用提交历史;用 git worktree add 创建,git worktree remove 删除,不能直接删文件夹。
第 9 章 GitHub:把本地历史备份到远程
本地代码和 Git 记录有丢失风险(电脑坏了、误删文件夹),需要备份到云端 GitHub。
9.1 配置 SSH Key 与原理
- 生成密钥:
ssh-keygen -t ed25519 -C "你的邮箱"
一路回车(不设密码)。
- 查看公钥:
cat ~/.ssh/id_ed25519.pub
复制输出的内容。
-
GitHub 页面:右上角头像 → Settings → SSH and GPG keys → New SSH key → 粘贴公钥 → Add SSH key。
-
测试连接:
ssh -T git@github.com
第一次会提示确认指纹,输入 yes。
私钥留在本地绝对不要给别人,公钥可以公开。GitHub 用公钥验证你的私钥签名,确认是你本人。就像你在文件上签了字,别人模仿不来。
9.2 创建远程仓库与推送
- GitHub 点击 New repository,命名(英文,例如
todo-app),不勾选初始化文件。 - 本地执行:
git remote add origin git@github.com:你的用户名/todo-app.git
这是给远程仓库起个别名叫 origin,以后不用写一长串地址。
- 推送:
git push -u origin master
-u 把本地 master 和远程 master 绑定,以后直接 git push 即可。如果本地主分支叫 master,远程默认可能是 main,推送时注意改一下命令里的分支名。
9.3 日常开发流程与经验
改代码 → git add . → git commit -m "说明" → git push。
git status 会提示 Your branch is ahead of 'origin/master' by 1 commit,说明本地领先远程,需要 push。
9.4 从 GitHub 恢复:git clone
删除本地文件夹模拟丢失,然后执行:
git clone git@github.com:你的用户名/todo-app.git todo-app
克隆会拉取完整的提交历史,git log 能看到所有记录。不仅是文件,连历史都在。
小结: SSH 公钥给 GitHub,私钥留本地;git remote add origin 关联远程仓库;git push -u 绑定分支;日常 add → commit → push;丢失后 git clone 可恢复完整历史。
第 10 章 命令速查表
| 命令 | 作用 | 常用参数 | 示例 | 注意事项 |
|---|---|---|---|---|
git --version |
查看 Git 版本 | – | git --version |
出现版本号即可用 |
git init |
初始化 Git 仓库 | – | git init |
会在当前目录创建 .git 文件夹 |
git status |
查看当前仓库状态 | – | git status |
常看 working tree clean 代表无改动 |
git add |
把工作区改动放入暂存区 | .(当前目录) |
git add . |
被 .gitignore 忽略的未跟踪文件不会被加进去 |
git commit |
把暂存区内容提交为 commit | -m "说明" |
git commit -m "添加待办页面" |
必须加 -m 或进入编辑器 |
git log |
查看提交历史 | --oneline |
git log --oneline |
按 Q 退出 |
git restore |
撤销工作区改动 | <文件> / . |
git restore index.html |
默认从暂存区恢复工作区;会覆盖工作区未保存的改动,慎用 |
git restore --staged |
把改动从暂存区撤回工作区 | <文件> / . |
git restore --staged . |
仅修改 Git 暂存区记录,文件内容不变 |
git reset --hard |
回滚工作区、暂存区、提交历史 | HEAD~1 |
git reset --hard HEAD~1 |
危险!会彻底清除未提交改动和提交记录 |
git reset --mixed |
回滚暂存区和提交历史,保留工作区 | HEAD~1 |
git reset HEAD~1 |
默认模式(不加选项) |
git reset --soft |
仅回滚提交历史,保留工作区和暂存区 | HEAD~1 |
git reset --soft HEAD~1 |
适合修改上次提交内容 |
git revert |
创建一个抵消目标 commit 的新 commit | HEAD |
git revert HEAD |
安全,不删除历史 |
git branch |
查看/创建分支 | -d(删除) |
git branch feature/due-date / git branch -d feature |
创建后不会自动切换;-d 只能删已合并分支 |
git switch |
切换分支 | -c(创建并切换) |
git switch -c feature/due-date |
老写法是 git checkout -b |
git merge |
合并分支 | – | git merge feature/due-date |
先切回目标分支(如 master)再合并 |
git rebase |
变基 | master |
git rebase master |
冲突解决后用 git rebase --continue |
git stash |
把未提交改动存起来 | – | git stash |
工作区会变干净;默认不含未跟踪文件 |
git stash pop |
把存的改动取回工作区 | – | git stash pop |
与 git stash 对应 |
git worktree |
管理工作树 | add, list, remove |
git worktree add ../todo-app-stats -b feature/stat master |
删除时要用 git worktree remove |
ssh-keygen |
生成 SSH 密钥对 | -t ed25519 -C "邮箱" |
ssh-keygen -t ed25519 -C "your@email.com" |
公钥给 GitHub,私钥留本地 |
git remote add |
关联远程仓库 | origin <地址> |
git remote add origin git@github.com:xxx/todo-app.git |
origin 是默认名 |
git push |
推送本地提交到远程 | -u origin master |
git push -u origin master |
-u 绑定分支后,以后直接 git push |
git clone |
克隆远程仓库到本地 | – | git clone git@github.com:xxx/todo-app.git todo-app |
后面可接自定义文件夹名 |
补充:git branch -D <分支> 可强制删除未合并分支,但会丢失该分支未合并提交,慎用;公共分支不要随意 git push -f。
小结: 速查表用于快速查阅命令和危险点;重点掌握 add、commit、status、log、restore、reset、revert、branch、switch、merge、rebase、stash、worktree、push、clone 的用途和注意事项。
第 11 章 易错点与坑
.gitignore对已跟踪文件无效:必须先用git rm --cached <文件>取消跟踪,再提交。git reset --hard危险:会同时清空工作区、暂存区和提交历史,未提交的代码会彻底丢失。执行前最好git status确认。- 合并顺序:合并是把别的分支合并到当前分支,所以必须先切换到目标分支(如
master)再执行git merge。 - Rebase 冲突解决后:执行
git add .后,应继续git rebase --continue,而不是git commit。 - 删除 Worktree:不能直接拖进废纸篓,需用
git worktree remove,否则 Git 记录残留。 - SSH 私钥保密:私钥留在本地绝对不要公开或发给别人,只把公钥(
.pub结尾)给 GitHub。 - 不要随意
git push -f:在公共分支上强推会覆盖别人的代码,推荐用git revert来撤销远程提交。 git restore默认源是暂存区:不要误以为它永远从HEAD恢复;在场景一未暂存时效果等同恢复到上次提交。git stash默认不含未跟踪文件:需要连未跟踪文件一起收走时用git stash -u。git branch -d只删已合并分支:未合并分支要-D,但会丢失未合并提交,慎用。
小结: 易错点集中在 .gitignore 对已跟踪文件无效、reset --hard 危险、合并顺序、Rebase 冲突后要 --continue、Worktree 删除方式、私钥保密、不要随意 push -f。
第 12 章 术语中英对照
| Git 术语 | 英文 | 解释 |
|---|---|---|
| 工作区 | Working Directory / Working Tree | 当前编辑文件的目录 |
| 暂存区 | Staging Area / Index | 准备提交的改动存放区 |
| 提交历史 | Commit History | 所有已提交的版本记录 |
| 提交 | Commit | 一次版本存档 |
| 分支 | Branch | 指向 commit 的可移动指针,指向一条提交线 |
| 快进合并 | Fast-forward | 直接移动分支指针的合并,不产生新 commit |
| 三方合并 | Merge Commit | 两个分支合并时生成的新 commit |
| 变基 | Rebase | 重新定义分支的“地基”,重写历史 |
| 贮藏/储藏区 | Stash | 临时保存未提交改动的地方,是独立于工作区、暂存区、提交历史的“第四空间”教学类比 |
| 工作树 | Worktree | 同一仓库的多个工作目录,共用提交历史 |
| 远程仓库 | Remote Repository | 托管在 GitHub 等平台上的仓库 |
| 克隆 | Clone | 把远程仓库完整复制到本地 |
| 推送 | Push | 把本地提交上传到远程仓库 |
小结: 术语中英对照帮助阅读英文文档和报错信息;工作区、暂存区、提交历史、分支、快进合并、三方合并、变基、Stash、Worktree 是核心词汇。
第 13 章 经验总结
13.1 主分支与分支管理
master(或 main)是主分支,希望它随时处于稳定、可用的状态。不要把只做了一半、还不能正常工作的功能直接提交到主分支上。
一个功能一个分支。开发新功能时,先基于当前稳定的 master 拉出一个新分支,等功能全部开发完、测试通过后,再合并回 master。
分支命名建议:可以用 feature/ 开头表示新功能,用 hotfix/ 开头表示紧急修复。这只是团队习惯,不是硬性规定,但能让分支一目了然。分支名里可以带斜杠 /,比如 feature/due-date,这只是命名习惯,Git 并没有严格限制。
13.2 冲突与合并
冲突发生得越晚,解起来越痛苦。一个功能做一两周,最后合并时冲突可能有一大堆。在开发过程中,要时不时把自己的分支变基(Rebase)到最新的 master 上,让冲突早点暴露、早点解决,不要等到最后一刻。
合并前一定要先切回目标分支(比如 master),因为合并是把别的分支合并到当前所在的分支。如果不想解决冲突了,可以用 git merge --abort 放弃本次合并,回到合并前的状态。
13.3 回滚与安全
git reset --hard 非常彻底,用的时候一定要小心。它会同时清空工作区、暂存区和提交历史,如果你工作区还有没提交的改动,执行后它们也会一起消失。执行前最好先用 git status 看一眼。
公共分支的回滚优先用 git revert。因为它会创建一个新的 commit 来抵消原来的改动,历史记录仍然保留,以后后悔了还能找回来。
提交信息(-m)要写清楚。一个项目可能有几十上百个 commit,写好说明方便以后查阅。如果不想让 Git 跟踪某些文件,在 .gitignore 里加上它。但注意,.gitignore 只对未跟踪文件生效,已跟踪的文件需要先用 git rm --cached 取消跟踪。
13.4 Stash 与 Worktree 的选择
Stash 适合“临时打断”:先去干点别的,很快就回来。比如修个紧急 bug,切个分支。如果要同时开发多个分支,频繁 stash 和 pop 会非常麻烦。这时候更好的方案是使用 Worktree。
Worktree 的核心优势:一个仓库对应多个工作目录,每个 Worktree 有独立的工作区和暂存区,但所有的 Worktree 共用同一份提交历史。在任何一个 Worktree 里提交,另一个 Worktree 里都能看到。删除 Worktree 不能直接删文件夹,必须用 git worktree remove,否则 Git 记录会残留。
13.5 SSH 与 GitHub
私钥留在本地绝对不要给别人,公钥可以公开。GitHub 用公钥验证你的私钥签名,确认是你本人。
git push -u origin master 里的 -u 是把本地分支和远程分支绑定,以后直接 git push 即可,不用每次都写一长串。
日常开发流程要养成习惯:改代码 → git add . → git commit -m "说明" → git push。这样才能保证 GitHub 上一直有最新的备份。如果本地主分支叫 master,远程默认可能是 main,推送时注意改一下命令里的分支名。
小结: 主分支保持稳定,一个功能一个分支;冲突早暴露早解决;危险命令先 git status;公共分支回滚用 git revert;Stash 适合临时打断,Worktree 适合并行开发;私钥不离本地,日常 add → commit → push 形成习惯。
结语
一旦你理解了工作区、暂存区、提交历史、分支指针、Stash、Worktree 和远程仓库之间的关系,很多命令就不再需要死记硬背:add 是把改动放入暂存区,commit 是把暂存区内容写成提交,restore 是撤销,reset 是移动历史指针,revert 是追加一个反向提交,branch/switch/merge/rebase 是在提交图上移动和拼接分支,stash/worktree 是处理并行工作的两种工具,push/clone 则是把本地历史和远程备份连接起来。
最后记住几条原则:主分支保持稳定,一个功能一个分支,冲突早点暴露早点解决,危险命令先用 git status 看清现场,公共分支回滚优先 git revert,私钥永远留在本地。