Git 是一种分布式版本的版本控制系统,2019 年记录的太过肤浅,2022 年打算重新整理一下。
2019 年整理的 Git使用技巧 有点粗糙,那时候也不懂得找官方文档,其实最好的学习方式,还是直接跟着官方学,这是最好的。
那时候,我自以为我已经把 Git 玩花了,其实不然,Git 使用门槛低,但上限却是出奇的高,由此打算重新整理一份实用的,当然了,也还是偏向基础的。
我这次是有备而来,我准备了官方文档、官方电子版的书、京东购买的书。并且汲取了其中 60% 对我有用的价值吧。


一、基础概念与概况
1.1 Git 与 SVN 的区别
SVN:集中式版本控制系统,所有历史记录都存储在中央服务器,提交和更新都依赖中央服务器。
Git:分布式版本控制系统,每个开发者的工作目录都可以是一个完整本地仓库,可以独立离线工作。支持同步到远程仓库。
1.2 三大区域
Git 仓库下,分为工作区域(Working Directory)、暂存区域(Staging Area)、存储库(Repository)。

add 是由工作区域提交到暂存区域。
commit 是由暂存区域提交到存储库。
1.3 分支的本质
分支只是指向某个 commit 的地址,就跟 Java 对象引用地址一样,我把对象清空,只是清空了指向,并没有将开辟的空间回收(回收那就是 GC 的事了)。
所以,分支(包括后面的标签),都是随意删除的,我甚至删一个 aaa 分支,再建一个 aaa 分支,都互不影响。
演示一下删除分支,我从 master 检出一个分支,并 commit 后,如图。

此时如果我把分支 cat 干掉,就变成了如下图。

由此也可知,分支是可以恢复的,只要你记住了 commit 地址即可,因为 commit 存在啊。
1.4 标签与分支的区别
标签与分支作用一样,只是起到指向的作用。标签与分支被删除都不会影响到实际的数据。
两者的作用是,分支会随着 commit 移动,但标签不会。
分支 = 会移动的标签,留下来的是标签,跟着走的是分支。
二、常用命令
2.1 仓库基础操作
2.1.1 初始化与文件管控
初始化仓库
| |
把文件交给 Git 暂存区
| |
如果我后悔提交到暂存区,可以通过如下命令撤回。
git restore --staged *
将暂存区内容,提交到存储库。
| |
如果觉得,先 git add -A,再 git commit,太麻烦。
可以 git commit -a -m "提交描述" 一步到位。
但这个 -a,只对于已跟踪的文件有效,新增的是无效的。
查看差异
| |
2.1.2 查看日志
通过如下命令,可以查看具体的 commit。
| |

2.1.3 修补最新 commit
如果 commit 之后,发现漏掉了某个文件,或者需要重新修改提交。
可以将修改暂存,然后执行如下命令,更新最新提交。
| |
当你在修补最后的提交时,与其说是修复旧提交,倒不如说是完全用一个新的提交替换旧的提交,理解这一点非常重要。从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。
修补提交最明显的价值是可以稍微改进你最后的提交,而不会让"啊,忘了添加一个文件"或者"小修补,修正笔误"这种提交信息弄乱你的仓库历史。
如果是远程仓库,本地 amend 之后,强制推送更新即可。搜索
--force后面有记录
2.1.4 暂存区贮藏(stash)
如果我已经修改了代码,但是此时又未完成,不能提交,而此时比如我要切换分支。
可以使用 stash,将修改 add 到暂存区,然后 stash 贮藏起来。
一定要存储到暂存区,否则 stash 也不会存储。
| |
查看贮藏列表
| |
查看修改内容
| |
恢复并删除贮藏
| |
恢复并保留贮藏
| |
删除贮藏
| |
清空贮藏
| |
2.2 远程仓库
以下示例是使用 http,ssh 个人习惯上感觉过于麻烦。
2.2.1 连接远程仓库
查看远程仓库连接信息
| |

与远程仓库建立远程连接
| |
git remote 主要进行与远端 Git 有关的操作。
origin 指的是远端 Git 的一个别名,而且默认就是 origin。
add、remove 可以删除本地连接的远端 Git。
从远程仓库获取更新
| |
fetch 与 pull 的区别:fetch 只下载远程更新到本地,不自动合并;pull = fetch + merge。 推荐先 fetch 查看差异,确认无误后再手动 merge,更安全。
2.2.2 push / pull
从远程分支拉取
| |
将本地分支推送到远程分支
| |
像使用 GitHub 时,会推荐 git push -u origin master。
-u 就是 upstream,此处可以理解成自动跟踪 master 分支。
也就是说,如果下次,我还是想推送到 master 分支,只需要执行 git push 即可。
强制推送
| |
--force会无条件覆盖远程分支,如果他人已经推送了新提交,这些提交会丢失。--force-with-lease会先检查远程分支是否与本地预期一致,只有在没有他人推送的情况下才会覆盖,更安全。 推荐使用--force-with-lease代替--force。
2.3 分支与标签
2.3.1 分支:新增 / 重命名 / 删除 / 切换 / 跟踪
查看分支列表
| |
在当前分支内容上,新开辟一个分支
| |
切换分支
| |
重命名分支
| |

删除分支
| |
因为对于 Git 来说,分支本身也是指向的 commit,所以 checkout 也可以直接指向 commit。
标签同理,标签也是指向 commit,实际切换的还是 commit。
| |

将修改后的某个文件,回滚到指定的分支或者 commitId。
| |
跟踪远端分支
| |

一开始我跟踪的是 origin/h2-diy-api 分支,所以会提示比远程分支多修改了内容,尽快提交。
我重新跟踪正确分支,问题解决。在 Git 中,跟踪(track)是指建立一个分支与另一个分支之间的关联关系,使得它们可以相互追踪对方的提交记录。跟踪的作用是方便在推送和拉取代码时进行操作,并提供了一种简洁和直观的方式来管理分支之间的关系。
2.3.2 分支:合并(merge)
比如我在 master 分支,此时我要将 dev 的分支合并过来。
| |
合并常见三种情况:
- Fast-forward:快进合并,自动处理
- Recursive strategy:递归合并,自动处理
- CONFLICT (content):冲突合并,手动处理
像 Fast-forward,如下图,此时 master 分支要合并 hotfix,是没有任何冲突的,master 只需要指向前方的地址值 C4 即可。这种合并叫做 Fast-forward。

像 recursive strategy,如下图,一般是因为两个分支有共同的祖先,但是各自分支上进行了更改,并没有发生冲突。

像 CONFLICT (content),如下图,一般是由于多人同时改了同一个文件,甚至同一行。git 并不会提交 commit,而是将冲突的内容保存在暂存区,等人工去纠正后再 commit。
人工处理冲突,可以通过三向合并工具。ide 基本都有内置该功能,比如 idea 的三向合并工具如图。在 cherry-pick、merge、stash 等发生冲突时,均会触发三向合并。

[Git - git-merge Documentation](https://git-scm.com/docs/git-merge#:~:text=With --no-commit perform,merges with --no-commit)
2.3.3 分支:复制 commit(cherry-pick)
cherry-pick,顾名思义,精心挑选。
与 merge 不同,它只合并指定的 commit。
| |
git cherry-pick 命令用法详解 - CSDN 博客
2.3.4 分支:回退(reset)
将当前分支的内容回退到指定的分支,指定分支之后的都被删除。
| |
2.3.5 分支:变基(rebase)
我的 Git 提交记录是 A -> B -> C -> D,我现在想要在 A 里面添加一个文件,并且不影响 git 记录。如下操作。
| |
2.3.6 标签:新增 / 删除 / 切换 / 推送
为 commit 为 51d54ff 的创建标签 ava。
| |
切换标签
| |
如果我想再切换到最新的 commit,只需要切换分支即可。
因为分支就是标识了最新的 commit。
创建了标签推送到远程分支
| |
删除本地标签 ava
| |
删除远程标签
| |
2.4 历史重写工具(git-filter-repo)
git-filter-repo 是一个 Git 仓库历史重写工具,它可以对 Git 仓库的提交历史、文件、作者信息等做大规模修改。它是官方推荐替代 git filter-branch 的工具,比 filter-branch 快、稳定、易用,而且更安全。
安装了 python 环境后(推荐使用 pyenv),通过 pip 安装
| |
2.4.1 替换 commit message
保持 git 元信息,替换 commit message。
| |
其中 a.txt 的内容结构如下:
| |
2.4.2 替换 commit 的某个文件
保持 git 元信息,直接替换文件内容。适合只改动过一次的文件。
| |
其中 a.txt 的内容结构如下:
| |
2.4.3 重建历史并删除某个文件夹
保持历史结构,在所有提交中,删除某个文件夹的内容。
| |
三、提交规范与约定
3.1 Conventional Commits 规范
参考约定式提交
| 类型 | 说明 | 示例场景 |
|---|---|---|
| feat | 新增功能 | feat: 添加用户注册模块 |
| fix | 修复缺陷 | fix: 解决登录页面崩溃问题 |
| docs | 文档变更 | docs: 更新 API 使用说明 |
| style | 代码样式调整(不改变逻辑) | style: 修正缩进、删除多余空行 |
| refactor | 代码重构(既非修复也非新增功能) | refactor: 优化数据验证逻辑结构 |
| perf | 性能优化 | perf: 减少数据库查询次数 |
| test | 测试相关变更 | test: 添加用户登录单元测试 |
| chore | 构建/依赖维护 | chore: 更新 webpack 配置、升级 npm 包 |
| ci | 持续集成配置变更 | ci: 调整 GitHub Actions 流程 |
| build | 影响构建系统的变更 | build: 修改 Dockerfile 配置 |
| revert | 回滚之前的提交 | revert: 撤销某次错误合并 |
