Git | 青训营笔记

90 阅读8分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

名词解释:

image-20230119110358216

Git是什么

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

版本控制工具举例:

image-20230119110844606

本地版本控制

基本原理:本地保存所有变更的补丁集,可以理解成就是所有的Diff,通过这些补丁,可以计算出每个版本的文件内容

缺点:只能本地使用,不能团队协作

集中式版本控制

基本原理:

  • 提供一个远程服务保存文件,所有用户的提交到该服务器中
  • 增量保存每次提交的Diff,如果提交的增量中和远端的现存的文件存在冲突,则需要本地提前解决冲突

优点:学习简单,容易操作。二进制文件,对大文件支持更友好

缺点:

  • 本地不存储版本控制,所有提交都只能联上服务器后才能提交
  • 分支的支持不友好,对于大型项目团队合作比较困难
  • 用户本地不保存所有版本的代码,如果服务端故障容易导致历史版本的丢失

分布式版本控制

基本原理:

  • 每个库都有完整的提交历史,可以直接在本地进行代码提交
  • 每次提交记录的都是完整的文件快照,而不是记录增量
  • 通过Push等操作完成和远端代码的同步

优点:

  • 分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体
  • 分支管理功能强大,方便团队合作,多人协同开发
  • 校验和机制保证完整性,一般只添加数据,很少执行删除操作,不容易导致代码丢失

缺点:命令多,学习成本高。对大文件支持不是特别好(git-lfs工具可以弥补)

Git的基本使用方式

配置

项目初始化

mkdir git-demo
cd git demo
git init

其他参数:

--initial-branch    初始化的分支
--bare  创建一个裸仓库(纯Git目录,没有工作目录)
--template      可以通过模板来创建预先构建好的自定义git目录

.git目录:

image-20230119112939897

工作区:本地

暂存区:git add、commit上去的

image-20230119113454021

Git Config

不同级别的配置:全局(--global) > 系统(system) > 本地(local)

查询全局配置:

git config --global

每个级别的配置可能会重复,但是低级别的配置会覆盖高级别的配置

常见的Git配置

用户名配置:

git config --global user.name "username"
git config --global user.email "email"

Instead of 配置

git config --global url.git@github.com:.insteadOf https://github.com/

Git 命令别名配置

git config --global alias.cin "commit --amend --no-edit"

Git Remote

Remote 是本地和远端的关联信息

查看Remote:

git remote -v

添加Remote

git remote add origin_ssh git@github.com:git/git.git
git remote add origin_http https://github.com/git/git.git

再次查看:

image-20230119114629462

同一个Origin设置不同的Push和Fetch URL,比如从开源仓库拉取代码,再Push到自己的仓库

git remote add origin git@github.com:git/git.git
git remote set-url --add --push origin git@github.com:my_repo/git.git

image-20230119115255980

image-20230119115325903

HTTP Remote

URL:github.com/git/git.git

免密配置:

image-20230119115514692

不推荐HTTP方式连接,不安全

SSH Remote

URL:git@github.com:git/git.git

免密配置:

image-20230119115709446

提交代码

Git add

git add .

image-20230119120019454

在objects目录下存放着提交的记录,可以使用命令查看

image-20230119120123314

git cat-file -p 95d09f2b10159347eece71399a7e2e907ea3df4f

image-20230119120215772

Git Commit

git commit -m "readme.md"

查询,objects目录多了两个文件:

image-20230119120449165

image-20230119120525024

Objects

commit / tree / blob 在git里面统一称为Object,除此之外还有个tag类型的object

Blob : 存储文件的内容

Tree:存储文件的目录信息

Commit:存储提交信息,一个Commit可以对应唯一版本的代码

Tag:附注tag,可以给Tag提供一些额外的信息

三个信息的串联方式:

  1. 通过Commit寻找到Tree信息,每个Commit都会存储对应的Tree ID
  2. 通过Tree存储的信息,找到对应的文件目录树的信息
  3. 从Tree中获得blob的ID,通过Blob ID获取对应的文件内容

image-20230119121000085

Refs

Refs文件存储对应的Commit ID,因此把ref当作指针,指向对应的Commit来表示当前Ref对应的版本

image-20230119121441420

Branch:

git checkout -b  创建分支

一般用于开发阶段,是可以不断添加commit进行迭代的

Tag:

一般表示一个稳定版本,指向的Commit一般不会变更

git tag

创建附注标签:

git tag -a v0.0.2 -m "add feature"

查看:

cat .git/refs/tags/v0.0.2

image-20230119133119739

真正指向的commit Object是什么,然后还会带一些附注信息,谁打的标签,内容是什么

历史版本

追溯历史版本:

git log

修改历史版本:

修改一次最近的commit信息,修改之后commit id 会变

但是修改之后会新增Commit Object,之前的Commit Object并没有删除,这个Commit Object没有指针指向它,称为悬空Commit

git commit --amend

通过git rebase -i HEAD~3可以实现对最近三个commit的修改

  • 合并commit
  • 修改具体的commit message
  • 删除某个commit

删除所有提交中的某个文件或者全局修改邮箱地址等操作:

filter --branch

Git GC

通过git gc 命令删除一些不需要的Object

image-20230119135635866

Git视图

image-20230119135820056

远端同步

Clone: 拉取完整的仓库到本地目录,可以指定分支、深度

Fetch: 将远端某些分支最新代码拉渠道本地,不会执行merge操作,会修改refs/remote 内的分支信息,如果需要和本地代码合并需要手动操作

Pull: 拉取远端某分支,并和本地代码进行合并,操作等同于 git fetch + git merge,也可以git pull --rebase完成git fetch + git rebase操作

Git Push

git push origin master

image-20230119140155745

Git研发流程

不同的工作流:

image-20230119140500520

集中式工作流:

  1. 获取远端master分支
  2. 直接在master分支完成修改
  3. 提交前拉取最新的master代码和本地进行代码合并(使用rebase),如果有冲突需要解决冲突
  4. 提交本地代码到master

image-20230119140655039

分支管理工作流

image-20230119140913344

GitHub工作流: 只有一个主干分支,基于Pull Request往主干分支中提交代码

团队合作方式:

  • owner创建好仓库以后,其他用户通过Fork的方式来创建仓库,并在Fork的仓库上进行开发(开源项目)
  • owner创建好仓库以后,统一给团队内成员分配权限,直接在一个仓库内进行开发

GitLab工作流:

原则:upstream first上游优先,只有上有分支采纳的代码才可以进入到下游分支,一般上游分支就是master

代码合并

Fast-Forward:不会产生一个merge节点,合并后会保持一个线性历史,如果target分支有了更新,则需要通过rebase操作更新source branch后才可以进入

git checkout -b dev
git add .
git commit -m "test"
git checkout main
git merge -dev -ff-only

git log 以后查看没有merge节点

image-20230119144333775

Three-Way Merge 三方合并,会产生新的merge节点

get merge dev --no-ff

image-20230119144619351

选择合适的工作流: 小型团队,Github工作流就行

  • 少量多次
  • 提交Pull Request后最少需要保证有CR后再合入
  • 主干分支尽量保持整洁,使用first-forward合入方式,合入前 rebase