这是我参与「第五届青训营」伴学笔记创作活动的第 18 天
本节课主要介绍:
| 方向介绍 | 具体能力 |
|---|---|
| 1.代码托管 | 负责管理公司内数十万的代码仓库,并在这之上对代码管理的相关功能进行迭代,提升研发活动的效率及质量 |
| 2.代码智能 | 提供更准确高效的代码搜索能力和代码导航能力,支持多种场景下的代码跳转,帮助用户更高效的去阅读代码 |
| 3.代码分析 | 提供一种代码检查能力,目的是在整个研发流程中自动的发现并反馈代码中存在的代码结构、代码漏洞、代码风格等问题 |
| 4.持续集成 | 一种软件开发实践,团队成员频繁将他们的工作成果集成在一起。每次提交后,自动触发运行一次包含自动化验证集的构建任务,以便能尽早发现集成问题 |
| 5.Cloud IDE | 一个开箱即用的云端开发环境,支持node/python/go/java/c++等多种编程语言。你可以在云端开发环境中编写、编译、运行和调试你的项目 |
一、Git是什么
1.1版本控制
一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统
更好的关注变更,了解到每个版本的改动是什么,方便对改动的代码进行检查,预防事故发生; 也能够随时切换到不同的版本,回滚误删误改的问题代码。
1.1.1本地版本控制
最初的方式
通过本地复制文件夹,来完成版本控制,一般可以通过不同的文件名来区分版本
解决方案
开发了一些本地的版本控制软件,其中最流行的是RCS
基本原理
本地保存所有变更的补丁集,可以理解成就是所有的Diff,通过这些补丁,我们可以计算出每个版本的实际的文件内容
缺点
RCS这种本地版本控制存在最致命的缺陷就是只能在本地使用,无法进行团队协作,因此使用的场景非常有限,因 此衍生出了集中式版本控制
1.1.2集中版本控制
代表性工具:SVN
基本原理:
1.提供一个远端服务来保存文件,所有用户的提交都提交到该服务器中
2.增量保存每次提交的Diff,如果提交的增量中和远端现存的文件存在冲突,则需要本地提前解决冲突
优点:
1.学习简单,更容易操作
2.支持二进制文件,对大文件支持更友好
缺点:
1.本地不存储版本管理的概念,所有提交都只能联上服务器后才可以提交
2.分支上的支持不够好,对于大型项目团队合作比较困难
3.用户本地不保存所有版本的代码,如果服务端故障容易导致历史版本的丢失。
1.1.3分布式版本控制
代表性工具:Git
基本原理
1.每个库都存有完整的提交历史,可以直接在本地进行代码提交
2.每次提交记录的都是完整的文件快照,而不是记录增量
3.通过Push等操作来完成和远端代码的同步
优点:
1.分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体
2.分支管理功能强大,方便团队合作,多人协同开发
3.校验和机制保证完整性,一般只添加数据,很少执行删除操作,不容易导致代码丢失
缺点:
1.相对SVN更复杂,学习成本更高
2.对于大文件的支持不是特别好(git-lfs工具可以弥补这个功能)
1.2Git发展历史
作者 Linus Torvalds(就是Linux这个项目的作者,同时也是Git的作者)
开发原因
怀疑Linux团队对BitKeeper(另一种分布式版本控制系统,专有软件)进行了逆向工程,BitKeeper不允许Linux团队 继续无偿使用。因此决定自己开发一个分布式版本控制系统
基于Git衍生出各种平台:
Github 全球最大的代码托管平台,大部分的开源项目都放在这个平台上。
Gitlab 全球最大的开源代码托管平台,项目的所有代码都是开源的,便于在自己的服务器上完成Gitlab的搭建。
Gerrit 由Google开发的一个代码托管平台,Android这个开源项目就托管在Gerrit之上
除此之外,还有BitBucket,Coding,码云,阿里云效平台等等
二、Git基本使用方式
基本命令:
2.1Git目录介绍
项目初始化
mkdir study
cd study
git init
其他参数
--initial-branch初始化的分支
--bare创建一个裸仓库(纯Git目录,没有工作目录)
--template可以通过模版来创建预先构建好的自定义git目录
2.1.1Git Config
不同级别的Git配置
可能重复,但是低级别的配置会覆盖高级别的配置
2.1.2常见Git配置
用户名配置
git config --global user.name "xxx"
git config --global user.email xxx@yyy.com
Instead of 配置
git config --global url.git@github.com:.insteadOf github.com/
Git命令别名配置
git config --global alias.cin "commit --amend --no-edit"
2.2 Git Remote
查看Remote
git remote -v
添加Remote
git remote add origin_ssh git@github.com:git/git.git
git remote add origin_http github.com/git/git.git
同一个Origin设置不同的Push和Fetch URL
2.2.1 HTTP Remote
免密配置
内存:git config --global credential.helper 'cache-timeout=3600'
硬盘:git config --global credential.helper "store --file /path/to/credential-file" 不指定目录的情况默认是~/.git-credentials
将密钥信息存在指定文件中
具体格式:{user}:${password}@github.com
2.2.2 SSH Remote
URL:git@github.com:git/git.git
免密配置
SSH可以通过公私钥的机制,将生成公钥存放在服务端,从而实现免密访问
目前的Key的类型四种,分别是dsa、rsa、ecdsa、ed25519
默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa和rsa了,优先推荐使用ed25519
ssh-keygen -t ed25519-C "your_email@example.com"
密钥默认存在~/.ssh/id_ed25519.pub
2.3 2.4Git add&Git commit
2.5 Objects
commit/tree/blob在git里面都统一称为Object,除此之外还有个tag的object
Blob 存储文件的内容
Tree 存储文件的目录信息
Commit 存储提交信息,一个Commit可以对应唯一版本的代码
2.6 Refs
refs的内容就是对应的Commit ID ,因此把ref当做指针,指向对应的Commit来表示当前Ref对应的版本,
不同种类的ref
refs/heads前缀表示的是分支,除此,之外还有其他种类的ref,比如refs/tags前缀表示的是标签。
Branch
git checkout-b可以创建一个新分支
分支一般用于开发阶段,是可以不断添加Commit进行迭代的
Tag
标签一般表示的是一个稳定版本,指向的Commit一般不会变更
通过git tag命令生成tag
2.7 Annotation Tag
什么是附注标签? 一种特殊的Tag,可以给Tag提供一些额外的信息。
2.8追溯历史版本
获取当前版本代码
通过Ref指向的Commit可以获取唯一的代码版本。
获取历史版本代码
Commit里面会存有parent commit字段,通过commit的串联获取历史版本代码。
两者Diff
1.新增 tree object 3a
2.新增 blob object 55
3.新增 commit object 64
test ref指向新的commit
2.9修改历史版本
1.commit amend
通过这个命令可以修改最近的一次commit信息,修改之后commit id会变
2.rebase
通过git rebase-i HEAD~3可以实现对最近三个commit的修改:
1.合并commit 2.修改具体的commit message 3.删除某个commit
3.filter branch
该命令可以指定删除所有提交中的某个文件或者全局修改邮箱地址等操作
2.10 Objects
新增的Object
修改Commit后我们可以发现git object又出现了变化
新增commit object 7f
但是之前的commit object 63并没有被删除
悬空的Object
顾名思义就是没有ref指向的object
2.11 Git GC
GC
通过git gc命令,可以删除一些不需要的object, 以及会对object进行一些打包压缩来减少仓库的体积。
Reflog
reflog是用于记录操作日志,防止误操作后数据丢失
通过reflog来找到丢失的数据,手动将日志设置为过期。
指定时间
git gc prune=now指定的是修剪多久之前的对象 默认是两周前
2.13 Git Clone Pull Fetch
Clone
拉取完整的仓库到本地目录,可以指定分支,深度
Fetch
将远端某些分支最新代码拉取到本地,不会执行merge操作,
会修改refs/remote内的分支信息,如果需要和本地代码合并需要手动操作
Pull
拉取远端某分支,并和本地代码进行合并,操作等同于git fetch+git merge
也可以通过git pull-rebase完成git fetch+git rebase操作。
可能存在冲突,需要解决冲突。
2.14 Git Push
Push是将本地代码同步至远端的方式。
常用命令
般使用git push origin master命令即可完成
冲突问题
1.如果本地的commit记录和远端的commit历史不一致,则会产生冲突,比如git commit --amend or git rebase都有可能导致这个问题,
2.如果该分支就自己一个人使用,或者团队内确认过可以修改历史则可以通过git push origin master -f 来完成强制推送,一般不推荐主干分支进行该操作,正常都应该解决冲突后再进行推送。
推送规则限制
可以通过保护分支,来配置一些保护规则,防止误操作,或者一些不合规的操作出现,导致代码丢失。
2.15 常见问题
1.为什么我明明配置了Git配置,但是依然没有办法拉取代码?
·免密认证没有配。
·Instead Of配置没有配,配的SSH免密配置,但是使用的还是HTTP协议访问。
2.为什么我Fetch了远端分支,但是我看本地当前的分支历史还是没有变化?
Fetch会把代码拉取到本地的远端分支,但是并不会合并到当前分支,所以当前分支历史没有变化。
三、Git研发流程
3.1不同的工作流
3.2集中式工作流
什么是集中式工作流?
只依托于master分支进行研发活动
工作方式
1.获取远端master代码
2.直接在master分支完成修改
3.提交前拉取最新的master代码和本地代码进行合 并(使用rebase),如果有冲突需要解决冲突
4.提交本地代码到master
3.3分支管理工作流
3.3.2分支管理工作流-Github Flow
Github的工作流,只有一个主干分支,基于Pull Request往主干分支中提交代码
选择团队合作的方式
1.owner创建好仓库后,其他用户通过Fork的方式来创建自己的仓库,并在fork的仓库上进行开发
2.owner创建好仓库后,统一给团队内成员分配权限,直接在同一个仓库内进行开发
创建一个Pull Request
1.创建一个main主分支
2.创建一个feature分支
3.创建一个feature到main的Pull Request
可以在Pull Request页面执行CI/CA/CR等操作,都检查通过后,执行合入。
可以通过进行一些保护分支设置,来限制合入的策略,以及限制直接的push操作。
3.4代码合并
Fast-Forward
不会产生一个merge节点,合并后保持一个
线性历史,如果target分支有了更新,则需要通过rebase操作更新
source branch后才可以合入。
Three-Way Merge 三方合并,会产生一个新的merge节点
3.5如何选择合适的工作流
选择原则
没有最好的,只有最合适的
针对小型团队合作,推荐使用Github工作流即可
1.尽量保证少量多次,最好不要一次性提交上干行代码
2.提交Pull Request后最少需要保证有CR后再合入
3.主干分支尽量保持整洁,使用fast-forward合入方式,合入前进行rebase
引用
字节内部课 -Git 的研发流程 - 掘金 (juejin.cn)