DevOps之代码仓库

一、项目开发管理模型

1.1 DevOps的发展历程

DevOps是一种思想、一组最佳实践、以及一种文化。DevOps落地实施,从组织架构、设计人员、流程、人员分工、人员技能到工具,变化很大,要求很高,完全颠覆了现有的开发运维模式,建设风险很高。

软件开发最开始是由两个团队组成:

  • 开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。
  • 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。

这看似两个目标不同的团队需要协同完成一个软件的开发。

在开发团队指定好计划并完成coding后,需要提供到运维团队。

运维团队向开发团队反馈需要修复的BUG以及一些需要返工的任务。

这时开发团队需要经常等待运维团队的反馈。这无疑延长了事件并推迟了整个软件开发的周期。

会有一种方式,在开发团队等待的时候,让开发团队转移到下一个项目中。等待运维团队为之前的代码提供反馈。

可是这样就意味着一个完整的项目需要一个更长的周期才可以开发出最终代码。

1.1.1 瀑布式开发模型

image-20230627143727655

瀑布模型的优点

瀑布模型作为最典型的预见性方法,其优点主要在于:

  1. 阶段清晰:从计划到开发最后到上线运行,三个阶段非常清晰。
  2. 时间顺序:每个阶段顺序必须是从上到下,严格按照时间先后进行。
  3. 环环相扣:在每一个阶段都必须有产出物然后才能进入到下一个阶段进行。
  4. 黑盒模式:每个阶段都有各自的角色和分工,各自只关心自己的任务。比如需求阶段开发人员无需关注。

瀑布模型的缺点

而其缺点也突出:

  1. 需求隔离:由于各阶段的人员只能接触到自己工作范围内的东西,所以对客户需求的理解程度高低不等,开发人员更像是定义为流水线上的工人。
  2. 变更代价大:既然叫做瀑布,就意味着不应该走回头路。否则如果出现返工,付出的代价会很大。需求变更,编码人员会很强的抵触情绪。
  3. 束缚创造性:由于强调文档管理,所以管理人员会比较喜欢,但是他束缚了开发人员的创造性。
  4. 周期漫长:整个开发持续的生命周期很长,需求和设计的时间会耗费特别多,有时候会占用三分之一甚至更多时间,这样整个周期就会变长,大都在半年到一年左右的时间,所以更适合需求相对稳定的大项目
1.1.2 敏捷开发模型

软件开发生命周期(SDLC)是设计,开发和测试高质量软件的一种现象。

在敏捷的SDLC开发过程中,客户能够看到结果并了解他/她是否满意。这是敏捷SDLC模型的优势之一。

敏捷SDLC的每次迭代都包含跨不同阶段的跨职能团队:

  • 需求收集和分析
  • 设计要求
  • 构造/迭代
  • 部署
  • 测试
  • 反馈

image

敏捷开发主要包含三种模式:

1)迭代式开发生命周期

听说过敏捷的同学一定都听说过迭代这个东西。有的人说我们要迭代一个版本,有的人说我们要在这个迭代周期内完成什么,不管它指的是具体的软件版本,还是一段时间,这两字的含义其实都是一样的,那就是在整个项目开发过程中,切分出来的一个一个的小时间段。这一个时间段就是一次迭代。通过一次次的迭代,让整个项目更加清晰。最出名的针对迭代的概念的图示就是这个图。 image

从这个图中我们能看出什么呢?迭代就是不断丰富细节的过程。每一次的迭代,我们都应该让这个项目更加的清晰明了,细节也一步步地完善。

2)增量式开发生命周期

说完迭代式开发过程,我们再来说说增量,迭代和增量是所有敏捷教程都会说的东西,因为这两个东西很多人容易搞混。增量实际上是不断的添加待开始项目的产品的模块功能。就像搭积木一样地将不同的模板拼成一个完整的产品。同样地,也有一张图是专门针对增量这个概念的。 image

看出来增量和迭代的不同了吗?迭代的时候,有轮廓,不断完善细节。而增量,没有整体轮廓,上来就是细节完整的一个部分,不断地一部分一部分地完成,最终形成一个完整的产品

补充:迭代和增量这两种图,同时对应 Web 应用中图片的两种展示形式,不知道大家有没有印象,在网速不好的时候,有些网站打开大图是一块一块出来的,而有些网站打开大图是先模糊然后一步一步清晰的。有兴趣的同学可以搜索查找一下 PhotoShop 中导出 WEB 格式时选择连续功能的作用。

3)混合式开发生命周期

将上面的迭代和增量合起来,也就是在一次迭代中同时包含着增量,这样的形式就是混合式的生命周期 。这种情况下可以很好地运用这两种开发形式的优点。其实,我们目前大部分公司中的迭代冲刺都是这种混合式的生命周期的开发形式。在每次迭代中,我们添加的新功能模块其实就是在整个项目的轮廓中不断添加完善细节

敏捷开发的优缺点

image-20220413223759188

1.1.3 dev+ops

DevOps是一种思想、一组最佳实践、以及一种文化。DevOps落地实施,从组织架构、设计人员、流程、人员分工、人员技能到工具,变化很大,要求很高,完全颠覆了现有的开发运维模式,建设风险很高。

DevOps落地困境包括:

  • 涉及的部门多(开发中心、质量控制部门、生产运行部门);

  • 流程改造复杂;

  • 责任边界需要重新划分;

  • 自动化是核心问题;

    image-20240112152709909

    DevOps维基百科定义 DevOps(Development和Operations的组合词)是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。

image-20221129122627664

  • 从传统的IT项目交付的角度来看,DevOps实践框架包括:敏捷管理、持续集成、持续交付和自动化测试。

image-20220413205704276

敏捷管理
指将需求以用户故事的方式进行拆解,然后以最小化、快速迭代的方式进行开发管理。

持续集成
指针对开发人员的代码提交过程,以单件流的方式进行流水线式的自动化管理。

持续交付
预先定义、规划从代码生成到产品产出的流水线,并以自动化、模板化方式进行交付。

自动化测试
根据测试流程,以模板化、自动化的方式实现测试的手段。
1.1.4 为什么要 DevOps

传统的模式是开发人员只关心开发程序,追求功能的变化和实现

运维只负责基础环境管理和代码部署及监控等,更看重应用的稳定运行

双方缺少一个共同的目标

![1 00_00_00-00_00_30](/upload/~/.halo2/attachments/picture/1 00_00_00-00_00_30.gif)

DevOps 强调团队协作、相互协助、持续发展,实现团队作战,即无论是开发、运维还是测试,都为了最终的代码发布、持续部署和业务稳定而付出各自的努力,从而实现产品设计、开发、测试和部署的良性循环,实现产品的最终持续交付。

image-20221123111538183

想要将DevOps真正落地,首先第一点,是思维转变,也就是“洗脑”。不仅是运维的要洗,开发的也要洗。员工要洗,领导更要洗。

DevOps并不仅仅是组织架构变革,更是企业文化和思想观念的变革。如果不能改变观念,即使将员工放在一起,也不会产生火花。

除了洗脑之外,就是根据DevOps思想重新梳理全流程的规范和标准

在DevOps的流程下,运维人员会在项目开发期间就介入到开发过程中,了解开发人员使用的系统架构和技术路线,从而制定适当的运维方案。而开发人员也会在运维的初期参与到系统部署中,并提供系统部署的优化建议。

DevOps的实施,促进开发和运维人员的沟通,增进彼此的理(gan)解(qing)。

1.1.5 DevOps 相关的软件

在思维和流程改变的同时,想要充分落地DevOps,当然离不开软件和平台的支持。目前支持DevOps的软件很多了。

image-20221123111638318

DevOps 涉及的四大相关平台

  • 项目管理:如:Jira,禅道
  • 代码托管:如:Gitlab,SVN
  • 持续交付:如:Jenkins,Gitlab
  • 运维平台:如:腾讯蓝鲸,Spug等

二、CI/CD

持续集成和持续交付(CI/CD)是DevOps背后的助推力之一。如果你的企业正在考虑使用DevOps,那么CI/CD绝对是需要考虑的其中一部分。但是CI/CD到底意味着什么?为什么它如此重要呢?我们一起来了解一下。

2.1 CI

2.1.1 CI:持续集成(continuonus Integration)

功能:代码测试,代码合并,构建,部署,都在一起,并重复执行这个流程,并对结果进行反馈

CI中,开发人员将会频繁地向主干提交代码,这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证。 持续集成(CI)是在源代码变更后自动检测、拉取、构建和(在大多数情况下)进行单元测试的过程。持续集成的目标是快速确保开发人员新提交的变更是好的,并且适合在代码库中进一步使用。CI的流程执行和理论实践让我们可以确定新代码和原有代码能否正确地集成在一起。

CI 的目标是将集成简化成一个简单、易于重复的日常开发任务, 这样有助于降低总体的构建成本并在开发周期的早期发现缺陷。 要想有效地使用 CI 必须转变开发团队的习惯,要鼓励频繁迭代构建, 并且在发现 bug 的早期积极解决

从图例上来看流程,分为3个步骤:

  • 首先,开发人员提交代码到 Source Repository (源代码仓库)。
  • 然后,通过 git hook 等触发 CI Server(持续集成服务器)的相关功能。执行 编译 -> 测试 -> 输出结果 等。
  • 最后,向开发人员反馈结果的 report。

可以看出,持续集成的 核心 在于 确保新增的代码能够与原先代码正确的集成。与后续要介绍的持续交付以及持续部署,其最主要的差别也就在于其目标不同。

2.2 CD:持续交付(Continuous Delivery)和持续部署

这里的CD可对应多个英文名称,持续交付(Continuous Delivery)和持续部署(Continuous Deployment)。下面我们分别来看看什么是持续交付和持续部署。

2.2.1 持续交付(CD)

CD:持续交付(continuonus Delivery):将最终产品发布到生产环境,给用户使用

持续交付(CD)实际上是 CI 的扩展,其中软件交付流程进一步自动化,以便随时轻松地部署到生成环境中。 成熟的持续交付方案也展示了一个始终可部署的代码库。使用 CD 后,软件发布将成为一个没有任何紧张感的例行事件。 开发团队可以在日常开发的任何时间进行产品级的发布,而不需要详细的发布方案或者特殊的后期测试。

完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保 CI 已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。

img

在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中或发布给最终使用的用户。

CD 集中依赖于部署流水线,团队通过流水线自动化测试和部署过程。此流水线是一个自动化系统, 可以针对构建执行一组渐进的测试套件。CD 具有高度的自动化,并且在一些云计算环境中也易于配置。在流水线的每个阶段,如果构建无法通过关键测试会向团队发出警报。否则,将继续进入下一个测试, 并在连续通过测试后自动进入下一个阶段。流水线的最后一个部分会将构建部署到和生产环境等效的环境中。 这是一个整体的过程,因为构建、部署和环境都是一起执行和测试的,它能让构建在实际的生产环境可部署和可验证。

2.2.2 持续部署(CD)

CD:持续部署(continuonus Deployment):将代码部署到测试环境,预生产环境,生产环境

持续部署扩展了持续交付,以便软件构建在通过所有测试时自动部署。在这样的流程中, 不需要人为决定何时及如何投入生产环境。CI/CD 系统的最后一步将在构建后的组件/包退出流水线时自动部署。 此类自动部署可以配置为快速向客户分发组件、功能模块或修复补丁,并准确说明当前提供的内容。采用持续部署的组织可以将新功能快速传递给用户,得到用户对于新版本的快速反馈,并且可以迅速处理任何明显的缺陷。 用户对无用或者误解需求的功能的快速反馈有助于团队规划投入,避免将精力集中于不容易产生回报的地方。

随着 DevOps 的发展,新的用来实现 CI/CD 流水线的自动化工具也在不断涌现。这些工具通常能与各种开发工具配合, 包括像 GitHub 这样的代码仓库和 Jira 这样的 bug 跟踪工具。此外,随着 SaaS 这种交付方式变得更受欢迎, 许多工具都可以在现代开发人员运行应用程序的云环境中运行,例如 GCP 和 AWS。但是对于一个成熟的CI/CD管道(Pipeline)来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。目前最受欢迎的自动化工具是 Jenkins,后面我们也将详细介绍关于 Jenkins 的相关内容。

img

持续部署意味着所有的变更都会被自动部署到生产环境中。持续交付意味着所有的变更都可以被部署到生产环境中,但是出于业务考虑,可以选择不部署。如果要实施持续部署,必须先实施持续交付。持续交付并不是指软件每一个改动都要尽快部署到产品环境中,它指的是任何的代码修改都可以在任何时候实施部署。持续交付表示的是一种能力,而持续部署表示的则一种方式;持续部署是持续交付的最高阶段。

2.3 CICD 流程过程和架构

2.3.1 应用部署发展阶段
  • 开发人员自行上传代码

    早期项目,没有专业的运维人员,运维的工作由开发兼职完成,项目发布很不专业,很容易出错,也是最原始的方式

  • 开发人员先将代码发给运维,再由运维人员手动上传至生产环境

    专业的运维人员完成应用的部署,每次项目发布都由运维人员一步一步手动实现,效率低下且容易出错

  • 运维利用脚本和自动化运维工具实现部署

    由运维人员编写Shell,Python等脚本或利用自动化运维工具,如Ansible等实现半自动化应用部署,效率很高,但对技术的专业性有较高要求

  • 通过 Web 等 GUI 界面实现一键自动化部署

    可以通过开源或自研的运维平台实现方便的应用部署,操作容易,效率高,但需要提前构建运维平台

2.3.2 CICD 相关工具

image-20221123125855637

2.3.3 CICD 流程

image-20221123125912628

image-20221123125918687

  • 开发人员不断的进行代码提交到本地,再提交到运程的代码仓库服务器
  • Jenkins作为持续集成工具,使用Git工具到Git仓库拉取代码到集成服务器,代码测试与审查,再配合JDK,Maven,Go等软件完成代码编译,测试,打包等工作,在这个过程中每一步如果出错,都需要重新再执行一次整个流程。
  • Jenkins把生成的软件jar或war包等分发到测试服务器或者生产服务器,测试人员或用户就可以访问应用。
2.3.4 Kubernetes 环境的 CICD

image-20221123125956524

2.3.5 CICD 服务器架构

image-20221123130008799

2.4 CICD和DevOps的区别

CICD更关注的是整个开发,测试,部署的自动化的过程,当我们在本地单元测试通过后,我们提交到git上,触发相应的webhook或者类似的东西进行代码的构建,并打包部署到相应的机器上,自动化的完成这整个过程。

而DevOps更关注的是打通用户、PMO、需求、设计、开发(Dev)、测试、运维(Ops)等各上下游部门或不同角色;打通业务、架构、代码、测试、部署、监控、安全、性能等各领域工具链;尤其是打通开发与运维之间的gap,因为两者实际上存在着很多的冲突。DevOps是基于CICD的,自动化的流程是基础,DevOps是一个项目由idea到实际稳定运行的产品的一个最佳实践。

DevOps是CICD思想的延伸,CICD是DevOps的基础核心,如果没有CICD自动化的工具和流程,DevOps是没有意义的。

2.5 代码发布方式

2.5.1 蓝绿部署(Blue-green Deployments)
蓝绿部署的目的是减少发布时的中断时间、能够快速撤回发布。
蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的,并且正在运行的系统,只是系统版本和对外服务情况不同。

最初,没有任何系统,没有蓝绿之分。

然后,第一套系统开发完成,直接上线,这个过程只有一个系统,也没有蓝绿之分。

后来,开发了新版本,要用新版本替换线上的旧版本,在线上的系统之外搭建了一个使用新版本代码的全新系统。 这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。

img

蓝色系统不对外提供服务,用来做啥?

用来做发布前测试,测试过程中发现任何问题,可以直接在蓝色系统上修改,不干扰用户正在使用的系统。(注意,两套系统没有耦合的时候才能百分百保证不干扰)

蓝色系统经过反复的测试、修改、验证,确定达到上线标准之后,直接将用户切换到蓝色系统:

img

    切换后的一段时间内,依旧是蓝绿两套系统并存,但是用户访问的已经是蓝色系统。这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。

    当确信对外提供服务的蓝色系统工作正常,不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。 原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。

    蓝绿部署只是上线策略中的一种,它不是可以应对所有情况的万能方案。 蓝绿部署能够简单快捷实施的前提假设是目标系统是非常内聚的,如果目标系统相当复杂,那么如何切换、两套系统的数据是否需要以及如何同步等,都需要仔细考虑。
2.5.2 金丝雀发布(anCanary Releases)
金丝雀发布(Canary)也是一种发布策略,和国内常说的灰度发布是同一类策略,金丝雀发布(canary release)也叫灰度发布。

金丝雀发布(Canary releas)是一种降低在生产中引入新软件版本的风险的技术,方法是在将更改推广到整个基础架构并使其可供所有人使用之前,缓慢地将更改推广到一小部分用户。

与(蓝-绿部署)BlueGreenDeployment类似,您首先将软件的新版本部署到基础架构的子集,没有用户被路由到该子集。

image-20230627111256050

当您对新版本感到满意时,您可以开始将一些选定的用户路由到它。选择哪些用户会看到新版本有不同的策略:一个简单的策略是使用随机样本;一些公司选择将新版本发布给内部用户和员工,然后再发布给全世界;另一种更复杂的方法是根据用户的个人资料和其他人口统计数据来选择用户。

image-20230627111349579

随着您对新版本越来越有信心,您可以开始将其发布到基础架构中的更多服务器并将更多用户路由到它。推出新版本的一个好做法是使用PhoenixServers重新调整现有基础架构的用途,或者使用ImmutableServers配置新的基础架构并停用旧的基础架构。

Canary 版本是ParallelChange的一个应用程序,迁移阶段一直持续到所有用户都被路由到新版本。届时,您可以停用旧的基础设施。如果您发现新版本有任何问题,回滚策略只是将用户重新路由回旧版本,直到您解决了问题。

image-20230627111430891

使用金丝雀版本的一个好处是,如果发现问题,可以在生产环境中使用安全回滚策略对新版本进行容量测试。通过缓慢增加负载,您可以监控和捕获有关新版本如何影响生产环境的指标。这是创建完全独立的容量测试环境的另一种方法,因为该环境将尽可能地类似于生产环境。

在大型分布式场景中,不是使用路由器来决定哪些用户将被重定向到新版本,而是使用不同的分区策略也很常见。例如:如果您有地理分布的用户,您可以先将新版本推出到一个区域或特定位置;如果你有多个品牌,你可以先推广到一个品牌,等等

譬如说,目标系统是一组无状态的Web服务器,但是数量非常多,假设有一万台。这时候,蓝绿部署就不能用了,因为你不可能申请一万台服务器专门用来部署蓝色系统(在蓝绿部署的定义中,蓝色的系统要能够承接所有访问)。

可以想到的一个方法是:

    只准备几台服务器,在上面部署新版本的系统并测试验证。测试通过之后,担心出现意外,还不敢立即更新所有的服务器。 先将线上的一万台服务器中的10台更新为最新的系统,然后观察验证。确认没有异常之后,再将剩余的所有服务器更新。这个方法就是金丝雀发布。

    实际操作中还可以做更多控制,譬如说给最初更新的10台服务器设置较低的权重、控制发送给这10台服务器的请求数,然后逐渐提高权重、增加请求数。

    这个控制叫做“流量切分”,既可以用于金丝雀发布,也可以用于后面的A/B测试。

    蓝绿部署和金丝雀发布是两种发布策略,都不是万能的。有时候两者都可以使用,有时候只能用其中一种。
2.5.3 A/B测试(A/B Testing)

首先需要明确的是,A/B测试和蓝绿部署以及金丝雀,完全是两回事。

蓝绿部署和金丝雀是发布策略,目标是确保新上线的系统稳定,关注的是新系统的BUG、隐患。

    A/B测试是效果测试,同一时间有多个版本的服务对外服务,这些服务都是经过足够测试,达到了上线标准的服务,有差异但是没有新旧之分(它们上线时可能采用了蓝绿部署的方式)。

    A/B测试关注的是不同版本的服务的实际效果,譬如说转化率、订单情况等。

    A/B测试时,线上同时运行多个版本的服务,这些服务通常会有一些体验上的差异,譬如说页面样式、颜色、操作流程不同。相关人员通过分析各个版本服务的实际效果,选出效果最好的版本。

img

在A/B测试中,需要能够控制流量的分配,譬如说,为A版本分配10%的流量,为B版本分配10%的流量,为C版本分配80%的流量。

A/B版本

A/B测试即同时对外提供两个APP运行环境,这和蓝绿部署的同时只有一个版本在线是不同的

A/B 测试是用来测试应用功能表现的方法,例如可用性、受欢迎程度、可见性等等

蓝绿部署和A/B测试是不同的,蓝绿部署的目的是安全稳定地发布新版本应用,并在必要时回滚,即蓝绿部署是同一时间只有一套正式环境在线,而A/B测试是两套正式环境同时在线,一般用于多个产品竟争时使用
2.5.4 滚动发布(更新)

滚动发布故名思议,就是逐步升级服务中的节点

滚动发布是指每次只升级一个或多个服务实例,升级完成后加入生产环境,不断执行这个过程,直到集群中的全部旧版本升级新版本。

image-20221123142037837

红色:正在更新的实例

蓝色:更新完成并加入集群的实例

绿色:正在运行的实例

滚动发布过程:

1. 先升级1个服务实例,主要做部署验证;
2. 每次升级1个服务实例,自动从LB上摘掉,升级成功后自动加入集群
3. 事先需要有自动更新策略,分为若干次,每次数量/百分比可配置
4. 回滚是发布的逆过程,先从LB摘掉新版本,再升级老版本,这个过程一般时间比较长
5. 自动化要求高

三、版本控制

3.1 什么是版本?

操作系统版本:centos7.1,centos7.9,redhat7.x,windows server 2012
软件版本:nginx-1.12,nginx-1.18,nginx-1.20
配置文件版本:beta,v1,v3

3.2 什么是版本控制?

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理多人协同开发项目的技术。

3.3 为什么要有版本控制?

没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。无论是工作还是学习,或者是自己做笔记,都经历过这样一个阶段!我们就迫切需要一个版本控制工具。(多人开发就必须要使用版本控制)

image-20221129125359538

使用版本控制之后可以给你带来的一些便利:
● 实现跨区域多人协同开发
● 追踪和记载一个或者多个文件的历史记录
● 组织和保护你的源代码和文档
● 统计工作量
● 并行开发、提高开发效率
● 跟踪记录整个软件的开发过程
● 减轻开发人员的负担,节省时间,同时降低人为错误

image-20221129125831341

3.4 常见的版本控制工具

主流的版本控制器:

● Git
● SVN(Subversion)
● CVS(Concurrent Versions System)
● VSS(Micorosoft Visual SourceSafe)
● TFS(Team Foundation Server)
● Visual Studio Online
● 阿里云 云效
● 腾讯云 tapd
3.4.1 CVS(Concurrent Version System) 集中式版本控制系统

并发版本系统(Concurrent Versions System,CVS)是最初的第二代版本控制系统。大约十年间,它是最为流行的版本控制系统,直到 2000 年被 Subversion 所取代。

CVS 最早是由一位名叫 Dick Grune 的荷兰科学家于 1986 年 6 月 23 日公开发布了该代码。CVS 最初仅仅只是一个包装了 RCS( 修订控制系统(Revision Control System)) 的 Shell 脚本集合。最终演变成当前版本的 CVS 的代码始于 1989 年 4 月的 Brian Berliner 的贡献,后来由 Jeff Polk 和许多其他贡献者提供帮助。 Brian Berliner 撰写了一篇论文,介绍了他对 CVS 程序的改进 - 该程序描述了该工具是如何在Prysma 内部扩展和使用的。 1990 年 11 月 19 日,CVS 1.0 版被提交给自由软件基金会进行开发和分发。

CVS是一个C/S系统,是一个早期常用的代码版本控制软件。多个开发人员通过一个中心版本控制系统来记录文件版本,从而达到保证文件同步的目的。CVS版本控制系统是一种GNU软件包,主要用于在多人开发环境下的源码的维护。

由于 CVS 是集中式版本控制系统,所以它有客户端和服务端之区分。但要开始使用 CVS 的话,即使只在你的本地机器上使用,也必须设置 CVS 的服务端。

3.4.2 SVN(Subversion) 集中式版本控制系统

SVN 由 CollabNet 公司于 2000 年资助并发起开发,目的是创建一个更好用的版本控制系统以取代CVS。

2000 年 2 月,CollabNet 联系了 Open Source Development with CVS(Coriolis, 1999)的作者 Karl Fogel,问他是否愿意为这个新项目工作。这时 Karl 已经在和他的朋友 Jim Blandy 讨论一个新的版本控制系统的设计。他不仅已经起好了名字 “Subversion”,而且有了 Subvesion 资料库的基本设计。

经过 14 个月的编码,在 2001 年 8 月 31 号,Subversion 可以“自我寄生”了。就是说,Subversion 开发人员停止使用 CVS 管理 Subversion 的源代码,开始使用 Subversion 代替。

2009 年 11 月,Subversion 被 Apache Incubator 项目所接收。2010 年 1 月,正式成为 Apache 软件基金会的一个顶级项目

SVN 依赖于网络,需要在各个开发主机上安装客户端软件,并且在一台服务器集中进行版本管理和存储.目前依然有部分公司在使用

优点:

  • 管理方便,逻辑明确,符合一般人思维习惯。
  • 易于管理,集中式服务器更能保证安全性。
  • 代码一致性非常高。
  • 适合开发人数不多的项目开发。

缺点:

  • 服务器压力太大,数据库容量暴增。
  • 如果不能连接到服务器上,基本上不可以工作,如果服务器不能连接上,就不能提交,还原,对比等等。
  • 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。
3.4.3 Git

image-20221123140754178

在 Linux 开源的初期,Linux 开源项目的代码是 linus 本人通过 linux 命令 diff 和 patch 两条命令手动完成。随着 Linux 代码越来越壮大,靠 Linus 一个人来手动合并已经不现实。2002 年,Linus 选择了一个商业版本控制系统 BitKeeper 作为 Linux 内核的代码管理工具(BitKeeper 的开发商 BitMover 授权linux 社区免费使用)。但是,免费使用是有很多的限制的,因此 linux 社区的大佬开始破解BitKeeper。其中,samba 的作者 andrew 破解成功了。但是被 BitMover 公司发现,收回免费使用权。

迫不得已,Linus 选择了自己开发一个分布式版本控制工具以替代 BitKeeper。linus 闭关一个月,写出了 Git。在一个月后,Git 成功接管了 Linux 社区的版本控制工作,并且开始开源。维基百科中,有如下历史记录:

2005年4月3日,开始开发 Git。
2005年4月6日,项目发布。
2005年4月7日,Git就可以作为自身的版本控制工具了。
2005年4月18日,发生第一个多分支合并。
2005年4月29日,Git 的性能就已经达到了 Linus 的预期。
2005年6月16日,Linux 2.6.12 发布,那时 Git 已经在维护 Linux 核心的源代码了。
2005年7月26日,Linus 功成身退,将 Git 的维护交给另外一个 Git 的主要贡献者 Junio C Hamano。
2016年5月,BitKeeper宣布使用 Apache 2.0许可证开源。

Git 重要特性:

在本地就可以完成提交,因此不需要网络,提交完成后,可以有网络环境时,再同步到远程仓库服务器

优点:

  • 适合分布式开发,强调个体。
  • 公共服务器压力和数据量都不会太大。
  • 速度快、灵活。
  • 任意两个开发者之间可以很容易的解决冲突。
  • 支持离线工作。

缺点:

  • 不符合常规思维。
  • 学习周期相对而言比较长。
  • 代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

3.5 SVN和Git的特点

3.5.1 SVN的特点
1.每个版本库有唯一的URL(官方地址),每个用户都从这个地址获取代码和数据;

2.获取代码的更新,也只能连接到这个唯一的版本库,同步以取得最新数据;

3.提交必须有网络连接(非本地版本库);

4.提交需要授权,如果没有写权限,提交会失败;

5.提交并非每次都能够成功。如果有其他人先于你提交,会提示“改动基于过时的版本,先更新再提交”… 诸如此类;

6.冲突解决是一个提交速度的竞赛:手快者,先提交,平安无事;手慢者,后提交,可能遇到麻烦的冲突解决。
3.5.2 Git特点
1.Git是一款免费、开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目

2.Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

3.分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者通过克隆(git clone),在本地机器上拷贝一个完整的Git仓库.

3.6 Git 相关概念和原理

3.6.1 Git 的区域

image-20221123155256066

  • 工作区 workspace:clone的代码或者开发编写代码文件所在的目录 ,通常是一个服务代码所在的目录名称 ,对应于<项目目录>
  • 暂存区index :用于存储在工作区中对代码进行修改后的文件所保存的地方,只有放入此区的文件才能被git进行管理,使用 git add添加,对应为<项目目录>/.git/index文件
  • 本地仓库repo: 用于存储在工作区和暂存区中改过并提交的文件地方,使用 git commit 提交,对应于/<项目目录>/.git/
  • 远程仓库 :多个开发人员共同协作提交代码的仓库,即 私有 gitlab 服务器或公有云github,gitee网站等.

image-20221123155328839

3.6.2文件的状态变化周期

image-20221123155344987

  • untracked: 在工作目录下创建的新文件,这个时候本地git仓库不知道,不能对其进行版本跟踪管理
  • unmodified: 添加到暂存区的文件未修改,把文件从暂存区推动到本地仓库
  • modified: 已经添加到暂存区的文件,在本地工作区的文件被修改了 ,需要重新添加至暂存区
  • staged: 文件添加到了本地仓库里面的暂存区
3.6.2 Git 分支和标签
  • 分支: 对文件的副本,可以实现多个不同用途的软件版本同时的演进,实现多个开发版本的隔离

    image-20221123155421464

    分支在实际中有什么用呢?

    假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能测试等工作。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

    现在有了分支,就不用担心了。你创建了一个独立的分支,对其他人是透明的,没有影响,他们还继续在原来的分支上正常工作,而你在自己的分支上工作,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样既安全,又不影响别人工作。

  • tag: 给某个状态打个标签用于记录当前状态,相当于里程碑

    tag是git版本库的一个标记,指向某个commit的指针。

    tag主要用于发布版本的管理,一个版本发布之后,可以为git打上 v1.0.1,v1.0.2 ...这样的类似的标签。

    tag跟branch有点相似,但是本质上和分工上是不同的:

    tag 对应某次commit, 是一个点,是不可移动的。

    branch 对应一系列commit,是很多点连成的一根线,有一个HEAD 指针,是可以依靠 HEAD 指针移动的。

    所以,两者的区别决定了使用方式,改动代码用 branch ,不改动只查看用 tag。

    tag 和 branch 的相互配合使用,有时候起到非常方便的效果

    例如:已经发布了 v1.0 v2.0 v3.0 三个版本,这个时候,我突然想不改现有代码的前提下,在 v2.0 的基础上加个新功能,作为 v4.0 发布。就可以检出 v2.0 的代码作为一个 branch ,然后作为开发分支。

3.6.3 开发分支流程

image-20221123155531859

image-20221123155538311

四、代码托管平台介绍

4.1代码托管平台

4.1.1 Github 网站

官网: http://www.github.com

2008年1月,Wanstrath和Preston-Werner推出使用Ruby on Rails编写而成的GitHub的个人测试版。2月,他们又增加了第三位联合创始人PJ Hyett,到2008年3月,GitHub的beta版已经拥有了2000名用户。GitHub于2008年4月推出公共版本,然后逐渐在开发者社区中流行起来,到2009年7月,用户数量达到了10万。

由于GitHub在软件开发人员中很受欢迎,成立后的四年,GitHub通过向个人程序员和企业收取每月访问平台的费用,在没有外部资金的情况下得以生存下来。

GitHub网站为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。GitHub同时提供付费账户和免费账户。这两种账户都可以创建公开的代码仓库,但是只有付费账户可以创建私有的代码仓库。

2018年6月5日 微软花费 75 亿美元收购 GitHub。

2019年1月7日 免费的 GitHub 用户现在可以获得不受限制的私人项目,最多可以有三个协同合作者。

2020年4月14日 GitHub宣布向所有用户和团队提供不限制协作人数的私有仓库,同时GitHub的核心功能对所有人免费开放。

4.1.2 GitLab 网站和软件

GitLab 官方网站: https://about.gitlab.com/

Github 提供了公有云的软件仓库服务,但实现私有仓库早期是收费的,而GitLab的出现解决了这一问题。GitLab由乌克兰程序员DmitriyZaporozhets和ValerySizov开发,它使用Ruby语言写成。后来,一些部分用Go语言重写,是完全免费的开源软件,按照MIT许可证分发。2013年7月,GitLab产品被拆分为两个版本:GitLab CE(社区版)和GitLab EE(企业版),2014年2月,GitLab宣布采用开放核心业务模式。GitLabEE设置在专有许可证下,并且包含CE版本中不存在的功能。GitLabCE是使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。

从安全方面来看,公司不希望员工获取到全部的代码,这个时候Gi tLab是最佳的选择。但对于开源项目而言,GitHub 依然是代码托管的首选平台。

Gitlab 企业版:

image-20221123141109299

Gitlab 的优势

  • 开源免费,搭建简单、维护成本较低、可适用于中小型公司内部项目使用。
  • 权限管理功能强大灵活,能实现代码对部分人可见,确保项目的安全性。
  • 支持离线提交,基于git实现,可以不在实时依赖网络环境进行代码提交。

4.2 git使用

使用git命令之前,先安装git

https://git-scm.com/download/linux
[root@server1 ~]# yum -y install git
4.2.1 设置提交代码时的用户信息

(首次提交代码提交设置用户信息)

$ git config [--global] user.name "[name]"

$ git config [--global] user.email "[email address]"

$ git config [--global] color.ui true

Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。

# 显示当前的Git配置

$ git config --list

# 编辑Git配置文件

$ git config -e [--global]

示例:拉取代码

#拉取代码
[root@server1~]# git clone https://github.com/wuchaofeng/demo.git  
Cloning into 'demo'...
remote: Enumerating objects: 16, done.
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 16 (delta 2), reused 11 (delta 1), pack-reused 0
Unpacking objects: 100% (16/16), done.
[root@server1 ~]# ls
anaconda-ks.cfg  demo
[root@node01 ~]# cd demo/
[root@node01 demo]# ls
1.html  2.html  3.html  README.md

#修改1.html文件
[root@server1 demo]# vim 1.html  

#添加到暂存区
[root@server1 demo]# git add . 

#查看暂存区状态
[root@server1 demo]# git status  
# On branch main
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   1.html     
#

 #提交代码
[root@server1 demo]# git commit -m "第一次提交 1.html"  

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@server1.(none)')

#设置用户提交信息
[root@server1 ~]# git config --global user.name wcfeng
[root@server1 ~]# git config --global user.email "wuchaofeng@qq.com"
[root@server1 ~]# git config --list
user.name=wcfeng
user.email=wuchaofeng@qq.com
4.2.2 创建本地仓库

仓库(repository):也叫版本库,当使用git init命令后,会在本地的目录下生成一个.git的隐藏目录,可以理解为git的仓库或者版本库

仓库为本地仓库远程仓库

工作目录:也叫工作区,是存在项目代码的一个目录

image-20221129205206925

# 在当前目录新建一个Git代码库

$ git init

# 新建一个目录,将其初始化为Git代码库

$ git init [project-name]  

# 下载一个项目和它的整个代码历史

$ git clone [url]

示例:

[root@server1 ~]# mkdir gitwork   ##新建工作目录
[root@server1 ~]# cd gitwork/
[root@server1 gitwork]# git init     ##新建仓库
Initialized empty Git repository in /root/gitwork/.git/
[root@server1 gitwork]# cd ..
[root@server1 ~]# git init test     ##新建目录和仓库
Initialized empty Git repository in /root/test/.git/
4.2.3 添加和提交文件到仓库
#添加单个文件到暂存区
$ git add [file1]

# 添加多个文件到暂存区
$ git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
$ git add [dir]

# 添加当前目录的所有文件到暂存区
$ git add .

# 提交暂存区到仓库区
$ git commit -m [message]

# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]

示例:

增加/提交文件--第一次

1)新增文件
[root@server1 gitwork]# cat 1.html
this is first version!
2)添加到暂存区
[root@server1 gitwork]# git add 1.html   
3)查看状态
[root@server1 gitwork]# git status   
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#	new file:   1.html  
4)提交
[root@server1 gitwork]# git commit -m "第一次提交 1.html"  
[master (root-commit) 9c89d73] 第一次提交 1.html
 1 file changed, 1 insertion(+)
 create mode 100644 1.html

5)再次查看状态,是空的,没有可提交文件
[root@server1 gitwork]# git status
# On branch master
nothing to commit, working directory clean

增加/提交文件--第二次

[root@server1 gitwork]# cat 1.html
this is second version!
[root@server1 gitwork]# git add 1.html
[root@server1 gitwork]# git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   1.html
#
[root@server1 gitwork]# git commit -m "第二次提交 1.html"
[master a8b550f] 第二次提交 1.html
 1 file changed, 1 insertion(+), 1 deletion(-)
[root@server1 gitwork]# git status
# On branch master
nothing to commit, working directory clean

#提交多个文件
[root@server1 gitwork]# git add 2.html 3.html
[root@server1 gitwork]# git commit -m "提交 2.html 3.html"
[master 6f62c49] 提交 2.html 3.html
 2 files changed, 2 insertions(+)
 create mode 100644 2.html
 create mode 100644 3.html
[root@server1 gitwork]#

增加/提交文件--第三次

#新建文件
[root@server1 gitwork]# cat 4.html 5.html
44444444

55555555555
[root@server1 gitwork]# cat 4.html 5.html

#查看状态
[root@server1 gitwork]# git status  
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	4.html                                 ##检查到了有2个新的文件
#	5.html
nothing added to commit but untracked files present (use "git add" to track)

#添加到暂存区
[root@server1 gitwork]# git add .

#查看状态
[root@server1 gitwork]# git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   4.html
#	new file:   5.html
#
#提交
[root@server1 gitwork]# git commit -m "提交 4.html,5.html"
[master bab64cf] 提交 4.html,5.html
 2 files changed, 3 insertions(+)
 create mode 100644 4.html
 create mode 100644 5.html
[root@server1 gitwork]#
4.2.4 查看版本历史

使用git log可以看到历史版本信息,如果想看修改的信息,可以使用git log --stat

[root@server1 gitwork]# git log
commit bab64cf4dd33fcb74b64880a478d9ce2ae8156bd
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:24:47 2022 +0800

    提交 4.html,5.html

commit 6f62c49db965898a2a512063552542f54032528f
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:13:10 2022 +0800

    提交 2.html 3.html

commit a8b550f01b1521137d092a9d40bd0bc08441014b
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:09:10 2022 +0800

    第二次提交 1.html

commit 9c89d738f0a5959c8d3cfa29f1bba890aa463108
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:04:09 2022 +0800

    第一次提交 1.html
[root@server1 gitwork]#
[root@server1 gitwork]#  git log --stat
commit bab64cf4dd33fcb74b64880a478d9ce2ae8156bd
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:24:47 2022 +0800

    提交 4.html,5.html

 4.html | 2 ++
 5.html | 1 +
 2 files changed, 3 insertions(+)

commit 6f62c49db965898a2a512063552542f54032528f
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:13:10 2022 +0800

    提交 2.html 3.html

 2.html | 1 +
 3.html | 1 +
 2 files changed, 2 insertions(+)

commit a8b550f01b1521137d092a9d40bd0bc08441014b
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:09:10 2022 +0800

    第二次提交 1.html

 1.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 9c89d738f0a5959c8d3cfa29f1bba890aa463108
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:04:09 2022 +0800

    第一次提交 1.html

 1.html | 1 +
 1 file changed, 1 insertion(+)

显示过去3次提交

[root@server1 gitwork]# git log -3 --pretty --oneline
bab64cf 提交 4.html,5.html
6f62c49 提交 2.html 3.html
a8b550f 第二次提交 1.html
4.2.5 版本回退和还原

1)使用git reset --hard HEAD^回退到上一个版本

git reset --hard  HEAD^

如果是回退到是上上个版本,则使用

git reset --hard  HEAD^^

以此类推即可,如果是回退到前100个版本,则可以使用

git reset --hard HEAD~100

示例:回退到上一个版本

[root@server1 gitwork]# git reset --hard HEAD^  
HEAD is now at 6f62c49 提交 2.html 3.html
[root@server1 gitwork]# git log
commit 6f62c49db965898a2a512063552542f54032528f
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:13:10 2022 +0800

    提交 2.html 3.html

commit a8b550f01b1521137d092a9d40bd0bc08441014b
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:09:10 2022 +0800

    第二次提交 1.html

commit 9c89d738f0a5959c8d3cfa29f1bba890aa463108
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:04:09 2022 +0800

    第一次提交 1.html
[root@server1 gitwork]#

2)使用git reset --hard 第2个版本 HEAD_ID

[root@server1 gitwork]# git reset --hard bab64cf
HEAD is now at bab64cf 提交 4.html,5.html
[root@server1 gitwork]# git log
commit bab64cf4dd33fcb74b64880a478d9ce2ae8156bd
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:24:47 2022 +0800

    提交 4.html,5.html

commit 6f62c49db965898a2a512063552542f54032528f
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:13:10 2022 +0800

    提交 2.html 3.html

commit a8b550f01b1521137d092a9d40bd0bc08441014b
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:09:10 2022 +0800

    第二次提交 1.html

commit 9c89d738f0a5959c8d3cfa29f1bba890aa463108
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:04:09 2022 +0800

    第一次提交 1.html

3)还原版本

还原版本可以使用git reflog查看ID信息,使用ID进行还原版本

[root@server1 gitwork]# git reflog
6f62c49 HEAD@{0}: reset: moving to HEAD^
bab64cf HEAD@{1}: commit: 提交 4.html,5.html
6f62c49 HEAD@{2}: commit: 提交 2.html 3.html
a8b550f HEAD@{3}: commit: 第二次提交 1.html
9c89d73 HEAD@{4}: commit (initial): 第一次提交 1.html
[root@server1 gitwork]# git reset --hard bab64cf
HEAD is now at bab64cf 提交 4.html,5.html
[root@server1 gitwork]# git log
commit bab64cf4dd33fcb74b64880a478d9ce2ae8156bd
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:24:47 2022 +0800

    提交 4.html,5.html

commit 6f62c49db965898a2a512063552542f54032528f
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:13:10 2022 +0800

    提交 2.html 3.html

commit a8b550f01b1521137d092a9d40bd0bc08441014b
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:09:10 2022 +0800

    第二次提交 1.html

commit 9c89d738f0a5959c8d3cfa29f1bba890aa463108
Author: wcfeng <wuchaofeng@qq.com>
Date:   Sat Oct 29 14:04:09 2022 +0800

    第一次提交 1.html

小结:

1)提交代码后,可以使用git log查看当前版本和历史版本信息

2)回退版本可以使用git reset --hard HEAD^和git reset --hard  版本ID号来操作

3)使用git reflog查看ID信息,使用ID进行还原到任意的版本
4.2.6 撤销已添加到暂存区文件

image-20221129221032061

刚才我们了解了版本的回退和还原,可以将版本从版本库回退至暂存区,假如开发人员此刻写的代码出现了问题,并且已经添加到了暂存区,该如何回退了,git给我们提供了一些办法:

1、将修改错误的代码直接删除
2、如果已经添加到了暂存区,并提交,使用git reset --hard HEAD取消暂存区,在使用git checkout --文件名 来进行撤销
3、如果是还未提交到暂存区,则直接使用git checkout --文件名 来进行撤销
# 切换到上一个分支
$ git checkout -- file1

示例:已经修改文件,但是未添加到暂存区

模拟开发人员状态不好时代码修改错误的情况!

1)先修改1.html文件

[root@server1 gitwork]# cat 1.html
this is second version!
111111111111111111                     <-------#新修改的内容
  1. 撤销修改
[root@server1 gitwork]# git checkout -- 1.html    ##撤销
[root@server1 gitwork]# cat 1.html             <-------#文件又恢复了
this is second version!

示例:已经添加到了暂存区已经提交

模拟开发人员状态不好时代码修改错误的情况!

1)先修改1.html文件

[root@gitlab demo]# echo hello >> test.py 
[root@gitlab demo]# cat test.py 
test
hello   #新增的内容  

2)添加到暂存区并提交

[root@gitlab demo]# git add test.py 
[root@gitlab demo]# git commit -m "第二次提交到test.py"
[main 0893db9] 第二次提交到test.py
 1 file changed, 1 insertion(+)

3)先将仓库中的版本回退到暂存区,

[root@gitlab demo]# git reset --hard HEAD^
HEAD is now at 3ef0e2b 第一次提交到test.py

4)撤销到工作目录

[root@gitlab demo]# git checkout -- test.py 
[root@gitlab demo]# cat test.py   #文件内容恢复
test
4.2.7 误删恢复

误删恢复可以使用git checkout 来进行恢复,但是需要添加到暂存区才能恢复,如果没有添加到暂存区,则删除互无法恢复

示例:

[root@server1 gitwork]# vim code.py  
[root@server1 gitwork]# cat code.py    
1                                               ##第一次添加数据

[root@server1 gitwork]# git add code.py         ##第一次添加到暂存区
[root@server1 gitwork]# vim code.py             ##第二次添加数据
[root@server1 gitwork]# cat code.py
1
2
[root@server1 gitwork]# git add code.py         ##第二次添加到暂存区
[root@server1 gitwork]# vim code.py             ##第三次添加数据
[root@server1 gitwork]# cat code.py      
1
2
3
[root@server1 gitwork]# git add code.py      ##第三次添加到暂存区
[root@server1 gitwork]# git status           ##查看状态
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   code.py
#
[root@server1 gitwork]# rm -rf code.py           ##模拟文件被误删除
[root@server1 gitwork]# git checkout -- code.py     ##恢复
[root@server1 gitwork]# ls
1.html  code.py
[root@server1 gitwork]# cat code.py             ##恢复成功
1
2
3

[root@server1 gitwork]# cat code.py        ##第四次添加数据  
1
2
3
4
[root@server1 gitwork]# rm -rf code.py     ##删除文件
[root@server1 gitwork]# git checkout -- code.py    ##恢复
[root@server1 gitwork]# cat code.py              ##查看并没有新增的数据
1
2
3
[root@server1 gitwork]#
4.2.8 文件删除

文件删除,是指将工作目录、暂存区、版本库中的文件都删除。

image-20221129221229839

1)没有提交到暂存区的文件,直接在工作目录删除即可

2)如果已经提交到了暂存区,则直接使用git rm来删除即可
[root@server1 gitwork]# vim test.py
[root@server1 gitwork]# git add test.py              ##添加到暂存区
[root@server1 gitwork]# git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	deleted:    1.html
#	new file:   test.py                     
[root@server1 gitwork]# rm -rf test.py                ##删除工作目录文件
[root@server1 gitwork]# git rm test.py                ##删除暂存区文件
rm 'test.py'
[root@server1 gitwork]# git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	deleted:    1.html
#

3)如果已经提交到了仓库中,则需要先rm删除工作目录的文件,在git rm暂存区内容,然后再次提交

[root@server1 gitwork]# vim test.py
[root@server1 gitwork]# git add test.py    ##添加到暂存区
[root@server1 gitwork]# git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	deleted:    1.html
#	new file:   test.py
#
[root@server1 gitwork]# git commit -m "第一次提交新建文件 test.py"  ##提交
[master 6b73d09] 第一次提交新建文件 test.py
 2 files changed, 1 insertion(+), 1 deletion(-)
 delete mode 100644 1.html
 create mode 100644 test.py
[root@server1 gitwork]# rm -rf test.py            ##删除工作目录文件
[root@server1 gitwork]# git rm test.py            ##删除暂存区文件
rm 'test.py'
[root@server1 gitwork]# git commit -m "删除test.py"  ##提交
[master e567bfc] 删除test.py
 1 file changed, 1 deletion(-)
 delete mode 100644 test.py
[root@server1 gitwork]#

4.3 分支管理

4.3.1 git分支的概念

可以认为分支就是当前工作目录中代码的一份副本。使用分支,可以让我们从开发主线上分离出来,以免影响开发主线。

image-20221130212529817

假设在一个项目中,有4位开发者,分别开发不同的模块功能,当项目开发到一定阶段后,张三就想将代码提交到远程的仓库中,此时赵六需要接收开发其他的模块,需要下载源码到本地继续开发,而原本张三的功能并未开发完,导致赵六在使用了张三的代码后,运行始终是存在问题,这就导致问题的发生

有了分支的功能后,每个开发者都可以从远程主分支中拉取一个完整的源代码进行开发,而且开发过程不受其他的开发者影响,每个人都有一个独立的开发环境,开发完成后,再将完整的代码合并到主分支中即可。

4.3.2 查看分支
[root@server1 gitwork]# git branch
* master                      #*号表示当前所属分支
4.3.2 创建新分支
[root@server1 gitwork]# git branch dev
[root@server1 gitwork]# git branch
  dev
* master
4.3.4 切换分支
[root@server1 gitwork]# git checkout dev       ##切换分支
Switched to branch 'dev'
[root@server1 gitwork]# git branch
* dev
  master
[root@server1 gitwork]# ls
1.html                        ##dev分支保持和主分支一样的代码
4.3.5 合并分支
[root@server1 gitwork]# git branch dev                   ##创建分支
[root@server1 gitwork]# git checkout dev                   ##切换到dev分支
Switched to branch 'dev'
[root@server1 gitwork]# echo "新增加了一些新功能" >>1.html  ##创建一个新的文件
[root@server1 gitwork]# git add 1.html                   ##添加到暂存区
[root@server1 gitwork]# git commit -m "新增加了一些新功能"    ##提交到仓库
[dev a707fde] 新增加了一些新功能
 1 file changed, 1 insertion(+)
 create mode 100644 1.html
[root@server1 gitwork]#  git checkout master             ##切换到主分支
Switched to branch 'master' 
[root@server1 gitwork]# ls                               ##此时ls是看不到文件
[root@server1 gitwork]# git merge dev                    ##代码合并
Updating e567bfc..a707fde
Fast-forward
 1.html | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 1.html
[root@server1 gitwork]# ls                        ##再次查看可以看到1.html文件
1.html
[root@server1 gitwork]# cat 1.html
新增加了一些新功能
4.3.5 分支冲突

分支冲突在代码开发过程中会经常遇到,比如张三和赵六同时在修改1.html中的文件,这样就会导致冲突,Git却不能帮我们解决此问题,需要我们手动解决冲突。

1)开发者1在dev分支上修改1.html文件

[root@server1 gitwork]# git checkout dev
Switched to branch 'dev'
[root@server1 gitwork]# echo "张三修改部分代码" >> 1.html

2)提交在dev分支上的代码

[root@server1 gitwork]# git add 1.html
[root@server1 gitwork]# git commit -m "张三修改部分代码"
[dev bf88c43] 张三修改部分代码
 1 file changed, 1 insertion(+)

3)开发者2在dev2分支上修改1.html文件

[root@server1 gitwork]# git branch dev2
[root@server1 gitwork]# git checkout dev2
Switched to branch 'dev2'
[root@server1 gitwork]# ls
1.html
[root@server1 gitwork]# cat 1.html
11111
[root@server1 gitwork]# echo "李四修改部分代码" >>1.html

4)提交在dev2分支上的代码

[root@server1 gitwork]# git add 1.html
[root@server1 gitwork]# git commit -m "李四修改部分代码"
[dev2 49e2b76] 李四修改部分代码
 1 file changed, 1 insertion(+)

5)切换到主分支,合并分支代码

[root@server1 gitwork]# git checkout master    ##切换主分支
Switched to branch 'master'
[root@server1 gitwork]# git merge dev dev2     ##合并代码
Fast-forwarding to: dev
Trying simple merge with dev2
Simple merge did not work, trying automatic merge.
Auto-merging 1.html
ERROR: content conflict in 1.html                            ##内容冲突
fatal: merge program failed
Automatic merge failed; fix conflicts and then commit the result.

6)手动打开1.html解决冲突

git中表示冲突的部分使用<<<<<<< ======= >>>>>>>表示,手动删除冲突部分

新增加了一些新功能
11111
<<<<<<< .merge_file_z5Jsma
张三修改部分代码
=======
李四修改部分代码
>>>>>>> .merge_file_Cxtkg9

修改后如下

新增加了一些新功能
11111
张三修改部分代码
李四修改部分代码

7)在master中重新进行提交

[root@server1 gitwork]# git add 1.html
[root@server1 gitwork]# git commit -m "手动解决冲突后的1.html"
[master 74de7ce] 手动解决冲突后的1.html

6.4.7 删除分支

[root@server1 gitwork]# git branch -d dev
Deleted branch dev (was 1adc7a0).
[root@server1 gitwork]# git branch -d dev2
Deleted branch dev2 (was 731d1a2).
[root@server1 gitwork]# git branch
* master

4.4 远程仓库

Git中存在两种类型的仓库,即本地仓库和远程仓库

可以借助互联网上提供的一些代码托管服务来实现,常用的有码云、github,gitlab等。 gitHub( 地址:https://github.com/ )是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名gitHub。

码云(地址: https://gitee.com/ )是国内的一个代码托管平台,由于服务器在国内,所以相比于 GitHub,码云速度会更快。

GitLab (地址: https://about.gitlab.com/ )是一个用于仓库管理系统的开源项目,使用Git作 为代码管理工具,并在此基础上搭建起来的web服务,一般用于在企业、学校等内部网络搭建git私服。

4.4.1 github
4.4.1.1 注册github

image-20221201200554869

image-20221201200646587

登录你的邮箱地址,进行验证,设置好账号密码即可登录,如下

image-20221201211438418

image-20221201211608088

image-20221201201524559

4.4.1.2 创建新的仓库

image-20221201201832002

image-20221201202553192

image-20221201203443573

4.4.1.3 远程上传本地代码到ops仓库中
[root@server1 ~]# mkdir ops      #新建工作目录
[root@server1 ~]# cd ops/
[root@server1 ops]# echo "# ops" >> README.md  #新建README文件
[root@server1 ops]# git init
Initialized empty Git repository in /root/ops/.git/
[root@server1 ops]# git add README.md        #添加到暂存区
[root@server1 ops]# git commit -m "first commit"     #提交代码
[master (root-commit) 6ef82b5] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
[root@server1 ops]# git branch -M main    新建分支
[root@server1 ops]# git remote add origin https://github.com/wuchaofeng/ops.git  #添加仓库
[root@server1 ops]# git push -u origin main     ##推送错误
Username for 'https://github.com': wuchaofeng
Password for 'https://wuchaofeng@github.com':
remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/wuchaofeng/ops.git/'

如上说明2021年8月13日移除对密码认证的支持。请改用个人访问令牌,我们当前使用的是密码认证,而密码认证早在2021年8月13日就已被移除。我们需要获取一个个人访问令牌。那么,如何获取呢

个人访问令牌获取步骤

  • 确保github上登录的是你要连接的用户;
  • 点击个人资料-settings;

image-20221201212547505

  • 在左侧边栏中,点击**<>Developer settings**。

image-20221201212628580

在左侧边栏中,点击Personal access tokens

image-20221201212809373

  • 点击generate new token生成新令牌

image-20221201212856531

  • 设置好令牌名字、有效期和权限后点击generate token

image-20221201215350436

  • 将令牌复制下来

注意!一定要复制保存到别的地方,一旦离开这个界面你就无法再次查看之前生成的令牌了。如果忘记了则需要重新生成。

  • 之后就可以登录git并且上传代码了

image-20221201213037374

再次测试上传:

[root@server1 ops]# git push -u origin main
Username for 'https://github.com': wuchaofeng
Password for 'https://wuchaofeng@github.com':
Counting objects: 3, done.
Writing objects: 100% (3/3), 215 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/wuchaofeng/ops.git
 * [new branch]      main -> main
Branch main set up to track remote branch main from origin.
[root@server1 ops]#
4.4.1.4 查看仓库

image-20221201215607751

4.4.1.5 将代码下载到本地

1)HTTPS方式下载

image-20221203144816039

SSH方式下载由于需要SSH公钥信息,我们采取HTTPS方式下载,代码下载在你当前目录下,目录名是你当前的项目名称

[root@server1 ~]# git clone https://github.com/wuchaofeng/ops.git
Cloning into 'ops'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
[root@server1 ~]# ls
anaconda-ks.cfg  gitwork  ops  README.md  test

代码更新和提交

[root@server1 ops]# vim README.md
[root@server1 ops]# cat README.md
# ops
张三第一次修改的代码                           ##新增代码
[root@server1 ops]# git add README.md
[root@server1 ops]# git commit -m "张三第一次修改代码 README.md"
[main d816465] 张三第一次修改代码 README.md
 1 file changed, 1 insertion(+)   

上传到远程仓库

[root@server1 ops]# git push -u origin main
Username for 'https://github.com': wuchaofeng
Password for 'https://wuchaofeng@github.com':             ##输入秘钥
Counting objects: 5, done.
Writing objects: 100% (3/3), 326 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/wuchaofeng/ops.git
   10607a2..d816465  main -> main
Branch main set up to track remote branch main from origin.

image-20221203145850490

有没有注意到,我们每一次上传代码都需要输入用户名和秘钥,我们可以使用如下的命令来记住密码信息,这样下次我们再上传密码时就不需要在输入秘钥信息了。

[root@server1 ops]# git config --global credential.helper store

测试免密登录

[root@server1 ops]# git push -u origin main
Username for 'https://github.com': wuchaofeng
Password for 'https://wuchaofeng@github.com':             ##首次登录时需要提供秘钥
Branch main set up to track remote branch main from origin.
Everything up-to-date
[root@server1 ops]# git push -u origin main               ##再次登录时不需要秘钥
Branch main set up to track remote branch main from origin.
Everything up-to-date

2)SSH免密下载

由于SSH方式下载需要提前生成公钥信息,所以默认无法使用SSH

image-20221203151344312

在服务器上生成密钥对

[root@server1 ops]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:7AnIO5TdDVudHtz24y2ouMIFR8gIxSCTuphYd+sVa3Y root@server1
The key's randomart image is:
+---[RSA 2048]----+
|o.o=.o .         |
|.o  o o .  o o   |
|.      .. . = o  |
|. ...+ooo= . o . |
|o+ .=.o+So. .  ..|
|=  . ..o*.E  .. o|
|    oo =o.  . ...|
|     .+  . .   . |
|       .o..      |
+----[SHA256]-----+

将公钥上传到github中

复制公钥信息

[root@server1 .ssh]# cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGYqcMjWLm53Tioybi8NBhOOUBvYyCIzZy24aT+3UzN5weKRpfRbVx3VowZotaqNTTyI5y2m3+/3CEGABKAlZTF914aZuX5Due2Zmi8LMxRH/8Ezt43F3cWDA/i6Psgq9pAsNPZwktM1nnM5/pJhC5Ay87EowEqOzLgkCPzuFnPAvGUYbIBkL5luoaoSHYwCis+MQ+AKsSDMhRr7VpXdUD5kKzajxpuwlkb/qA9KETnLlaIOTqF7g1+qpRp9uMLye+VobIzUc7Tr0JMj4wu1ARleKjSnU5TYVlWhWZrBhCGdmaw7ONCRrkZvDmFtbU2HYay/vUrHOjifgsarl9Gw3h root@server1

将公钥上传到github

image-20221203152108652

image-20221203152131925

image-20221203152158757

image-20221203152405619

image-20221203152459343

测试SSH免密下载代码

image-20221203152855954

[root@server1 ~]# git clone git@github.com:wuchaofeng/ops.git
Cloning into 'ops'...
The authenticity of host 'github.com (20.27.177.113)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
ECDSA key fingerprint is MD5:7b:99:81:1e:4c:91:a5:0d:5a:2e:2e:80:13:3f:24:ca.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,20.27.177.113' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
[root@server1 ~]# ls
anaconda-ks.cfg  gitwork  ops  README.md  test
[root@server1 ~]# cd ops/
[root@server1 ops]# ls
README.md
[root@server1 ops]# cat README.md
# ops
张三第一次修改的代码

代码下载成功了,我们尝试修改代码,再次测试上传代码

[root@server1 ops]# cat README.md
# ops
张三第一次修改的代码
张三第二次修改的代码
[root@server1 ops]# git add README.md
[root@server1 ops]# git commit -m "张三第二次提交代码"
[main c6c67b9] 张三第二次提交代码
 1 file changed, 1 insertion(+)
[root@server1 ops]# git push -u origin main
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 318 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:wuchaofeng/ops.git
   d816465..c6c67b9  main -> main
Branch main set up to track remote branch main from origin.

image-20221203153317010

4.4.1.6 github的分支

1)在github上创建分支

image-20221203153738592

image-20221203154005250

2)在本地的开发者的电脑上开发完代码后,提交到dev分支上(这里你可以使用git clone来获取github的dev分支,或者直接在本地创建dev分支)

[root@server1 ~]# git clone git@github.com:wuchaofeng/ops.git
Cloning into 'ops'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 9 (delta 0), reused 9 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), done.
[root@server1 ~]# ls
anaconda-ks.cfg  gitwork  ops  README.md  test
[root@server1 ~]# cd ops/
[root@server1 ops]# ls
README.md

提交代码到dev分支

[root@server1 ops]# echo 1111111 > 1.html
[root@server1 ops]# git add 1.html
[root@server1 ops]# git commit -m "第一次提交1.html代码"
[dev b9d2386] 第一次提交1.html代码
 1 file changed, 1 insertion(+)
 create mode 100644 1.html
[root@server1 ops]# git push -u origin dev       ##提交到dev分支
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 303 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:wuchaofeng/ops.git
   c6c67b9..b9d2386  dev -> dev
Branch dev set up to track remote branch dev from origin.
[root@server1 ops]# git branch
* dev                                                 ##可以看到当前的分支是dev分支

3)在github上查看

image-20221203154833714

4)在github上创建一个pull request来将dev分支的代码merge到main主分支上。

image-20221203155332710

image-20221203155534737

image-20221203155807973

image-20221203155835402

image-20221203155935574

image-20221203160030737

4.4.2 gitlab

官方安装步骤:https://about.gitlab.com/install/#centos-7

GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。GitLab由乌克兰程序员DmitriyZaporozhets和ValerySizov开发,它由Ruby写成。后来,一些部分用Go语言重写,现今并在国内外大中型互联网公司广泛使用。

gitlab的安装配置,官网给的配置最低要求为4G,使用虚拟机配置的话结合物理机的配置要求分配内存

image-20211212152340642

4.4.2.1 安装必要的依赖
[root@gitlab ~]# yum -y install policycoreutils policycoreutils-python ##安装必要的依赖
[root@gitlab ~]# yum install -y net-tools 
4.4.2.2 下载gitlab

我们这里采用的是清华源的镜像:

https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/

wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-14.4.1-ce.0.el7.x86_64.rpm
4.4.2.3 安装gitlab
[root@server1 ~]# rpm -ivh gitlab-ce-14.7.6-ce.0.el7.x86_64.rpm
warning: gitlab-ce-14.7.6-ce.0.el7.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID f27eab47: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:gitlab-ce-14.7.6-ce.0.el7        ################################# [100%]
It looks like GitLab has not been configured yet; skipping the upgrade script.

       *.                  *.
      ***                 ***
     *****               *****
    .******             *******
    ********            ********
   ,,,,,,,,,***********,,,,,,,,,
  ,,,,,,,,,,,*********,,,,,,,,,,,
  .,,,,,,,,,,,*******,,,,,,,,,,,,
      ,,,,,,,,,*****,,,,,,,,,.
         ,,,,,,,****,,,,,,
            .,,,***,,,,
                ,*,.



     _______ __  __          __
    / ____(_) /_/ /   ____ _/ /_
   / / __/ / __/ /   / __ `/ __ \
  / /_/ / / /_/ /___/ /_/ / /_/ /
  \____/_/\__/_____/\__,_/_.___/


Thank you for installing GitLab!
GitLab was unable to detect a valid hostname for your instance.
Please configure a URL for your GitLab instance by setting `external_url`
configuration in /etc/gitlab/gitlab.rb file.
Then, you can start your GitLab instance by running the following command:
  sudo gitlab-ctl reconfigure

For a comprehensive list of configuration options please see the Omnibus GitLab readme
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md

Help us improve the installation experience, let us know how we did with a 1 minute survey:
https://gitlab.fra1.qualtrics.com/jfe/form/SV_6kVqZANThUQ1bZb?installation=omnibus&release=14-7
4.4.2.4 修改配置文件绑定本地IP地址
[root@gitlab ~]# vim /etc/gitlab/gitlab.rb 

image-20211212154643935

4.4.2.5 初始化gitlab
[root@gitlab ~]# gitlab-ctl reconfigure   #初始化的时间比较长。

image-20211212155118610

4.4.2.6 重载服务
[root@gitlab ~]#  gitlab-ctl status   ##查看状态
[root@gitlab ~]#  gitlab-ctl restart  ##重启gitlab

gitlab其他常见命令

gitlab-ctl start #启动全部服务
gitlab-ctl restart#重启全部服务
gitlab-ctl stop #停止全部服务
gitlab-ctl restart nginx #重启单个服务,如重启nginx
gitlab-ctl status #查看服务状态
gitlab-ctl reconfigure #使配置文件生效
gitlab-ctl show-config #验证配置文件
gitlab-ctl uninstall #删除gitlab(保留数据)
gitlab-ctl cleanse #删除所有数据,从新开始
gitlab-ctl tail <service name>查看服务的日志
gitlab-ctl tail nginx  #如查看gitlab下nginx日志

image-20211212155225036

4.4.2.7 访问gitlab
http://ip:80

#默认登录的账号是root,密码文件保存在/etc/gitlab/initial_root_password中

如果访问出现了502的错误,请点击“GO BACK”尝试重新登录。

同时,根据/var/log/gitlab/nginx的错误日志来判断问题

image-20211213203535121

image-20211212165823854

  • 登录后,修改密码
  • image-20230707102229522

image-20230707102253755

首次登录如果忘记密码,重设一下密码:

[root@gitlab ssl]# cd /opt/gitlab/bin/
[root@gitlab bin]# gitlab-rails console  
irb(main):002:0> u=User.where(id:1).first           ##查看id为1的是哪个账号,显示为root
=> #<User id:1 @root>
irb(main):006:0> u.password='123456789'               ##设置密码
=> "123456789"
irb(main):007:0> u.password_confirmation='123456789'     ##确认密码
=> "123456789"
irb(main):008:0> u.save    ##保存
=> true
irb(main):009:0> exit   ##退出

完成后,重启gitlab,再次登录:

[root@server1 bin]# gitlab-ctl restart

image-20211212164312855

4.4.2.8 Gitlab邮箱设置(非必须)
[root@gitlab ~]# vim /etc/gitlab/gitlab.rb 
参考配置如下:
### Email Settings
gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] ='wuchaofengainio@qq.com'
gitlab_rails['gitlab_email_display_name'] ='gitlab'
gitlab_rails['gitlab_email_reply_to'] ='wuchaofengainio@qq.com'
gitlab_rails['gitlab_email_subject_suffix'] ='[gitlab]'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] ="wuchaofengainio@qq.com"
gitlab_rails['smtp_password'] ="zvsdbqvdgvzjbiih"  #QQ授权码
gitlab_rails['smtp_domain'] ="smtp.qq.com"
gitlab_rails['smtp_authentication'] ="login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true

[root@gitlab ~]# gitlab-ctl reconfigure   #重新配置一遍
[root@gitlab ~]#  gitlab-ctl restart  ##完成后重启gitlab 

控制台添加SMTP邮箱地址

image-20230630160750502

image-20230630160819150

image-20230630160840135

发送邮件测试

[root@gitlab ~]# gitlab-rails console
irb(main):002:0> Notify.test_email('wuchaofengainio@qq.com','Message Subject','Message Body').deliver_now #测试命令,回车即可
Delivered mail 649e8e6567d71_7a2c5adc796dd@gitlab.mail (932.4ms)
=> #<Mail::Message:269560, Multipart: false, Headers: <Date: Fri, 30 Jun 2023 16:12:21 +0800>, <From: gitlab <wuchaofengainio@qq.com>>, <Reply-To: gitlab <wuchaofengainio@qq.com>>, <To: wuchaofengainio@qq.com>, <Message-ID: <649e8e6567d71_7a2c5adc796dd@gitlab.mail>>, <Subject: Message Subject>, <Mime-Version: 1.0>, <Content-Type: text/html; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>, <Auto-Submitted: auto-generated>, <X-Auto-Response-Suppress: All>>
irb(main):003:0> 

查看测试邮件

image-20230630161625327

4.4.2.9 创建一个工程

项目名称:demo,完成后,点击create project;

image-20221204193614759

image-20221204193728606

7、更改语言

image-20211212171036728

刷新页面就变成了中文的

image-20211212171115153

到此,gitlab已经安装好了。

4.4.2.10 添加开发电脑的SSH秘钥,使得可以免密登录

1)生成秘钥对

[root@dev ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:XCVxxlsCFVnorpOMFn8W3xGIszy5I2LWoasiUTb5ohs root@dev
The key's randomart image is:
+---[RSA 2048]----+
|          +=*=.  |
|           == .  |
|    .     ...+.  |
|   =   . . oo. . |
|  o o   S ..+   .|
| . . .  .. =o  . |
| Eo .   o=.ooo ..|
| o..   =oo*oo . .|
| .o ..+oo .+.    |
+----[SHA256]-----+

2)将公钥添加到gitlab上

[root@dev .ssh]# vim id_rsa.pub

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCji7bj2nVbqLaMIV0xfeNrnK7owyH54HPYzp3mntBe+Wm1pxku+VQzOpW4CGSAgpXAXfqOSyom2zWDZn6OlMZAGGjEpSo+mbg3ZN+pOnC1NS99UE+eCVLvOfhJrD8hGJlVZ439sXKBNTJGIyRXypuRc0Muyx5rUkhuH/k91d9dV9uK2p4KLtz5c1sBgenhnfKQTiox7hsgLSdTon0p6suO3Yn1G2DUTzyzn4N8KYdPJ9LSq0onnqXl8msQj6PebI/06jl3tLfHYk+OHbDmZLCudmgnV9wmB52ARYgeBqUOU6Sx8ljKqtR+VoYVVvgYiFGvrHDQisAPvlhNe1UckSFR root@dev

SSH key添加位置在如下位置

image-20221204194317137

image-20221204194430880

4.4.2.11 测试SSH方式拉取项目代码

image-20221204194555163

在dev开发电脑上执行下面命令进行clone(提前在dev电脑上安装git命令)

[root@dev .ssh]# yum -y install git
[root@dev ~]# git clone git@192.168.1.100:root/demo.git     ##拉取代码
Cloning into 'demo'...
The authenticity of host '192.168.1.100 (192.168.1.100)' can't be established.
ECDSA key fingerprint is SHA256:qveV1bOch+2j/ZQuvc8uAexhaiQN3wqXZsZ0YMaR9gs.
ECDSA key fingerprint is MD5:7d:d3:87:ef:42:71:11:32:5e:59:22:ce:7b:3f:10:bf.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.100' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
[root@dev ~]# ls
anaconda-ks.cfg  demo
4.4.2.12 测试上传代码

公司代码提交合并流程

1、PM(项目主管/项目经理)在gitlab创建任务,分配给开发人员
2、开发人员领取任务后,在本地使用git clone拉取代码库
3、开发人员创建开发分支 (git checkout -b dev),并进行开发
4、开发人员完成之后,提交到本地仓库(git commit)
5、开发人员在gitlab界面上申请分支合并请求(Merge request)
6、PM在gitlab上查看提交和代码修改情况,确认无误后,确认将开发人员的分支合并到主分支(master)
7、开发人员在gitlab上Mark done确认开发完成,并关闭issue。这一步在提交合并请求时可以通过抵述中填写"close#1"等字样,可以直接关闭issue
[root@dev demo]# echo 11111 >1.html
[root@dev demo]# git add 1.html
[root@dev demo]# git commit -m "第一次添加新功能 1.html"

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@dev.(none)')
[root@dev demo]# git config --global user.email wuchaofengainio@qq.com
[root@dev demo]#  git config --global user.name wuchaofeng
[root@dev demo]# git commit -m "第一次添加新功能 1.html"
[main 53a8137] 第一次添加新功能 1.html
 1 file changed, 1 insertion(+)
 create mode 100644 1.html
[root@dev demo]# git push -u origin main
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 310 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@192.168.1.100:root/demo.git
   3db04c1..53a8137  main -> main
Branch main set up to track remote branch main from origin.

image-20221204195305293

4.4.2.13 创建分支

image-20230630112137933

image-20230630112205689

4.4.2.14 推送代码至dev分支
[root@gitlab demo]# echo 2222 >> 1.html 
[root@gitlab demo]# git add 1.html 
[root@gitlab demo]# git commit -m '1.html'
[dev 6968dc2] 1.html
 1 file changed, 1 insertion(+)
[root@gitlab demo]# git push -u origin dev
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 271 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: 
remote: To create a merge request for dev, visit:
remote:   http://192.168.1.100/root/demo/-/merge_requests/new?merge_request%5Bsource_branch%5D=dev
remote: 
To git@192.168.1.100:root/demo.git
   4c21c50..6968dc2  dev -> dev
Branch dev set up to track remote branch dev from origin.

查看gitlab仓库信息

image-20230630112950370

4.4.2.15 合并分支

image-20230630113035554

image-20230630113104076

image-20230630113129860

image-20230630113218469

image-20230630113233440

image-20230630113259464

可以看到dev分支的新增内容已经合并到了main分支中了。

4.4.2.16 Gitlab的备份

1)查看gitlab备份恢复设置项

[root@gitlab ~]# vim /etc/gitlab/gitlab.rb 
gitlab_rails['manage_backup_path'] = true
gitlab_rails['backup_path'] = "/data/gitlab/backups"     #定义了gitlab的备份路径,可以修改,完成后重新配置gitlab即可
[root@gitlab ~]# gitlab-ctl reconfigure  #重新配置
[root@gitlab ~]# gitlab-ctl restart  #重新启动gitlab


[root@gitlab ~]# mkdir /data/gitlab/backups -p   #创建备份目录

2)执行备份命令

[root@gitlab ~]# /opt/gitlab/bin/gitlab-rake gitlab:backup:create
[root@gitlab backups]# ls
1688116523_2023_06_30_14.7.6_gitlab_backup.tar

3)放置在计划任务中运行

[root@gitlab backups]# crontab -l
0 2 * * * bash /opt/gitlab/bin/gitlab-rake gitlab:backup:create  #表示每天的凌晨2点进行备份

4)目前安全设置

每天定期备份时间过长可能存在磁盘空间不足问题,可以设置备份的有效期时长

[root@gitlab ~]# vim /etc/gitlab/gitlab.rb 
gitlab_rails['backup_keep_time'] = 604800   #定义备份的有效时长

#这里的604800表示7天,单位是秒,可以自己根据磁盘容量大小定义
4.4.2.17 Gitlab的恢复

1)安装新的gitlab服务器(参考之前的部分)

2)设置gitlab服务器的数据备份路径

[root@gitlab ~]# vim /etc/gitlab/gitlab.rb 
gitlab_rails['backup_path'] = "/data/gitlab/backups"     #定义了gitlab的备份路径,可以修改,完成后重新配置gitlab即可

3)恢复之前建议先停止掉gitlab服务

[root@gitlab backups]# gitlab-ctl stop unicon
[root@gitlab backups]# gitlab-ctl stop sidekiq
ok: down: sidekiq: 0s, normally up

unicon:在 GitLab 的部署架构中,Unicorn 作为应用服务器用于托管 GitLab 的 Rails 应用程序,而 Nginx 作为代理服务器处理 HTTP/HTTPS 和静态资源访问请求

Sidekiq是一个后台作业处理器,用于在后台执行队列任务(异步执行)。在GitLab中,Sidekiq用于处理后台任务,例如发送邮件、更新缓存等。这些任务通常不会被直接处理,而是在后台异步执行,以避免阻塞主线程并提高应用程序的性能。

#如果是新搭建的主机,不需要操作,理论上不停这两个服务也可以。停这两个服务是为了保证数据一致性。

4)将原来备份的tar包复制到新的gitlab服务器上

[root@gitlab backups]# pwd
/data/gitlab/backups
[root@gitlab backups]# ls
1688116523_2023_06_30_14.7.6_gitlab_backup.tar
[root@gitlab backups]# chmod 777 1688116523_2023_06_30_14.7.6_gitlab_backup.tar   #修改权限

5)执行恢复命令

[root@gitlab ~]# gitlab-rake gitlab:backup:restore BACKUP=1688116523_2023_06_30_14.7.6
[root@gitlab ~]# gitlab-ctl start unicon
[root@gitlab ~]# gitlab-ctl start sidekiq
#执行两次yes后即可,在进行还原的时候,注意我们的还原的包不是*.tar包,而是备份的文件名,否则会报错,提示文件不存在!

6)登录新的gitlab查看是否还原成功

image-20230701124151747

可以看到新的gitlab服务器上已经存在了原有服务器上的数据

注意:

在进行恢复的时候要求gitlab的版本一致,否则会出现版本不匹配的问题