Git 概述

版本控制系统

版本控制系统是一种记录一个或若干文件内容变化以便将来查阅特定版本修订情况的系统

  • 本地版本控制系统
    • 在本地保存文件的修订版本
    • 缺点无法跨设备协作数据容易丢失
  • 集中式版本控制系统CVCS
    • 如 SVNCVS
    • 单一中央服务器存储所有版本
    • 缺点单点故障必须联网才能工作
  • 分布式版本控制系统DVCS
    • 如 GitMercurial
    • 每个客户端都保存完整的代码库镜像
    • 优点离线工作速度快安全性高

Git 的核心优势

  • 分布式架构每个开发者都有完整的仓库副本
  • 快速高效大部分操作在本地执行速度极快
  • 分支管理强大创建切换合并分支非常轻量
  • 数据完整性保证使用 SHA-1 哈希算法确保数据完整性
  • 快照而非差异Git 保存的是文件快照而非文件差异

Git 的工作原理

三个工作区域

Git 本地有三个工作区域

  • 工作区Working Directory
    • 实际存放项目的目录
    • 我们日常编辑文件的地方
  • 暂存区Staging Area / Index
    • 临时存放改动的地方
    • 通过 git add 将文件添加到这里
  • 版本库Repository / HEAD
    • Git 正式保存数据的地方
    • 通过 git commit 将暂存区内容提交到这里

文件状态流转

文件在 Git 中有四种状态

  • Untracked未跟踪新创建的文件Git 还未跟踪
  • Modified已修改已跟踪的文件被修改但未暂存
  • Staged已暂存已修改的文件被添加到暂存区
  • Committed已提交已暂存的文件被提交到版本库

状态转换流程

1
2
3
4
5
Untracked → (git add) → Staged → (git commit) → Committed

Modified ← (修改文件)

(git add) → Staged

安装配置

安装 Git

Linux 安装

1
2
3
4
5
6
7
8
# Ubuntu/Debian
sudo apt-get install git

# CentOS/RHEL
sudo yum install git

# 验证安装
git --version

macOS 安装

1
2
3
4
5
# 使用 Homebrew
brew install git

# 或者安装 Xcode Command Line Tools包含 Git
xcode-select --install

Windows 安装

下载 Git for Windows 安装包https://git-scm.com/install/windows

初始配置

安装完成后需要配置用户信息这些信息会出现在每次的 Git 提交中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 配置用户名
git config --global user.name "Your Name"

# 配置邮箱
git config --global user.email "your.email@example.com"

# 查看配置
git config --list
git config user.name
git config user.email


# 细节注意
# 1. `--global` 参数表示对当前用户的所有仓库生效
# 2. 如果去掉 `--global`则只对当前仓库生效
# 3. 配置文件位置`~/.gitconfig`全局`.git/config`当前仓库

常用配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 设置默认编辑器
git config --global core.editor vim

# 设置差异分析工具
git config --global merge.tool vimdiff

# 设置行尾符处理方式
git config --global core.autocrlf input # Mac/Linux
git config --global core.autocrlf true # Windows

# 设置颜色输出
git config --global color.ui true

# 设置别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --decorate"

# 长期保存登录凭证
git config --global credential.helper store

# 暂时缓存登录凭证
# 默认储存15分钟可以自定义设置保存时间
git config --global credential.helper cache
git config --global credential.helper 'cache --timeout=3600'

基本操作

创建仓库

初始化新仓库

1
2
3
4
5
# 在当前目录初始化 Git 仓库
git init

# 在指定目录初始化 Git 仓库
git init project-name

克隆现有仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
# 克隆远程仓库到当前目录
git clone <repository-url>

# 克隆远程仓库到指定目录
git clone <repository-url> <directory-name>

# 示例
git clone https://github.com/user/repo.git
git clone https://github.com/user/repo.git my-project

# 细节注意
# 1. 克隆会自动配置远程仓库默认名为 origin
# 2. 克隆会获取所有历史版本和分支

查看状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看详细状态
git status

# 查看简短状态
git status -s


# 状态符号说明
# - `??`未跟踪的文件
# - `M `工作区已修改未暂存
# - ` M`暂存区已修改工作区又有新修改
# - `MM`工作区和暂存区都已修改
# - `A `新添加到暂存区的文件
# - `D `已删除的文件

暂存文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 添加指定文件
git add <file>

# 添加所有更改
git add .

# 使用通配符
git add *.txt

# 交互式添加选择性添加
git add -i


# 示例
# 添加单个文件
git add hello.txt

# 添加目录下所有文件
git add src/

# 添加所有修改的文件
git add -A

提交更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 提交并添加消息
git commit -m "commit message"

# 跳过暂存直接提交仅限已跟踪文件
git commit -am "message"

# 修改最近一次提交
git commit --amend

# 使用编辑器编写提交消息
git commit


# 细节注意
# 1. 提交消息应该简洁明了说明本次改动的目的
# 2. `-a` 参数只能提交已跟踪的文件新文件仍需先 `git add`
# 3. `--amend` 可以修改最近一次提交的文件或消息

提交历史

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 查看详细日志
git log

# 简洁显示一行一条
git log --oneline

# 图形化显示分支合并
git log --graph

# 显示每次提交的差异统计
git log --stat

# 按作者筛选
git log --author="name"

# 按时间范围筛选
git log --since="2 weeks ago"
git log --until="2024-01-01"

# 限制显示条数
git log -n 5

# 组合使用
git log --oneline --graph --all -n 10


# 日志格式说明
# - `commit`提交的 SHA-1 校验和
# - `Author`作者信息
# - `Date`提交日期
# - 提交消息

提交规范

使用规范的提交消息格式便于自动化生成变更日志

格式模版

1
2
3
4
5
6
7
8
<type>(<scope>): <description>

[optional body]

[optional footer(s)]

1. typescopedescription是必需的
2. bodyfooter是可选的

常用类型

1
2
3
4
5
6
7
8
9
`feat`新功能
`fix`修复 bug
`docs`文档更新
`style`代码格式不影响代码运行
`refactor`代码重构
`test`测试相关
`chore`构建过程或辅助工具变动
`perf`性能优化
`ci`CI 配置相关

提交示例

1
2
3
4
5
6
feat(auth): add login functionality

add JWT authentication
update user model

Closes #123

撤销操作

撤销工作区修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Git 2.23 之前
git checkout -- <file>

# Git 2.23+推荐
git restore <file>


# 示例
git restore hello.txt # 撤销对 hello.txt 的修改
git restore . # 撤销所有文件的修改


# 细节注意
# 1. 此操作不可逆会丢弃工作区的所有修改
# 2. 只能撤销已跟踪文件的修改

撤销暂存

1
2
3
4
5
6
7
8
# Git 2.23 之前
git reset HEAD <file>

# Git 2.23+推荐
git restore --staged <file>

# 示例
git restore --staged hello.txt # 将 hello.txt 从暂存区移除

修改最近一次提交

1
2
3
4
5
6
7
8
9
10
11
# 修改提交消息
git commit --amend -m "new message"

# 添加遗漏的文件
git add forgotten-file.txt
git commit --amend --no-edit


# 细节注意
# 1. `--amend` 会创建一个新的提交替换旧的提交
# 2. 如果已经推送到远程需要强制推送谨慎使用

回退版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 回退到上一个版本
git reset --hard HEAD^

# 回退到上 N 个版本
git reset --hard HEAD~N

# 回退到指定版本
git reset --hard <commit-hash>

# 软回退保留工作区和暂存区
git reset --soft <commit-hash>

# 混合回退保留工作区清空暂存区
git reset --mixed <commit-hash>

# 硬回退清空工作区和暂存区
git reset --hard <commit-hash>


# 细节注意
# 1. `--hard` 会丢弃所有未提交的修改使用前务必确认
# 2. 已经推送到远程的版本不要随意回退
# 3. 可以使用 `git reflog` 查看操作历史找回误删的提交

分支管理

分支是指向某个提交的指针Git 的分支非常轻量创建和切换几乎瞬间完成

  • HEAD 指针指向当前所在的分支
  • master/main 分支默认主分支
  • 分支本质只是一个包含 40 个字符的 SHA-1 校验和的文件

查看分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看所有分支
git branch

# 查看详细信息最后提交
git branch -v

# 查看所有分支包括远程
git branch -a

# 查看已合并的分支
git branch --merged

# 查看未合并的分支
git branch --no-merged

创建分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 创建新分支
git branch <branch-name>

# 创建并切换到新分支
git checkout -b <branch-name>

# Git 2.23+推荐
git switch -c <branch-name>


# 示例
git branch feature-login
git checkout -b feature-login
git switch -c feature-login


# 分支命名规范
# `feature/xxx`功能分支如 `feature/user-auth`
# `bugfix/xxx`修复分支如 `bugfix/login-error`
# `hotfix/xxx`紧急修复分支如 `hotfix/security-patch`
# `release/x.x`发布分支如 `release/1.0.0`
# `docs/xxx`文档分支如 `docs/update-readme`

切换分支

1
2
3
4
5
6
7
8
9
10
# Git 2.23 之前
git checkout <branch-name>

# Git 2.23+推荐
git switch <branch-name>


# 示例
git switch main
git switch feature-login

删除分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安全删除只能删除已合并的分支
git branch -d <branch-name>

# 强制删除即使未合并也删除
git branch -D <branch-name>


# 示例
git branch -d feature-login
git branch -D feature-old


# 细节注意
# 1. 不能删除当前所在的分支
# 2. 删除前先确认分支是否已合并

合并分支

合并分支

1
2
3
4
5
6
7
8
9
10
# 切换到目标分支
git switch main

# 合并特性分支
git merge <branch-name>


# 示例
git switch main
git merge feature-login

合并类型

  • Fast-forward快进合并
    • 当目标分支是当前分支的直接祖先时
    • 只是移动指针不创建新的合并提交
  • Three-way merge三方合并
    • 当两个分支分叉后
    • 创建一个新的合并提交

解决冲突

当两个分支修改了同一文件的同一部分时会产生冲突

1
2
3
4
5
解决步骤
1. 查看冲突文件`git status`
2. 手动编辑文件解决冲突标记`<<<<<<<``=======``>>>>>>>`
3. 标记解决`git add <file>`
4. 完成合并`git commit`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看冲突文件
git status

# 编辑文件解决冲突后
git add conflicted-file.txt
git commit -m "resolve merge conflict"

# 中止合并
git merge --abort


# 细节注意
# 1. 冲突标记中`<<<<<<< HEAD` 到 `=======` 是当前分支的内容
# 2. `=======` 到 `>>>>>>>` 是要合并的分支内容
# 3. 解决冲突时要仔细检查确保逻辑正确

变基操作

Rebase 基础

变基可以将一系列提交重新应用到另一个分支上保持线性历史

1
2
3
4
5
6
7
# 将当前分支变基到目标分支
git rebase <branch-name>


# 示例
git switch feature
git rebase main

交互式变基

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 修改最近 N 次提交
git rebase -i HEAD~N

# 从指定提交开始交互式变基
git rebase -i <commit-hash>


# 交互式变基命令
# - `pick`保留该提交
# - `reword`保留提交修改提交消息
# - `edit`保留提交停下来修改
# - `squash`将该提交合并到上一个提交
# - `fixup`类似 squash但丢弃提交消息
# - `drop`删除该提交

Merge vs Rebase

特性 Merge Rebase
历史记录 保留完整历史 保持线性历史
适用场景 公共分支 私有分支
安全性 更安全 可能丢失历史
协作友好 适合团队协作 适合个人开发
1
2
3
4
细节注意
1. **不要在公共分支上使用 rebase**
2. rebase 会改写历史已经推送的提交不要 rebase
3. 个人特性分支可以使用 rebase 保持整洁

分支策略

Git Flow

适合长期维护的项目有明确的发布周期

1
2
3
4
5
6
分支类型
- `master/main`生产环境分支
- `develop`开发分支
- `feature/*`功能分支
- `release/*`发布分支
- `hotfix/*`紧急修复分支

GitHub Flow

适合持续部署的项目简单灵活

1
2
3
4
5
规则
- 只有一个主分支main
- 从 main 创建特性分支
- 通过 Pull Request 合并到 main
- 合并后立即部署

Trunk Based Development

适合大型团队强调快速迭代

1
2
3
4
特点
- 所有人都在主干上开发
- 特性通过特性开关控制
- 频繁小步提交

远程仓库

查看远程仓库

1
2
3
4
5
# 查看远程仓库名称
git remote

# 查看详细信息URL
git remote -v

添加远程仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
# 添加远程仓库
git remote add <name> <url>

# 修改远程仓库 URL
git remote set-url <name> <new-url>

# 删除远程仓库
git remote remove <name>


# 示例
git remote add origin https://github.com/user/repo.git
git remote set-url origin https://github.com/user/new-repo.git

推送代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 推送到远程分支
git push <remote> <branch>

# 首次推送并设置上游分支
git push -u <remote> <branch>

# 推送所有分支
git push --all <remote>

# 强制推送谨慎使用
git push --force
git push --force-with-lease # 更安全的强制推送


# 示例
git push origin main
git push -u origin feature-login


# 细节注意
# 1. `-u` 参数会建立本地分支和远程分支的追踪关系
# 2. 之后可以直接使用 `git push` 和 `git pull`
# 3. 强制推送会覆盖远程历史仅在必要时使用

拉取代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 拉取并合并fetch + merge
git pull

# 拉取并变基fetch + rebase
git pull --rebase

# 仅获取不合并
git fetch

# 获取所有远程分支
git fetch --all

# 获取指定远程仓库
git fetch origin


# 示例
git pull origin main
git fetch origin
git merge origin/main


# 细节注意
# 1. `git pull` = `git fetch` + `git merge`
# 2. `git pull --rebase` = `git fetch` + `git rebase`
# 3. 推荐使用 `fetch + merge/rebase` 的方式更可控

标签管理

标签用于标记重要的版本节点如发布版本

创建标签

1
2
3
4
5
6
7
8
# 轻量标签只包含校验和
git tag v1.0

# 附注标签包含完整信息推荐
git tag -a v1.0 -m "version 1.0"

# 给指定提交打标签
git tag -a v1.0 <commit-hash> -m "version 1.0"

查看标签

1
2
3
4
5
6
7
8
# 查看所有标签
git tag

# 查看匹配模式的标签
git tag -l "v1.*"

# 查看标签详情
git show v1.0

推送标签

1
2
3
4
5
# 推送指定标签
git push origin v1.0

# 推送所有标签
git push origin --tags

删除标签

1
2
3
4
5
# 删除本地标签
git tag -d v1.0

# 删除远程标签
git push origin --delete v1.0

高级功能

储藏工作进度

当需要切换分支但工作未完成时可以使用储藏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 储藏当前更改
git stash

# 储藏并添加消息
git stash save "work in progress"

# 查看储藏列表
git stash list

# 恢复最新储藏并删除
git stash pop

# 恢复指定储藏并删除
git stash pop stash@{0}

# 恢复但不删除
git stash apply

# 删除储藏
git stash drop stash@{0}

# 清空所有储藏
git stash clear

# 查看储藏内容
git stash show stash@{0}

# 查看储藏的详细差异
git stash show -p stash@{0}


# 细节注意
# 1. 储藏只保存已跟踪文件的修改
# 2. 新文件需要先 `git add` 才能被储藏
# 3. 可以使用 `git stash -u` 储藏未跟踪的文件

清理未跟踪文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 预览将删除的文件
git clean -n

# 强制删除未跟踪的文件
git clean -f

# 删除未跟踪的文件和目录
git clean -fd

# 交互式清理
git clean -i


# 细节注意
# 1. `git clean` 操作不可逆使用前务必确认
# 2. 建议先用 `-n` 预览再用 `-f` 删除

查看差异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 工作区与暂存区的差异
git diff

# 暂存区与版本库的差异
git diff --staged
git diff --cached

# 两个提交的差异
git diff <commit1> <commit2>

# 两个分支的差异
git diff main develop

# 查看指定文件的差异
git diff <file>

# 查看简要统计
git diff --stat

查找提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 按提交消息搜索
git log --grep="keyword"

# 按作者搜索
git log --author="name"

# 搜索代码变化
git log -S "function_name"

# 查看某行的修改历史
git blame <file>

# 查看文件的完整历史
git log --follow <file>


# 示例
git log --grep="fix bug"
git log -S "console.log"
git blame src/app.js

选择提交

选择性地应用某个提交到当前分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 应用指定提交
git cherry-pick <commit-hash>

# 应用多个提交
git cherry-pick <commit1> <commit2>

# 应用提交范围
git cherry-pick <commit1>..<commit2>

# 应用但不自动提交
git cherry-pick -n <commit-hash>


# 细节注意
# 1. cherry-pick 会创建新的提交而不是移动原有提交
# 2. 可能产生冲突需要手动解决
# 3. 适用于将特定修复应用到其他分支

子模块

子模块允许在一个 Git 仓库中嵌入另一个 Git 仓库

添加子模块

1
2
3
4
5
# 添加子模块
git submodule add <url> <path>

# 示例
git submodule add https://github.com/user/lib.git libs/mylib

更新子模块

1
2
3
4
5
6
7
8
9
10
11
# 初始化子模块
git submodule init

# 更新子模块
git submodule update

# 初始化和更新推荐
git submodule update --init --recursive

# 拉取子模块的最新代码
git submodule foreach git pull

删除子模块

1
2
3
4
5
6
7
8
# 取消注册子模块
git submodule deinit <path>

# 从版本库中移除
git rm <path>

# 删除子模块目录
rm -rf .git/modules/<path>

工具与优化

.gitignore 规则

创建 .gitignore 文件来指定哪些文件应该被 Git 忽略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 注释以 # 开头

# 忽略所有 .log 文件
*.log

# 忽略 node_modules 目录
node_modules/

# 忽略 build 目录
build/

# 例外规则不忽略 important.log
!important.log

# 忽略特定文件
config.local.json

# 忽略所有以 temp 开头的文件
temp*

# 忽略所有 .class 文件Java
*.class

# 忽略 IDE 配置
.vscode/
.idea/
*.swp


# 细节注意
# 1. `.gitignore` 只对未跟踪的文件生效
# 2. 已跟踪的文件需要在 `.gitignore` 中添加后先移除跟踪`git rm --cached <file>`
# 3. 可以使用多个 `.gitignore` 文件放在不同目录下

全局忽略文件

1
2
3
4
5
# 创建全局忽略文件
touch ~/.gitignore_global

# 配置全局忽略
git config --global core.excludesfile ~/.gitignore_global

Hooks 钩子

Git Hooks 是在特定事件发生时自动执行的脚本

客户端钩子

位于 .git/hooks/ 目录

  • pre-commit提交前执行可用于代码检查
  • commit-msg提交消息验证
  • post-commit提交后执行
  • pre-push推送前执行
  • post-checkout切换分支后执行

服务端钩子

  • pre-receive接收推送前执行
  • update更新引用前执行
  • post-receive接收推送后执行

创建 pre-commit 钩子进行代码检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 进入 hooks 目录
cd .git/hooks

# 创建 pre-commit 钩子
cat > pre-commit << 'EOF'
#!/bin/bash
# 运行代码检查
npm run lint
if [ $? -ne 0 ]; then
echo "代码检查失败提交中止"
exit 1
fi
EOF

# 添加执行权限
chmod +x pre-commit

错误处理

误删提交

1
2
3
4
5
# 查看操作历史
git reflog

# 恢复到指定状态
git reset --hard <commit-hash>

推送了敏感信息

1
2
3
4
5
6
7
8
9
10
# 使用 BFG 或 git filter-branch 清理历史
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch path/to/file' \
--prune-empty --tag-name-filter cat -- --all


# 细节注意
# 1. 敏感信息泄露后应立即更换密码/密钥
# 2. 清理历史后需要强制推送
# 3. 通知团队成员重新克隆仓库

合并冲突频繁

  • 定期从主分支同步代码
  • 使用 git pull --rebase 保持线性历史
  • 分解大功能为小任务
  • 加强团队沟通避免多人修改同一文件

大文件导致仓库膨胀

1
2
3
4
5
6
# 查看大文件
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

# 使用 Git LFS 管理大文件
git lfs track "*.psd"
git lfs track "*.mp4"

报错处理

💗💗 git 报错信息SSL certificate problem: certificate has expired 解决方案

1
2
3
4
5
使用git时报错错误信息如下
unable to access 'https:/xxxxxxx.git/': SSL certificate problem: certificate has expired

修改配置忽略SSL证书验证
git config --global http.sslVerify false

学习资源

  • 视频
    • 尚硅谷5h打通Git全套教程丨2021最新IDEA版https://www.bilibili.com/video/BV1vy4y1s7k6
  • 书籍
    • Pro Git 书籍中文版https://git-scm.com/book/zh/v2
    • 猴子都能懂的 Git 入门https://backlog.com/git-tutorial/cn/
    • GitHub 漫游指南https://github.phodal.com/
  • 文档
    • Git 官方文档https://git-scm.com/doc
    • GitHub 官方文档https://docs.github.com/cn
  • 游戏
    • Learning Git Branchinghttps://learngitbranching.js.org/?locale=zh_CN
  • Git 可视化学习https://learngitbranching.js.org