1. Git基础概念与文件结构
1.1 基础概念
-
分布式版本控制系统(DVCS)
- 每个开发者拥有完整仓库副本,包括全部历史记录。
- 支持离线操作,仅在推送/拉取时需要网络。
-
快照机制
- Git记录每次文件快照,而不是单纯的差异。
- 每一次提交都可以回溯和恢复。
-
数据完整性
- 所有数据通过SHA-1哈希校验,防止篡改。
- SHA-1 可以将任意长度的数据(如文件内容、目录结构、提交信息等)转换为一个长度为 40 位的十六进制字符串。这种哈希值几乎不会重复(极低概率),因此可以唯一标识每一个对象(文件快照、提交、分支等)。
-
分支与合并
- 分支操作轻量,便于并行开发。
- 合并与变基让代码历史更清晰。
-
协作与审查
- 支持多人协作,代码审查(Pull Request/Merge Request)是业界标准流程。
1.2 文件结构
Git仓库中主要包含以下文件和目录:
1.2.1 工作区(Working Directory)
- 当前项目文件夹,开发者实际操作和编辑的地方。
- 文件状态分为:已修改(modified)、已暂存(staged)、已提交(committed)。
1.2.2 暂存区(Stage/Index)
- 一个临时区域,用于记录你准备提交到仓库的文件和更改
- 通过
git add命令将修改从工作区添加到暂存区。暂存区相当于“快照”,只有被添加到暂存区的内容才会被下一次提交记录。 - 位于
.git/index
2.3 本地仓库(Local Repository)
- 本地仓库是你电脑上的 Git 仓库,包含所有提交(commit)的历史记录,当你执行
git commit命令时,暂存区的内容会被保存到本地仓库,生成一个新的提交。 - 本地仓库记录了项目的所有版本和变更历史。
- 本地仓库位于
.git目录下,包含所有项目元数据和对象。
2.4 远程仓库(Remote Repository)
- 远程仓库是托管在服务器上的 Git 仓库,比如 GitHub、GitLab、Gitee、GitCode 等。
- 通过
git push和git pull与远程仓库同步数据。
2.5 HEAD
- HEAD 是 Git 的一个指针,指向当前本地仓库的最新提交(commit)。
- 它帮助你知道当前处于哪个分支、哪个版本。
- tips: 保存在
.git/HEAD中
2.6 分支(Branch)
- 分支允许你在主线之外进行开发,便于多人协作和功能开发。
- 一些客户端还存在虚拟分支的概念(GitButler)
2.7 总结
工作流程
graph LR
A[工作区] --> B[暂存区]
B --> C[本地仓库]
C --> D[远程仓库]
总结描述
| 区域 | 作用 | 典型操作 |
|---|---|---|
| 工作区 | 编辑和查看代码 | 编辑、修改文件 |
| 暂存区 | 临时保存待提交的更改 | git add |
| 本地仓库 | 保存所有提交的历史记录 | git commit |
| 远程仓库 | 团队共享和备份代码 | git push/pull |
2. Git安装/配置
安装
配置
- 用户信息
# --global 配置全局,不指定会配置为当前工作目录(--local) git config --global user.name "runoob" git config --global user.email test@runoob.com - 仓库配置(没什么卵用)
git config --local remote.origin.url "https://github.com/your/repo.git" - 文本编辑器(没什么用,默认是vi/vim,可以指定为vscode)
git config --global core.editor "code --wait" - 生成SSH秘钥
# 无特殊要求无脑回车即可 ssh-keygen -t rsa -b 4096 -C "yourname.email@example.com" - 查看配置
git config --list
3. Git基本命令详解(含场景与代码)
3.1 初始化与克隆
- 场景:新项目或获取已有项目代码
git init:初始化本地仓库git initgit clone:克隆远程仓库git clone https://github.com/user/repo.git
3.2 文件管理
-
git add:跟踪/添加文件到暂存区git add <file> git add . # 添加所有改动过的文件(注意不要把不需要管理的添加进去,如一些本地的配置文件) git add a.txt b.js c.java d.go # 添加多个文件 # 使用通配符添加 git add *.txt # 添加当前目录下所有txt后缀的文件 git add '**/*.js' # 添加当前目录以及子目录下所有的 `.js` 文件 git add test_* # 添加当前目录下所有以 `test_` 开头的文件 # 添加所有未跟踪文件 git add --all git add -A # 添加已修改文件(删除或修改的,不会添加新增的) git add -u # 交互式添加(只能对已被Git跟踪的文件的“部分修改”进行交互式暂存,而新建的文件(未被跟踪的)并不会被 `git add -p` 识别) # git add -p [filename]git add -p交互式选项选项 含义 y 暂存(stage)这块改动,即把这块修改加入到本次提交中 n 跳过(do not stage)这块改动,即这块修改不会加入到暂存区 q 退出(quit) ,停止当前操作 a 暂存所有剩余的块(stage all) ,把后面所有块都暂存 d 跳过所有剩余的块(do not stage all) ,后面所有块都不暂存 s 拆分(split)当前块为更小的块,便于更精细地选择哪些改动要暂存 e 编辑(edit)当前块,可以手动修改要暂存的内容(有点麻烦) ? 显示帮助信息,列出所有可用的选项 -
git status:查看当前状态
# 当前所在分支
# 工作区和暂存区的文件状态
# 哪些文件被修改但还未暂存
# 哪些文件已被暂存准备提交
# 是否有新建未跟踪(untracked)的文件
# 是否有文件被删除或重命名
git status [filename]
git rm:删除文件并从Git中移除
# 删除操作完成后需要git commit 提交
git rm [filename] # 会删除本地文件和暂存区
git rm test.1 test.2 #删除多个文件
git rm -r testfolder # 递归删除目录下的所有文件
git rm --cached [filename] # 将文件从暂存区删除,但本地文件不删除,比如.env和一些本地环境文件
# git rm配合.gitignore
# 如果某个文件**已经被 Git 追踪(已经 add 或 commit)** ,即使你后来把它写进 `.gitignore`,Git 依然会继续追踪它。
#此时,单靠 `.gitignore` 没法让 Git 忽略该文件。你需要用 `git rm --cached <文件/目录>` 将其从版本库中移除(但保留本地文件),这样后续 `.gitignore` 才能生效
3.3 提交与日志
3.3.1 git commit:提交暂存区到本地仓库
3.3.1.1 基础使用
# 标准提交
git add [filename]
git commit -m '提交说明' #如果不添加-m 就会打开默认编辑器让输入(vi/vim/上面指定的vscode编辑器)
# 提交所有已暂存的更改 -a会自动把所有已跟踪(tracked)文件的更改添加到暂存区并提交,不会添加新文件(未被add 的新文件不会被提交)
git commit -a -m "直接提交所有修改"
# 修正上一次提交说明
git commit --amend -m "新的提交说明"
3.3.1.2 典型场景
- 新增文件:必须先
git add,否则git commit -a不会提交新文件。 - 修改文件:如果都是已跟踪文件,可直接
git commit -a。
3.3.1.3 提交规范:约定式提交
-
格式
<类型>[可选范围]: <描述> # 类型:必填,标明本次提交的变更类别 # 范围:可选,说明影响的模块或文件 # 描述:必填,对本次变更的简要说明 -
类型说明
类型 说明 feat 新功能(feature) fix 修复 bug docs 文档变更 style 代码格式(不影响逻辑) refactor 重构(不影响功能的代码变动) perf 性能优化 test 增加或修改测试 chore 其他杂项(构建、工具等) build 构建相关变更 ci CI/CD 配置变更 -
示例
- 单行提交
feat: 新增用户注册接口 fix: 修复订单列表分页错误 docs: 更新API使用说明文档 style: 格式化代码,统一缩进 refactor: 优化数据处理流程 perf: 提升首页加载速度 test: 增加订单模块单元测试 chore: 更新依赖包版本 build: 配置webpack打包 ci: 优化GitHub Actions流程- 带范围提交
feat(user): 新增用户注册接口 fix(order): 修复订单列表分页错误 docs(api): 更新API使用说明文档- 多行提交:第一行为简要说明,后面可以空一行补充详细内容:
fix(order): 修复订单列表分页错误 原因:分页参数校验不严导致数据重复。 解决方案:增加参数校验逻辑,优化分页处理。
3.3.2 git log:查看提交历史(可视化工具更好用)
基础使用:查看提交历史记录的命令。它可以帮助你追踪项目的变更、查找具体提交、了解每次提交的作者、时间和说明
3.3.2.1: 基础使用
git log
# 显示简洁一行(oneline)
git log --oneline --graph
# 指定展示数量
git log -n 5
# 显示提交内容差异
git log -p
# 按作者筛选
git log --author="张三"
# 按文件筛选
git log [filenmae]
3.4 比较与回退(对比变更、撤销操作)
用于比较文件差异的命令,可以帮助你查看代码的修改内容、未提交的变更、不同分支或提交之间的差异。 主要用于代码审查:查看本地未提交的变更,回溯历史:对比不同提交或分支的代码差异,协作开发:分析合并冲突前后的具体修改。
3.4.1 git diff:查看未暂存或已暂存的差异
3.4.1.1 基础使用
# 显示工作区与暂存区之间的差异(还没有 `git add` 的修改内容)。
git diff
# 查看已暂存但未提交的更改
git diff --cached
# 比较两个提交之间的差异
git diff <commit1> <commit2>
# 比较当前分支与其他分支差异
git diff master develop
# 比较某个文件的差异
git diff [文件名]
3.4.1.2 输出内容说明
- 开头表示被删除的内容
+ 开头表示新增的内容
3.4.1.3 常用组合
# 强制彩色输出,便于阅读(使用warp终端,不指定也是彩色,和终端有关?)
git diff --color
# 只显示被修改的文件名。
git diff --name-only
# 按单词显示差异,适合文本文件
git diff --word-diff
3.4.2 git checkout:恢复文件或切换分支
用于切换分支、还原文件、回退到指定提交的命令。它是日常开发中非常常用的操作工具
3.4.2.1 基础使用
git checkout <branch>
# 新建并切换分支
git checkout -b <branch>
# 回退到某个提交(detached HEAD 游离HEAD-原本指向分支,执行后指向某次提交)
git checkout <commit_id>
# 恢复文件到某个版本
git checkout <commit_id> -- <filenmae>
# 丢弃工作区的修改
git checkout -- <filename>
3.4.2.2 使用场景
- 临时查看历史版本
git checkout <commit_id>
- 基于历史提交新建分支 比如发现某个历史提交是个稳定版本,想在此基础上开发新功能
git checkout <commit_id>
git checkout -b <new_branch_name>
- 调试、定位历史bug
git checkout 3e2f7a1
# 调试代码,再次条件下修改代码 后续切换回主分支回直接丢弃修改
- 撤销某个文件的部分修改
git checkout <commit_id> -- <filename>
- 局部回退 只回退某个文件,不影响其他文件
git checkout <commit_id> -- <filename>
git add <filename>
git commit -m '回退xx文件到历史版本'
- 对比
| 命令 | 影响范围 | 典型用途 | 风险/注意事项 |
|---|---|---|---|
| git checkout <commit_id> | 全部文件 | 回溯历史、调试、基于历史新建分支 | 游离HEAD,提交容易丢失 |
| git checkout <commit_id> -- <filename> | 单个文件 | 局部还原、撤销误操作、参考历史内容 | 只影响指定文件,需 add/commitHEAD,提交容易丢失 |
3.4.3 git switch
Git 2.23 及以上版本新增的命令,用于切换分支或创建新分支。它是对 git checkout 的语义化拆分,使操作更直观、更安全。
3.4.3.1 基础使用
# 切换到已有分支
git switch <branch> # 等价于 git checkout <branch>
# 新建并切换分支
git switch -c <new_branch> #等价于git checkout -b <new_branch>
# 强制切换(丢弃未提交的更改)
git switch --force <branch> # 如果工作区有未提交的修改,强制切换会丢弃这些更改。
# ### 切换到远程分支(自动创建本地分支)
git switch origin/dev
tip:未提交指的是没有git commit的内容(只要还没到“本地仓库”,都属于“未提交内容”。)
工作区(你编辑的文件)
│
git add
│
暂存区(stage/index)
│
git commit
│
本地仓库(repository)
3.4.4 git restore
Git 2.23+ 新增的命令,用于还原文件内容,替代部分 git checkout 的功能。它让文件恢复操作更直观、更安全
3.4.4.1 基础使用
# 丢弃工作区的修改(恢复到暂存区状态)
git restore <filename> # 只影响工作区,未 add 的修改会被丢弃,文件恢复到暂存区的内容
# 丢弃暂存区的修改(恢复到工作区状态)
git restore --staged <文件名> # 只影响暂存区,已 add 的内容会被移出暂存区,恢复到工作区当前状态。
# 恢复文件到某个历史提交
git restore --source <commit_id> <filename> # 把文件恢复到指定历史提交的内容,适合局部回退,相当于 git checkout <commit_id> -- <filename>
3.4.4.2 常见场景
- 你编辑了文件但发现有误,不想保留这些修改
git restore app.js - 不小心
git add了某个文件,想撤回到未暂存状态git restore --staged app.js - 局部回退到历史版本
git restore --source <commit_id> app.js
3.4.5 git reset
主要用于重置 HEAD 的指向、管理暂存区和工作区的内容。它可以用来撤销提交、撤销暂存、甚至丢弃本地修改。
根据参数不同,git reset 的影响范围也不同,操作需谨慎
3.4.5.1 基础使用
- 撤销暂存
git reset <filename>
- 作用:把文件从暂存区移回工作区,但不影响文件内容。
- 场景:你用
git add把文件加到了暂存区,但还不想提交。
- 回退最近的提交,但保留更改(soft)
git reset --soft HEAD^
- 作用:撤销最近一次提交,保留所有修改和暂存区内容。
- 场景:想修改上一次提交说明或补充内容后重新提交。
- 回退最近的提交,并取消暂存(mixed,默认)
git reset --mixed HEAD^ # 或简写为 git reset HEAD^
- 作用:撤销最近一次提交,保留所有修改,但移出暂存区。
- 场景:想撤销提交,并重新选择要提交的文件。
- 回退并丢弃本地修改(hard)
git reset --hard HEAD^
- 作用:撤销最近一次提交,所有本地修改和暂存内容都会被丢弃,工作区回到上一次提交的状态。
- 场景:想彻底回退到某个历史状态,放弃所有本地变更。
- 回退到任意历史提交
git reset --hard <commit_id>
- 作用:将分支指向某个历史 commit,工作区和暂存区都恢复到该状态。
3.4.6 git revert
*撤销(反向)某次提交的命令。它通过生成一个新的“反向提交”,来抵消指定提交的内容。与 git reset 不同,git revert 不会重写历史,非常适合多人协作和已推送到远程的分支。 *
3.4.6.1 基础使用
- 撤销单个提交
git revert <commit_id>
- 撤销多个提交
git revert <commit_id1> <commit_id2> ...
- 撤销一段连续的提交
git revert <old_commit_id>^..<new_commit_id>
3.4.6.2 典型场景
反向提交: 根据当次的改动,创建一次新的提交,内容是反转当次的操作,让文件恢复成当次提交之前的状态
- 已推送到远程的分支:撤销错误提交,又不影响他人历史。
- 多人协作:避免重写历史,安全撤销。
- 修复 bug:快速回退某次有问题的提交。
3.4.6.3 与git reset 区别
| 命令 | 是否重写历史 | 是否适合协作 | 撤销方式 | 备注 |
|---|---|---|---|---|
| git reset | 是 | 否 | 回退到历史状态 | 会改变提交链(本地历史),不推荐在已推送分支上用 |
| git revert | 否 | 是 | 生成反向提交 | 生成新的撤销提交,历史不会断裂,适合所有场景 |
3.4.7 git rebase 不推荐使用?
用于变基(rebase)操作的命令,主要作用是将当前分支的提交“移动”到另一个基底(通常是目标分支的最新提交之后),从而整理提交历史、保持提交链线性。它是代码协作、合并、压缩提交时非常重要的工具。
3.4.7.1 基础使用
# 把当前分支上的所有新提交,移动到 `<目标分支>` 的最新提交之后。
git rebase <目标分支>
# 交互式 rebase(整理、压缩提交)
git reabse -i <基底>
3.4.7.2 使用场景
- 本地开开发后,调试过程中有一些问题,需要修改,导致多次commit(实际上是开发同一功能),需要在推送到远程仓库时合并为一次
git log --oneline # 查询提交日志,确定需要合并的记录条数git rebase -i HEAD~3我这里是合并最近三次提交,会打开默认的编辑器,我这里是vscode- 修改内容,保存退出
- 会打开一个新的编辑器,在这里编辑提交信息
- 修改提交内容,保存退出
- 命令行显示
git log --oneline查看日志
4. Git进阶命令与功能(含场景与代码)
4.1 分支管理
-
场景:多人协作、并行开发
-
git branch git switch:查看、创建、删除分支git branch # 查看分支 git branch -a #查看本地和远程所有分支 git swicth git branch <name> # 创建分支 git branch -b <name> # 创建并切换 git switch -c <name> git branch -d <name> # 删除分支 git branch -m <新分支名> # 重命名分支 git branch -v # 显示每个分支最后一次提交的简要信息 -
git checkout -b <name>:创建并切换到新分支git checkout -b feature/login -
git merge <name>:合并分支git merge feature/login -
git rebase <name>:变基操作,整理提交历史git rebase main
4.2 远程仓库操作
-
场景:团队协作、代码共享
-
git remote:管理远程仓库git remote -v git remote add origin https://github.com/user/repo.git -
git fetch:获取远程更新但不合并git fetch origin -
git pull:获取并合并远程更新git pull origin main -
git push:推送本地提交到远程仓库git push origin main
4.3 标签管理
-
场景:发布版本、标记重要节点
-
git tag:查看、创建、删除标签git tag # 查看标签 git tag v1.0 # 创建标签 git tag -d v1.0 # 删除标签 git push origin v1.0 # 推送标签到远程
4.4 git stash 临时保存与恢复
用于临时保存当前工作区和暂存区的修改的命令。它非常适合在开发过程中需要切换分支、拉取代码、但又不想提交或丢弃当前修改时使用。 通过 git stash,你的修改会被“藏起来”,工作区恢复到干净状态,等你需要时再恢复。
-
git stash:保存当前工作区变更git stash # 保存 git stash pop # 恢复最近一次 stash 的内容,并将其从 stash 列表中删除。 git stash apply # 恢复最近一次内容,但不删除该stash git stash list # 查看 git stash apply stash@{1} # 恢复指定的stash git stash drop stash@{1} # 删除指定的stash git stash clear # 删除所有stash git stash --keep-index #只保存工作区修改,不保存暂存区(git add内容) git stash -u # 保存所有已跟踪文件的修改、暂存区内容,以及未跟踪文件。
4.5 reflog与历史恢复
-
场景:恢复误操作、找回丢失提交
-
git reflog:查看所有操作历史,包括丢失的commitgit reflog git reset --hard <commit_id> # 找到你需要恢复的 commit id 或 HEAD@{n}
4.6 git filter-branch
Git 提供的历史重写工具,可以批量修改、删除、替换仓库的所有提交
4.6.1. 基础使用
git filter-branch [选项] <过滤器> -- [分支范围]
4.6.2 常用过滤器
--index-filter- 操作暂存区(速度快,适合删除文件)
--tree-filter- 操作整个工作区(慢,适合复杂脚本)
--env-filter- 操作环境变量(如作者信息)
4.6.3 实际场景
-
删除历史大文件
# --force:强制执行(覆盖之前 filter-branch 操作)
# --index-filter:只操作暂存区,速度快
# git rm --cached --ignore-unmatch bigfile.zip 从每次提交中删除该文件
# --ignore-unmatch 如果你用 `git rm <文件名>` 删除一个不存在于当前提交的文件,Git 会报错,此参数可以忽略这样的情况,继续执行
# --prune-empty:清理空提交
# --tag-name-filter cat:保留标签名
# --all:遍历所有分支和标签
# 第一步
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch 文件名' --prune-empty --tag-name-filter cat -- --all
# 第二步:清理原始应用和垃圾对象
rm -rf .git/refs/original/ # 删除 filter-branch 操作产生的原始引用
git reflog expire --expire=now --all # 让所有引用日志立即过期
git gc --prune=now --aggressive # 垃圾回收,彻底清除无用对象,缩小仓库体积
# --force:因为历史被重写,必须强制推送,覆盖远端所有分支和标签。
# --all:推送所有分支
# --tags:推送所有标签
# 第三步:推送到远程仓库
git push origin --force --all
git push origin --force --tags
# 第四步 通知所有成员重新clone仓库,否则会有冲突和仓库文件残留
# 第五步 检查仓库体积(.git目录应该明显变小)
5. 其他功能与应用场景
5.1 忽略文件
-
场景:不希望某些文件被跟踪
-
.gitignore:在项目根目录创建.gitignore文件,写入需要忽略的文件/目录名node_modules/ *.log .env
5.2 常见协作流程
-
场景:多人开发、代码审查
- 克隆仓库:
git clone - 创建分支开发:
git checkout -b feature/xxx - 定期拉取更新:
git pull - 提交并推送:
git add、git commit、git push - 提交Pull Request(PR):在平台(如GitHub)发起代码审查和合并
- 克隆仓库: