分布式版本控制工具 —— Git

一、Git 基本介绍

1.1 相关概念

1️⃣ 首先,我们要知道什么是Git?

Git 是一个免费、开源的版本控制系统,它可以有效地跟踪文件的更改,协调多人在同一个项目上的开发,以及管理不同版本的代码。

Git 最初是由 Linus Torvalds 开发的,用于管理 Linux 内核的代码。
使用 Git,您可以将代码库(即代码的集合)保存在 Git 存储库中。

Git 存储库保存了有关代码的完整历史记录,包括所有修改、合并等详细信息。Git 提供了许多强大的功能,例如分支(branch)、合并(merge)、打标签(tag)、撤销更改(revert)、回滚版本(rollback)等。

Git 使用分布式版本控制系统,这意味着每个开发者都有一份完整的代码库副本,可以通过网络与其他开发者交换更改。这种模式可以更好地支持远程协作以及离线开发

在开发过程中,Git 使开发人员能够掌握代码库的状态,跟踪分支之间的差异,并提供一致的修改历史记录。这使得当代码出现问题时,开发人员可以迅速定位问题、恢复到之前的版本或代码状态。因此,Git 是开发人员必备的工具之一。

  • 我们需要知道下面四个核心概念:版本控制、集中式版本控制、分布式版本控制、多人协作开发

2️⃣ 如何来理解版本?

在这里插入图片描述
3️⃣ 版本控制有哪些基础功能?

在这里插入图片描述

4️⃣ 什么是集中式版本控制?

集中式版本控制(Centralized Version Control)是一种版本控制系统,在这种系统中,所有项目文件的历史记录都存储在一个中央服务器上。开发人员在工作时会从服务器上拉取最新的代码,并将其下载到自己的本地计算机上进行修改。修改后,开发人员将它们提交到中央服务器上,以便其他人可以查看和合并。

这种版本控制系统有一个中央服务器,所有的开发者必须连接服务器才能进行代码的提交、拉取、合并等操作。中央服务器扮演着一个“管理员”的角色,所有修改记录和版本控制信息都存储在服务器上。每个开发者都必须从服务器上检出最新的代码版本,并将自己的修改上传到服务器以进行合并。开发者之间的交流都是通过中央服务器传递的

集中式版本控制系统的优点在于它们能够有效地管理较小的开发团队,并且易于管理。中央服务器可以控制哪些人有权访问项目,以及他们可以访问的内容。此外,集中式版本控制系统的工具和流程相对简单,易于学习和使用。

但是,集中式版本控制系统也存在一些缺点。最显著的缺点之一是当中央服务器出现故障或网络连接断开时,所有开发者都不能进行代码的提交和拉取,开发工作将完全停滞。此外,由于每个开发者都必须连接中央服务器,这种系统的性能和可扩展性会受到限制,并且在处理分支和合并等复杂任务时可能会遇到问题
请添加图片描述

  • 在集中式版本控制系统中,由于所有开发人员都操作同一个中央版本库,很容易出现文件冲突的问题。
  • 当两个或多个开发人员同时编辑同一个文件时,他们可能会进行不同的修改并且试图提交这些修改,此时就会出现冲突

在这里插入图片描述

  • 如果这个冲突没有得到妥善处理,在下次版本库更新时,可能会导致代码的不一致或重大错误
  • 那么有什么方式可以来规避这种问题或者降低文件冲突发生的概率呢?

(1)VSS(Visual SourceSafe) 是一个集中式版本控制系统,早期使用非常广泛。

VSS 在处理文件冲突时,使用了添加锁定状态”的方法来解决冲突

在 VSS 中,当一个开发人员想要编辑某个文件时,他或她会在这个文件上添加一个“独占锁定”的状态,这意味着其他开发人员不能编辑该文件,直到该文件被解锁。这就有效地防止了其他开发人员在同一时间对同一文件进行更改,从而避免了文件冲突。

在这里插入图片描述

该方法的缺点是,如果某个开发人员忘记解锁文件,那么其他开发人员就无法编辑该文件。如果另一个人急需编辑该文件,则必须联系添加锁定状态的开发人员来解锁它。这也会导致工作流程上的延迟和阻塞。此外,如果多个开发人员需要编辑同一文件,则必须进行多个锁定和解锁过程,这可能会导致更多的延迟和工作阻塞

(2)SVN(Subversion) 是一个集中式版本控制系统,它也提供了一些方法来解决文件冲突。

当多个人对同一个文件进行修改时,SVN 会尝试自动合并这些修改。如果 SVN 可以确定如何合并文件的多个版本,则可以自动完成合并,合并后的结果是一个包含所有修改的新版本。然而,如果修改不能自动合并,则 SVN 将标记这个文件为“冲突状态”,并提示用户手动解决文件冲突。

在冲突状态下,SVN 会为开发人员提供需要合并的文件版本,以及包含开发人员本地更改的文件版本。开发人员可以在两个版本之间进行比较,并手动解决版本之间的不一致之处。在解决冲突后,开发人员将更改提交到服务器上,SVN 将会生成一个新的文件版本,包含开发人员的更改和他们之前手动解决的更改。

在这里插入图片描述

除了手动解决冲突,SVN 还提供了锁定机制来避免文件冲突的发生。开发人员在开始编辑文件时可以锁定文件,这样就可以防止其他人在同一时间更改该文件。使用锁定系统可以有效减少文件冲突,但是系统管理员需要确保正确管理锁定,以避免过度限制文件上的访问。

总之,SVN 提供了一些方法来解决文件冲突,包括自动合并和手动解决冲突。与 VSS 不同的是,SVN 的解决方法更加灵活,同时也可以通过锁定来更细粒度地管理文件上的访问

  • 当我们中央服务器出现问题,那么谁都无法进行操作了,引出我们的分布式版本控制

5️⃣ 什么是分布式版本控制?

分布式版本控制(Distributed Version Control System,简称DVCS) 是一种用于跟踪和管理软件开发中的变更的技术,它可以帮助团队协作开发代码,并跟踪每个版本的变更历史。相比于传统的集中式版本控制系统(Centralized Version Control System,简称CVCS),分布式版本控制可以更方便、更灵活地协作开发,并且在一些情况下能够提供更好的性能和可靠性

在这里插入图片描述

在一个分布式版本控制系统中,每个开发者的本地工作环境都包含了完整的代码库副本,这些副本都是相互独立、相互平等的,没有一份代码库是所有其他代码库的中心。这种分布式的架构让开发者可以离线地对代码进行修改和提交,而不需要连接到中心服务器。开发者之间可以相互推送(push)和拉取(pull)变更,也可以在自己的本地分支(branch)上进行开发和测试。这些分支可以并行存在,不会相互干扰。

常见的分布式版本控制系统包括Git、Mercurial、Bazaar等。这些系统都有各自的特点和优缺点,但总的来说,它们都可以帮助团队更高效、更协同地开发和维护代码。

  • 缺点分析:需要在本地搭建一样的资源库(占用资源),如果网络延迟大就会导致同步速度特别慢
  • 优点分析:资源更安全、本地操作速度更快

1.2 软件安装

  • 点击跳转软件资源包下载
    在这里插入图片描述
  • 然后直接安装即可
  • 接下来我们基于这个 GitHubDesktop 来完成 git 相关功能的学习

二、Git 客户端

在这里插入图片描述

2.1 仓库操作

  • 首先,用客户端创建一个本地仓库:左上角File -> New respority -> 输入相关信息 -> 创建成功
    在这里插入图片描述
  • 删除仓库,分为客户端删除和客户端+本地删除两种
    • 如果是客户端删除,我们可以在本地通过拖拽直接将仓库添加到客户端中
    • 如果是本地+客户端删除,我们可以通过电脑的回收站找回仓库
      在这里插入图片描述

2.2 文件操作

  • 添加文件

    • 我们在仓库的目录下创建一个新文件 a.txt,输入内容 aaa,并创建一个文件 c.txt
    • 客户端会帮我们比较仓库中的文件和用户文件的区别
      在这里插入图片描述
    • 我们在左下角进行提交,可以添加一些对本次提交的描述信息
      在这里插入图片描述
    • 提交后我们可以通过历史记录查看
      在这里插入图片描述
  • 修改文件

    • 我们为 c.txt 文件增加内容 ccc ,可以端会对比出来本地文件的改变,并提醒开发者
      在这里插入图片描述
    • 修改文件内容也是提交,因为仓库里是创建一个新的文件,与原来的 c.txt 文件属于不同的版本
      在这里插入图片描述
    • 提交后我们数据库里面就会有两个版本的 c.txt 文件,比对结果也会相同
      在这里插入图片描述
    • 对于每次的提交操作,都会为我们产生一个唯一的版本号,我们可以在客户端的历史记录中进行查看
      在这里插入图片描述
    • 这个版本号由40位16进制数组成,前两位对应目录名,后38位对应文件名,我们可以在 .git/objects 目录下找到对应文件
      请添加图片描述
      在这里插入图片描述
  • 删除文件:

    • 我们删除 c.txt 文件 ,客户端的 Changes 里会给我们对比出来当前文件和仓库中文件的差异
      在这里插入图片描述
  • 在我们提交后,仓库里的 c.txt 的指向也会消失 【并不是实际删除文件,后面会详细介绍】
    在这里插入图片描述

2.3 分支操作

在介绍分支操作之前,我们需要了解多人协作的相关内容

(1)对于不同的开发人员开发不同的功能,到最后汇总到一起,我们可以用下面这个图来表示

在这里插入图片描述

  • 这里面存在许多问题:
    • 人操作一个文件,可能存在版本冲突的问题
    • 多次操作产生大量版本,仓库体积变大
    • 操作顺序不固定,产生冲突的隐患更大

(2)让我们开发者不在同一个版本库里进行操作,而是创建多个库的副本

  • 每个开发者开发不同的分支,再最后进行合并,这样可以降低文件冲突的发生概率

在这里插入图片描述

接下来我们演示如何通过客户端进行分支的一些相关操作:

  • wangwu 作为项目经理只负责版本库的维护和管理,无需进行开发
    在这里插入图片描述

  • 当我们创建一个仓库时,默认只有一个分支(此处为 main[可以改名]),对应的是我们的仓库管理者wangwu

  • 点击 current branch 可以查看分支,再点击 new branch 可以创建新的分支
    在这里插入图片描述

  • 我们创建两个分支 userorder
    在这里插入图片描述

  • 在两个分支下分别创建 user.txt 文件 和 order.txt 文件并提交到我们对应的分支数据库中
    在这里插入图片描述

  • 分支合并:先切换到我们的 mian 分支,点击 current branch -> 点击下面选择一个分支合并到我们的main分支
    在这里插入图片描述
    重复操作,将oder分支合并到mian分支,此时我们的 main 分支下就有了这两个分支仓库中的内容
    在这里插入图片描述

  • 如果在合并的多个分支中存在相同的文件怎么办?【分支文件冲突问题

    • 在user分支下创建 common.txt 然后提交到本地仓库,然后再合并到main分支,order分支做相同操作
    • 文件内容不同,然后分别将 user 分支、order 分支与 main 分支进行合并,在与order分支合并时会有提示
      在这里插入图片描述
    • 我们编辑合并后的内容 【手动解决文件冲突问题】,然后保存再提交一下就可以了
      在这里插入图片描述

2.4 标签操作

  • 因为和并操作是自动完成的,我们没法修改它的描述信息,我们可以给它添加个标签
  • 添加标签流程如图所示
    在这里插入图片描述
  • 删除标签:选择添加标签的提交记录,右键删除 tag 即可
    在这里插入图片描述

2.5 远程仓库

远程仓库一:GitHub

1️⃣ 登录 github 官网网站

2️⃣ 创建远程仓库 remote-test

在这里插入图片描述

3️⃣ 点击 Add file 为我们的仓库添加文件 【此处我们就创建一个 test.txt 内容为 123123】

在这里插入图片描述
4️⃣ 点击我们的 test.txt 然后通过右下角的铅笔按钮编辑,来完成文件的修改

在这里插入图片描述
5️⃣ 通过查看 History 查看历史提交记录

在这里插入图片描述
6️⃣ 通过下图流程操作完成新建分支并切换分支

在这里插入图片描述

7️⃣ 点击Settings 按钮,下拉到最下面,点击删除仓库,输入仓库名确定删除

在这里插入图片描述
8️⃣ 将我们的 GitHub Desktop 关联
在这里插入图片描述

9️⃣ 通过 File -> Clone a repository 来克隆我们GitHub远程仓库中的项目

在这里插入图片描述

  • 在本地客户端,我们可以通过 Push origin 按钮将本地仓库文件推送到远程仓库

在这里插入图片描述

远程仓库二:Gitee

  • 与 GitHub 中的操作大同小异,但是 GitHub 是国外的网站,所以访问和操作起来可能有时会很慢

1️⃣ 登录 Gitee 账户并新建一个仓库
在这里插入图片描述

2️⃣ 使用我们的 Git 客户端来克隆我们的 Gitee 项目

在克隆启动后会有一个弹窗,让我们输入 Gitee 的账户和密码
在这里插入图片描述

3️⃣ 在我们的本地仓库可以通过Publish branch按钮推送到我们的 Gitee 远程仓库

在这里插入图片描述

2.6 其他功能

1️⃣ 使用客户端管理工具,可以在我们创建仓库的时候直接生成 README 文件

  • readme 文件就是对我们仓库的一个描述
  • 如果我们想忽略我们本地仓库中的一些文件,就是在操作这些文件时不会被客户端对比,可以通过右键 Ignore 来完成
    • git客户端可以对文本文件进行比对,对于文档、压缩包、图片等不具备此功能
      在这里插入图片描述

2️⃣ 客户端文件操作与图标的对应关系

在这里插入图片描述
3️⃣ 客户端的对比功能

在这里插入图片描述


三、IDEA集成

2.1 IDEA 集成 GitHub

1️⃣ 使用IDEA创建一个普通的Java空项目

在这里插入图片描述
2️⃣ 编写一个 a.txt 文件,将IDEA与github连接,然后再将我们的文件发送到远程仓库中

在这里插入图片描述

3️⃣ 文件修改后,可以通过 git -> commit Fiel -> Commit and Push 更新我们的远程仓库

在这里插入图片描述

4️⃣ 如果我们在远程仓库中修改了文件,可以通过 Git -> Pull 将远程仓库文件下载到本地与本地文件进行合并,就可以实现更新本地文件

在这里插入图片描述

5️⃣ 通过IDEA克隆我们GitHub中的项目 Git -> clone -> GitHub -> 选择我们要克隆的项目 【可以修改项目名和本地保存地址】

2.2 IDEA 集成 Gitee

1️⃣ 创建一个新的空项目,创建文件 a.txt, 搜索插件gitee并安装,插件安装完成后,我们VCS选项下会多一个 Share Project on Gitee

在这里插入图片描述
2️⃣ 添加我们的 Gitee 账号 【就是将IDEA与Gitee远程仓库关联起来】

3️⃣ 修改我们本地文件,然后提交到我们本地仓库和远程仓库中

在这里插入图片描述
4️⃣ 在远程仓库更新了我们的文件,在IDEA中我们可以通过 Git -> pull 获取到远程文件并更新本地文件

5️⃣ 如果其他开发人员想要使用我们这个远程仓库,也可以克隆到本地

在这里插入图片描述


四、版本号

  • 版本号可以在合并的时候避免冲突,也可以定位我们的文件

  • 采用 2 + 38 的形式,前两位是文件夹、后三十八位是文件名

  • 创建一个本地仓库,通过版本号定位到我们的文件

    • git cat-file -p 版本号 可以用来查看文件内容

在这里插入图片描述
在这里插入图片描述

  • 我们根据 tree 中的版本号再次查看文件内容,发现是我们提交的 .gitattributes
    在这里插入图片描述
    在这里插入图片描述

1️⃣ 通过这些文件我们可以知道与版本号之间的关系:

在这里插入图片描述
2️⃣ 创建文件

在这里插入图片描述

3️⃣ 修改文件

在这里插入图片描述
4️⃣ 删除文件 【我们并没有把文件真正的删除,只是文件状态不再指向我们存储的文件了】

在这里插入图片描述
5️⃣ 我们当前的分支是谁,我们 head 中文件地址就是谁

在这里插入图片描述

  • 此时这个 main 文件的内容是当前分支中最新操作的版本号

在这里插入图片描述

  • 对于不同的分支可以指向相同的提交,实际分为三个区域

在这里插入图片描述
在Git客户端中的对比,就是 工作区域与暂存区进行比对,提交实际分为两步,只不过是被我们的客户端隐藏起来了


五、命令

  • 通过上面的文章,我们需要明白四个概念:拷贝、拉取、推送、发布
    在这里插入图片描述
  • 工作区就是编辑代码的,暂存区完成比对功能,存储区域是我们的本地仓库,上面的是我们的远程仓库
  • git -v 查看我们的 git 版本

5.1 仓库操作

  • 我们创建仓库的文件夹,然后在文件夹内打开 git bash,使用 git init 初始化仓库,会为我们生成 .git 文件
    在这里插入图片描述
  • 通过 git 客户端创建的本地仓库,会多出来一个 .gitattributes 文件
  • 我们还可以通过 git clone 项目地址 克隆项目,在克隆到本地之前可以起个别名
  • 需要对我们的邮箱进行配置,包括 用户名和邮箱 【我们也可以不通过命令行直接编辑这个配置文件】
    在这里插入图片描述
  • 配置后的文件在我们 .git 文件夹下的 config 文件中
    在这里插入图片描述
  • 如果我们存在多个仓库,那么我们挨个配置会很费事儿
    • 所以我们通过 git config --global user.name zhaowenhan 为我们本地git所有仓库的所有者都起名

5.2 文件操作

  • 通过 git status 可以查看我们暂存区的状态
    在这里插入图片描述

  • 在目录下创建 a.txt 并输入内容 aaaa,再次查看状态
    在这里插入图片描述

  • 通过 git add 文件名 的方式将文件添加到暂存区
    在这里插入图片描述

  • 通过 git rm --cached 文件名 可以将文件从暂存区移除
    在这里插入图片描述

  • 对于文件名是支持使用 * 代表任意多个字符的,比如 *.txt 代表操作所有以 .txt 结尾的文件
    在这里插入图片描述

  • 通过 git commit -m 说明内容可以将当前暂存区里的所有信息都提交到我们的存储区域
    在这里插入图片描述

  • 通过 git log 可以查看提交的历史记录【新的记录排在上面】
    在这里插入图片描述
    在这里插入图片描述

  • 修改我们a.txt文件,然后重新 add commit,然后用 git log --oneline 查看日志

    • oneline 选项是将所有的commit 提交用一行显示
      在这里插入图片描述
  • 对于删除操作本质上也是一种提交,此处我们删除 b.txt 查看暂存区的状态
    在这里插入图片描述
    在这里插入图片描述

  • 如果我们误删除了,如果这个文件之前已经存贮到了存储区域,我们可以通过git restore 文件名命令进行恢复【我们以删除 a.txt 文件为例】
    在这里插入图片描述

  • 但是如果存储区域没有我们误删的文件,那么我们就无法恢复这个文件
    在这里插入图片描述

  • 我们可以将数据库恢复到包含这个误删文件的时期,但是在这个时期之后的所有操作都会丢失

    • git reset 版本号
  • 我们还可以将数据库还原到误删操作之前的那个时期

    • git revert 版本号 此处这个版本号为误删操作的版本号

5.3 分支操作

  • 要想通过命令行创建其他分支,首先得创建出 master 分支 【也就是得至少有一次提交操作】
    在这里插入图片描述
    在这里插入图片描述
  • 我们通过 git checkout 分支名 可以切换分支
    在这里插入图片描述
  • 我们还可以通过 git checkout -b 分支名 直接新建并切换到这个分支 【上面两个操作的结合】
    在这里插入图片描述
  • 通过 git branch -d 分支名 可以删除指定的分支
    在这里插入图片描述
  • 通过 git branch -v 可以查看我们的分支
    在这里插入图片描述
  • 合并分支首先要切换到 master 分支,然后选择一个分支使用 git merge 分支名与master分支合并
    • 同时我们希望将指定分支中的文件也合并过去
    • 此处演示出现文件冲突问题如何解决
      在这里插入图片描述
  • 上图我们可以发现,两个分支中存储文件冲突提示我们需要解决,已经将我们 master 中的文件和 order 的文件整合到了这个冲突文件中,需要我们手动进行处理
  • 在我们编辑结束之后,将其当作一个全新的文件重新提交就可以了
    在这里插入图片描述

5.4 标签操作

  • 创建文件a.txt(然后提交),修改文件a然后提交,创建文件b然后提交
    在这里插入图片描述
  • 通过 git log 版本号 我们可以查看某个版本号之前的日志
    在这里插入图片描述
  • 但是这个序列号有些长不好记,我们可以通过git tag 标签名 版本号标签给当前这个commit起个别名
    在这里插入图片描述
  • 在查看历史记录的时候就可以使用我们别名,查看这个commit之前的历史记录
    在这里插入图片描述
  • 我们可以给每个版本都添加一个标签,但是标签不能重复
    在这里插入图片描述
  • 我们可以通过 git tag -d 标签名 删除标签
    在这里插入图片描述
  • 我们的标签就是给版本增加了个别名,所以我们就可以根据某个指定的提交进行分支创建 git checkout -b addfile `
    在这里插入图片描述

5.5 远程仓库

  • 对于我们从远程克隆下来的项目,都会有一个远程地址,通过配置文件可以看到
    在这里插入图片描述
  • 如果没有我们可以通过 git remote add 远程仓库名 远程仓库地址 将当前这个本地项目绑定到我们的远程仓库
  • 我们也可以通过 git remote remove 远程仓库名 删除这个绑定
  • 还可以通过 git remote rename 远程仓库名 新名 来更改名字
  • 其实也可以直接打开配置文件进行修改

在这里插入图片描述

  • 通过 git push 远程仓库名 将本地文件推送到远程仓库
    在这里插入图片描述
  • 通过 git pull 远程仓库名 将远程仓库的文件拉取到本地,用于更新本地文件
    在这里插入图片描述

六、GitLab 自定义托管平台

1️⃣ 将我们的 gitlab-ce-15.7.0.el7.x86_64.rpm 放到虚拟机中

在这里插入图片描述
2️⃣ 安装我们这个 gitlab 资源包

报错:警告:/opt/module/software/gitlab-ce-15.7.0-ce.0.el7.x86_64.rpm: 头V4 RSA/SHA1 Signature, 密钥 ID f27eab47: NOKEY
错误:依赖检测失败:
policycoreutils-python 被 gitlab-ce-15.7.0-ce.0.el7.x86_64 需要

  • 提示我需要一个其他的依赖,那么我们就下载一下 yum install policycoreutils-python -y
  • 接下来再次尝试 sudo rpm -ivh /opt/module/software/gitlab-ce-15.7.0-ce.0.el7.x86_64.rpm,成功安装

在这里插入图片描述
3️⃣ 进行配置,指令按顺序执行

sudo yum install -y curl policycoreutils-python openssh-server perl
sudo systemctl enable sshd
sudo systemctl start sshd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo systemctl reload firewalld
# sudo systemctl stop firewalld` 也可以不对防火墙进行设置,我们直接关闭防火墙

在这里插入图片描述
4️⃣ 初始化我们 GitLab

  • curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh

在这里插入图片描述

  • sudo EXTERNAL URL="https://centOS1" yum install -y gitlab-ce 【centOS1是我自己虚拟机的名字】
  • sudo gitlab-ctl reconfigure 初始化

5️⃣ 启动 GitLab

# 启动
gitlab-ctl start
# 停止
gitlab-ctl stop

6️⃣ 访问 GitLab

  • 使用浏览器输入网址 http://centOS1/users/sign_in 访问 GitLab
    在这里插入图片描述
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bow.贾斯汀

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值