这是我参与「第三届青训营 -后端场」笔记创作活动的的第10篇笔记. 课前资料: juejin.cn/post/709818…
Git是什么
版本控制
-
是什么? 一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
-
为什么需要? 更好的关注变更,了解改动,方便及时检查。能随时切换不同版本,回滚误删误改的问题代码。
本地版本控制
- 最初的方式:本地复制文件夹。通过不同文件名区分版本
- 解决方案:如RCS
- 基本原理:本地保存所有变更的补丁集(Diff,通过补丁计算每个版本的实际的文件内容
集中版本控制(如SVN
- 基本原理:
- 提供远端服务保存文件,所有用户提交到远程服务器。
- 增量保存每次提交的Diff,如果提交的增量与远端现存文件冲突,需要本地解决冲突
- 优点:支持二进制文件,对大文件友好
- 缺点:
- 本地不存储版本管理的概念,所有的提交需要连接远程服务器
- 分支上支持不友好,对于团队合作较困难
- 用户本地不保存所有版本的代码,服务端故障会导致历史版本丢失
分布式版本控制(如Git
- 基本原理
- 每个库存储完整的提交历史,可以直接在本地进行代码提交
- 每次提交的是完整的文件快照,而不是记录增量
- 通过Push等操作完成与远端代码的同步
- 优点:
- 分布式开发,每个库都是完整的提交历史。支持本地提交,强调个体
- 分支管理强大,方便团队合作
- 校验和机制保证完整性,只添加数据很少进行删除,不容易导致代码丢失
- 缺点:
- 对于大文件支持不友好(可以使用git-lfs文件
基本使用
对于git init命令的其他参数
- --initial-branch 指定其他分支
- --bare 创建一个裸仓库,不会允许添加文件,一般用该命令行创建服务器仓库
- --template 可以通过指定模板来创建预先构件好的自定义git目录
- HEAD 存储当前指向的分支
- objects 存储文件信息,存放所有git对象
- ref 存储分支信息
- hooks .sample是一些例子,不会执行
通过在本地(工作区)改动代码,使用git add 将本地改动代码提交到暂存区,通过git commit 将代码提交到git目录。
Git Config
每个级别的配置可能重复,但是低级别的配置会覆盖高级别的配置
- --global
- --system
- --local
常见的git配置
- 用户名配置
- Instead of 配置
- Git命令别名配置
Git Remote
- git remote -v 查询远程信息
- git remote add 增加远程
- origin_ssh
- origin_http
- 可以通过配置不同源来配置不同平台
此时remote配置发生变化。
相应的,我们删除配置文件中的远程配置,也会删除对应的远程信息。
- 如何在同一个Origin设置不同的Push和FetchURL?
git remote set-url --add --push origin
Http Remote
使用http协议。推荐使用ssh协议。
SSH Remote
通过公私钥机制,将生成的公钥存放在服务端,从而实现免密访问。
目前的key类型有: dsa rsa ecdsa ed25519
Git Add
新建一个文件,通过git add从工作区提交到暂存区。
blob
第一个数 100644 是对象的文件属性的八进制表示。3b18e是hello world的blob的对象名。readme.md是与该blob关联的名字
散列
为readme.md创建一个对象时,Git不关心readme.md的文件名,只关心文件内容:表示hello world的12个字节和换行符。Git为blob执行一些操作,计算它的SHA1散列值,把散列值的十六进制作为文件名放入对象库中。
散列值是3b18e512dba79e4c8300dd08aeb37f8e728b8dad。160位的SHA1散列值对应20个字节,需要40个字节的16进制表示,因此内容另存为.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad.
可以使用散列值把hello world从对象库中提取。
文件和树
helloworld存在对象库,也可以通过文件名找到文件git。
git通过目录树的对象跟踪文件的对象名。git add时,git会给添加的每个文件的内容创建一个对象,但不会马上创建对象。而是更新索引。索引位于.git/index,跟踪文件的路径名和相应的blob。每次执行命令,git会使用新的路径名和blob来更新索引。
Refs
refs的内容就是对应的commitId.ref当做指针,指向对应的commit来表示当前ref对应的版本。
refs/heads前缀表示的是分支。refs/tags前缀表示的是标签。
- Tag表示一个稳定版本,指向的commit不会变更。但是branch是可以不断添加commit进行迭代。
(base) main $ git tag v0.0.1
(base) main $ cat .git/refs/tags/v0.0.1
b8220eb7916dcafe5ccd6e41b13c0994d4b4d3ce
- Annotation Tag: 也可以使用git tag命令创建一个带有提交信息、带附注且未签名的标签
(base) main $ git tag -a v0.0.2 -m "add feature1"
(base) main $ cat .git/refs/tags/v0.0.2
225ce37cf5ba07ccf801b113c55125e9e5f16676
(base) main $ git cat-file -p 225ce37cf5ba07ccf801b113c55125e9e5f16676
//真正指向的提交对象
object b8220eb7916dcafe5ccd6e41b13c0994d4b4d3ce
type commit
tag v0.0.2
//作者消息
tagger 李一 <1280144091@qq.com> 1653382520 +0800
add feature1
使用git cat-file -p 查看标签对象。
追溯版本代码
- 可以通过ref指向的commit获取唯一的版本代码
- 通过commit存储的parent commit字段,通过commit的串联获取历史版本代码
(base) ⚙ main $ git cat-file -p cdd647f24a2c810bb913d262cce9ff59e7081bc3
tree 386eb799bbfd0826f510b6587c5afaae2a962279
parent b8220eb7916dcafe5ccd6e41b13c0994d4b4d3ce
author 李一 <1280144091@qq.com> 1653383110 +0800
committer 李一 <1280144091@qq.com> 1653383110 +0800
根据当前的SHA1获取当前版本,根据parent获取之前的版本。
更改代码后新增三个SHA1 tree object、blob object、commit object ### 修改历史版本
commit --amend
修改后commidId会改变
会新增commit object
rebase
git rebase -i HEAD~3
- 合并commit
- 修改具体的commit message
- 修改某个commit
filter --branch
指定删除所有提交中的某个文件或全局修改邮箱地址等
Objects
新增的
悬空的
git fsck --lost-found
git GC
删除不需要的object,以及对object打包压缩来减少仓库体积。
- Reflog 记录操作日志,防止误操作后数据丢失。需要手动设置过期
- 指定时间 git gc --prune=<时间>
(base) main git reflog expire --expire=now --all
(base) main git gc --prune=now
枚举对象中: 7, 完成.
对象计数中: 100% (7/7), 完成.
使用 4 个线程进行压缩
压缩对象中: 100% (3/3), 完成.
写入对象中: 100% (7/7), 完成.
总共 7(差异 0),复用 0(差异 0),包复用 0
完整视图
研发流程
- merge合并代码
- 保护分支、Code Review、ci
分支管理工作流
Git Flow
- Master
- Develop
- Featrue
- Release
- Hotfix
Github Flow
基于Pull Request向唯一的主干分支提交代码
其他用户通过Fork方式来创建自己的仓库,并在此开发
也可以统一为团队成员分配权限,在仓库内开发。
在已有main分支的基础上增加feature分支:
(base) feature $ git push origin feature
Enter passphrase for key '/Users/luna/.ssh/id_rsa':
枚举对象中: 5, 完成.
对象计数中: 100% (5/5), 完成.
写入对象中: 100% (3/3), 258 字节 | 258.00 KiB/s, 完成.
总共 3(差异 0),复用 0(差异 0),包复用 0
remote:
remote: Create a pull request for 'feature' on GitHub by visiting:
//复制下链接在浏览器打开 得到github界面
remote: https://github.com/Zerlina-ysl/demo/pull/new/feature
remote:
To github.com:Zerlina-ysl/demo.git
* [new branch] feature -> feature
打开github.com/Zerlina-ysl… pull request,得到:
也可以在平台的分支选项进行操作。
点击merge pull request,confirm后该featrue分支被合并。
切换到main 分支 通过git pull origin main同步数据
(base) ⚙ main git pull origin main
Enter passphrase for key '/Users/luna/.ssh/id_rsa':
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
展开对象中: 100% (1/1), 618 字节 | 309.00 KiB/s, 完成.
来自 github.com:Zerlina-ysl/demo
* branch main -> FETCH_HEAD
e790d42..9046d59 main -> origin/main
更新 e790d42..9046d59
Fast-forward
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
git log后 ,可以理解为多了一次commit操作
Merge: e790d42 096fbc8
Author: Zerlina-ysl <56157846+Zerlina-ysl@users.noreply.github.com>
Date: Tue May 24 17:51:40 2022 +0800
Merge pull request #1 from Zerlina-ysl/feature
change
commit 096fbc8dd0dcd7436fe8abf4e85359bcb03f50ea (origin/feature, feature)
Author: 李一 <1280144091@qq.com>
Date: Tue May 24 17:44:21 2022 +0800
change
commit e790d42d944156b8efdd4f509592c20fe6ccc32e
Author: 李一 <1280144091@qq.com>
Date: Tue May 24 17:43:03 2022 +0800
readme
(END)
在github中有许多规则,settings->Branches->Add rule
Gitlab Floe
原则:upstream first
代码合并
Fast-Forward
保护产生merge节点,合并后历史线性。如果target结点更新,需要rebase操作更新source branch才可以合入。
(base) ✘ ⚙ main git checkout -b test
切换到一个新分支 'test'
(base) ⚙ test vim readme.md
(base) ⚙ test ± git add .
(base) ⚙ test ✚ git commit -m "fast-forward"
[test 8f0a59b] fast-forward
1 file changed, 1 insertion(+)
(base) ⚙ test git checkout main
切换到分支 'main'
您的分支与上游分支 'origin/main' 一致。
(base) ⚙ main git merge test --ff-only
更新 9046d59..8f0a59b
Fast-forward
readme.md | 1 +
1 file changed, 1 insertion(+)
git log后
commit 8f0a59b8c09811e9f20a3f171111a678965225f6 (HEAD -> main, test)
Author: 李一 <1280144091@qq.com>
Date: Tue May 24 18:02:02 2022 +0800
fast-forward
Three-Way Merge
三方合并,产生新的merge节点 git merge test --no-ff
(base) ⚙ test vim readme.md
(base) ✘ ⚙ test ± git add .
(base) ⚙ test ✚ git commit -m "test agin:
dquote> Ω"
[test 753e679] test agin: Ω
1 file changed, 1 insertion(+), 1 deletion(-)
(base) ⚙ luna@localhost ~/DeskTop/demo test git checkout main
切换到分支 'main'
您的分支领先 'origin/main' 共 3 个提交。
(使用 "git push" 来发布您的本地提交)
(base) ⚙ main git merge test --no-ff
提示:等待您的编辑器关闭文件... error: There was a problem with the editor 'vi'.
未提交合并,使用 'git commit' 完成此次合并。
(base) ✘ ⚙ main ✚ >M< git commit
[main f53b2f4] Merge branch 'test'
git log
commit f53b2f4d6c81699f6cf3512a833c3ee8d834fe78 (HEAD -> main)
Merge: b9bb9a8 753e679
Author: 李一 <1280144091@qq.com>
Date: Tue May 24 18:10:21 2022 +0800
Merge branch 'test'
commit 753e679f787be433d0a6e1c1c6b5d0d8d6e7fb4e (test)
Author: 李一 <1280144091@qq.com>
Date: Tue May 24 18:09:52 2022 +0800
test agin:
Ω
Q&A
cherry-pick
(base) ✘ ⚙ luna@localhost ~/DeskTop/demo main vim test.txt
(base) ⚙ luna@localhost ~/DeskTop/demo main git add .
(base) ⚙ luna@localhost ~/DeskTop/demo main ✚ git commit -m "11"
[main 412a948] 11
1 file changed, 1 insertion(+)
create mode 100644 test.txt
(base) ⚙ luna@localhost ~/DeskTop/demo main git log
[13] + 27081 suspended git log
(base) ✘ ⚙ luna@localhost ~/DeskTop/demo main git checkout main
已经位于 'main'
您的分支领先 'origin/main' 共 6 个提交。
(使用 "git push" 来发布您的本地提交)
(base) ⚙ luna@localhost ~/DeskTop/demo main git checkout test
切换到分支 'test'
(base) ⚙ luna@localhost ~/DeskTop/demo test git cherry-pick 412a948aac5bc05340c2af230f3c05c8c709d58a
[test dc10714] 11
Date: Tue May 24 18:17:20 2022 +0800
1 file changed, 1 insertion(+)
create mode 100644 test.txt
在当前分支上应用给定提交引入的变更(通过commit的SHA1