大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
Git:版本控制与协作基础
这一课你将能做到
- 初始化仓库、提交更改、查看历史,独立完成完整的版本管理流程
- 创建和合并分支,用分支隔离不同功能开发,避免互相干扰
- 解决合并冲突,正确配置
.gitignore,让仓库保持干净
为什么要学
写代码不可能一次写对。你会改需求、修 bug、尝试新方案、回滚旧版本。没有版本控制,你只能 代码_final_最终版_真的最终版.zip——这不是玩笑,是很多团队的真实经历。Git 是事实上的行业标准,99% 的互联网公司用它管理代码。
对初学者来说,Git 的门槛在于它的「分布式」概念和命令行操作。但一旦上手,你会发现它是最可靠的后悔药:改坏了?回退。想试新功能?切分支。想知道谁改的?看日志。
先建立图像
Git 把文件的状态分成三个区域:
工作区(Working Directory)
你看到的文件,可以随便改
↓ git add
暂存区(Staging Area / Index)
准备提交的更改,可以撤回
↓ git commit
本地仓库(Repository)
永久保存的快照,形成历史链
↓ git push
远程仓库(Remote)
GitHub/GitLab 上的共享仓库
每次 git commit 就是给当前状态拍一张快照,并附上说明。这些快照组成一条时间线,你可以随时跳到任意一个快照。
跟着做
步骤 1:安装与配置
下载 Git(git-scm.com),安装后打开终端:
# 配置身份(提交记录会显示你是谁)
git config --global user.name "你的名字"
git config --global user.email "your@email.com"
# 设置默认分支名为 main(现代标准)
git config --global init.defaultBranch main
# 验证
git --version
git config --list
步骤 2:初始化仓库并提交
# 进入项目文件夹
mkdir my-project && cd my-project
# 初始化 Git 仓库
git init
# 创建文件
echo "# 我的项目" > README.md
# 查看状态(哪些改了、哪些没跟踪)
git status
# 添加到暂存区
git add README.md
# 或添加所有更改
git add .
# 提交到本地仓库
git commit -m "初始化项目,添加 README"
# 查看提交历史
git log --oneline
git status 是你最好的朋友,状态不明时先运行它。
步骤 3:修改、再提交、看差异
# 修改 README.md
echo "这是项目说明。" >> README.md
# 查看改了什么(工作区 vs 暂存区)
git diff
# 添加并提交
git add README.md
git commit -m "补充项目说明"
git diff 显示具体的行级差异,红色是删除,绿色是新增。
步骤 4:分支管理
# 查看当前分支
git branch
# 创建并切换到新分支
git checkout -b feature-login
# 或新版语法
git switch -c feature-login
# 在新分支上开发
echo "登录功能代码" > login.js
git add login.js
git commit -m "添加登录功能"
# 切回主分支
git switch main
# 把 feature-login 合并到 main
git merge feature-login
# 删除已合并的分支
git branch -d feature-login
分支的本质是指向某个提交的「可移动指针」。main 随提交前进,feature-login 在独立线上前进,合并时 Git 尝试把两条线合二为一。
步骤 5:合并冲突
当两个分支修改了同一文件的同一位置,Git 无法自动判断该保留哪个,就会产生冲突:
# 模拟冲突
# 分支 A 修改第 1 行,分支 B 也修改第 1 行
git merge another-branch
# 提示 CONFLICT (content): Merge conflict in README.md
# Automatic merge failed; fix conflicts and commit
打开冲突文件,会看到:
<<<<<<< HEAD
这是 main 分支的内容
=======
这是 another-branch 的内容
>>>>>>> another-branch
手动编辑,保留正确的内容,删除 <<<<<<<、=======、>>>>>>> 这些标记,然后:
git add README.md
git commit -m "解决合并冲突"
步骤 6:回退与撤销
# 撤销工作区的修改(还没 add)
git checkout -- README.md
# 撤销暂存区的修改(已 add 未 commit)
git reset HEAD README.md
# 回退到上一个提交(保留修改到工作区)
git reset --soft HEAD~1
# 回退到上一个提交(丢弃修改)
git reset --hard HEAD~1
# 查看所有操作记录(用于找回)
git reflog
--hard 是危险操作,会丢失未提交的修改。不确定时先用 --soft。
步骤 7:.gitignore
新建 .gitignore 文件:
# 依赖目录
node_modules/
# 构建产物
dist/
build/
# 日志
*.log
# 环境变量(含敏感信息)
.env
.env.local
# 编辑器配置
.vscode/
.idea/
# 操作系统文件
.DS_Store
Thumbs.db
.gitignore 里的文件不会被 Git 跟踪。注意:已经被跟踪的文件再添加进 .gitignore 不会生效,需要先用 git rm --cached 文件名 移除跟踪。
讲清楚要点
- Git 是快照系统,不是差异系统:每次
commit保存的是当时所有文件的完整快照,不是和上一版的差异。这是它能快速切换分支和回退的原因。 - 三个区域必须分清楚:工作区是你改代码的地方;暂存区是「准备提交」的缓冲区;本地仓库是永久历史。
add是把工作区搬到暂存区,commit是把暂存区搬到仓库。 - 分支是轻量的:创建分支只是多一个 40 字节的指针,不是复制文件。所以分支应该大胆用,每个功能、每个 bug 修一个分支,是最佳实践。
- 提交信息要写得像命令:用动词开头、现在时,比如 "Add login form"、"Fix navigation overflow"。不要写 "修改"、"更新" 这种模糊的话。
.gitignore越早越好:项目初始化时就写好,避免把 node_modules、密钥、构建产物提交上去——这些东西上去了再删除,历史里仍然有记录。
你可能会懵的地方
-
Git 和 GitHub 是一回事吗? 不是。Git 是本地版本控制工具;GitHub 是基于 Git 的代码托管平台。就像 Word 是文字处理软件,OneDrive 是云存储服务。
-
为什么要先 add 再 commit? 因为一次提交可能只包含部分更改。你可能改了 5 个文件,但只想把其中 2 个的更改打包成一个逻辑提交。add 让你精确控制提交内容。
-
git pull和git fetch的区别?fetch只是把远程的更新下载到本地,不会合并;pull是fetch + merge,直接把远程分支合并到当前分支。想先看改了什么再用fetch,不确定时用pull。 -
HEAD 是什么? HEAD 是当前分支的别名,指向你当前所在的提交。
HEAD~1是上一个提交,HEAD~2是上上个。 -
为什么有时候
git log看不到我要找的分支?git log默认只显示当前分支的历史。用git log --all --graph --oneline看全部分支的拓扑图。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
git commit 不写 -m | 进入 vi 编辑器,初学者不会退 | git commit -m "说明" |
| 直接把密钥提交到仓库 | 安全风险,历史里永久留存 | 加入 .gitignore,用环境变量 |
git add . 后后悔 | 把不想提交的也加进去了 | git reset HEAD 文件名 撤回暂存 |
| 在错误的分支上开发 | 代码提交到了 main | git stash 暂存,切分支,git stash pop |
git reset --hard 丢了代码 | 未提交的修改全没了 | 先用 git stash 备份,或 --soft |
.gitignore 对已有文件无效 | Git 继续跟踪 | git rm --cached 文件 再提交 |
| 每次提交都写「更新」 | 提交历史无法阅读 | 动词开头,描述做了什么和为什么 |
卡点急救
- 不小心
git reset --hard丢了代码:立刻执行git reflog,找到之前的 commit hash,然后git checkout -b recovery <hash>找回。 - 合并冲突不知道怎么解:用
git status看哪些文件冲突,打开文件搜索<<<<<<<,手动编辑后add + commit。 - 想撤销已经 push 到远程的提交:不要直接改历史(除非确认团队同意)。正确做法是用
git revert <hash>生成一个反向提交,安全回退。 - 提交后发现漏了一个文件:
git add 漏的文件然后git commit --amend --no-edit,把漏的文件补进上一次提交。
面试常问
-
Git 的工作流程? 工作区修改 →
git add到暂存区 →git commit到本地仓库 →git push到远程仓库。多人协作时还有fetch、pull、merge、rebase。 -
merge 和 rebase 的区别?
merge保留分支历史,生成一个合并提交;rebase把当前分支的提交「挪」到目标分支的最新提交后面,历史变成直线。rebase 历史更整洁,但不要对已经 push 的公共分支 rebase。 -
git stash 的作用? 临时保存工作区的修改(不提交),让你可以切分支或拉代码。
git stash pop恢复最近一次 stash。 -
.gitignore为什么有时不生效? 因为文件已经被跟踪了。.gitignore只影响未跟踪的文件。解决:git rm --cached 文件,然后提交.gitignore。
自测三问
git add、git commit、git push分别把代码送到哪个区域?- 新建功能分支的完整命令序列是什么?
- 合并冲突时,文件里的
<<<<<<< HEAD是什么意思?你应该怎么处理?
小结一句话
Git 是时间机器:用分支隔离风险,用提交记录历史,用回退纠正错误——学会这三件事,代码再也不怕改坏。
延伸
- Pro Git 中文在线书
- 下一课:GitHub——把代码推上云端,学会远程协作和 Pull Request。