«

Git的工作流有哪些

时间:2024-7-25 09:07     作者:韩俊     分类: Linux


本篇内容主要讲解“Git的工作流有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Git的工作流有哪些”吧!

在讲 Git Flow 之前,我们先讲讲别的东西

    什么是版本?
    版是指印刷时的版,本就是印刷出来的书本;版本是一种称谓,用于描述同一事物的相互之间有差异的各种形式、状态或内容。
    换言之,任何事物只要有差异化都会涉及到版本这个概念,但是,我们这里说的版本,包括后面聊到的东西,都应该是一些有意义的版本,举个例子,小明 1 月 1 日 至 1 月 31 日 每天都在改一份策划书,2 月 1 号小明的甲方说还是上一个版本好,此时对于小明来说,上一个版本是什么?也许是最近一次小明发给甲方的一个方案,也许是上一个甲方说还可以的方案,小明可能已经不记得具体是几号改完给甲方的方案了。

    常见的版本控制有哪些?
    copy 文件以命名区分的方式、本编辑器的撤回/前进功能、使用专业工具如 svn、git 等等都属于版本控制的范畴,不同的版本控制有不同的用途,比如文本编辑器的撤回,可以轻松撤销本次修改,比如 copy 文件,可以让新旧文件同时存在,方便对比,但这些方式太过简单了,而且中间过程都是一些临时性的东西,不足以作为一个修改历史参考或者完整版本来看待,为此,还需要一些专业工具,如 集中式版本管理系统 SVN、CVS,分布式版本管理系统 BitKeeper、Git 等。

    Git 开发背景

    同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。 Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。
    到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。 他们对新的系统制订了若干目标:

      速度

      简单的设计

      对非线性开发模式的强力支持(允许成千上万个并行开发的分支)

      完全分布式

      有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量) 自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统(参见 Git 分支)。

    1991 年 Linux 开发了 linux 系统这个开源项目,采用邮件发送源文件附带patch的方式进行写作开发,由 Linux 本人进行手工合并;

    2002 年 BitKeeper 与 Linux 社区达成协议,允许 Linux 社区免费试用 BitKeeper,由于免费试用,协议内容更多地是保护 BitKeeper 自身。

    2005 年 BitKeeper 不满 Linux 社区破坏协议内容(说白了就是反编译 BitKeeper,试图做破解版或其他),终止合作;

    同 2005 年,Linux 花费了 2 周时间,开发了 Git 第一版,一个月内使用 Git 来管理 Linux 代码;

Git 基础知识

工作区(Workspace)、暂存区(Index)、版本库(Repository)

# 创建并进入 testGitFlow 目录
# 此时 testGitFlow 就是我们的工作区(Workspace),也就是工作目录

$ mkdir testGitFlow && cd testGitFlow

# 初始化 git 仓库
# 此时目录中增加了 .git 目录,.git 目录就是 git 仓库,不属于工作区

$ git init

# 新增两个文件
$ echo 111 > a.txt
$ echo 222 > b.txt

# 添加两个文件到暂存区/索引(Index)
$ git add .

# 把索引中的两个文件添加到版本库(Repository)
$ git commit -m 'init'

以上涉及的几个概念:
Workspace: 简单理解就是我们的项目目录
Index: 简单理解就是存储即将提交的内容的区域
Repository: 版本仓库

Commit、Tree、Blob 对象

# 通过 git log 查看版本
$ git log

>
commit 2b304a56998989dbcfd77f370f4b43fcad9e5872 (HEAD -> master)
Author: huihuipan <huihuipan163@163.com>
Date:   Mon Feb 27 17:56:53 2023 +0800

    init

# 通过 git cat-file 查看 commit 信息

# 查看 commit 类型
$ git cat-file -t 2b304a
> commit

# 查看 commit 内容
$ git cat-file -p 10d717

>
tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
author huihuipan <huihuipan163@163.com> 1677491813 +0800
committer huihuipan <huihuipan163@163.com> 1677491813 +0800

init

# 可以发现有 tree, author, committer 等信息
# 继续查看 tree 内容
$ git cat-file -t 4caaa1
> tree

$ git cat-file -p 4caaa1
>
100644 blob 58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c  a.txt
100644 blob c200906efd24ec5e783bee7f23b5d7c941b0c12c  b.txt

# 可以发现有 blob 信息
# 继续查看 blob 内容
$ git cat-file -t 58c9bd 
> blob

$ git cat-file -p 58c9bd 
> 111

# 可以看到里面存储的是 a.txt 的内容

以上涉及的几个概念:
commit: commit 记录提交的版本
tree: tree 记录不同版本下的目录结构和文件名
blob: blob 记录文件内容

修改文件及提交 commit 的时发生了什么?

首先,a.txt 内容 从 111 修改为 333,此时 git 仓库没有变化,只是工作区和索引的内容对不上了;

执行 git add 命令

git 仓库根据新的 a.txt 内容(333)创建出一个新的 blob 结点,记录 a.txt 内容

索引从旧 blob 的指向新的 blob

执行 git commit 命令

根据索引的状态,生成 tree 对象

根据新生成的 tree 对象和 上一个 commit 对象,生成新的 commit 对象

把分支指针从旧的 commit 对象移动到新的 commit 对象

HEAD、Branch、Tag

Branch: 是指向 Commit 的指针,每一次提交新的commit,当前的 Branch 都会指向最新的 commit;

HEAD: 指向 Branch 的指针,当checkout 到非 branch 时,会提示处于分离头指针状态,可以做一些试验性的动作;

Tag: 指向 Commit 的指针,用作标签,通常用作记录固定版本,也可以理解为是指定 commit 的别名;

以上我们可以得知,git 的版本管理粒度去到了文件级别,blob 之间的对比即可得到 diff,这里也引申出了一个开发上的一个思考,当我们的程序设计的基础是一个比较小粒度的时候,后续开发和扩展就会更加灵活,事实上git 对commit 的操作也是非常灵活,灵活到稍不注意就有可能酿成事故。

Checkout、Merge、Rebase、Fetch、Pull

checkout 检出: 把 HEAD 检出到指定 branch 或 commit,或者检出指定版本指定文件的内容,由于在 git 里面checkout 承载了太多的功能,所有切换分支有专属命令

switch

merge 合并:

rebase 变基:

rebase 会修改版本历史,即使 rebase 前与 rebase 后的内容一致,但版本不再是同一个版本

fetch: 从另一个存储库下载对象和引用,如远程库

pull: git pull = fetch + merge

基于 Git 的几种工作流

Git Flow

简介

主要分支

有两个分支会贯穿整个版本的生命周期,也就是长期分支:

    master 分支:用于发布

    develop 分支:用于开发 master 分支和 develop 分支的关系如上,虚线部分指着两个分支并不是直接发生关联,而是通过 release/hotfix 分支发生关联

支撑分支

    feature branches: 用于需求开发

开发需求时从 develop 分支拉出 feature 分支,feature 分支开发完毕后(开发自测无问题)则合并回 develop 分支,合并后删除分支,后续出现 bug 则在 develop 分支修改。

    release branches: 用于发布

当 develop 分支处于一个相对稳定的状态时即可从 develop 分支拉出 release 分支准备发布,release 分支不进行功能开发,仅进行 bug 修复,直至无问题时合并到 master 分支进行发布,同时合并回 develop 分支后删除 release 分支。

    hotfix branches: 用于修复生产问题

hotfix 分支用于修复生产环境上急需修复的 bug, 当生产环境出现 bug 时,从 master 分支拉出 hotfix 分支,修复后合并回 master 分支进行发布,同时合并到 develop 分支后删除。

补充

2020年 Vincent Driessen 补充了一条反思笔记,大概说 Git Flow这种模式在持续交付的软件下显得复杂,可以考虑使用 Github Flow 而不是将 Git Flow 硬塞到项目中。

Git Flow 之后 Adam Ruka 针对 Git Flow 的技术细节做了优化,提出了 One Flow

Github Flow

相对于 Git FlowGithub Flow 只有一条主干分支,通过 github 平台加持增加 PR 流程: 进行某功能开发时,从 master 分支拉出 feature 分支,完成功能后提交 pr, 让相关人员进行 review, review 期间仍可以对 feature 进行提交,直至确认无问题后通过 pr, 可以把 feature 分支合并到 master 分支进行发布

GitLab Flow

GitLab Flow 使用 master 分支作为开发分支,基于 master 分支另起发布分支 production
GitLab Flow 增加以下分支定义:
环境分支:当你需要在不同环境发布不同的版本时使用
发布分支:当项目需要发布不同的版本时使用,声明了一个发布分支后,这个分支只会合并严重的漏洞修复更新。

持续发布

gitlab-flow 推荐使用 master 分支进行开发,基于 master 分支另建 production 分支进行发布,另外提出了 环境分支的概念,根据不同环境,逐层合并,最后汇总到 production 发布分支后进行发布

版本发布

如果你的项目需要发布不同的版本, gitlab-flow 版本发布模式可能更适合,在持续发布模式下,不同的版本会有不同的发布分支进行发布。

Aone Flow

Aone-flow 是以 master 分支为基础,除 master 分支外其他都是临时分支。基于 master 分支拉出环境分支,环境分支之间不进行任何关联,独立发展,环境分支也不允许直接修改,而是通过合并不同的 feature 分支进行组合。 feature 分支直至合并到 发布分支后才会删除。有点是操作粒度更高更可控,缺点是环境分支的内容即使是一样的,但版本历史却有可能不一致。

怎样选择版本控制

上面介绍了好几种 flow, 从 gitflow 开始,gitflow 让自由度超高的 git 得到了指导性的使用方式;
而 github-flow 又针对了 gitflow 的复杂性提出了极简版的 flow;
gitlab-flow 又针对 gitflow 和 github-flow 过于复杂或过于简单的方式,提出了自己折中的方案,同时还给出了两种交付方式(持续交付、版本交付)的方案;
最后也介绍了 AoneFlow,一种操作粒度更自由的方案。

其实没有一种万能方案,不同的团队/项目有着其特殊的情况,针对不同情况,flow 也在变化,合适的就是最好的。

标签: linux

热门推荐