什么是 Git?
Git 是一个分布式版本控制系统(Distributed Version Control System,DVCS)。它通过提交保存项目在某个时间点的完整快照,用分支让不同改动并行开发,再用合并把经过验证的成果汇回主线。

Git 主要解决三个问题:旧版本难以找回、多人修改容易互相覆盖,以及改动缺少清晰的责任和上下文。它不是网盘,也不等于 GitHub;Git 是运行在本地的版本控制工具,GitHub 和 GitLab 是可以托管远程仓库并提供协作界面的平台。
一句话总结:Git 是一台代码时光机,负责记录变化、支持并行开发,并让已经提交的代码可以被追溯和恢复。
Git 为什么诞生于 Linux 内核开发?
Git 的诞生背景是大规模、分布式的 Linux 内核协作。2005 年,Linus Torvalds 为 Linux 内核开发写出了 Git,目标是提供一个速度快、可靠,并且能容纳大量开发者分布式协作的版本控制工具。

在没有 Git 的时代,开发者经常通过邮件传递补丁。几百个人同时修改同一份代码时,补丁顺序、重复修改和冲突都需要人工判断。Git 的“分布式”意味着每位开发者本地都有一份完整仓库和历史记录,不必每次查看历史都依赖中心服务器。
分布式不代表团队不需要远程服务器。远程仓库仍然常用于备份、代码评审、权限管理和持续集成;它只是协作入口,而不是 Git 能工作的前提。
Git 和普通保存有什么区别?
普通保存通常会覆盖文件当前内容。Git 的提交则会记录一次可命名、可比较、可回退的项目快照,因此“保存一次”和“留下一个版本”是两件不同的事。

| 对比维度 | 普通保存文件 | Git 提交 |
|---|---|---|
| 历史记录 | 常常只有当前文件,旧版本需要手动备份 | 每次提交都保留项目状态和提交说明 |
| 回退方式 | 依赖备份文件、自动恢复或文件历史 | 按提交、分支或文件定位并恢复 |
| 多人协作 | 容易互相覆盖,冲突靠人工传文件解决 | 可以比较差异、合并分支并保留责任信息 |
| 变更范围 | 很难只保存其中一部分修改 | 可以先选择文件或代码块进入暂存区 |
| 离线能力 | 通常依赖共享盘或在线服务 | 本地仓库可离线查看历史和提交 |
Git 也不是自动保存工具。只有你主动执行 git add 和 git commit,改动才会进入可追溯的提交历史;没有提交的内容,Git 不保证能够找回。
Git 的三个区域分别是什么?
Git 的提交模型由工作区、暂存区和本地仓库三个区域组成。文件从工作区经过 add 进入暂存区,再经过 commit 进入仓库。

可以用“草稿、待拍内容和照片”来理解:
- 工作区(Working tree):你当前正在编辑的文件,随时可以继续修改。
- 暂存区(Staging area / Index):你已经挑选、准备放进下一次提交的改动清单。
- 本地仓库(Local repository):已经提交的快照、提交信息和历史关系,保存在项目的
.git目录中。

典型流程如下:
git add src/login.ts
git commit -m "修复登录超时校验"
git add 不会创建历史版本,它只是在暂存区选择下一张快照要包含什么;git commit 才会把暂存区的内容固定下来。提交之后还可以用 git show 查看这次快照,用 git diff 比较尚未提交的差异。
暂存区为什么允许分批提交?
暂存区的价值是把“我改过什么”和“这次应该记录什么”分开。你可以同时修改登录功能和首页文案,但只把登录相关文件加入暂存区并提交,文案留到下一个提交。

分批提交带来三个实际好处:
- 更容易审查:同事可以快速判断一次提交是否只做了一件事。
- 更容易回退:如果登录修复需要撤销,不必连首页文案一起回退。
- 更容易定位问题:使用
git log、git blame或二分查找时,提交边界越清楚,排查范围越小。
推荐让提交说明回答“改了什么”和“为什么改”,例如 fix: reject expired login token,而不是只写 update 或 test。
Git 分支是什么?为什么创建成本很低?
Git 分支本质上是一个指向某次提交的可移动指针,不是把整个项目复制一份。创建分支通常只需要记录一个新的引用,因此可以快速创建和删除。

例如,稳定代码在 main,修复登录漏洞时可以创建独立分支:
git switch main
git pull --ff-only origin main
git switch -c fix-login
# 修改代码并验证
git add src/auth/login.ts
git commit -m "fix: validate login token expiry"
git switch -c fix-login 会创建并切换到新分支。分支上的提交只会移动 fix-login 指针,不会改变 main;测试通过后,再通过合并请求或本地 merge 把成果汇回主线。
一个真实项目里的 Git 分支流程是怎样的?
一次常见的漏洞修复流程可以拆成六步:

- 从最新的
main创建fix-login分支。 - 在
fix-login上修改代码,补充测试并提交。 - 用
git push -u origin fix-login把分支和提交上传到远程仓库。 - 在 GitHub 或 GitLab 创建合并请求(Pull Request / Merge Request)。
- 同事检查差异,CI 运行测试、类型检查和安全扫描。
- 检查通过后合并到
main,删除已完成的特性分支。
这套流程把“开发”和“发布主线”隔离开:开发者可以在分支中快速试错,主分支则通过评审和自动检查保持可用。分支不会自动解决冲突,也不会替代测试;它只是降低并行开发时的协调成本。
clone、push 和 pull 分别做什么?
远程协作的三个常用动作可以这样记:clone 复制项目,push 上传本地提交,pull 拉取远程更新并整合到当前分支。

| 命令 | 方向 | 作用 | 常见场景 |
|---|---|---|---|
git clone <url> | 远程 → 本地 | 复制仓库、分支和历史 | 第一次加入项目 |
git push origin feature | 本地 → 远程 | 上传本地提交和分支 | 分享改动、创建合并请求 |
git pull --ff-only | 远程 → 本地 | 获取更新并整合到当前分支 | 开始工作前同步主线 |
git pull 默认会执行获取和整合,可能产生合并提交。对只希望快进更新的主分支,可以使用 git pull --ff-only,让不符合预期的历史分叉直接报错,避免无意生成合并提交。
GitHub、GitLab、Gitea 等平台提供仓库托管、权限、代码评审、Issue 和 CI/CD,但它们不是 Git 本身。没有网络时,你仍然可以在本地初始化、查看历史、创建分支和提交。
新手先掌握哪五个 Git 命令?
日常开发先掌握五个命令就能覆盖大多数基础场景:

| 命令 | 作用 | 关键问题 |
|---|---|---|
git init | 在当前目录初始化本地仓库 | 让 Git 开始管理这个项目 |
git add | 把改动放入暂存区 | 下一次提交要包含什么 |
git commit | 创建一个本地快照 | 这次改动为什么值得记录 |
git push | 上传本地提交到远程 | 如何让同事或 CI 看见改动 |
git pull | 获取并整合远程更新 | 如何把别人的新提交带到本地 |
第一次创建项目可以这样开始:
mkdir demo-app
cd demo-app
git init
git add .
git commit -m "chore: initial commit"
git branch -M main
git remote add origin https://github.com/example/demo-app.git
git push -u origin main
在真实项目中,git status、git log --oneline --graph 和 git diff 同样值得尽早使用:它们分别告诉你当前状态、历史结构和未提交差异。命令数量不是主要门槛,真正需要理解的是“快照”和“指针”。
merge 和 rebase 有什么区别?
merge 和 rebase 都可以把一个分支的改动整合到另一个分支,但它们对提交历史的处理不同。

| 维度 | merge | rebase |
|---|---|---|
| 历史形状 | 保留分叉,并可能生成合并提交 | 把提交重新应用到目标分支顶端,历史更线性 |
| 提交哈希 | 已有提交通常保持不变 | 被重新应用的提交会产生新的哈希 |
| 协作风险 | 适合已经共享的分支,历史更忠实 | 不应随意改写别人已经基于其开发的公共分支 |
| 常见用途 | 合并合并请求、保留协作上下文 | 整理个人分支、同步最新主线 |
初学者先用 merge 更稳妥。若要在自己的未发布分支上整理历史,可以这样做:
git fetch origin
git rebase origin/main
发生冲突时需要手动解决、执行 git add,再运行 git rebase --continue。因为 rebase 会改写提交哈希,已经推送过的分支通常要使用 git push --force-with-lease,并确认不会覆盖同事的新提交。
Git 能找回误删或改坏的代码吗?
只要内容曾经提交过,Git 通常就能通过历史、引用或对象记录帮助找回;没有提交过的工作区内容,Git 没有可靠的历史可供恢复。

常见恢复动作如下:
# 丢弃工作区对某个文件的未提交修改
git restore src/login.ts
# 从最近一次提交恢复一个被删除的文件
git restore --source=HEAD -- src/login.ts
# 查看分支和 HEAD 曾经指向过哪些位置
git reflog
# 撤销一次提交,但保留改动在工作区,便于重新整理
git reset --mixed HEAD~1
git reset 会移动当前分支指针,使用前要确认目标提交和是否有未备份改动;在已经共享的公共分支上,通常优先用 git revert 创建一个反向提交,而不是改写公共历史。
恢复能力有边界:提交越多、引用保留越完整,定位越容易;如果文件从未提交、对象已被清理,或者密钥曾经提交后又删除,不能把 Git 当成绝对备份或安全擦除工具。密钥泄露时必须立即轮换凭证,并清理历史中的敏感内容。
Git 的常见误区和限制是什么?
Git 记录的是文件内容和历史关系,不会自动判断代码是否正确,也不会替你解决所有协作问题。
| 误区或限制 | 真实情况 | 改进方式 |
|---|---|---|
| Git 会自动保存 | 只有提交后的内容才进入可靠历史 | 在可回退的阶段主动提交 |
| 分支越多越专业 | 长期不合并的分支会增加冲突和上下文成本 | 保持分支短生命周期,小步合并 |
push 等于备份 | 远程权限、分支保护或误删仍可能造成损失 | 使用远程备份、保护规则和恢复演练 |
| 提交过密或过大都没关系 | 太碎难以理解,太大难以审查和回退 | 每次提交围绕一个完整意图 |
| Git 能管理大文件和构建产物 | 二进制大文件会拖慢仓库和克隆 | 使用 .gitignore,必要时采用 Git LFS 或制品仓库 |
| Git 能解决合并冲突 | Git 只能标出冲突区域,语义正确性仍需人和测试判断 | 及时同步主线,增加测试并做代码评审 |
还要把 .env、私钥、访问令牌和生成的 dist 等内容加入 .gitignore。.gitignore 只能阻止尚未追踪的文件被加入,已经提交过的密钥仍然存在于历史中,不能靠后来添加一行规则来删除风险。
常见问题
Git 适合个人项目吗?
适合。个人项目使用 Git 可以保留实验、重构和发布前的历史,即使没有远程仓库,也能在本地比较差异、创建分支和回退版本。
Git 和 GitHub 有什么区别?
Git 是本地运行的分布式版本控制系统;GitHub 是托管 Git 远程仓库的平台,还提供合并请求、权限管理、Issue 和 CI 等协作服务。Git 不依赖 GitHub 才能工作。
git add 后是不是已经保存了?
不是。git add 只把选中的改动放进暂存区,仍未形成历史快照。只有执行 git commit 后,这些内容才会进入本地仓库的提交历史。
git pull 和 git fetch 有什么区别?
git fetch 只获取远程对象和引用,不会改变当前分支文件;git pull 通常等价于先 fetch,再 merge 或 rebase。想先检查远程变化时,可以先执行 git fetch,再决定如何整合。
新手应该用 merge 还是 rebase?
新手在合并协作分支时优先用 merge,因为它保留原始分叉和合并上下文。熟悉提交哈希、冲突处理和强制推送风险后,再在未共享的个人分支上使用 rebase 整理线性历史。
没有提交的代码能找回吗?
不一定。Git 只能可靠恢复已经进入提交、暂存对象或仍被引用的内容;单纯留在工作区、从未被 Git 记录的修改,删除后通常无法依靠 Git 找回。编辑器本地历史、系统备份或文件恢复工具可能提供额外机会。
总结:Git 记录的不是代码,而是变化
Git 是一个分布式版本控制系统。它用提交快照记录变化,用工作区、暂存区和本地仓库构成可控的提交模型,用分支指针让多人低成本并行开发,再通过远程仓库和合并请求完成协作。

入门时先记住这条路径:工作区 → git add → 暂存区 → git commit → 本地仓库 → git push → 远程仓库。再掌握 init、add、commit、push、pull 五个命令,就能处理大多数日常开发场景。
Git 的核心价值不是“把代码放起来”,而是把每一次变化变成可以解释、协作、回退和复盘的历史。

