3.DevOps体系之Git

DevOps体系之Git

认识Git

官网

https://git-scm.com/

Git 是一个免费的开源 分布式版本控制系统,旨在快速高效地处理从小到大的所有项目。

Git易于学习占用空间小,性能快如闪电。它优于 Subversion、CVS、Perforce 和 ClearCase 等 SCM 工具,具有便宜的本地分支、方便的暂存区多个工作流等功能

Git基本概念、Git解决了哪些问题、Git的安装使用

版本控制

版本控制是一种记录文件内容变化,方便以后查阅特定版本修订情况的系统

思考:

如何实现一个版本控制系统?

  1. 每次提交的内容进行存储一份数据(提交这的信息、日期、版本号)

  2. 每次叫的时候,只存储发生变化的内容(提交这的信息、日期、版本号)

版本控制的发展史

本地版本控制系统

采用简单的数据库记录文件的历次更新差异

image-20210814212728489

集中化的版本控制系统

有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新

image-20210814212834061image-20210814212901217

优点
 可以看到项目中的其他人在做什么
 可以掌控每个开发者的权限
 管理一个 CVCS 比在各客户端上维护本地数据库容易

缺点
中央服务器的单点故障
磁盘发生损坏-可能丢失所有数据

分布式版本控制系统

客户端每次的克隆操作,都是对代码仓库的完整备份,不只提取最新版本的文件快照,任何一处协同工作用的服务
器发生故障,事后都可以用任何一个镜像的本地仓库恢复

image-20210814213239354

 可以指定和若干不同的远端代码仓库进行交互
 可以在同一个项目中,分别和不同工作小组的人相互协作
 可以根据需要设定不同的协作流程
如层次模型式的工作流,这在集中式系统中无法实现

Git

Git起源

这故事还得从Linux内核开发工作说起,当初Linux内核通过分布式版本控制系统BitKeeper来管理维护提交补丁、保存归档事务后来跟BitKeeper合作结束Linux内核作者开发了自己的分布式版本控制系统——Git

Git设计目标

 速度
 简单的设计
 对非线性开发模式的支持—需要上万个并行开发分支
 完全分布式
 能够高效管理超大规模项目

Git安装

在使用Git前我们需要先安装 Git。Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行。

Git 各平台安装包下载地址为:http://git-scm.com/downloads

Linux 平台上安装

Git 的工作需要调用 curl,zlib,openssl,expat,libiconv 等库的代码,所以需要先安装这些依赖工具。

在有 yum 的系统上(比如 Fedora)或者有 apt-get 的系统上(比如 Debian 体系),可以用下面的命令安装:

各 Linux 系统可以使用其安装包管理工具(apt-get、yum 等)进行安装:

Debian/Ubuntu

Debian/Ubuntu Git 安装命令为:

$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
  libz-dev libssl-dev

$ apt-get install git

$ git --version
git version 1.8.1.2
Centos/RedHat

如果你使用的系统是 Centos/RedHat 安装命令为:

$ yum install curl-devel expat-devel gettext-devel \
  openssl-devel zlib-devel

$ yum -y install git-core

$ git --version
git version 1.7.1
源码安装

我们也可以在官网下载源码包来安装,最新源码包下载地址:https://git-scm.com/download

安装指定系统的依赖包:

########## Centos/RedHat ##########
$ yum install curl-devel expat-devel gettext-devel \
  openssl-devel zlib-devel

########## Debian/Ubuntu ##########
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
  libz-dev libssl-dev

解压安装下载的源码包:

$ tar -zxf git-1.7.2.2.tar.gz
$ cd git-1.7.2.2
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install
Windows 平台上安装

在 Windows 平台上安装 Git 同样轻松,有个叫做 msysGit 的项目提供了安装包,可以到 GitHub 的页面上下载 exe 安装文件并运行:

安装包下载地址:https://gitforwindows.org/

官网慢,可以用国内的镜像:https://npm.taobao.org/mirrors/git-for-windows/。

image-20210814214155355

完成安装之后,就可以使用命令行的 git 工具(已经自带了 ssh 客户端)了,另外还有一个图形界面的 Git 项目管理工具。

在开始菜单里找到"Git"->“Git Bash”,会弹出 Git 命令窗口,你可以在该窗口进行 Git 操作。


Mac 平台上安装

在 Mac 平台上安装 Git 最容易的当属使用图形化的 Git 安装工具,下载地址为:

http://sourceforge.net/projects/git-osx-installer/

Git本地配置
在本地生成ssh key 秘钥
#第一步:执行下边的命令
ssh-keygen -t rsa -C "11******30@qq.com"
#第二步:连续三次回车,即可生产  ssh key
#查看ssh key ,window下 C:\Users\Administrator\.ssh中,
#id_rsa中的是私钥
#id_rsa.pub中的是公钥

image-20210815200141064

配置Git服务器ssh key

比如使用GitLab,在Profile Settings 下的SSH Keys中,添加ssh key,然后进入添加页面,将公钥粘贴保存即可,如下图:

image-20210815200810694

image-20210815200950102

测试
#添加后,在终端中输入
#Gitee
$ ssh -T git@gitee.com
#GitHub
$ ssh -T git@github.com

例如:
$ ssh -T git@192.168.0.43
#再次执行上面的命令,检查是否成功连接,如果返回一下信息,则表示添加成功
The authenticity of host '192.168.0.43 (192.168.0.43)' can't be established.
ED25519 key fingerprint is SHA256:eH9lC5bzUwYhQBCD96iO/Bdon0bXfgRsT9lY2XmI61s.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? Y
Please type 'yes', 'no' or the fingerprint: yes
Warning: Permanently added '192.168.0.43' (ED25519) to the list of known hosts.
Welcome to GitLab, Administrator!

配置用户信息
#用户名和邮箱
git config --global user.name "fengb"
git config --global user.email "11******30@qq.com"

#通过命令查看配置信息
git config --global -- list

GitLab安装搭建

国内安装方式

官网很多资源在国内安装都不那么便利,这里提供一个国内CentOS7的镜像安装包的方式。

  1. 安装依赖软件

    sudo yum install -y curl policycoreutils-python openssh-server opensshclient postfix
    # 设置ssh服务开机启动
    sudo systemctl enable sshd
    sudo systemctl start sshd
    # 设置postifx邮件服务开机自启动
    sudo systemctl enable postfix
    sudo systemctl start postfix
    
  2. 下载gitlab安装包
    在清华大学开源软件镜像站,https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce下面也能找到更加
    新的版本,以及gitlab-ee版本

wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-8.0.0-ce.0.el7.x86_64.rpm
rpm -i gitlab-ce-8.0.0-ce.0.el7.x86_64.rpm
#或者高版本的,如下:
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.0.0-ce.0.el7.x86_64.rpm
rpm -i gitlab-ce-12.0.0-ce.0.el7.x86_64.rpm

image-20210814220938791

image-20210814221020624

image-20210814221945634

  1. 修改gitlab配置
    指定gitlab服务器ip和自定义端口,设置为自己机器的ip地址和端口号,后面在浏览器登录gitlab会
    用到这个地址。
vim /etc/gitlab/gitlab.rb
external_url "http://ip:port"
  1. 重置并启动GitLab

    #查看gitlab所有安装包的文件存储位置
    rpm -qal |grep gitlab
    # 进入gitlab文件位置,我的例子中在/opt/gitlab目录
    bin/gitlab-ctl reconfigure
    bin/gitlab-ctl restart
    
  2. 用户名密码设置
    设置密码为12345678,同学可以自己定义。

sudo bin/gitlab-rails console production
Loading production environment (Rails 4.1.12)
irb(main):001:0> u=User.where(id:1).first
=> #<User id: 1, email: "admin@example.com", encrypted_password:
"$2a$10$foLIteHM6rRrV/crdQU1POzH84T.Bz2L6FbzvPIMTgm...",
reset_password_token: nil, reset_password_sent_at: nil, remember_created_at:
nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil,
current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2020-02-23
04:18:10", updated_at: "2020-02-23 04:18:11", name: "Administrator", admin:
true, projects_limit: 10000, skype: "", linkedin: "", twitter: "",
authentication_token: "A6khrCzAC5yqBvJQ-hVg", theme_id: 2, bio: nil,
failed_attempts: 0, locked_at: nil, username: "root", can_create_group:
true, can_create_team: false, state: "active", color_scheme_id: 1,
notification_level: 1, password_expires_at: "2020-02-23 04:18:09",
created_by_id: nil, last_credential_check_at: nil, avatar: nil,
confirmation_token: "XcbcpbBEdxVgYCTJS-kL", confirmed_at: "2020-02-23
04:18:11", confirmation_sent_at: "2020-02-23 04:18:10", unconfirmed_email:
nil, hide_no_ssh_key: false, website_url: "", notification_email:
"admin@example.com", hide_no_password: false, password_automatically_set:
false, location: nil, encrypted_otp_secret: nil, encrypted_otp_secret_iv:
nil, encrypted_otp_secret_salt: nil, otp_required_for_login: false,
otp_backup_codes: nil, public_email: "", dashboard: 0, project_view: 0,
consumed_timestep: nil>
irb(main):002:0> u.password='12345678'
=> "12345678"
irb(main):003:0> u.password_confirmation='12345678'
=> "12345678"
irb(main):004:0> u.save!
=> true
irb(main):005:0> exit

  1. 登录检测
    根据前面配置的ip和端口号到浏览器进行访问,通过前面配置的用户名和密码进行登录。

    账号:root
    密码:root12345678
    
官网安装方式
  1. 打开GitLab官网:https://about.gitlab.com/

  2. 找到Resources(资源) | 选择Install GitLab(安装)

  3. 找到服务器相对应的版本

  4. 选择CentOS7,点击后安装的代码会在下面显示出来

    # 安装和配置必要的依赖项
    sudo yum install -y curl policycoreutils-python openssh-server
    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
    # 安装Postfix发送通知电子邮件
    sudo yum install postfix
    sudo systemctl enable postfix
    sudo systemctl start postfix
    # 添加GitLab软件包存储库并安装软件包
    curl https://packages.gitlab.com/install/repositories/gitlab/gitlabee/script.rpm.sh | sudo bash
    # 更改GitLab实例的URL
    sudo EXTERNAL_URL="http://192.168.1.4" yum install -y gitlab-ee
    
    
卸载
 #查看gitlat的安装
 rpm -qa|grep gitlab
 #卸载命令
 rpm -e  --nodeps  jdk版本
 rpm -e  --nodeps  gitlab版本
 

Git核心概念

**参考**官方网站 https://git-scm.com/book/en/v2

image-20211110201139512

Git工作原理

  1. 直接记录快照,而非差异比较

    • CVS、SVN 等大部分系统以文件变更列表的方式存储信息,将保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异

      image-20210815174149524

    • Git把数据看做对小型文件系统的一组快照存储每个文件与初始版本的差异

     文件发生变化,对全部文件制作一个快照并保存这个快照的索引
     文件没有修改,保留一个链接指向之前存储的文件

image-20210815174207817

  1. 几乎所有操作都是本地执行

     大多数操作都只需要访问本地文件和资源
     在本地磁盘上就有项目的完整历史,操作快
    浏览项目的历史,Git 不需外连到服务器去获取历史
     没有网络也能进行提交,有网络再上传。SVN、CVS就不能

  2. 保证完整性

    Git 中所有数据在存储前都计算校验和,然后以校验和来引用,不可能在 Git 不知情时更改任何文件内容或目录内容。
    Git 用SHA-1 散列方式计算校验和

    #一个SHA-1 校验和值
    
    24b9da6552252987aa493b52f8696cd6d3b00373
    

    Git 数据库中保存的信息都是以文件内容的哈希值来索引

  3. 一般只添加数据

  4. Git的三种状态

     已提交(committed)
    数据已经安全的保存在本地数据库中
     已修改(modified)
    修改了文件,但还没保存到数据库中
     已暂存(staged)
    对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
    

Git工作流程

一般工作流程如下:

  • 克隆 Git 资源作为工作目录。
  • 在克隆的资源上添加或修改文件。
  • 如果其他人修改了,你可以更新资源。
  • 在提交前查看修改。
  • 提交修改。
  • 在修改完成后,如果发现错误,可以撤回提交并再次修改并提交。

image-20210815174935558

Git与SVN的区别

功能SVNGit
分布式×
数据存储方式按文件按元数据方式存储
分支另外的一个目录一个指针标记
全局版本号任何一个相应时间的源代 码快照代码快照,SHA-1来唯一的标识
内容完整性-使用SHA-1校验和,确保代码内容的完整性
网络依赖需要联网才能提交查看整个版本控制信息无需联网,本地即可操作

Git工作区、暂存区和版本库

  • **工作区:**就是你在电脑里能看到的目录。
  • **暂存区:**英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • **版本库:**工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

image-20210815194718269

  • 图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage/index),标记为 “master” 的是 master 分支所代表的目录树。
  • 图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
  • 图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。
  • 当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
  • 当执行 git rm --cached 命令时,会直接从暂存区删除文件,工作区则不做出改变。
  • 当执行 git checkout . 或者 git checkout – 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。
  • 当执行 git checkout HEAD . 或者 git checkout HEAD 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

分支

Git鼓励在工作流程中频繁地使用分支与合并,哪怕一听啊之内进行许多次。

Git特性
  1. Git的必杀技特性—分支模型
  2. Git分支处理非常的轻量级,瞬间完成新建分支
  3. 分支切换快捷方便
  4. 分支是Git强大独特之处
Git如何保存数据

Git保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照

git add 操作步骤

假设您有一个包含三个文件的目录,您将它们全部暂存并提交

  1. 通过SHA-1哈希算法为每个文件计算校验和、校验和与文件名对应

  2. 使用blob对象将当前版本文件快照保存到Git仓库中

  3. 将校验和信息加入到暂存区等待提交

文件快照:

​ 其实就是值添加文件那一时刻的文件内容,就像照相机摄影保留了生活中某一时刻的样子。

git commit操作步骤
  1. 按照提交的文件目录,计算每个目录的校验和
  2. 仓库中将上面目录结构、对应的校验和保存为树对象
  3. 创建一个提交对象,包含树对象指针、提交信息
  4. 为后面需要的时候重现本次保存的快照
$ git cat-file -p 804205891c55913da1fa5c288710b758fc1449cd
tree 2b20576b1537ddd7c905b67fd3e027d30ecaa10b
parent b81fd21c85ef73620c1c16407cb8c9a4f2f1d0ff
author fengb <11******30@qq.com> 1636525137 +0800
committer fengb <11******30@qq.com> 1636525137 +0800

保存在Git数据库中的内容都是用校验和哈希值来作索引的,不是用文件名

此时Git仓库中的对象包含五个对象:

三个blobs对象,分别代表三个文件的内容

一个树对象,它列出目录结构和blob对象索引

一个提交对象,包含指向前面树对象指针和提交信息

image-20211110201835643

修改后在提交

如果您进行了一些更改并再次提交,则下一次提交会存储一个指向紧接在它之前的提交的指针。

image-20211110202707079

Git中默认的分支名称是master,当你提交后,master只想你最后一次提交的分支。每次提交时,master分支指针都会自动向前移动。

image-20211110203347639

​ Git 中的“master”分支并不是一个特殊的分支。它与任何其他分支完全一样。几乎每个存储库都有一个的唯一原因是该git init命令默认创建它并且大多数人不费心去更改它。

创建新分支
$ git branch testing

这将创建一个指向您当前所在的同一提交的新指针。

image-20211110203717161

Git如何知道你当前哪个分支?

它保留了一个特殊的指针,称为HEAD,指向您当前所在的本地分支的指针,在通过 git branch testing 这种情况下,您仍然使用的时master分支,git branch testing命令只会创建一个新的分支,不会切换分支,因此当前分支HEAD指向master

image-20211110204326662

您可以通过运行一个简单的git log命令来轻松看到这一点,该命令向您显示分支指针指向的位置。此选项称为--decorate

$ git log --oneline --decorate
f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface
34ac2 Fix bug #1328 - stack overflow under certain conditions
98ca9 Initial commit
切换分支

要切换到现有分支,请运行该git checkout命令。让我们切换到新testing分支:

$ git checkout testing

image-20211110204633441

分支切换梳理

image-20211110210624717

image-20211110212303877

来源动脑

image-20211110212352684

来源动脑

image-20211110212426125

来源动脑

远程分支
单一远程仓库

假设您的网络上有一个 Git 服务器,位于git.ourcompany.com. 如果你从这里克隆,Git 的clone命令会自动origin为你命名,拉下它的所有数据,创建一个指向它的master分支所在位置的指针,并在origin/master本地命名它。Git 还为您提供了您自己的本地master分支,起始于 originmaster分支的同一位置,因此您可以使用一些东西。

克隆后的服务器和本地存储库。

如果你在本地master分支上做了一些工作,与此同时,其他人推送git.ourcompany.com并更新了它的master分支,那么你的历史就会以不同的方式向前发展。此外,只要您不与origin服务器接触,您的origin/master指针就不会移动。

本地和远程工作可能会有所不同

要将您的工作与给定的遥控器同步,您可以运行一个git fetch <remote>命令,从中获取您还没有的任何数据,并更新您的本地数据库,将您的origin/master指针移动到它的新的、更新的位置

 更新你的远程引用

多个远程仓库

添加另一台服务器作为远程服务器

添加另一个服务器作为远程服务器

现在,您可以运行git fetch teamone以获取远程teamone服务器上您还没有的所有内容。因为该服务器拥有您的origin服务器现在拥有的数据子集,所以Git 不获取任何数据,但会设置一个远程跟踪分支teamone/master,该分支被调用以指向teamone作为其master分支的提交。

“teamone/master”的远程跟踪分支

分支工作流
Long-Running Branches 长期运行的分支

渐进稳定分支的流水线模式

master,保留完全稳定的代码

develop,用来做后续开发或者测试稳定性,一旦达到稳定状态可以合并入master

topic,完成某个特性的分支

image-20211110214508919

渐进稳定性分支的线性视图

通常更容易将它们视为工作孤岛,当它们经过全面测试时,提交集会升级为更稳定的孤岛。

渐进稳定性分支的“筒仓”视图

用这种方法可以维护不同层次的稳定性

每个分支具有不同级别的稳定性

当它们稳定后,再合并入具有更高稳定性的分支中

在庞大或复杂的项目中,这种模式很有帮助

Topic Branches 主题分支

主题分支在任何规模的项目中都很有用。主题分支是您为单个特定功能或相关工作创建和使用的短期分支

image-20211110214837949image-20211110215119578

Git Flow工作流

参考:https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow

​ https://www.jianshu.com/p/41910dc6ef29

Gitflow 是一个遗留的 Git 工作流,它最初是一种用于管理 Git 分支的颠覆性和新颖的策略。Gitflow 越来越受欢迎,转而支持基于主干的工作流,后者现在被认为是现代持续软件开发和DevOps实践的最佳 实践。Gitflow 与CI/CD一起使用也可能具有挑战性。出于历史目的,这篇文章详细介绍了 Gitflow。

什么是 Gitflow?

Giflow 是另一种 Git 分支模型,它涉及使用功能分支和多个主分支。它由文森特·德里森( Vincent Driessen) 在 nvie首次出版并广受欢迎。与基于主干的开发相比,Giflow 拥有众多、寿命更长的分支和更大的提交。在这个模型下,开发者创建一个功能分支,并延迟合并到主干分支,直到功能完成。这些长期存在的特性分支需要更多的协作来合并,并且有更高的偏离主干分支的风险。它们还可以引入冲突的更新。

一个成功的 Git 分支模型https://nvie.com/posts/a-successful-git-branching-model/

以下是基于Vincent Driessen提出的Git Flow 流程图

img
Git Flow 的常用分支
Master分支

这个分支最近发布到生产环境的代码,最近发布的Release, 这个分支只能从其他分支合并,不能在这个分支直接修改

Develop 分支

这个分支是我们是我们的主开发分支,包含所有要发布到下一个Release的代码,这个主要合并与其他分支,比如Feature分支

Feature 分支

这个分支主要是用来开发一个新的功能,一旦开发完成,我们合并回Develop分支进入下一个Release

Release分支

当你需要一个发布一个新Release的时候,我们基于Develop分支创建一个Release分支,完成Release后,我们合并到Master和Develop分支

Hotfix分支

当我们在Production发现新的Bug时候,我们需要创建一个Hotfix, 完成Hotfix后,我们合并回Master和Develop分支,所以Hotfix的改动会进入下一个Release

Git Flow 如何使用
Master/Devlop 开发和主要分支

所有在Master分支上的Commit应该打上Tag,一般情况下Master不存在Commit,Devlop分支基于Master分支创建

image-20211110221836177

git branch develop
git push -u origin develop
Feature 功能分支

Feature分支做完后,必须合并回Develop分支, 合并完分支后一般会删点这个Feature分支,毕竟保留下来意义也不大。

image-20211110221947506

git checkout develop
git checkout -b feature_branch	
Release 发布分支

Release分支基于Develop分支创建,打完Release分支之后,我们可以在这个Release分支上测试,修改Bug等。同时,其它开发人员可以基于Develop分支新建Feature (记住:一旦打了Release分支之后不要从Develop分支上合并新的改动到Release分支)发布Release分支时,合并Release到Master和Develop, 同时在Master分支上打个Tag记住Release版本号,然后可以删除Release分支了。

image-20211110222046718

git checkout develop
git checkout -b release/0.1.0

git checkout main
git merge release/0.1.0
Hotfix 修补程序分支

hotfix分支基于Master分支创建,开发完后需要合并回Master和Develop分支,同时在Master上打一个tag。

image-20211110222255502

git checkout main
git checkout -b hotfix_branch
#类似于完成一个release分支,一个hotfix分支被合并到两个main 和develop
git checkout main
git merge hotfix_branch
git checkout develop
git merge hotfix_branch
git branch -D hotfix_branch
例子

演示功能分支流的完整示例如下。假设我们有一个带有main 分支的 repo 设置。

#切换到主分支
git checkout main
#从主分支中,创建develop分支,并切换到develop分支上
git checkout -b develop
#从develop分支中,创建feature_branch分支,并切换到feature_branch分支上
git checkout -b feature_branch
# work happens on feature branch,在feature_branch分支开发代码
#切换到develop分支
git checkout develop
#将feature_branch分支合并到 develop分支
git merge feature_branch
#切换到main分支
git checkout main
#将develop分支合并到 main 分支
git merge develop
#删除功能分支feature_branch
git branch -d feature_branch

除了featurerelease流程,一个hotfix例子如下:

#切换到主分支
git checkout main
#从主分支中,创建 hotfix_branch 分支,并切换到 hotfix_branch 分支上
git checkout -b hotfix_branch
# work is done commits are added to the hotfix_branch,在 hotfix_branch 分支开发代码,并提交代码
#切换到 develop 分支
git checkout develop
#将 hotfix_branch 分支合并到 develop 分支
git merge hotfix_branch
#切换到 main 分支
git checkout main
#将 hotfix_branch 分支合并到 main 分支
git merge hotfix_branch

Git使用

Git命令行、Git客户端工具、在IDE中使用Git

可以参考官方文档 https://git-scm.com/docs

创建仓库

创建仓库两种方式:

  1. 通过git init创建

    #1.使用当前目录作为Git仓库,我们只需在它内部,右键 Git Base Here ,然后执行如下命令初始化,该命令执行完后会在当前目录生成一个 .git 目录
    git init
    
    #2.使用指定目录作为Git仓库
    git init newrepo
    
    #小实例,git使用,如下:
    $ git add *.c
    $ git add README
    $ git commit -m '初始化项目版本'
    
  2. 通过git clone创建

    #1.在当前目录进行创建,克隆仓库的命令格式:git clone <repo>
    #例如:
    git clone git://github.com/schacon/grit.git
    
    #2.在指定目录进行创建,克隆仓库的命令格式:git clone <repo> <directory>
    #例如:
    git clone git://github.com/schacon/grit.git mygrit
    

Git基本操作

Git 常用的是以下 6 个命令:git clonegit pushgit addgit commitgit checkoutgit pull

image-20210815203044058

img

说明:

  • workspace:工作区
  • staging area:暂存区/缓存区
  • local repository:版本库或本地仓库
  • remote repository:远程仓库

一个简单的操作步骤:

$ git init    
$ git add .    
$ git commit  
  • git init - 初始化仓库。
  • git add . - 添加文件到暂存区。
  • git commit - 将暂存区内容添加到仓库中。
创建仓库命令
命令说明
git init初始化仓库,项目创建时使用
git clone拷贝一份远程仓库,项目中使用比较多
git init

git init 命令用于在目录中创建新的 Git 仓库。

git clone

git clone 拷贝一个 Git 仓库到本地,让自己能够查看该项目,或者进行修改。

git clone [url]
#例如:
git clone https://github.com/tianqixin/runoob-git-test
提交修改
命令说明
git add添加文件到仓库
git status查看仓库当前的状态,显示有变更的文件。
git diff比较文件的不同,即暂存区和工作区的差异。
git commit提交暂存区到本地仓库。
git reset回退版本。
git rm删除工作区文件。
git mv移动或重命名工作区文件。
git add

git add 命令可将该文件添加到暂存区。

#git add 命令可将该文件添加到暂存区。
#1.添加一个或多个文件到暂存区
git add [file1] [file2] ...
#2.添加指定目录到暂存区,包括子目录:
git add [dir]
#3.添加当前目录下的所有文件到暂存区:
git add .
git status

git status 命令用于查看在你上次提交之后是否有对文件进行再次修改

 git status
git diff

git diff 命令比较文件的不同,即比较文件在暂存区和工作区的差异。

git diff 命令显示已写入暂存区和已经被修改但尚未写入暂存区文件对区别。

git diff 有两个主要的应用场景。

  • 尚未缓存的改动:git diff
  • 查看已缓存的改动: git diff --cached
  • 查看已缓存的与未缓存的所有改动:git diff HEAD
  • 显示摘要而非整个 diff:git diff --stat
  1. 显示暂存区和工作区的差异:
$ git diff [file]
  1. 显示暂存区和上一次提交(commit)的差异:
$ git diff --cached [file]
或
$ git diff --staged [file]
#例如:
$ git diff --cached 3.DevOps体系之Git.md
diff --git "a/2.\345\255\246\344\271\240\347\254\224\350\256\260/C.JAVA/a.JAVA \345\212\250\350\204\221/1.DevOps\344\275\223\347\263\273/3.DevOps\344\275\223\347\263\273\344\271\213Git.md" "b/2.\345\255\246\344\271\240\347\254\224\350\256\260/C.JAVA/a.JAVA \345\212\250\350\204\221/1.DevOps\344\275\223\347\263\273/3.DevOps\344\275\223\347\263\273\344\271\213Git.md"
index b4301b4..e305945 100644
--- "a/2.\345\255\246\344\271\240\347\254\224\350\256\260/C.JAVA/a.JAVA \345\212\250\350\204\221/1.DevOps\344\275\223\347\263\273/3.DevOps\344\275\223\347\263\273\344\271\213Git.md"
+++ "b/2.\345\255\246\344\271\240\347\254\224\350\256\260/C.JAVA/a.JAVA \345\212\250\350\204\221/1.DevOps\344\275\223\347\263\273/3.DevOps\344\275\223\347\263\273\344\271\213Git.md"
@@ -13,8 +13,10 @@
 > 如何实现一个版本控制系统?
 >
 >      1. 每次提交的内容进行存储一份数据(提交这的信息、日期、版本号)
->
+>
 >      2. 每次叫的时候,只存储发生变化的内容(提交这的信息、日期、版本号)
+>
+>

 ### 版本控制的发展史

@@ -531,6 +533,20 @@ $ git commit
 | git init  | 初始化仓库,项目创建时使用         |
 | git clone | 拷贝一份远程仓库,项目中使用比较多 |

+##### git init
+
+**git init** 命令用于在目录中创建新的 Git 仓库。

  1. 显示两次提交之间的差异:
$ git diff [first-branch]...[second-branch]
git commit

git commit 命令将暂存区内容添加到本地仓库中。

#git commit 命令将暂存区内容添加到本地仓库中
#1.提交暂存区到本地仓库中:
git commit -m [message]
#2.提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m [message]
#如果你觉得 git add 提交缓存的流程太过繁琐,Git 也允许你用 -a 选项跳过这一步。命令格式如下:
#3.-a 参数设置修改文件后不需要执行 git add 命令,直接来提交
git commit -a
git reset

git reset 命令用于回退版本,可以指定退回某一次提交的版本。

git reset 命令语法格式如下:

git reset [--soft | --mixed | --hard] [HEAD]

–mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。

git reset  [HEAD]

#实例
$ git reset HEAD^            # 回退所有内容到上一个版本  
$ git reset HEAD^ hello.php  # 回退 hello.php 文件的版本到上一个版本  
$ git reset  052e           # 回退到指定版本

–soft 参数用于回退到某个版本:

git reset --soft HEAD

#实例
$ git reset --soft HEAD~3 # 回退上上上一个版本 

–hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:

git reset --hard HEAD
#实例
$ git reset --hard HEAD~3  # 回退上上上一个版本  
$ git reset --hard bae128  # 回退到某个版本回退点之前的所有信息。 
$ git reset --hard origin/master    # 将本地的状态回退到和远程的一样 

**注意:**谨慎使用 –hard 参数,它会删除回退点之前的所有信息。

HEAD 说明:

  • HEAD 表示当前版本
  • HEAD^ 上一个版本
  • HEAD^^ 上上一个版本
  • HEAD^^^ 上上上一个版本
  • 以此类推…

可以使用 ~数字表示

  • HEAD~0 表示当前版本
  • HEAD~1 上一个版本
  • HEAD^2 上上一个版本
  • HEAD^3 上上上一个版本
  • 以此类推…
git rm

git rm 命令用于删除文件。

如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 Changes not staged for commit 的提示。

git rm 删除文件有以下几种形式:

  1. 将文件从暂存区和工作区中删除:

    git rm <file>
    
    #实例:从暂存区和工作区中删除 runoob.txt 文件
    git rm runoob.txt 
    
  2. 如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f。

    #强行从暂存区和工作区中删除修改后的 runoob.txt 文件:
    git rm -f runoob.txt 
    
  3. 如果想把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 --cached 选项即可:

    git rm --cached <file>
    
    #以下实例从暂存区中删除 runoob.txt 文件:
    git rm --cached runoob.txt
    
  4. 可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件:

    git rm –r * 
    
git mv

git mv 命令用于移动或重命名一个文件、目录或软连接。

git mv [file] [newfile]

如果新但文件名已经存在,但还是要重命名它,可以使用 -f 参数:

git mv -f [file] [newfile]
提交日志
命令说明
git log查看历史提交记录
git blame <file>以列表形式查看指定文件的历史修改记录
git log

git log 查看历史提交记录

$ git log
commit b81fd21c85ef73620c1c16407cb8c9a4f2f1d0ff (HEAD -> master)
Author: fengb <11******30@qq.com>
Date:   Wed Nov 10 13:34:38 2021 +0800

    更新笔记

commit 63a4b553789c7214fe55705b4af045862b06771a (origin/master, origin/HEAD)
Author: fengb <11******30@qq.com>
Date:   Wed Nov 10 09:53:45 2021 +0800

    更新笔记20211110

commit 97846242b9905ab32c89b1f9a4036c5ae1997bc8
Author: fengb <11******30@qq.com>
Date:   Mon Nov 8 21:07:16 2021 +0800

    更新笔记20211108

commit b4c08907fe817ca88320ad22dd6a0cbdbd3e925d
Author: fengb <11******30@qq.com>
Date:   Fri Nov 5 10:00:52 2021 +0800

    更新笔记

我们可以用 --oneline 选项来查看历史记录的简洁的版本

$ git log --oneline
b81fd21 (HEAD -> master) 更新笔记
63a4b55 (origin/master, origin/HEAD) 更新笔记20211110
9784624 更新笔记20211108
b4c0890 更新笔记
5673c0d 更新笔记
83542b3 更新笔记
1d87736 更新笔记
53cd24d 更新笔记
......

我们还可以用 --graph 选项,查看历史中什么时候出现了分支、合并。以下为相同的命令,开启了拓扑图选项:

git log --graph
* commit b81fd21c85ef73620c1c16407cb8c9a4f2f1d0ff (HEAD -> master)
| Author: fengb <11******30@qq.com>
| Date:   Wed Nov 10 13:34:38 2021 +0800
|
|     更新笔记
|
* commit 63a4b553789c7214fe55705b4af045862b06771a (origin/master, origin/HEAD)
| Author: fengb <11******30@qq.com>
| Date:   Wed Nov 10 09:53:45 2021 +0800
|
|     更新笔记20211110
|
* commit 97846242b9905ab32c89b1f9a4036c5ae1997bc8
| Author: fengb <11******30@qq.com>
| Date:   Mon Nov 8 21:07:16 2021 +0800
|
|     更新笔记20211108
|
* commit b4c08907fe817ca88320ad22dd6a0cbdbd3e925d
| Author: fengb <11******30@qq.com>
| Date:   Fri Nov 5 10:00:52 2021 +0800
|
|     更新笔记

你也可以用 –reverse 参数来逆向显示所有日志。

git blame

如果要查看指定文件的修改记录可以使用 git blame 命令,格式如下:

git blame <file>
$ git blame 3.DevOps体系之Git.md
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   1) #  DevOps体系之Git
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   2)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   3) ## 认识Git
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   4)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   5) > Git基本概念、Git解决了哪些问题、Git的安装使用
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   6)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   7) ### 版本控制
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   8)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800   9) 版本控制是一种记录文件内容变化,方便以后查阅特定版本修订情况的系统
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  10)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  11) 思考:
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  12)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  13) > 如何实现一个版本控制系统?
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  14) >
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  15) >  1. 每次提交的内容进行存储一份数据(提交这的信息、日期、版本号)
b81fd21c 2.学习笔记/C.JAVA/a.JAVA 动脑/1.DevOps体系/3.DevOps体系之Git.md (fengb             2021-11-10 13:34:38 +0800  16) >
63a4b553 2.学习笔记/C.JAVA/a.JAVA 动脑/1.DevOps体系/3.DevOps体系之Git.md (fengb             2021-11-10 09:53:45 +0800  17) >    2. 每次叫的时候,只存储发生变化的内容(提交这的信息、日期、版本号)
b81fd21c 2.学习笔记/C.JAVA/a.JAVA 动脑/1.DevOps体系/3.DevOps体系之Git.md (fengb             2021-11-10 13:34:38 +0800  18) >
b81fd21c 2.学习笔记/C.JAVA/a.JAVA 动脑/1.DevOps体系/3.DevOps体系之Git.md (fengb             2021-11-10 13:34:38 +0800  19) >
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  20)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  21) ### 版本控制的发展史
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  22)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  23) #### 本地版本控制系统
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  24)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  25) 采用简单的数据库记录文件的历次更新差异
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  26)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  27) ![image-20210814212728489](https://gitee.com/rubywinner/assets/raw/master//img/image-20210814212728489.png)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  28)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  29) #### 集中化的版本控制系统
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  30)
25c0dad3 2.学习笔记/1.DevOps体系/3.DevOps体系之Git.md                      (fengb             2021-08-15 16:25:45 +0800  31) 有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连
到这台服务器,取出最新的文件或者提交更新

远程操作
命令说明
git remote远程仓库操作
git fetch从远程获取代码库
git pull下载远程代码并合并
git push上传远程代码并合并
git remote

git remote 命用于在远程仓库的操作。

显示所有远程仓库:

git remote -v
#实例
$ git clone https://github.com/tianqixin/runoob-git-test

origin 为远程地址的别名。

显示某个远程仓库的信息:

git remote show [remote]

#实例:
$ git remote show https://github.com/tianqixin/runoob-git-test
* remote https://github.com/tianqixin/runoob-git-test
  Fetch URL: https://github.com/tianqixin/runoob-git-test
  Push  URL: https://github.com/tianqixin/runoob-git-test
  HEAD branch: master
  Local ref configured for 'git push':
    master pushes to master (local out of date)

添加远程版本库:

git remote add [shortname] [url]

#实例
# 提交到 Github
$ git remote add origin git@github.com:tianqixin/runoob-git-test.git

其他相关命令:

git remote rm name  # 删除远程仓库
git remote rename old_name new_name  # 修改仓库名
git fetch

git fetch 命令用于从远程获取代码库。

该命令执行完后需要执行 git merge 远程分支到你所在的分支。

从远端仓库提取数据并尝试合并到当前分支:

#git fetch 命令用于从远程获取代码库
#第一步:执行git fetch
git fetch
#第二步:执行git merge,该命令就是在执行 git fetch 之后紧接着执行 git merge 远程分支到你所在的任意分支
git merge

#命令格式:
git fetch [alias]
git merge [alias]/[branch]
git pull

git pull 命令用于从远程获取代码并合并本地的版本。

git pull 其实就是 git fetch 和 git merge FETCH_HEAD 的简写。 命令格式如下:

git pull <远程主机名> <远程分支名>:<本地分支名>
#将远程主机 origin 的 master 分支拉取过来,与本地的 brantest 分支合并。
git pull origin master:brantest

如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

git pull origin master
#上面命令表示,取回 origin/master 分支,再与本地的 brantest 分支合并。
#git pull 命令用于从远程获取代码并合并本地的版本。
#git pull 其实就是 git fetch 和 git merge FETCH_HEAD 的简写。 命令格式如下:

git pull <远程主机名> <远程分支名>:<本地分支名>
#例如 :
#将远程主机 origin 的 master 分支拉取过来,与本地的 brantest 分支合并。
git pull origin master:brantest
#如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
git pull origin master
git push

git push 命用于从将本地的分支版本上传到远程并合并。

#git push 命用于从将本地的分支版本上传到远程并合并。
#命令格式如下:
git push <远程主机名> <本地分支名>:<远程分支名>

#如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程主机名> <本地分支名>

#例如:以下命令将本地的 master 分支推送到 origin 主机的 master 分支。
git push origin master
#等价与
git push origin master:master

#如果本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数:
git push --force origin master

#删除主机但分支可以使用 --delete 参数,以下命令表示删除 origin 主机的 master 分支:
git push origin --delete master

Git分支管理

几乎每一种版本控制系统都以某种形式支持分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。

有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。

创建分支命令:

git branch (branchname)

切换分支命令:

git checkout (branchname)

当你切换分支的时候,Git 会用该分支的最后提交的快照替换你的工作目录的内容, 所以多个分支不需要多个目录。

合并分支命令:

git merge 

列出分支

git branch

我们也可以使用 git checkout -b (branchname) 命令来创建新分支并立即切换到该分支下,从而在该分支中操作。

git checkout -b newtest

删除分支

git branch -d (branchname)

Git标签

如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签。

比如说,我们想为我们的 runoob 项目发布一个"1.0"版本。 我们可以用 git tag -a v1.0 命令给最新一次提交打上(HEAD)"v1.0"的标签。

-a 选项意为"创建一个带注解的标签"。 不用 -a 选项也可以执行的,但它不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解。

添加标签

我推荐一直创建带注解的标签。

$ git tag -a v1.0 
追加标签

如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。

例如,假设我们发布了提交 85fc7e7(上面实例最后一行),但是那时候忘了给它打标签。 我们现在也可以:

$ git log --oneline --decorate --graph
$ git tag -a v0.9 85fc7e7

查看标签

如果我们要查看所有标签可以使用以下命令:

$ git tag
v0.9
v1.0
指定标签信息

指定标签信息命令:

git tag -a <tagname> -m "runoob.com标签"

PGP签名标签命令:

git tag -s <tagname> -m "runoob.com标签"

Git总结

参考

https://www.cnblogs.com/syp172654682/p/7689328.html

https://www.liaoxuefeng.com/wiki/896043488029600

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习使用DevOps可以按照以下步骤进行: 1. 了解DevOps的原理和核心概念:学习DevOps的基本原理、目标和核心概念,包括持续集成、持续交付、自动化、协作等。可以通过阅读相关书籍、参加在线课程或观看教育视频来获得基础知识。 2. 学习常用的DevOps工具和技术:掌握一些常用的DevOps工具和技术,如版本控制系统(如Git)、持续集成工具(如Jenkins)、配置管理工具(如Ansible)、容器化技术(如Docker)、自动化部署工具(如Kubernetes)等。可以通过官方文档、在线培训课程和实践项目来深入了解和掌握这些工具和技术。 3. 实践项目和案例:通过实践项目和案例来巩固所学知识。可以尝试在实际项目中应用DevOps的实践,如搭建持续集成/持续交付流水线、自动化部署、自动化测试等。也可以参与开源项目或加入开发社区,与其他DevOps从业者进行交流和合作。 4. 培养协作和沟通能力:DevOps强调开发团队和运维团队之间的协作和沟通,因此培养良好的协作和沟通能力非常重要。与团队成员进行频繁的沟通,共同解决问题,共享知识和经验。 5. 持续学习和更新:DevOps是一个不断发展和演进的领域,因此需要保持持续学习和更新。关注DevOps领域的最新动态、参加技术研讨会和培训课程,以及阅读相关的博客和技术文章,都可以帮助你不断提升自己的技能。 总的来说,学习使用DevOps需要了解其原理和核心概念,学习常用的DevOps工具和技术,通过实践项目和案例来巩固知识,并培养良好的协作和沟通能力。同时,持续学习和与其他从业者的交流也是提升自己的关键。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值