项目配置管理工具研究

项目配置管理 专栏收录该内容
5 篇文章 0 订阅

配置管理工具研究

一、软件配置管理概念的提出

每一个软件项目,无论是工程类项目,还是产品类项目,都必须经历需求分析、系统设计、编码实现、集成测试、部署、交付、维护和支持的过程。在这个过程中,将生成各种各样不同的工件,包括文档、源程序、可执行代码、支持库。更可怕的是,频繁出现的变更是不可避免的,因此面向如此庞大且不断变动的信息集,如何使其有序、高效地存放、查找和利用就成为了一个突出的问题。

针对这一问题,最早的开发人员尝试过的解决办法是通过手工来实现:

  1)文档:每次修改时都另存为一个新的文件,然后通过文件名进行区分,例如 "XXX 软件需求说明书V1.0, XXX软件需求说明书V1.1, XXX软件需求说明书V2.0.",并且在文件中注明每次版本变化的内容;

  2) 源代码:每次要修改时就将整个工程目录复制一份,将原来的文件夹进行改名,例如 "XX 项目V1.0、 XX项目1.01、 .",然后在新的目录中进行修改;

   但是这种方法,不仅十分繁琐,容易出错,而且会带来大量的垃圾数据。如果是团队协同开发或者是项目规模较大时,还是会造成很大的混乱。很显然,这样简陋的方法是无法应对这一问题的。

  后来,有人尝试从制造工业领域引入了"配置管理"这一概念,通过不懈的研究与实践,最终形成了一套管理办法和活动原则,这也就是软件配置管理。

通过软件配置管理,将对软件系统中的多重版本实施系统的管理;全面记载系统开发的历史过程,包括为什么修改,谁作了修改,修改了什么;管理和追踪开发过程中危害软件质量以及影响开发周期的缺陷和变化。并对开发过程进行有效地管理和控制,完整、明确地记载开发过程中的历史变更,形成规范化的文档,不仅使日后的维护和升级得到保证,而且更重要的是,这还会保护宝贵的代码资源,积累软件财富,提高软件重用率,加快投资回报。

二、进行软件配置管理的目的

1、权限控制(Access Control)

权限控制对SCM工具来说至关重要。一方面,既然是团队开发,就可能需要限制某些成员的权限;特别是大项目往往牵扯到子项目外包,到最后联调阶段会涉及到很多不同的单位,更需要权限管理。另一方面,权限控制也减小了误操作的可能性,间接提高了SCM工具的可用性(Usability)。

2、版本控制(Version Control)

SCM工具记录项目和文件的修改轨迹,跟踪修改信息,使软件开发工作以基线(Baseline)渐进方式完成,从而避免了软件开发不受控制的局面,使开发状态变得有序。

SCM工具可以对同一文件的不同版本进行差异比较,可以恢复个别文件或整个项目的早期版本,使用户方便地得到升级和维护必需的程序和文档。

SCM工具内部对版本的标识,采用了版本号(Version Number)方式,但对用户提供了多种途径来标识版本,被广泛应用的有版本号、标签(Label)和时间戳(Time Stamp)。多样灵活的标识手段,为用户提供了方便。

3、增强的版本控制(Enhanced Version Control)

快照(Snapshot)和分支(Branch)以基本的版本控制功能为基础,使版本控制的功能又更进一步增强。

快照是比版本高一级的概念,它是项目中多个文件各自的当前版本的集合。快照使恢复项目的早期版本变得方便,它还支持批量签入(Check in)、批量签出(Check out)和批量加标签(Label)等操作。总之,快照是版本控制的一种增强,使版本控制更加方便高效。

分支允许用户创建独立的开发路径,我们认为分支的典型用途有二。第一,分支和合并(Merge)一起,是支持并行开发(Concurrent Development)的有力支持。第二,分支支持多版本开发,这对发布后的维护尤其有用。比如客户报告有打印bug,小组可能从某个还未引入打印bug的项目版本引出一个分支,最终发布一个bug修订版。分支是版本控制的另一种增强。

版本控制和增强的版本控制是SCM工具其它功能的基础。

4、变更管理(Change Management)

SCM工具提供有效的问题跟踪(Defect Tracking)和系统变更请求(System ChangeRequests (SCRs))管理。通过对软件生命周期各阶段所有的问题和变更请求进行跟踪记录,来支持团队成员报告(Report)、抓取(Capture)和跟踪(Track)与软件变更相关的问题,以此了解谁改变了什么,为什么改变。

变更管理有效地支持了不同开发人员之间,以及客户和开发人员之间的交流,避免了无序和各自为政的状态。

5、独立的工作空间(Independent Workspaces)

开发团队成员需要在开发项目上协同、并发地工作,这样可以大大提高软件开发的效率。沙箱(Sandbox)为并行开发提供了独立的工作空间,在有的SCM工具中也称为工作目录(Working Folder)。

使用沙箱(Sandbox),开发人员能够将所有必要的项目文件拷贝到私有的一个树型目录,修改在这些副本上进行。一旦对修改感到满意,就可以将修改合并(Merge)到开发主线(Main Line)上去;当然,如果该文件只有该成员一人修改,只需将修改过的文件签入(Check In)到主项目中即可。

“并发和共享是同一事物的不同方面”,并发的私有工作空间共享同一套主项目(Mater Project)文件,因此有必要让所有团队成员拥有得知项目当前状态的能力。SCM工具提供刷新(Refresh)操作,某位团队成员可以使其他团队成员在主项目文件上所做的变更,在自己沙箱的图形用户界面上反应出来。

6、管理项目的整个生命周期

从开发、测试、发布到发布后的维护,SCM工具的使命“始于项目开发之初,终于产品淘汰之时”。SCM工具应预先提供典型的开发模式的模板,以减少用户的劳动;另一方面,也应支持用户自定义生命周期模式,以适应特殊开发需要。

7、与主流开发环境的集成

  将版本控制功能与主流集成开发环境(IDE)集成,极大地方便了软件开发过程。从集成开发环境的角度看,版本控制是其一项新功能;从SCM工具的角度看,集成开发环境充当了沙箱的角色。

三、常见的配置管理工具(SCM Rools)

正如前面所述,由于软件配置管理过程十分繁杂,管理对象错综复杂,如果是采用人工的办法不仅费时费力,还容易出错,产生大量的废品。因此,引入一些自动化工具是十分有裨益的,这也是做好配置管理的必要条件。

正是因为如此,市场上出现了大量的自动化配置管理工具,这些工具的实现原理与基本机制均十分接近,但由于其定位不同,因此各有特点。现在常见的软件配置管理工具主要有:CCC、SCCS、RCS、Rational ClearCase、Merant PVCS、Hansky Firefly、Microsoft VSS、CVS、GIT、SVN,下面我们就对这些配置管理工具做一简单的介绍。

元老:CCC 、SCCS、 RCS

  上个世纪七十年代初期加利福利亚大学的Leon Presser 教授撰写了一篇论文,提出控制变更和配置的概念,之后在1975年,他成立了一家名为 SoftTool的公司,开发了自己的配置管理工具:CCC,这也是最早的配置管理工具之一。

在软件配置管理工具发展史上,继CCC之后,最具有里程碑式的是两个自由软件: Marc Rochkind 的SCCS (Source Code Control System) 和 WalterTichy 的RCS (Revision Control System),它们对配置管理工具的发展做出了重大的贡献,直到现在绝大多数配置管理工具基本上都源于它们的设计思想和体系架构。

中坚:Rational ClearCase

Rational 公司是全球最大的软件CASE 工具提供商,现已被IBM 收购。也许是受到其拳头产品、可视化建模第一工具Rose 的影响,它开发的配置管理工具ClearCase 也是深受用户的喜爱,是现在应用面最广的企业级、跨平台的配置管理工具之一。

ClearCase提供了比较全面的配置管理支持,其中包括版本控制、工作空间管理、Build管理等,而且开发人员无需针对其改变现有的环境、工具和工作方式。

 1)版本控制

 ClearCase 不仅可以对文件、目录、链接进行版本控制,同时还提供了先进的版本分支和归本功能用于支持并行开发。另外,它还支持广泛的文件类型。

 2)工作空间管理  

可以为开发人员提供私人存储区,同时可以实现成员之间的信息共享,从而为每一位开发人员提供一致、灵活、可重用的工作空间域。

3)Build管理  

对ClearCase 控制的数据,既可以使用定制脚本,也可使用本机提供的make 程序。

其最大的缺点就在于其价格不菲,每个客户端用户许可证大约需要几千美金,所以在国内应用群体有限。

小工作组级:Merant PVCS

MERANT 公司的 PVCS 能够提供对软件配置管理的基本支持,通过使用其图形界面或类似SCCS 的命令,能够基本满足小型项目开发的配置管理需求。 PVCS 虽然功能上也基本能够满足需求,但是其性能表现一直较差,逐渐地被市场所冷落。

新秀:Hansky Firefly

做为H a n s k y 公司软件开发管理套件中重要一员的Firefly,可以轻松管理、维护整个企业的软件资产,包括程序代码和相关文档。 Firefly是一个功能完善、运行速度极快的软件配置管理系统,可以支持不同的操作系统和多种集成开发环境,因此它能在整个企业中的不同团队,不同项目中得以应用。

Firefly基于真正的客户机/ 服务器体系结构,不依赖于任何特殊的网络文件系统,可以平滑地运行在不同的LAN、WAN 环境中。它的安装配置过程简单易用,Firefly 可以自动、安全地保存代码的每一次变化内容,避免代码被无意中覆盖、修改。项目管理人员使用 Firefly可以有效地组织开发力量进行并行开发和管理项目中各阶段点的各种资源,使得产品发布易于管理;并可以快速地回溯到任一历史版本。系统管理员使用Firefly 的内置工具可以方便的进行存储库的备份和恢复,而不依赖于任何第三方工具。

入门级:Microsoft VisualSource Safe

Visual Source Safe,即VSS ,是微软公司为Visual Studio配套开发的一个小型的配置管理工具,准确来说,它仅能够称得上是一个小型的版本控制软件。 VSS的优点在于其与Visual Studio实现了无缝集成,使用简单。提供了历史版本记录、修改控制、文件比较、日志等基本功能。

但其缺点也是十分明显的,只支持Windows平台,不支持并行开发,通过 Check out - Modify -Check in的管理方式,一个时间只允许一个人修改代码,而且速度慢、伸缩性差,不支持异地开发。甚至于微软本身也不采用其做为配置管理工具,而是使用一个名为SLM 的内部工具。

开源免费: CVS、GIT、SVN

CVS:

CVS 是Concurrent VersionsSystem 的缩写,它是开放源代码软件世界的一个伟大杰作,由于其简单易用、功能强大,跨平台,支持并发版本控制,而且免费,它在全球中小型软件企业中得到了广泛使用。其最大的遗憾就是缺少相应的技术支持,许多问题的解决需要自已寻找资料,甚至是读源代码。

SVN(Subversion):

SVN全名Subversion,即版本控制系统。SVN与CVS一样,是一个跨平台的软件,支持大多数常见的操作系统。作为一个开源的版本控制系统,Subversion管理着随时间改变的数据。这些数据放置在一个中央资料档案库(repository)中。这个档案库很像一个普通的文件服务器,不过它会记住每一次文件的变动。这样你就可以把档案恢复到旧的版本,或是浏览文件的变动历史。Subversion是一个通用的系统,可用来管理任何类型的文件,其中包括了程序源码。作为版本管理工具,CVS出现至今,已经有二十个年头,可以说他已经走到了尽头,但可以肯定,它将继续存在着。SVN是作为CVS的代替产品而出现的。现在很多开源组织,都慢慢地转到SVN上,比如Apache跟SourceForge。SVN有着比CVS更强大的功能,比如,它可记录目录的更改,它的性能比CVS会快很多等等。

GIT(Georgia Institute of Technology):

GIT 是一个快速、开源、可扩展的分布式版本控制系统,因此它在(开源)和(协作编程社区)有取代SVN的趋势。GIT具有极为丰富的命令集,对内部系统提供了高级操作和完全访问。GIT与我们熟悉的大部分版本控制系统的差别是很大的。我们熟悉的Subversion、CVS、Perforce、Mercurial等等,他们使用“增量文件系统” (Delta Storage systems), 就是说它们存储每次提交(commit)之间的差异。GIT正好与之相反,它会把你的每次提交的文件的全部内容(snapshot)都会记录下来。理论上,GIT可以保存任何文档,但是最善于保存文本文档,因为它本来就是为解决软件源代码(也是一种文本文档)版本管理问题而开发的,提供了许多有助于文本分析的工具。对于非文本文档,GIT 只是简单地为其进行备份并实施版本管理。

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

GIT的缺点是:资料少(起码中文资料很少);学习周期相对而言比较长;不符合常规思维;代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

四、如何选择配置管理工具

面对这些形形色色,各有千秋的配置管理工具,如何根据组织特点、开发团队需要,选择切合适用的工具呢?

配置管理工具的选择所需考虑的因素大体包括以下几个因素:功能是否符合实际需求?是否符合团队特点?性能是否满意?费用是否可以接受?售后服务如何?接下来,我们就这几方面逐一深入地探讨:

1)功能是否符合实际需求,是否符合团队特点

工具就是用来帮助您解决问题的,因此功能是否符合实际需求是最重要的判断因素。而大多数主流配置管理工具的基本功能都能够满足,因此主要需要判断以下几个因素:

并行开发支持

在团队协作开发过程中,有两种主要的模式:集体代码权和个体代码权。采用集体代码权模式进行开发时,一段代码可能同时会被多个开发人员同时修改;而采用个体代码权模式进行开发时,每一段代码都始终被一个开发人员独享,别人需要修改时也会通过该开发人员完成。

而配置管理软件针对这一情况,也采用了不同的策略:Copy-Modify-Merge(拷贝、修改、合并 ) 的并行开发模式、Check out-Modify-Check in(签出、修改、签入)的独占开发模式。

异地开发支持

如果你的开发团队分布在不同的开发地点,就需要对工具的异地开发功能进行仔细的评估了。大多数工具都提供基于 Web的界面,用户可以通过浏览器执行配置管理的相关操作,而且有些工具就通过这样的方法来实现对异地开发的支持。

这种实现方法有太多的局限性,例如网络(Internet)连接带宽的限制、防火墙以及安全问题等。真正意义上的异地开发支持,是指在不同的开发地点建立各自的存储库,通过工具提供同步功能自动或手动同步。这样做的好处是与网络无关,即便各个开发地点之间没有实时连通的网络,也可以通过 E-Mail 附件等其它方式将同步包发给对方,实现手动的同步。       跨平台开发支持

如果企业需要从事多个不同平台下的开发工作,就需要配置管理工具能够对跨平台开发提供支持,否则势必会给开发、测试、发布等各个环节带来不便,将使大量的时间被浪费于代码的手工上传、下载中。

与开发工具的集成性

配置管理工具与开发工具是编码过程中最常用到两种工具,因此它们之间的集成性直接影响到开发人员的便利性,如果无法良好集成,开发人员将不可避免地在配置管理工具与开发工具之间来回切换。

2)性能是否满意

配置管理工具软件的一些性能指标对于最终的选择也有着至关重要的影响。

运行性能

如果开发团队规模不大的情况下,配置管理工具软件的性能不会造成很大影响,但如果项目规模比较大,团队成员逐渐增多的情况下,其运行性能就会带来很大的影响。

易用性

 从工具安装、配置、使用等容易程度出发,是否需要专业培训还简单培训即可。

安全性

是否存在相应的安全隐患。

3)费用是否可以接受

Rational ClearCase Hansky Firefly 等企业级配置管理工具软件都是收费的商业软件。

4)技术支持如何

出现相关的技术问题是否能及时的得到相应的技术支持,工具在使用过程中出现这样那样的问题是很平常的事,有些是因为使用不当,有些则是工具本身的缺陷。这些问题都会直接影响到开发团队的使用,因此随时能够找到专业技术人员解决这些问题就变成十分重要。

五、主流免费开源配置管理工具(CVS、GIT、SVN)比较

* 原子提交性(Atomic commit):描述了在提交更改时,能否保证所有更改要么全部提交或合并,要么不会发生任何改变。

* 版本库模型(Repository model):描述了多个源码版本库副本间的关系,有客户端/服务器和分布式两种模式。在客户端/服务器模式下,每一用户通过客户端访问位于服务器的主版本库,每一客户机只需保存它所关注的文件副本,对当前工作副本(working copy)的更改只有在提交到服务器之后,其它用户才能看到对应文件的修改。而在分布式模式下,这些源码版本库副本间是对等的实体,用户的机器出了保存他们的工作副本外,还拥有本地版本库的历史信息。

* 并发模式(Concurrency model):描述了当同时对同一工作副本/文件进行更改或编辑时,如何管理这种冲突以避免产生无意义的数据,有排它锁和合并模式。在排它锁模式下,只有发出请求并获得当前文件排它锁的用户才能对对该文件进行更改。而在合并模式下,用户可以随意编辑或更改文件,但可能随时会被通知存在冲突(两个或多个用户同时编辑同一文件),于是版本控制工具或用户需要合并更改以解决这种冲突。因此,几乎所有的分布式版本控制软件采用合并方式解决并发冲突。

* 历史模式(History model):描述了如何在版本库中存贮文件的更改信息,有快照和改变集两种模式。在快照模式下,版本库会分别存储更改发生前后的工作副本;而在改变集模式下,版本库除了保存更改发生前的工作副本外,只保存更改发生后的改变信息。

* 变更范围(Scope of change):描述了版本编号是针对单个文件还是整个目录树。

* 网络协议(Network protocols):描述了多个版本库间进行同步时采用的网络协议。

* 部分克隆(Partial checkout/clone):是否支持只拷贝版本库中特定的子目录。

 

 

特征

CVS

GIT

SVN

是否原子提交

CVS: 没有. CVS提交不是原子的

Git: 是的. 提交都是原子的

Subversion: 提交都是原子的

版本库模型

客户端/服务器

分布式

客户端/服务器

并发模式

合并

合并或锁定

合并

历史模式

改变集

快照

改版集/快照

部分克隆

支持

不支持

支持

变更范围

文件

目录树

目录树

    

文件和目录是否可以移动或重命名

CVS: 不是. 重命名不支持. 如果手动进行, 可能会损坏历史记录

Git: 支持重命名, 这是很实用的目的. git甚至能检测到重命名之后文件的改变. 尽管如此, 基于特殊的存储结构, 重命名不会被显示的记录, git能够推导出来(在实际使用中很容易做到)

Subversion: 是的. 支持重命名

在移动或重命名之后智能合并

CVS: 不能. 重命名都不支持, 就不必说智能了

Git: 不支持.在Git FAQ里: “Git有一个重命名的命令git mv, 但是这仅仅是为了便利. 效果和移掉某个文件, 增加另外一个文件没有任何区别”

Subversion: 不支持.

文件和目录拷贝

CVS: 不能. 拷贝不支持

Git: 不能. 拷贝不支持

Subversion: 是的. 并且拷贝非常容易. 包括产生分支

远程存储仓库的备份

CVS: 间接的. 可以使用John Polstra写的CVSup

Git: 是的. 是git的内部特征

Subversion: 间接的.

是否传递变更到父仓库

CVS: 不会

Git: 是的(Linux内核开发过程经常使用这个特征)

Subversion: 是的

仓库权限

CVS: 很有限.

Git: 请看和Git一起附带的contrib/hooks/update-paranoid. 看和svnperms类似的path_rules的代码

Subversion: 是的. 基于HTTP权限的WebDAV-based模块能够支持基于目录级的仓库

变更集

CVS: 不是. 变更是基于文件的

Git: 是的. 是支持的, 创建他们很容易

Subversion: 部分支持. 对于一次提交会隐式创建一个变更集

跟踪线性的文件历史

CVS: 是的. cvs annotate

Git: 是的.(git blame)

Subversion: 是的(svn blame)

能够只在仓库的单目录下作用

CVS: 是的

Git: 不是. 尽管如此, 提交多少能被限制, 请看“Repository Permissions”

Subversion: 是的

跟踪未提交的变化

CVS: 是的. 通过cvs diff

Git: 是的. 另外, 分支在git里非常智能, 在某些工作流里能够被当成是另外一个未提交代码的存储库. 请看“git stash“命令

Subversion: 是的. 使用svn diff

基于单个文件的提交信息

CVS: 不是. 提交信息是基于单次变化的

Git: 是的. 提交信息基于变更集

Subversion: 不是. 没有这个特征

文档

CVS: 非常棒. 有很多在线的tutorials和资源, 在线的书籍. 命令行客户端也支持一个在线的帮助系统

Git: 良好. 短的帮助比较简洁难懂. man页很有分量, 但容易误解. 有很多tutorial

Subversion: 很好. 有一些在线的书籍和一些在线的tutorials和资源. 并且书籍是以docbook/xml写的所以很容易变换成其他格式. 命令行同样提供了在线的帮助系统

配置是否轻松

CVS: 好. 是个事实上的标准. 基于每个系统都有并且很容易配置

Git: 好. 在现有平台上二进制可用. 需要C编译器和Perl. 在windows上需要cygwin. 并有一些Unix特征

Subversion: Subversion服务器需要安装在apache2模块里(如果有人希望HTTP作为底层协议的话)或使用它自身的服务器. 客户端需要Subversion特征的逻辑还有WebDAV库(针对HTTP). 安装组件很直接, 但是需要一些额外的工作(假定subversion在某些平台没有二进制包可用)

命令集

CVS: 包含了3个经常用到的命令的简单的命令集(cvs commit, cvs update和cvs checkout)和其它一些

Git: 命令集很丰富, 并且和CVS不兼容

Subversion: 类CVS的命令集, 能够很容易被CVS用户使用

网络协议

CVS: 好. cvs在不同的场合使用不同的协议. 协议能够通过ssh链接的加密隧道进行

Git: 非常棒. 能够使用本地的git协议, 但也能在rsync, ssh, HTTP和HTTPS上使用

Subversion: 非常好. Subversion服务器支持WebDAV+DeltaV(基于HTTP或HTTPS)作为底层协议, 或者它自身的协议同样能在ssh链接通道里使用.

可移植性

CVS: 好. 客户端能在UNIX, Windows和Mac OS上使用. 服务器端能在UNIX, 附有UNIX模拟层的Windows上使用

Git: 客户端运行在大多数的UNIX系统上, 但没有MS-Windows本地程序. 基于cygwin的系统看起来也能使用

Subversion: 非常好. 客户端和服务器端都能在UNIX, Windows和Mac OS X上运行

web接口

CVS: 是的. CVSweb, ViewVC, Chora和wwCVS

Git: 是的. Gitweb包含在发布包中

Subversion: 是的. ViewVC, SVN::Web, WebSVN, ViewSVN, mod_svn_view, Chora, Trac, SVN::RaWeb::Light, SVN Browser, Insurrection和perl_svn.另外, Subversion的apache服务也提供了一个基础的web接口

图形用户界面

CVS: 非常好. 有很多图形界面可以用: WinCVS, Cervisia(对于KDE), TortoiseCVS(Windows浏览器插件)

Git: Gitk包含在发行版中. Qqit和Git-gui工具也可使用

Subversion: 非常好. 有很多GUIs可用: RapidSVN(跨平台), TortoiseSVN(Windows浏览器插件), Jsvn(java), 等. 大多数都还在开发中

六、配置管理工具选择

通过对常见的配置管理工具的了解并结合开发人员的操作系统、开发流程、项目规模、易用性、费用及与开发环境的良好结合性等考虑,我们将采用主流的免费开源配置管理工具(CVS、GIT、SVN)中的一个。

通过它们之间的对比,可以看出SVN有着比CVS更强大的功能,比如,它可记录目录的更改,它的性能比CVS会快很多,适用于各种级别的开发团队,它的权限控制很方便等等。

SVN相对于GIT的优点是:管理方便,逻辑明确,符合一般人思维习惯;易于管理,集中式服务器更能保证安全性;代码一致性非常高。而相对于GIT的缺点是:服务器压力太大,数据库容量暴增;如果不能连接到服务器上,基本上不可以工作;不适合开源开发。

GIT相对于SVN的优点是:适合分布式开发;公共服务器压力和数据量都不会太大;速度快、灵活;任意两个开发者之间可以很容易的解决冲突。但相对于SVN的缺点也很明显:资料少(起码中文资料很少);学习周期相对而言比较长;不符合常规思维;代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

      综合考虑之后,个人觉得框架开发项目采用SVN进行配置管理比较合适。

  • 1
    点赞
  • 0
    评论
  • 7
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

chengjh06

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值