Git 是现代软件工程里最重要的基础工具之一。它不仅是"保存代码版本"的工具,更是团队协作、代码评审、发布回滚、问题追踪和知识沉淀的基础设施。 很多人学 Git 时会陷入两个误区:一是把命令背成孤立清单,遇到真实问题仍然不知道该用哪个;二是把 GitHub、GitLab、Gitee 这类平台等同于 Git 本身。前者会让操作变得机械,后者会让概念混乱。
一、先分清:Git、远程仓库和托管平台
Git 是一个分布式版本控制系统。它运行在你的本机,负责记录文件快照、提交历史、分支指针和标签。即使没有网络,Git 仍然可以提交、查看历史、创建分支、回滚本地改动。
远程仓库是另一份 Git 仓库副本,通常放在服务器上,用来和团队共享提交。origin 只是远程仓库的默认别名,不是固定概念,也可以叫 upstream、company 或其他名字。
GitHub、GitLab、Gitee、Gitcode等平台是 Git 仓库托管服务。它们在 Git 之上提供 Pull Request、Merge Request、代码评审、CI、权限管理、Issue、Release 等协作能力。
| 名称 | 本质 | 主要作用 |
|---|---|---|
| Git | 本地版本控制工具 | 记录历史、分支、合并、回滚 |
| 远程仓库 | 另一份 Git 仓库副本 | 多人同步提交 |
| GitHub 等平台 | Git 托管与协作平台 | 评审、CI、权限、发布管理 |
二、Git 的四个核心区域
学习 Git 最重要的不是先背命令,而是理解改动在不同区域之间如何流动。

Git 日常操作围绕四个区域展开:
| 区域 | 英文常见说法 | 你需要知道什么 |
|---|---|---|
| 工作区 | Working Tree | 你正在编辑的真实文件 |
| 暂存区 | Staging Area / Index | 下一次提交要包含的改动清单 |
| 本地仓库 | Local Repository | 已提交的历史、分支、标签都在这里 |
| 远程仓库 | Remote Repository | 团队共享的仓库副本 |
最基本的流动关系如下:
bash
工作区 --git add--> 暂存区 --git commit--> 本地仓库 --git push--> 远程仓库
从远程获取别人改动时,通常是:
bash
远程仓库 --git fetch / git pull--> 本地仓库和工作区
你只要记住一句话:每次不知道下一步怎么做,先执行 git status。它会告诉你改动在哪个区域、哪些文件已暂存、当前分支是否落后或领先远程分支。
三、第一次使用 Git:配置与初始化
3.1. 配置身份
Git 的每次提交都会记录作者信息。首次使用建议设置全局用户名和邮箱:
bash
git config --global user.name "你的名字"
git config --global user.email "you@example.com"
查看配置:
bash
git config --global --list
3.2. 设置默认分支名
现在很多项目默认主分支叫 main。你可以设置新仓库的默认分支名:
bash
git config --global init.defaultBranch main
已经创建过的仓库如果主分支不是 main,可以在仓库内改名:
bash
git branch -M main
3.3. 新建一个仓库
在已有项目目录中启用 Git:
bash
git init
git status
git add README.md
git commit -m "docs: 初始化项目说明"
如果要关联远程仓库:
bash
git remote add origin <仓库地址>
git push -u origin main
-u 的意思是建立当前本地分支和远程分支的跟踪关系。设置之后,后续在这个分支上可以直接使用 git push 或 git pull。
3.4. 克隆已有仓库
参与已有项目时,一般从克隆开始:
bash
git clone <仓库地址>
cd <项目目录>
git status
克隆完成后,你本地会得到完整历史,以及默认远程名 origin。
四、最常用的一套日常流程
真实项目里,Git 不应该随手乱用。建议把日常流程固定下来:同步主线、创建分支、修改代码、检查变化、提交、同步、推送、发起评审。

一个标准功能开发流程可以这样做:
bash
# 1. 切回主线
git switch main
# 2. 获取远程最新提交,并要求只能快进合并
git pull --ff-only
# 3. 创建功能分支
git switch -c feat/login
# 4. 修改代码后查看状态
git status
git diff
# 5. 挑选要提交的改动
git add -p
# 6. 提交
git commit -m "feat: 增加短信登录入口"
# 7. 推送当前分支,并建立上游跟踪
git push -u origin feat/login
这里有几个细节值得养成习惯。
第一,尽量不要直接在 main 上开发。主线分支应该保持稳定,功能、修复、实验都放在独立分支。
第二,提交前先看 git diff。很多糟糕提交不是因为 Git 难,而是因为作者没有检查自己到底提交了什么。
第三,优先使用 git add -p。它可以按代码块挑选改动,适合把无关变化拆开提交。
第四,推送前先同步主线。如果团队约定使用线性历史,可以在个人分支上执行:
bash
git fetch origin
git rebase origin/main
如果团队不使用 rebase,就按团队约定 merge。关键不是某个命令绝对正确,而是团队策略一致。
五、看懂分支:分支不是文件夹
很多初学者会把分支理解成"复制了一份文件夹"。这个理解不够准确。Git 分支本质上只是一个指针,指向某个提交。你每次提交,当前分支指针就向前移动。

常用分支命令:
bash
# 查看本地分支
git branch
# 查看本地和远程分支
git branch -a
# 查看分支跟踪关系
git branch -vv
# 切换分支
git switch main
# 创建并切换到新分支
git switch -c feat/login
# 删除已合并分支
git branch -d feat/login
# 强制删除未合并分支,谨慎使用
git branch -D feat/login
分支命名建议
分支名不需要复杂,但要能表达目的。常见规范如下:
| 类型 | 示例 | 含义 |
|---|---|---|
feat/ |
feat/login |
新功能 |
fix/ |
fix/payment-timeout |
缺陷修复 |
hotfix/ |
hotfix/order-crash |
紧急线上修复 |
chore/ |
chore/update-deps |
构建、依赖、工程事务 |
docs/ |
docs/git-guide |
文档 |
一个好分支名应该让评审者不用点开代码,也能大致知道这个分支要解决什么问题。
六、提交不是保存按钮:写好 Commit
git commit 不是"我怕代码丢了,所以先保存一下"。提交应该代表一个完整、可理解、可验证的变更单元。

6.1. 好提交的三个标准
第一,单一目的。一次提交只解决一个问题。不要把功能开发、格式化、重构、依赖升级混在一起。
第二,可验证。提交后项目应该尽量保持可构建、可测试。至少不要把明显无法运行的中间状态提交到共享分支。
第三,可回滚。如果这个提交上线后出问题,团队能独立撤销它,而不会误伤一堆无关改动。
6.2. 提交信息怎么写
推荐使用"类型 + 简短说明"的格式:
bash
git commit -m "feat: 增加短信登录入口"
git commit -m "fix: 修复订单金额精度问题"
git commit -m "refactor: 提取用户权限判断逻辑"
git commit -m "docs: 更新部署说明"
git commit -m "test: 补充支付超时用例"
常见类型:
| 类型 | 适用场景 |
|---|---|
feat |
新功能 |
fix |
缺陷修复 |
refactor |
不改变外部行为的重构 |
docs |
文档 |
test |
测试 |
chore |
工程配置、依赖、脚本等事务 |
perf |
性能优化 |
style |
格式、空白、样式,不影响逻辑 |
当变更复杂时,不要只写一行标题。可以打开编辑器写多行提交信息:
bash
git commit
推荐结构:
text
feat: 增加短信登录入口
当前账号体系只支持密码登录,移动端注册转化率较低。
本次增加短信验证码登录入口,并复用现有验证码发送限流逻辑。
验证方式:
- npm test
- 手动验证验证码过期提示
关联:#123
6.3. 修改最近一次提交
如果刚提交完发现漏了一个文件,且还没有推送,可以使用:
bash
git add <文件>
git commit --amend
如果只是改提交信息:
bash
git commit --amend -m "fix: 修正验证码过期提示"
注意:--amend 会产生新的提交哈希。如果提交已经推送到多人共享分支,不要随意 amend。
七、Merge 与 Rebase:两种整合历史的方式
分支开发完成后,需要把改动整合回主线。常见方式是 merge 和 rebase。

7.1. Merge:保留真实分叉历史
bash
git switch main
git merge feat/login
merge 的特点是不会改写已有提交。它会把两条历史线合并起来,必要时生成一个合并提交。优点是历史真实、审计友好;缺点是分支多时提交图可能比较复杂。
适合场景:
- 主线集成功能分支。
- 多人共同维护同一个长期分支。
- 团队希望保留完整分叉与合并记录。
7.2. Rebase:把提交重放到新基底上
bash
git fetch origin
git rebase origin/main
rebase 的特点是会改写提交哈希。它把当前分支上的提交拿出来,放到新的基底后面重新应用。优点是历史线性、评审清晰;风险是如果别人已经基于你的旧提交继续开发,改写历史会影响他们。
适合场景:
- 整理自己的本地功能分支。
- 提交 PR 前让分支跟上最新主线。
- 团队明确约定使用线性历史。
重要原则:
text
可以 rebase 自己尚未共享的分支。
不要随意 rebase 已经被他人基于开发的共享分支。
7.3. Pull 到底做了什么
git pull 本质上相当于:
bash
git fetch
git merge
如果使用:
bash
git pull --rebase
则相当于:
bash
git fetch
git rebase
很多团队会要求使用 git pull --ff-only,它只允许快进合并。如果本地和远程出现分叉,命令会失败,提示你先明确选择 merge 或 rebase。这种方式能避免不小心生成意外的合并提交。
八、冲突处理:不要害怕,但要认真
冲突不是 Git 出错,而是 Git 无法自动判断最终应该保留哪段内容。比如你和同事都修改了同一行,Git 不知道哪一边代表正确业务语义。

冲突处理流程:
bash
# 1. 查看冲突文件
git status
# 2. 打开文件,找到冲突标记
<<<<<<< HEAD
当前分支中的内容
=======
对方分支中的内容
>>>>>>> origin/main
# 3. 手动编辑为最终正确结果,并删除冲突标记
# 4. 标记已解决
git add <文件>
# 5. 如果是 merge
git commit
# 6. 如果是 rebase
git rebase --continue
如果 rebase 过程中发现方向错了,可以中止:
bash
git rebase --abort
如果 merge 过程中想回到合并前状态:
bash
git merge --abort
处理冲突时最危险的做法,是为了"让冲突消失"而直接选择某一边。正确做法是理解双方改动目的,必要时找相关同事确认,再保留真正正确的最终代码。
九、撤销与回滚:先判断改动在哪个阶段
Git 撤销命令很多,真正难点不是命令本身,而是判断当前改动处于哪个阶段,以及是否已经推送到共享分支。

9.1. 丢弃工作区改动
适用于文件已经修改,但还没有暂存:
bash
git restore <文件>
丢弃当前目录下已跟踪文件的工作区改动要非常谨慎:
bash
git restore .
执行前建议先看:
bash
git diff
9.2. 从暂存区撤出
适用于已经 git add,但不想让某些文件进入下一次提交:
bash
git restore --staged <文件>
这不会丢弃文件内容,只是把改动从暂存区拿回工作区。
9.3. 撤销本地未推送提交
如果最近一次提交还没有推送,可以根据目的选择:
bash
# 撤销提交,但保留改动在暂存区
git reset --soft HEAD~1
# 撤销提交,保留改动在工作区
git reset --mixed HEAD~1
# 撤销提交,并丢弃对应工作区改动,危险
git reset --hard HEAD~1
git reset --hard 是高风险命令。它会移动分支指针,并让工作区回到目标提交状态。执行前必须确认没有未保存的重要改动。
9.4. 回滚已经推送的提交
如果提交已经进入共享分支,优先使用 revert:
bash
git revert <提交哈希>
revert 会生成一个新的反向提交,用来抵消指定提交的影响。它不会改写公共历史,因此更适合团队协作和审计。
9.5. 找回误删提交
如果你误删分支、reset 错了,先别慌。Git 可能还能通过 reflog 找到旧位置:
bash
git reflog
git switch -c rescue <提交哈希>
reflog 是本地引用日志,记录 HEAD 和分支指针曾经指向哪里。它不是永久备份,过期清理后可能消失,所以越早处理越好。
十、进阶命令:提升效率与排障能力
当你掌握基础流程后,这些命令会显著提升真实项目效率。

10.1. Stash:临时保存现场
当你正在开发一半,但需要马上切换分支修一个线上问题,可以先 stash:
bash
git stash push -u -m "登录页开发到一半"
说明:
-u会包含未跟踪文件。- 默认不会包含被
.gitignore忽略的文件。 -m给这次 stash 加说明,方便以后识别。
查看 stash:
bash
git stash list
恢复并删除最近一次 stash:
bash
git stash pop
恢复但保留 stash 记录:
bash
git stash apply
10.2. Cherry-pick:拣选某个提交
当你只想把另一个分支上的某个提交拿过来:
bash
git cherry-pick <提交哈希>
它会把该提交的补丁应用到当前分支,并生成一个新的提交,因此新提交哈希和原提交通常不同。
适合场景:
- 把修复提交同步到 release 分支。
- 从实验分支挑一个稳定改动。
- 临时补齐某个环境缺失的提交。
10.3. Tag:标记发布版本
标签常用于标记发布点:
bash
git tag -a v1.2.0 -m "发布 v1.2.0"
git push origin v1.2.0
查看标签:
bash
git tag
查看某个标签信息:
bash
git show v1.2.0
建议生产发布使用带说明的注解标签,即 git tag -a。
10.4. Bisect:二分定位问题提交
当你知道"某个旧版本是好的,现在坏了",但不知道哪个提交引入问题,可以用 bisect:
bash
git bisect start
git bisect bad
git bisect good <旧提交哈希>
Git 会切到中间提交,你运行测试或手动验证后告诉它:
bash
git bisect good
# 或
git bisect bad
重复几轮后,Git 会定位到最可能引入问题的提交。结束后:
bash
git bisect reset
10.5. Worktree:同时检出多个分支
如果你经常需要在功能开发和线上修复之间切换,git worktree 比频繁 stash 更舒服:
bash
git worktree add ../project-hotfix hotfix/payment
这样你可以在另一个目录同时打开 hotfix 分支,而原目录继续保留当前开发现场。
查看 worktree:
bash
git worktree list
删除不再使用的 worktree:
bash
git worktree remove ../project-hotfix
十一、远程协作:PR / MR 是质量闸门
团队项目中,远程仓库不是简单备份。它连接了代码评审、自动化测试、权限控制、版本发布和回滚审计。

一个成熟 PR 应该包含:
- 背景:为什么要改。
- 变更:改了哪些核心内容。
- 验证:跑了哪些测试,手动验证了哪些路径。
- 风险:是否涉及兼容性、数据迁移、性能或安全。
- 截图:前端或可视化改动应提供前后对比。
示例 PR 描述:
markdown
## 背景
登录页目前只支持密码登录,移动端转化率低。
## 变更
- 增加短信验证码登录入口
- 复用已有验证码限流逻辑
- 增加验证码过期提示
## 验证
- npm test
- 手动验证验证码发送、过期、重试路径
## 风险
- 依赖短信服务可用性
- 需要观察发送失败率
常见远程命令
查看远程仓库:
bash
git remote -v
获取远程最新状态,但不自动合并:
bash
git fetch origin
删除本地已经失效的远程跟踪分支:
bash
git fetch --prune
推送当前分支并建立跟踪关系:
bash
git push -u origin <分支名>
删除远程分支:
bash
git push origin --delete <分支名>
十二、.gitignore、LFS 与仓库治理
仓库治理影响长期可维护性。忽略规则、大文件策略和密钥管理如果做得不好,仓库会越来越慢,甚至引发安全事故。

12.1. .gitignore 只影响未跟踪文件
常见 .gitignore:
gitignore
# 依赖
node_modules/
# 构建产物
dist/
build/
# 日志
*.log
# 本地环境
.env
.env.local
# 系统文件
.DS_Store
Thumbs.db
一个常见误区是:把文件写进 .gitignore 后,Git 就不再跟踪它。实际上,如果文件已经被提交过,.gitignore 不会让它自动消失。
停止跟踪但保留本地文件:
bash
git rm --cached <文件>
git commit -m "chore: 停止跟踪本地配置文件"
12.2. 用 .gitattributes 管理换行和二进制文件
跨平台团队容易遇到 CRLF 和 LF 换行差异。更稳妥的做法是在仓库中使用 .gitattributes 明确规则,而不是依赖每个人的全局配置。
示例:
gitattributes
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
个人的 core.autocrlf 应遵循团队约定。项目内有 .gitattributes 时,优先以项目规则为准。
12.3. 大文件使用 Git LFS
Git 擅长管理源码文本,不擅长频繁变化的大型二进制文件。图片源文件、模型、设计稿、压缩包等大文件可以考虑 Git LFS:
bash
git lfs install
git lfs track "*.psd"
git add .gitattributes
git add design.psd
git commit -m "chore: 使用 LFS 管理设计源文件"
注意:LFS 对后续新增文件有效。已经进入历史的大文件,需要专门做历史迁移,不能简单认为 git lfs track 会自动瘦身旧历史。
12.4. 密钥泄露必须轮换
如果 .env、私钥、Token 被提交过,正确处理不是只删掉文件。只要进入过 Git 历史,就可能被别人拉取过。
严谨处理步骤:
- 立即撤销或轮换泄露的密钥。
- 从当前代码中删除密钥。
- 必要时用
git filter-repo或 BFG 等工具清理历史。 - 通知团队重新拉取或按迁移方案处理。
- 增加扫描工具,避免再次提交。
安全原则很简单:提交过的密钥视为已经泄露。
十三、故障排查:不要先复制命令
Git 出问题时,最重要的是先定位问题范围。盲目复制 reset --hard、force push 之类命令,往往会把小问题变成团队事故。

排查三件套:
bash
git status
git diff
git log --oneline --graph --decorate -n 12
如果涉及远程:
bash
git branch -vv
git remote -v
git fetch origin
如果怀疑提交丢失:
bash
git reflog
常见场景处理
场景 1:我改乱了一个文件,想恢复到上次提交
bash
git restore <文件>
场景 2:我 add 错了文件
bash
git restore --staged <文件>
场景 3:刚提交完发现漏了文件
bash
git add <文件>
git commit --amend
前提是还没有推送到共享分支。
场景 4:提交已经推送,想撤销它
bash
git revert <提交哈希>
这是公共历史中更稳妥的做法。
场景 5:本地分支和远程主线分叉了
先获取远程状态:
bash
git fetch origin
如果是个人功能分支,团队也允许线性历史:
bash
git rebase origin/main
如果团队保留合并记录:
bash
git merge origin/main
场景 6:我把分支删了
先查 reflog:
bash
git reflog
找到旧提交后创建救援分支:
bash
git switch -c rescue <提交哈希>
场景 7:远程分支已经删了,本地还看得到
bash
git fetch --prune
这会清理失效的远程跟踪分支。
十四、常用命令速查
下面这张图适合收藏,也适合放到团队 Wiki。

补充一个更完整的命令表:
| 目的 | 命令 | 说明 |
|---|---|---|
| 查看状态 | git status |
查看当前分支、工作区、暂存区 |
| 查看未暂存差异 | git diff |
对比工作区和暂存区 |
| 查看已暂存差异 | git diff --staged |
对比暂存区和最近提交 |
| 暂存文件 | git add <文件> |
加入下一次提交 |
| 分块暂存 | git add -p |
按块选择改动 |
| 提交 | git commit -m "说明" |
生成提交 |
| 修改最近提交 | git commit --amend |
改写最近一次提交 |
| 查看历史 | git log --oneline --graph |
图形化简洁历史 |
| 查看提交详情 | git show <提交哈希> |
查看某次提交内容 |
| 查看文件归属 | git blame <文件> |
查看每行最后修改者 |
| 创建分支 | git switch -c <分支> |
创建并切换 |
| 切换分支 | git switch <分支> |
切到已有分支 |
| 合并分支 | git merge <分支> |
合并指定分支 |
| 变基 | git rebase <基底> |
把当前提交重放到新基底 |
| 获取远程 | git fetch origin |
只获取,不合并 |
| 拉取并快进 | git pull --ff-only |
只允许快进 |
| 推送 | git push |
推送当前分支 |
| 推送并跟踪 | git push -u origin <分支> |
建立上游关系 |
| 撤出暂存 | git restore --staged <文件> |
暂存区回到工作区 |
| 丢弃工作区改动 | git restore <文件> |
恢复为最近提交状态 |
| 公共回滚 | git revert <提交哈希> |
新增反向提交 |
| 本地重置 | git reset --soft HEAD~1 |
撤销提交,保留暂存 |
| 临时保存 | git stash push -u -m "说明" |
保存当前现场 |
| 找回历史位置 | git reflog |
查看本地引用移动记录 |
十五、团队 Git 规范建议
个人会用 Git 只是第一步,团队要靠规范降低协作成本。下面是一套可落地的建议。
15.1. 主线保护
主线分支建议开启保护:
- 禁止直接 push。
- 必须通过 PR / MR。
- 必须通过自动化测试。
- 至少一名评审者批准。
- 对高风险仓库启用 CODEOWNERS 或类似机制。
15.2. 分支生命周期要短
功能分支存在越久,越容易和主线偏离,冲突风险越高。建议:
- 小需求 1 到 3 天内合入。
- 大需求拆成多个可评审 PR。
- 长期分支定期同步主线。
- 合并后及时删除远程分支。
15.3. 提交历史保持可读
推荐:
- 一次提交一个意图。
- 提交信息说明"为什么"。
- 无关格式化单独提交。
- 不提交临时代码、调试日志、个人配置。
- 推送前用
git log --oneline --graph -n 12看一眼历史。
15.4. 危险命令建立团队约束
以下命令不是不能用,而是要清楚后果:
| 命令 | 风险 |
|---|---|
git reset --hard |
丢弃工作区和暂存区改动 |
git push --force |
改写远程历史,可能影响他人 |
git clean -fd |
删除未跟踪文件 |
git rebase |
改写提交哈希,不适合随意用于共享分支 |
如果确实需要强推,优先使用带保护的方式:
bash
git push --force-with-lease
它会在远程分支没有被别人更新时才允许强推,比 --force 更稳妥,但仍然需要遵守团队约定。
15.5. 让自动化替你守门
Git 工作流最好和自动化检查结合:
- 提交前运行格式化和测试。
- PR 自动运行 CI。
- 合并前检查测试、Lint、类型检查、构建。
- 对密钥、许可证、大文件进行扫描。
- 发布时用 tag 和 release note 记录版本。
十六、一套推荐的新手练习路径
如果你刚开始学 Git,不建议只看教程。最好拿一个临时目录练习下面这些场景:
git init创建仓库,提交 README。- 修改同一个文件,分别练习
git diff、git add、git commit。 - 创建两个分支,分别提交,再 merge。
- 人为制造冲突,练习解决冲突。
- 使用
git restore丢弃工作区改动。 - 使用
git restore --staged撤出暂存。 - 使用
git reset --soft撤销未推送提交。 - 使用
git revert回滚一个提交。 - 使用
git stash临时保存现场。 - 使用
git reflog找回一个旧提交。
练习时不要怕把仓库弄坏。真正的能力来自你知道弄坏后如何恢复。
十七、最终心法
Git 的难点不是命令数量,而是历史意识。你要始终知道三件事:
第一,当前改动在哪个区域:工作区、暂存区、本地仓库,还是远程仓库。
第二,当前操作是否会改写历史:commit --amend、reset、rebase 都会产生新的提交关系。
第三,这段历史是否已经共享给别人:只要进入共享分支,就优先选择保留审计痕迹的修复方式,例如 revert。
最后记住这条原则:
text
本地私有历史可以整理,远程共享历史要谨慎。
先看 status,再做决定。
如果你能真正理解这两句话,Git 就不再是一堆吓人的命令,而会变成一套帮助你管理变化、协作和风险的工程系统。