Git是当前最先进、最主流的分布式版本控制系统,免费、开源。
主要概念:
基本流程:
命令:
git commit -a # 省略了add到暂存区的步骤,直接提交工作区的修改内容到版本库,不包括新增的文件。git fetch
git pull # 都是从远程服务端获取最新记录,区别是git pull多了一个步骤,就是自动合并更新工作区。git checkout .
git checkout [file] # 会清除工作区中未添加到暂存区的修改,用暂存区内容替换工作区。git diff #用来对比不同部分之间的区别,如暂存区、工作区,最新版本与未提交内容,不同版本之间等。git reset # 用来撤销修改、回退版本的指令,替代上面checkout的撤销功能
Git 安装
Git的使用有两种方式:Git官网:https://www.git-scm.com/ 下载安装包进行安装。
- 命令行:Git的命令通过系统命令行工具,或Git提供的命令行工具运行
- GUI工具:Windows(GUI)、Mac(GUI)工具,需单独安装,使用更简单、更易上手。
git --version # 查看是否安装成功
Git配置文件
①、系统全局配置
包含了适用于系统所有用户和所有仓库(项目)的配置信息,存放在Git安装目录下C:\Program Files\Git\etc\gitconfig
②、用户全局配置
当前系统用户的全局配置,存放用户目录:C:\Users[系统用户名].gitconfig
③、仓库、项目配置
仓库(项目)的特定配置,存放在项目目录下.git/config
优先级:① < ② < ③
#查看git配置
git config --list
git config -l#查看系统配置
git config --system --list#查看当前用户(global)全局配置
git config --list --global#查看当前仓库配置信息
git config --local --list
配置初始化用户
配置 用户名、邮箱地址,每次提交文件时都会带上这个用户信息,查看历史记录时就知道是谁干的了
$ git config --global user.name "Your Name" # --global 表示用户全局配置
$ git config --global user.email "email@example.com" # 如果要给特定仓库配置用户信息,则用参数--local配置即可,或直接在仓库配置文件.git/config里修改# 配置完后,看看用户配置文件:
$ cat 'C:\Users\Kwongad\.gitconfig'
[user]name = Kandingemail = 123anding@163.com
配置忽略.gitignore
如日志、临时文件、私有配置文件等不需要也不能纳入版本管理
①、在工作区根目录创建.gitignore文件,配置不需要版本管理的文件、文件夹
- #符号开头为注释
- 星号(*)代表任意多个字符
- 问号(?)代表一个字符
- 方括号([abc])代表可选字符范围
- 大括号({string1,string2,…})代表可选的字符串等
- 感叹号(!)开头:表示例外规则,将不被忽略
- 路径分隔符(/f)开头:,表示要忽略根目录下的文件f
- 路径分隔符(f/)结尾:,表示要忽略文件夹f下面的所有文件
#为注释
*.txt #忽略所有“.txt”结尾的文件
!lib.txt #lib.txt除外
/temp #仅忽略项目根目录下的temp文件,不包括其它目录下的temp,如不包括“src/temp”
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
创建仓库
- 创建全新的仓库,git init
- 克隆远程仓库,git clone [url]
# 在指定目录中
git init# 从远程仓库克隆到本地
git clone 'https://github.com/kwonganding/KWebNote.git'
# 添加指定文件到暂存区,包括被修改的文件
git add [file1][file2]...# 添加当前目录的所有文件到暂存区
git add.# 删除工作区文件,并且将这次删除放入暂存区
git rm [file1][file2]...# 改名文件,并且将这个改名存入暂存区
git mv [file-opriginal][file-renamed]
提交commit
# 提交暂存区到仓库区
$ git commit -m [message]
# 提交所有修改到仓库
$ git commit -a -m'修改README的版权信息'# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
$ git commit --amend -m [message]$ git log -n2# 用参数“--oneline”可以让日志输出更简洁(一行)
$ git log -n2 --oneline
远程仓库
- 公共Git服务器,如Github、Gitlab、码云Gitee、腾讯Coding等。
- 搭建私有Git服务器,如开源的Gitlab、Gitea、等。
一、登录
- HTTS,使用用户名、密码身份验证。每次都要输入用户名密码
- SSL,基于公私钥身份验证,需要额外配置。不用每次输入用户名和密码
git remote -v #查看当前远程仓库使用的那种协议连接git config --global http.sslVerify false # 更改为https地址,即可切换连接模式,还需要禁用掉SSL才能正常使用https管理gitgit clone 'https://github.com/kwonganding/KWebNote.git'
SSH(Secure Shell,安全外壳)是一种网络安全协议,通过加密和认证机制实现安全的访问和文件传输等业务,多用来进行远程登录、数据传输。
SSH通过公钥、私钥非对称加密数据,所以SSH需要生成一个公私钥对,公钥放服务器上,私钥自己留着进行认证。
①、生成公私钥
通过git指令:ssh-keygen-t rsa生成公私钥,一路回车即可完成
生成在“C:\Users\用户名.ssh”目录下,文件id_rsa.pub的内容就是公钥
②、配置私钥
打开id_rsa.pub文件,复制内容
Github上,打开Setting➤ SSH and GPG keys ➤ SSH keys ➤ 按钮New SSH key,标题(Title)随意,秘钥内容粘贴进去即可
SSH配置完后,可用ssh -T git@github.com来检测是否连接成功
fetch与pull有什么不同:
两者都是从服务端获取更新,主要区别是fetch不会自动合并,不会影响当前工作区内容
git pull=git fetch+git merge
Git分支
- master主分支,存放测试通过的代码,不允许随便修改和合并
- 开发分支,用于团队日常开发,比如团队计划10月份开发10个功能并发版,则在此分支上进行,不影响主分支的稳定。
- 功能A开发,开发人员根据自己的需要,可以创建一些临时分支用于特定功能的开发,开发完毕后再合并到开发分支,并删除该分支
分支指令
git branch dev # 创建一个名为dev的分支,Git实际上是在.git\refs\heads下创建一个dev的引用文件(没有扩展名)git switch dev # 切换到dev分支
合并merge&冲突
把两个分支的修改内容合并到一起的办法有两种:merge 和 rebase,作用都是一样的,区别是rebase的提交历史更简洁,干掉了分叉,merge的提交历史更完整。
git merge [branch] # 将分支branch合并到当前分支
①、快速合并
先切换到master分支,然后
git merge dev 合并分支到master,速度非常快,直接移动master的指针引用到dev
②、如果master有变更,则会被两边的变更合并成一个提交
- 如果两边文件变更不同,没有冲突,就自动合并
- 如果存在冲突,人工修改后,才能合并
rebase
git rebase master # 在dev上执行git merge dev # 然后回到master分支,进行快速合并
撤销变更
- 未提交的怎么撤销?checkout/reset
- 已提交未push的如何撤销?reset/revert
- 已push的提交如何撤销?同上,先本地撤销,然后强制推送git push prigin -f
Git的GUI工具
①、TortoiseGit
TortoiseGit 官网下载安装包,及中文语言包,按照提示完成安装。小乌龟的Git是集成到操作系统里的,直接右键文件夹就可以进行Git操作了。
先进入设置:右键文件夹菜单 --> TortoiseGit --> Settings 进入设置,设置中文语言
小乌龟的各种Git操作都在右键菜单了,深度集成到了操作系统的资源管理器中了,文件图标也是有Git状态的,比较容易分辨
②、SourceTree
SourceTree的官网 下载安装包,支持Window、Mac系统,按照提示完成安装。
SourceTree支持管理多个仓库,通过+按钮,可选择多种方式添加仓库
然后就是可视化的仓库管理了,不用记住繁琐的指令(参数)了,可视化操作。
③、VSCode自带的Git插件
=====================================
工作中开发流程
一、开发分支模型分类
主要是四种:dev(开发)、test(测试)、uat(预发)、release(生产)
二、开发主体流程
①、需求评审
②、开发排期
③、编码开发
④、冒烟测试(自检验)
⑤、冒烟通过,提交测试,合并代码到测试分支,部署测试环境
⑥、测试环境测试,开发修bug,测试完成,提交预发,合并代码到预发分支,部署预发环境
⑦、预发环境测试,开发修 bug(修完的 bug 要重新走测试再走预发,这个下面会解释)
⑧、测试完成,产品验收,提交生产,合并代码到生产环境,部署生产环境
⑨、生产运营(客户)验收
⑩、验收完成,(结项)
三、具体操作
①、拉取代码
#一般都会在本地默认创建一个 master 分支
git clone https://code.xxx.com/xxx/xxx.git
②、初次开发需求前,要先拉取生产/预发分支,然后基于这个分支之上,创建自己的特性分支进行开发
git fetch origin release:releasegit checkout releasegit checkout -b feat-0131-jie
此时,在你本地已经有了一个 release 分支对应着远程仓库的 release 分支,还有一个内容基于 release 分支的特性分支,之后便可以在这个特性分支上进行需求开发了。
如果不是初次开发,本地已有生产/预发分支,则需要重新拉取远程的最新代码,然后再创建
git checkout releasegit pull origin releasegit checkout -b feat-0229-jie
【注意】
分支名称是有规范和含义的,不能乱取
推荐格式:分支责任-需求日期/需求号-开发人姓名,一般按部门规范来,常见的有以下几种。
为啥拉取的是生产/预发分支
之所以要拉取 release/uat 分支而不是拉取 dev/test,是因为后者可能包含着一些其他成员还未上线或者可能有 bug 的需求代码,这些代码没有通过验证,如果被你给拉取了,然后又基于此进行新的需求开发,那当你需求开发完成,而其他成员的需求还没上线,你将会把这些未验证的代码一起发送到 uat/release 上,导致一系列问题。
③、需求开发完成,提交&合并代码
首先先在本地把新的改动提交,提交描述的格式可以参考着分支名的格式
- 如果是新需求的提交,可以写成 “feat: 需求0131-新增账期”
- 如果是 bug 修复,可以写成 “fix: 禅道3387-重复请求”
git add .git commit -m "提交描述"
此时,本地当前分支已经记录了你的提交记录,接下来进行代码合并了
合并代码
Ⅰ、首先,我们需要认知到的是,每一个分支应该只对应一个功能,例如当我们开发需求 01 时,那么就创建一个 feat-01-jie 分支进行开发;开发需求 02 时,就另外创建一个 feat-02-jie 分支进行开发;修改生产环境的某个 bug 时,就创建 fix-jie-3378 进行开发,等等。
这样做的目的是,能够把不同的功能/需求/修改分离开来。想象一下这样一个场景,如果有某些紧急的需求是需要提前上线的,而此时你的分支里既包含了这些紧急的需求,又包含了其他未开发好的需求,那么这两种需求就不能拆开来分别进行提测和上线了。
Ⅱ、其次,在合并代码时,我们要将四种分支模型(dev、test、uat、release)作为参照物,而不是把关注点放在自己的分支上。比如我们要在 dev 上调试,那就需要把自己的分支合并到 dev 分支上;如果我们需要提测,则把自己的分支合并到 test 分支上,以此类推。
即,我们要关注到,这四个环境的分支上,会有什么内容,会新增什么内容。「切记不能反过来将除了 release 之外的三个分支合并到自己的代码上!!」 如果其他成员将自己的代码也提交到 dev 分支上,但是这个代码是没有通过验证的,此时你将 dev 往自己的分支上合,那之后的提测、上预发、生产则很大概率会出问题。「所以一定要保持自己的分支是干净的!」 而 release 分支对应的是生产环境,一般是最新的稳定版本,所以合并到自己的分支以获取最新的更改也是没什么问题的。
第一种:线上合并
git push origin feat-0131-jie
先接着上面的提交步骤,将自己的分支推送到远程仓库。
然后在线上代码仓库中,申请将自己的分支合并到 xx 分支(具体是哪个分支就根据你当前的开发进度来,如 test),然后在线上解决冲突。如果有权限就自己通过了,如果没有就得找 mt 啥的
第二种:本地合并(前提你要有对应环境分支 push 的权限)
#先切换到要提交的环境分支上,如果本地还没有就先拉取下来
git fetch origin test:testgit check test# 然后将自己的分支合并到环境分支上(在编辑器解决冲突)
git merge feat-0131-jie# 最后将环境分支推送到远程仓库
git push origin test
#先切换到要提交的环境分支上,如果本地已有该分支,则需要先拉去最新代码
git checkout testgit pull origin test# 然后将自己的分支合并到环境分支上(在编辑器解决冲突)
git merge feat-0131-jie#最后将环境分支推送到远程仓库
git push origin test
两种方式的区别:(推荐使用第一种)
这是因为在团队协作开发的过程中,将合并操作限制在线上环境有以下几个好处:
避免本地合并冲突:如果多个开发人员同时在本地进行合并操作,并且对同一段代码进行了修改,可能会导致冲突。将合并操作集中在线上环境可以减少此类冲突的发生,因为不同开发人员的修改会先在线上进行合并,然后再通过更新拉取到本地。
更好的代码审查:将合并操作放在线上环境可以方便其他开发人员进行代码审查。其他人员可以在线上查看合并请求的代码变动、注释和讨论,并提供反馈和建议。这样可以确保代码的质量和可维护性。
提高可追溯性和可回滚性:将合并操作记录在线上可以更容易地进行版本控制和管理。如果出现问题或需要回滚到之前的版本,可以更轻松地找到相关的合并记录并进行处理。
当然,并非所有情况都适用于第一种方式。在某些特定情况下,例如个人项目或小团队内部开发,允许本地合并也是可以的。但在大多数团队协作的场景中,将合并操作集中在线上环境具有更多优势。
④、验收完成,删除分支
git branch -d <分支名>## 如果要强制删除分支(即使分支上有未合并的修改)
git branch -D <分支名>
常见问题:
代码合并错误,并且已经推送到远程分支,如何解决?
- 首先切换到特性分支合并到的错误分支,比如是 release
git checkout release
- 然后查看最近的合并信息(按 q 退出查看)
git log --merges
- 撤销合并
# 这里的 merge commit ID 就是上一步查询出来的 ID 或者 ID 的前几个字符
git revert -m 1 <merge commit ID>
- 撤销远程仓库的推送
#这个命令会强制推送本地撤销合并后的 release 分支到远程仓库,覆盖掉远程仓库上的内容。(即,得通过一个新的提交来“撤销”上一次的提交,本质上是覆盖)
git push -f origin release
当前分支有未提交的修改,但是暂时不想提交,想要切换到另一个分支该怎么做?
你正在开发 B 需求,突然产品说 A 需求有点问题,让你赶紧改改,但是当前 B 需求还没开发完成,你又不想留下过多无用的提交记录,此时就可以按照下面这样做:
- 首先,可以将当前修改暂存起来,以便之后恢复
git stash
- 然后切换到目标分支,例如需求 A 所在分支
git checkout feat-a-jie
- 改完 A 需求后,「需要先切换回之前的分支」,例如需求 B 所在分支
git checkout feat-b-jie
如果你不确定之前所在的分支名,可以使用以下命令列出暂存的修改以及它们所属的分支:
git stash list
最后从暂存中恢复之前的修改
git stash pop
四、扩展
cherry-pick 指令
- 作用:选择某些提交的变更并将其应用到当前分支
- 与 merge 的区别:如果你需要另一个分支的所有代码变动。那么就采用 merge;如果你只需要部分代码变动(某几个提交),那么就采用 cherry-pick
- 场景:有时候分支不一定是完全按照需求号来开发的,可能按照周期来进行开发,那当前版本内的分支上,可能就会包含着很多需求的提交,这时候,如果产品要求你只上某一个需求,但是其他的暂时还不能上,那就需要使用到 cherry pick 的操作,将该需求囊括的所有提交应用到对应环境分支上。「一定要注意梳理清楚被拆分需求是由多少 commit 组成的,不要有遗漏和多选。」
# 查看最近提交(按q退出查看)
git log#切换到应用的分支(比如提测时)
git checkout test#将指定的提交应用于当前分支(commitHash 就是通过第一步查询到的),这会在当前分支产生一个新的提交
git cherry-pick <commitHash>
更多了解:https://www.ruanyifeng.com/blog/2020/04/git-cherry-pick.html
rebase指令
- 作用:对一个分支做「变基」操作。将当前分支的提交挪动到另一个分支的最新提交之后,这样可以创建一个更线性、清晰的提交历史
- 与 merge 的区别:merge 会保留合并分支的提交历史,而 rebase 会改写提交历史
- 场景1:合并多次提交纪录。例如之前提到的:“当前分支有未提交的修改,但是暂时不想提交,想要切换到另一个分支该怎么做?”的另一个解决办法,就是先提交了,之后再把这些提交记录合并成一个提交记录。
- 场景2:合并分支。
- 切记:永远不要 rebase 一个共享分支
【注意:rebase 和 cherry-pick 使用不当都会给团队协作带来一些不可预估的问题,请尽量在了解清楚后再进行使用。】
三种广泛使用的Git工作流程规范
- Git flow
- Github flow
- Gitlab flow(本文类似于该工作流程)
具体:(https://www.ruanyifeng.com/blog/2015/12/git-workflow.html)