主题
第一阶段:Git 基础入门
一、Git 概念与安装
1.1 什么是版本控制?
版本控制(Version Control)是一种记录文件内容变化,以便将来查阅特定版本的系统。
为什么需要版本控制?
- 追踪每一次修改的内容、时间、作者
- 随时回退到任意历史版本
- 多人协作时避免互相覆盖
- 并行开发不同功能而互不干扰
没有版本控制时的痛点:
项目_v1.zip
项目_v2_最终版.zip
项目_v2_最终版_改改改.zip
项目_v2_最终版_老板说再改改.zip ← 是不是很熟悉?1.2 Git 与 SVN 的区别
| 特性 | Git(分布式) | SVN(集中式) |
|---|---|---|
| 架构 | 每个开发者都有完整仓库副本 | 只有一个中央服务器 |
| 离线工作 | 支持,几乎所有操作都在本地完成 | 不支持,大部分操作需联网 |
| 速度 | 极快(本地操作) | 较慢(依赖网络) |
| 分支 | 轻量级,创建/切换/合并都非常快 | 重量级,分支是目录拷贝 |
| 数据安全 | 每个副本都是完整备份 | 中央服务器故障可能丢失数据 |
| 存储方式 | 快照(snapshot) | 差异(delta) |
核心区别一句话总结: Git 是分布式的,每个人本地都有完整历史;SVN 是集中式的,所有人依赖同一台服务器。
1.3 Git 的三个区域(核心概念)
这是理解 Git 最关键的概念,务必牢记。
┌──────────────┐ git add ┌──────────────┐ git commit ┌──────────────┐
│ │ ──────────────> │ │ ──────────────> │ │
│ 工作区 │ │ 暂存区 │ │ 本地仓库 │
│ Working Dir │ │ Staging Area │ │ Repository │
│ │ <──────────── │ │ <──────────── │ │
│ (你编辑的 │ git restore │ (准备提交的 │ git reset │ (已提交的 │
│ 文件目录) │ │ 修改快照) │ │ 历史记录) │
└──────────────┘ └──────────────┘ └──────────────┘
│
git push
│
▼
┌──────────────┐
│ 远程仓库 │
│ Remote │
└──────────────┘三个区域详解:
| 区域 | 说明 | 类比 |
|---|---|---|
| 工作区(Working Directory) | 你在电脑上实际看到和编辑的文件目录 | 你的书桌 |
| 暂存区(Staging Area / Index) | 临时存放你准备提交的修改,像一个"购物车" | 收银台前的购物篮 |
本地仓库(Repository / .git) | 存放所有已提交的历史版本数据 | 仓库货架 |
为什么需要暂存区?
暂存区让你可以精细控制每次提交的内容。比如你修改了 5 个文件,但只想先提交其中 2 个,就可以只 git add 这 2 个文件。
1.4 安装与初始配置
安装 Git:
bash
# Ubuntu / Debian
sudo apt-get install git
# CentOS / RHEL
sudo yum install git
# macOS(通常自带,也可用 Homebrew)
brew install git
# 验证安装
git --version初始配置(安装后必做):
bash
# 设置用户名和邮箱(每次提交都会记录)
git config --global user.name "你的名字"
git config --global user.email "your.email@example.com"
# 查看当前配置
git config --list
# 查看某项配置
git config user.name配置的三个级别:
| 级别 | 命令参数 | 配置文件位置 | 作用范围 |
|---|---|---|---|
| 系统级 | --system | /etc/gitconfig | 所有用户的所有仓库 |
| 用户级 | --global | ~/.gitconfig | 当前用户的所有仓库 |
| 仓库级 | --local(默认) | .git/config | 仅当前仓库 |
优先级:仓库级 > 用户级 > 系统级(就近原则)
推荐的额外配置:
bash
# 设置默认分支名为 main(新版推荐)
git config --global init.defaultBranch main
# 设置默认编辑器
git config --global core.editor "vim"
# 开启颜色显示
git config --global color.ui auto
# 设置换行符处理(跨平台协作时很重要)
# Linux/Mac
git config --global core.autocrlf input
# Windows
git config --global core.autocrlf true二、基本操作
2.1 git init — 初始化仓库
将当前目录变成一个 Git 仓库。
bash
# 创建一个新项目并初始化
mkdir my-project
cd my-project
git init执行后会在当前目录下生成一个隐藏的 .git 文件夹,这就是本地仓库,所有版本信息都存储在其中。
bash
# 查看 .git 目录结构
ls -la .git/
# 主要内容:
# HEAD — 指向当前所在分支
# config — 仓库级配置
# objects/ — 存储所有数据内容(blob、tree、commit)
# refs/ — 存储分支和标签的指针2.2 git clone — 克隆远程仓库
从远程获取一个完整的仓库副本。
bash
# HTTPS 方式克隆
git clone https://github.com/user/repo.git
# SSH 方式克隆(推荐,需提前配置 SSH Key)
git clone git@github.com:user/repo.git
# 克隆到指定目录
git clone https://github.com/user/repo.git my-folder
# 只克隆最近一次提交(浅克隆,适用于大型仓库)
git clone --depth 1 https://github.com/user/repo.git2.3 git add — 将文件添加到暂存区
bash
# 添加单个文件
git add README.md
# 添加多个文件
git add file1.txt file2.txt
# 添加当前目录下所有变更
git add .
# 添加所有变更(包括删除的文件)
git add -A
# 交互式添加(按块选择要暂存的内容)
git add -pgit add . vs git add -A 的区别:
| 命令 | 新文件 | 修改的文件 | 删除的文件 |
|---|---|---|---|
git add . | ✅ | ✅ | ✅(Git 2.x) |
git add -A | ✅ | ✅ | ✅ |
在 Git 2.x 中两者几乎等价,但 git add -A 对整个仓库生效,git add . 只对当前目录及子目录生效。
2.4 git commit — 提交更改
将暂存区的内容保存为一个版本快照。
bash
# 标准提交
git commit -m "描述本次修改的内容"
# 跳过暂存区,直接提交所有已跟踪文件的修改(不包含新文件)
git commit -a -m "修改说明"
# 修改最近一次提交(注意:不要修改已推送的提交)
git commit --amend -m "新的提交信息"
# 提交空信息(不推荐)会打开编辑器让你写
git commit好的提交信息格式:
<type>: <简短描述>
<详细说明(可选)>
# 示例:
feat: 添加用户登录功能
fix: 修复首页加载缓慢的问题
docs: 更新 README 安装说明
refactor: 重构数据库连接池逻辑2.5 git status — 查看当前状态
bash
git status
# 精简输出
git status -s
# 输出示例:
# M README.md — 已修改,未暂存
# M app.js — 已修改,已暂存
# A new-file.txt — 新文件,已暂存
# ?? untracked.txt — 未跟踪的文件
# MM both.js — 暂存后又修改了状态标记说明:
| 标记 | 含义 |
|---|---|
?? | 未跟踪(Untracked) |
A | 新添加到暂存区 |
M(左列) | 已修改并暂存 |
M(右列) | 已修改但未暂存 |
D | 已删除 |
R | 重命名 |
2.6 git log — 查看提交历史
bash
# 默认输出
git log
# 单行简洁模式(推荐日常使用)
git log --oneline
# 带分支图的日志
git log --oneline --graph --all
# 查看最近 5 条
git log -5
# 查看某个文件的修改历史
git log -- path/to/file
# 按作者筛选
git log --author="张三"
# 按时间范围筛选
git log --since="2024-01-01" --until="2024-06-30"
# 按提交信息搜索
git log --grep="fix"
# 查看每次提交的具体改动
git log -p
# 查看统计信息
git log --stat推荐配置一个美观的 log 别名:
bash
git config --global alias.lg "log --oneline --graph --all --decorate"
# 之后就可以用 git lg2.7 git diff — 查看差异
bash
# 工作区 vs 暂存区(未暂存的修改)
git diff
# 暂存区 vs 最新提交(已暂存但未提交的修改)
git diff --cached
# 或
git diff --staged
# 工作区 vs 最新提交
git diff HEAD
# 比较两个提交
git diff abc1234 def5678
# 比较两个分支
git diff main feature-branch
# 只查看哪些文件有变化
git diff --name-only
# 查看某个文件的差异
git diff -- path/to/file理解 diff 输出:
diff
diff --git a/hello.txt b/hello.txt
index 5c1b149..f2e4113 100644
--- a/hello.txt ← 修改前
+++ b/hello.txt ← 修改后
@@ -1,3 +1,4 @@ ← 位置信息:从第1行开始,原来3行,现在4行
Hello World ← 未修改的行(上下文)
-This is old line ← 删除的行(红色)
+This is new line ← 新增的行(绿色)
+Another new line ← 新增的行(绿色)
Goodbye ← 未修改的行(上下文)2.8 .gitignore — 忽略文件配置
在项目根目录创建 .gitignore 文件,指定哪些文件/目录不需要纳入版本管理。
gitignore
# 忽略所有 .log 文件
*.log
# 忽略 node_modules 目录
node_modules/
# 忽略构建输出
dist/
build/
# 忽略环境配置文件
.env
.env.local
# 忽略 IDE 配置
.idea/
.vscode/
*.swp
# 忽略操作系统文件
.DS_Store
Thumbs.db
# 不忽略某个特定文件(取反)
!important.log.gitignore 规则语法:
| 语法 | 说明 | 示例 |
|---|---|---|
# | 注释 | # 这是注释 |
* | 匹配任意字符 | *.log |
? | 匹配单个字符 | file?.txt |
** | 匹配多级目录 | **/logs |
/ 开头 | 只匹配根目录 | /build |
/ 结尾 | 只匹配目录 | logs/ |
! | 取反(不忽略) | !keep.log |
注意: 已被 Git 跟踪的文件不会被 .gitignore 忽略。需要先取消跟踪:
bash
# 取消跟踪但保留文件
git rm --cached filename
# 取消跟踪整个目录
git rm -r --cached directory/三、实践 Demo
Demo 1:从零创建一个 Git 项目
bash
# ① 创建项目目录
mkdir git-demo && cd git-demo
# ② 初始化 Git 仓库
git init
# ③ 创建文件
echo "# Git Demo Project" > README.md
echo "console.log('Hello Git!');" > app.js
# ④ 查看状态 — 此时两个文件都是 Untracked
git status
# ⑤ 添加到暂存区
git add README.md app.js
# ⑥ 查看状态 — 此时文件变为 Staged
git status
# ⑦ 提交
git commit -m "feat: 初始化项目,添加 README 和 app.js"
# ⑧ 查看提交历史
git log --onelineDemo 2:体验修改 → 暂存 → 提交的完整流程
bash
# ① 修改文件
echo "console.log('New feature');" >> app.js
# ② 查看差异(工作区 vs 上次提交)
git diff
# ③ 添加到暂存区
git add app.js
# ④ 查看暂存区的差异
git diff --cached
# ⑤ 再次修改同一文件(注意:这次修改不在暂存区中)
echo "// TODO: add more" >> app.js
# ⑥ 查看状态 — app.js 同时出现在 staged 和 unstaged 中
git status
# ⑦ 查看未暂存的差异
git diff
# ⑧ 只提交暂存区中的内容
git commit -m "feat: 添加新功能输出"
# ⑨ 查看状态 — 还有一个未暂存的修改
git statusDemo 3:使用 .gitignore
bash
# ① 创建一些应该忽略的文件
mkdir logs node_modules
echo "error at 10:00" > logs/error.log
echo "{}" > node_modules/package.json
echo "SECRET_KEY=abc123" > .env
# ② 查看状态 — 这些文件都显示为 Untracked
git status
# ③ 创建 .gitignore
cat > .gitignore << 'EOF'
logs/
node_modules/
.env
EOF
# ④ 再次查看状态 — 被忽略的文件不再出现
git status
# ⑤ 提交 .gitignore
git add .gitignore
git commit -m "chore: 添加 .gitignore 配置"Demo 4:查看和理解提交历史
bash
# 多做几次修改和提交,积累一些历史
echo "v1.0" > version.txt && git add . && git commit -m "feat: 添加版本文件"
echo "v1.1" > version.txt && git add . && git commit -m "fix: 更新版本号"
echo "v2.0" > version.txt && git add . && git commit -m "feat: 升级到 v2.0"
# 查看简洁历史
git log --oneline
# 查看详细历史(含每次改动)
git log -p
# 查看统计信息
git log --stat
# 查看某个文件的修改历史
git log --oneline -- version.txt
# 查看某次提交的具体内容(用上面 log 中显示的 hash)
git show <commit-hash>四、常见问题 Q&A
Q1:git add . 和 git add -A 有什么区别?
A: 在 Git 2.x 中几乎没有区别。微小差异是 git add . 只处理当前目录及其子目录,而 git add -A 处理整个仓库。如果你在项目根目录执行,两者完全等价。
Q2:提交后发现提交信息写错了怎么办?
A: 使用 --amend 修改最近一次提交:
bash
git commit --amend -m "正确的提交信息"⚠️ 注意: 如果该提交已经推送到远程仓库,不要使用
--amend,否则会导致历史不一致。
Q3:已经 git add 的文件想撤回怎么办?
A: 使用 git restore --staged(推荐)或 git reset HEAD:
bash
# 推荐方式(Git 2.23+)
git restore --staged filename
# 旧方式
git reset HEAD filename文件会从暂存区移回工作区,修改内容不会丢失。
Q4:不小心修改了文件,想恢复到上次提交的状态?
A:
bash
# 推荐方式(Git 2.23+)
git restore filename
# 旧方式
git checkout -- filename⚠️ 警告: 此操作不可逆!工作区的修改会被永久丢弃。
Q5:.gitignore 不生效,已跟踪的文件无法忽略?
A: .gitignore 只能忽略尚未被 Git 跟踪的文件。如果文件已被跟踪,需要先移除跟踪:
bash
# 取消跟踪但保留本地文件
git rm --cached filename
# 然后将其添加到 .gitignore
echo "filename" >> .gitignore
# 提交这两个变更
git add .gitignore
git commit -m "chore: 停止跟踪 filename"Q6:git init 和 git clone 的区别?
A:
| 场景 | 使用的命令 |
|---|---|
| 从零创建一个新项目 | git init |
| 获取一个已存在的远程项目 | git clone <url> |
git clone 本质上做了这些事:mkdir → git init → git remote add → git fetch → git checkout
Q7:每次提交的 hash 值是怎么来的?
A: Git 使用 SHA-1 算法对以下信息计算哈希值:
- 提交内容(文件快照)
- 父提交的 hash
- 作者信息和时间
- 提交者信息和时间
- 提交信息
所以即使内容相同,不同时间的提交 hash 也不同。hash 值保证了数据完整性——任何篡改都会导致 hash 变化。
Q8:git diff 没有输出是怎么回事?
A: 可能的原因:
- 没有修改任何文件 — 工作区和暂存区一致
- 修改已暂存 —
git diff只比较工作区和暂存区,已暂存的修改用git diff --cached查看 - 文件是二进制文件 — Git 默认不显示二进制差异
bash
# 查看完整差异链路
git diff # 工作区 vs 暂存区
git diff --cached # 暂存区 vs 最新提交
git diff HEAD # 工作区 vs 最新提交Q9:git commit -a -m "msg" 为什么有时候不能提交新文件?
A: -a 参数只会自动暂存已跟踪文件的修改,不会添加未跟踪(Untracked)的新文件。新文件必须先用 git add 手动添加。
Q10:如何查看某一行代码是谁在什么时候写的?
A: 使用 git blame:
bash
# 查看某文件每一行的作者和提交信息
git blame filename
# 查看指定行范围
git blame -L 10,20 filename五、速查表
┌─────────────────────────────────────────────────────────┐
│ Git 基础命令速查 │
├──────────────────────┬──────────────────────────────────┤
│ git init │ 初始化仓库 │
│ git clone <url> │ 克隆远程仓库 │
│ git add <file> │ 添加到暂存区 │
│ git add . │ 添加所有变更 │
│ git commit -m "msg" │ 提交到本地仓库 │
│ git status │ 查看当前状态 │
│ git status -s │ 精简状态输出 │
│ git log --oneline │ 查看简洁历史 │
│ git diff │ 查看未暂存的修改 │
│ git diff --cached │ 查看已暂存的修改 │
│ git restore <file> │ 撤销工作区修改 │
│ git restore --staged │ 从暂存区撤回 │
│ git rm --cached │ 取消跟踪(保留文件) │
│ git blame <file> │ 查看每行的修改记录 │
└──────────────────────┴──────────────────────────────────┘六、学习检查清单
完成以下任务,确认你已掌握本阶段内容:
- [ ] 能说出 Git 和 SVN 的 3 个核心区别
- [ ] 能画出工作区、暂存区、本地仓库的关系图
- [ ] 能独立完成
init → add → commit的完整流程 - [ ] 能使用
git status判断文件处于哪个状态 - [ ] 能使用
git diff的三种形式查看不同阶段的差异 - [ ] 能使用
git log查看和筛选提交历史 - [ ] 能正确编写
.gitignore文件 - [ ] 能处理"已跟踪文件无法被 .gitignore 忽略"的问题