这是我参与「第三届青训营 -后端场」笔记创作活动的的第6篇笔记。
为什么要学习Git:
- 协同工作:业界绝大多数公司都是基于Git进行代码管理,因此Git是一个程序员必备技能。
- 开源社区:目前绝大多数的开源项目都是基于Git维护的,参与这些项目的开发都需要使用Git。
学习目标:
- 学习基本的Git命令,并了解原理,在遇到Git相关问题时,能自行排查并解决。
- 了解研发流程中的基本概念和规范,学会正确的使用Git。
一、Git是什么
1.1 版本控制
- 版本控制是什么?
一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
- 为什么需要版本控制?
为了更好的关注变更,了解到每个版本的改动是什么,方便的对改动的代码进行检查,预防事故发生;也能够随时切换到不同的版本,回滚误删改的问题代码。
1.2 Git的发展历史
作者: Linus Torvalds(是linux项目的作者,同时也是Git的作者)
开发原因: 怀疑Linux团队对BitKeeper(另一种分布式版本控制系统,专有软件)进行了逆向工程,BitKeeper不允许Linux团队继续无偿使用。因此决定自己开发一个分布式版本控制系统。
- Github:全球最大的代码托管平台,大部分的开源项目都放在这个平台上。
- Gitlab:全球最大的开源代码托管平台,项目的所有代码都是开源的,便于在自己的服务器上完成Gitlab的搭建。
- Gerrit:由谷歌开发的一个代码托管平台,Android这个开源项目就托管在Gerrit之上。
二、Git的基本使用方式
2.1 Git目录介绍
- 项目初始化:mkdir study、cd study、git init。
git init其他参数:
- --init-branch 初始化的分支
- --bare 创建一个裸仓库(纯Git目录,没有工作目录)
- --template 可以通过模板来创建预先构建好的自定义git目录。
2.2 Git Config
不同级别的Git配置
- --global
- --system
- --local
每个级别的配置可能重复,但是低级别的配置会覆盖高级别的配置。
- 用户名配置
- git config --global user.name "username"
- git config --global user.email youxiang@bytedance.com
- Instead of 配置
- git config --global url.git@github.com:.insteadOf github.com/
- 可以做一些url的替换,可以把http协议换成ssh协议,或者ssh协议换成http协议。
- Git命令别名配置(简化命令)
- git config --global alias.cin "commit --amend --no-edit"
2.3 Remote
Git Remote
查看Remote
- git remove -v
添加Remote
- git remote add origin_ssh git@github.com:git/git/git
- git remote add origin_http github.com/git/git.git
HTTP Remote
一般不推荐使用HTTP Remote,因为不是特别安全。
SSH Remote
URL: git@github.com:git/git.git
免密配置:SSH可以通过公私钥的机制,将生成公钥存放在服务端,从而实现免密访问。目前的Key的类型有四种,分别是dsa、rsa、ecdsa、ed25519,默认使用的是rsa,由于一些安全问题,不推荐使用dsa和rsa,优先推荐使用ed25519。
ssh-keygen -t ed25519 -C "you_email@example.com",密钥默认存储在~/.ssh/id_ed25519.pub
2.4 Git Add和Git Commit
- Git Add:将文件加入到暂存区。
- Git Commit:将文件提交到目录里面。
2.5 Git Clone & Pull & Fetch
- Clone:拉取完整的仓库到本地目录,可以指定分支,深度。
- Fetch:将远端某些分支最新代码拉取到本地,不会执行merge操作,会修改refs/remote内的分支信息,如果需要和本地代码合并需要手动操作。
- Pull:拉取远端某分支,并和本地代码进行合并,操作等同于git fetch + git merge,也可以通过git pull --rebase操作。可能存在冲突,需要解决。
2.6 Git push
push是将本地代码同步至远端的方式。
常用命令:一般使用git push origin master命令即可完成。
冲突问题:
- 如果本地的commit记录和远端的commit历史不一致,则会产生冲突,比如git commit --amend or git rebase都有可能导致这个问题。
- 如果该分支就自己一个人使用,或者团队内确认过可以修改历史则可以通过git push origin master -f来完成强制推送,一般不推荐主干分支进行该操作,正常都应该解决冲突后再进行推送。
推送规则限制:可以通过保护分支,来配置一些保护规则,防止误操作,或者一些不合规的操作出现,导致代码丢失。
三、Git研发流程
3.1 不同的工作流
3.2 集中式工作流
什么是集中式工作流:只依托于master分支进行研发活动。
工作方式:
- 获取远端master代码。
- 直接在master分支完成修改。
- 提交前拉取最新的master代码和本地代码进行合并(使用rebase),如果有冲突需要解决冲突。
- 提交本地代码到master。
Gerrit:是由谷歌开发的一款代码托管平台,主要特点是能够很好的进行代码评审。在aosp(android open source project)中使用很广,Gerrit的开发流程就是一种集中式工作流。
优点:
- 提供强制的代码评审机制,保证代码质量。
- 提供更丰富的权限功能,可以针对分支做细粒度的权限管控。
- 保证master的历史完整性。
- Aosp多仓的场景支持更好。
缺点:
- 开发人员角度的情况,更容易出现冲突。
- 对于多分支的支持较差,想要区分多个版本的线上代码时,更容易出现问题。
- 一般只有管理人员才能创建仓库,比较难以在项目之间形成代码复用,比如类似的fork操作不支持。
3.3 分支管理工作流
3.3.1 分支管理工作流 - GitFlow
- 包含五种类型的分支
- Mater:主干分支
- Develop:开发分支
- Feature:特性分支
- Release:发布分支
- Hotfix:热修复分支
- 优点:
- 如果能按照定义的标准严格执行,代码会很清晰,并且很难出现混乱。
- 缺点:
- 流程过于复杂,上线的节奏会比较慢。由于太复杂,研发容易不按照标准执行,从而导致代码出现混乱。
3.3.2 分支管理工作流 - GitHub Flow
Github的工作流,只有一个主干分支,基于Pull Request往主干分支中提交代码。
选择团队合作的方式:
- owner创建好仓库后,其他用户通过Fork的方式来创建自己的仓库,并在Fork的仓库上进行开发。
- owner创建好仓库后,统一给团队内成员分配权限,直接在同一个仓库内进行开发。
创建一个Pull Request
- 创建一个main主分支。
- 创建一个feature分支。
- 创建一个feature到main的pull request。
可以在pull request页面执行CI、CA、CR等操作,都检查通过后,执行合入。
可以通过进行一些保护分支设置,来限制合入的策略,以及限制直接的push操作。
3.3.3 分支管理工作流 - Gitlab Flow
Gitlab推荐的工作流是在GitFlow和Github Flow上做出优化,既保持了单一主分支的简便,又可以适应不同的开发环境。
原则:upstream first上游优先。 只有在上游分支采纳的代码才可以进入到下游分支,一般上游分支就是master。
3.4 代码合并
Fast-Forward:不会产生一个merge节点,合并后保持一个线性历史,如果target分支有了更新,则需要通过rebase操作更新source branch后才可以合入。
Three-Way Merge:三方合并,会产生一个新的merge节点。
3.5 如何选择合适的工作流
选择原则:没有最好的,只有最合适的。
针对小型团队合作,推荐使用Github工作流即可
- 尽量保证少量多次,最好不要一次性提交上千行代码。
- 提交Pull Request后最少需要保证有CR后再并入。
- 主干分支尽量保持整洁,使用fast-forward合入并入方式,合入前进行rebase。
大型团队合作,根据自己的需要指定不同的工作流,不需要局限在某种流程中。
四、总结
Git是工作中必备的技能,同时也是开源项目维护的工具。通过本次课程,明白了Git仓库管理的各种知识,对git的各种命令的使用也更加的熟练了。特别是工作流的知识是我之前没有接触到的。