Git 掌握

时间:2024-03-08 11:33:03

目录

一、前言

二、centos安装Git

三、Git基本操作

(1) 创建Git本地仓库

(2) 配置Git

(3) 认识工作区,暂存区,版本库

四、添加文件

五、查看.git文件

六、修改文件

七、版本回退

八、撤销修改

(1) 场景一 对于还没有add的代码

(2) 场景二 已经 add ,但没有 commit

(3) 场景三 已经 add ,并且也 commit 了

九、删除文件

十、分支管理

(1) 创建分支

(2) 切换分支

(3) 合并分支

(4) 删除分支

(5) 合并冲突

十一、分支管理策略

(1) master分支

(2) bug分支

(3) 删除临时分支

十二、远程操作

(1) 新建远程仓库

(2) 克隆远程仓库

a. 通过HTTPS克隆

b. 通过SSH克隆

(3) 向远程仓库推送

(4) 拉取远程仓库

十三、配置git

(1) .gitignore忽略特殊文件

(2) 给命令配置别名

十四、标签管理

(1) 理解标签

(2) 创建标签

(3) 操作标签

十五、多人协作

(1) 多人协作

(2) 将内容合并到master

(3) 远程分⽀删除后,本地git branch -a依然能看到的解决办法

十六、企业级开发模型

(1) 系统开发环境

(2) Git分支设计规范

十七、结尾


一、前言

大二上学期,学校开了数据库的课程,让做课程设计,数据库代码,文档等都搞好了,让老师看的时候文档写的不好,让修改,改了之后继续让老师看,来来回回弄了三四次,最后老师说:你把第一次的文档发给我吧。随着版本的不断增多,各自版本的内容是什么我们还知道吗?每个版本有各⾃的内容,但最终会只有⼀份报告需要被我们使⽤。文档是这样的,我们写的代码也是这样的。

如何解决这个问题?---- 版本控制器 Git

文件可能会有很多版本,通过版本控制器可以了解一个文件的历史,以及它发展过程中的系统。说白了,就是可以记录工程中的每一次改动和版本迭代的一个管理系统,也可以多人协同作业。

目前最主流的版本控制器是Git。Git可以控制电脑上的所有格式的文件,例如doc,execl,dwg等。当然,对于开发人员来说,Git最重要的是可以帮助我们管理软件开发项目中的源代码文件。

所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等。版本控制器可以告诉你每次的改动,比如某一行添加了什么,某一行删除了什么。但是图片,视频这些二进制文件,虽然也可以被版本控制器管理,但不能知道文件发生了什么变化,比如图片从120变成了100,图片哪里改变了,版本控制器是不知道的。

二、centos安装Git

输入git之后,如果出现git:command not found就是没有安装git。

sudo yum -y install git可以安装git。

通过git --version可以查看安装git的版本。

三、Git基本操作

(1) 创建Git本地仓库

仓库是进行版本控制的一个文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来。

mkdir gitcode

创建仓库 git init,创建之后cd .git就可以进入到创建的本地仓库中了。.git目录是Git来跟踪管理仓库的,不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

(2) 配置Git

安装Git后首要做的事情是设置你的用户名称和e-mail地址,这是非常重要的。

配置命令为

git config user.name "name"
git config user.email "xxxxx@qq.com"

通过git config -l可以查看是否配置成功


删除配置命令

git config --unset user.name 
git config --unset user.email


git config --global user.name "name"
git config --global user.email "email"
git config -l
    user.name=name
    user.email=email
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true

这个--global是一个可选项,如果使用了这个选项,标识这台机器上所有的git仓库都会使用这个配置。如果你希望在不同仓库中使用不同的name或e-mail,可以不要--global选项,但要注意,执行命令的时候必须要在仓库里。


删除对应的配置命令为

git config [--global] --unset user.name
git config [--global] --unset user.email

(3) 认识工作区,暂存区,版本库

在仓库中创建一个ReadMe文件,Git能否管理ReadMe文件??答案是不行的。

⼯作区:是在电脑上你要写代码或⽂件的⽬录。
暂存区:英⽂叫stage或 index。⼀般存放在 .git ⽬录下的index ⽂件(.git/index)中,我们把暂存区有时也叫作索引(index)。
版本库:⼜名仓库,英⽂名repository 。⼯作区有⼀个隐藏⽬录 .git ,它不算⼯作区,是Git的版本库。这个版本库⾥⾯的所有⽂件都可以被Git管理起来,每个⽂件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原” 。

在工作区中进行新增,修改,删除等之类的操作后,修改的工作区内容会写入对象库的一个新的git对象中。将对象管理起来就可以完成对版本的管理。

所有的对象都会存在这个objects中。

四、添加文件

使用git add 文件名可以将文件添加到暂存区,也可以使用git add . 这个命令是将当前目录下面的所有文件改动到暂存区当中。

在使用git commit 命令将暂存区内容添加到本地仓库中:

提交暂存区全部内容到本地仓库中: git commit -m "message"
提交暂存区的指定⽂件到仓库区: git commit [file1] [file2] ... -m "message"

这个 "message"是要提交的细节,也可以说是这次提交版本的一个备注。


使⽤ git log 命令,来查看下历史提交记录


该命令显⽰从最近到最远的提交⽇志,并且可以看到我们commit时的⽇志消息。如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline 参数:

这一大串数字是每次提交的commit id(版本号),这个数字是经过加密算法SHA1计算出来的一个非常大的数字,用十六进制表示。

五、查看.git文件

.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│?? ├── applypatch-msg.sample
│?? ├── commit-msg.sample
│?? ├── post-update.sample
│?? ├── pre-applypatch.sample
│?? ├── pre-commit.sample
│?? ├── prepare-commit-msg.sample
│?? ├── pre-push.sample
│?? ├── pre-rebase.sample
│?? └── update.sample
├── index
├── info
│?? └── exclude
├── logs
│?? ├── HEAD
│?? └── refs
│??     └── heads
│??         └── master
├── objects
│?? ├── 1e
│?? │?? └── d7c1605990be5792ee92e05286efb364b1a79f
│?? ├── 42
│?? │?? └── 8b97b82b6c59cad7488b24e6b618ebbcd819bc
│?? ├── 6f
│?? │?? └── 014900d134c7702d875fe8626fcde0ec46ce83
│?? ├── info
│?? └── pack
└── refs
    ├── heads
    │?? └── master
    └── tags

index 就是我们的暂存区,add后的内容都是添加到这⾥的。
HEAD 就是我们的默认指向master分⽀的指针
objects为Git的对象库,⾥⾯包含了创建的各种版本库对象及内容。当执⾏git add命令时,暂存区的⽬录树被更新,同时⼯作区修改(或新增)的⽂件内容被写⼊到对象库中的⼀个新的对象中,就位于".git/objects"⽬录下.

六、修改文件

Git⽐其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,⽽⾮⽂件。

什么是修改?⽐如你新增了⼀⾏,这就是⼀个修改,删除了⼀⾏,也是⼀个修改,更改了某些字符,
也是⼀个修改,删了⼀些⼜加了⼀些,也是⼀个修改,甚⾄创建⼀个新⽂件,也算⼀个修改。让我们将 ReadMe ⽂件进⾏⼀次修改。

我对ReadMe的文件进行了修改,此时仓库中的ReadMe和我们工作区的ReadMe是不同的,如何查看当前仓库的状态呢? git status 命令用于查看你上次提交之后是否对文件进行再次修改。

上⾯的结果告诉我们,ReadMe 被修改过了,但还没有完成添加与提交 。

我们只知道文件被修改了,并不知道什么地方被修改了。


git diff [file] 命令⽤来显⽰暂存区和⼯作区⽂件的差异,显⽰的格式正是Unix通⽤的diff格式。也可以使⽤ git diff HEAD -- [file] 命令来查看版本库和⼯作区⽂件的区别。知道了对ReadMe做了什么修改后,再把它提交到本地仓库就放⼼多了 。


add之后,就没看到no changes added to commit的消息了,接下来继续commit即可。

七、版本回退

前面说过,Git能够管理文件的历史版本,这也是版本控制器的重要能力之一。如果哪天工作出现了问题,可以先回退到上一个版本重新开始,这个时候就需要版本回退的功能了。

执行git reset 命令用于回退版本,可以指定退回某一次提交的版本。当然这个回退只是将版本库中的内容进行回退,工作区或暂存区是否进行回退需要有命令参数来决定。

git reset 命令语法格式为: git reset [--soft | --mixed | --hard] [HEAD]
--mixed 为默认选项,使⽤时可以不⽤带该参数。该参数将暂存区的内容退回为指定提交版本内
容,⼯作区⽂件保持不变。
--soft 参数对于⼯作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
--hard 参数将暂存区与⼯作区都退回到指定版本。切记⼯作区有未提交的代码时不要⽤这个命令,因为⼯作区会回滚,你没有提交的代码就再也找不回了,所以使⽤该参数前⼀定要慎重

八、撤销修改

(1) 场景一 对于还没有add的代码

在代码git add之后,又新添加了几行代码,发现代码出现问题,需要回退到git add的时候,可以使用

git checkout -- filename来撤销

[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ git checkout -- ReadMe
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ 

(2) 场景二 已经 add ,但没有 commit

已经 add ,但没有 commit ,需要回退版本,可以使用git reset --mixed HEAD,将暂存区回退,在使用场景一中的 git checkout -- filename将工作区中的版本回退。

[sxk@VM-4-13-centos gitcode]$ git reset HEAD ReadMe
[sxk@VM-4-13-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ git checkout -- ReadMe
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!

(3) 场景三 已经 add ,并且也 commit 了

要担⼼,我们可以 git reset --hard HEAD^ 回退到上⼀个版本!不过,这是有条件的,就是你还没有把⾃⼰的本地版本库推送到远程。还记得Git是分布式版本控制系统吗?我们后⾯会讲到远程版本库,⼀旦推送到远程版本库,就真的惨了……

[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ git add ReadMe
[sxk@VM-4-13-centos gitcode]$ git commit -m "modify"
[master f5a061b] modify
 1 file changed, 1 insertion(+)
[sxk@VM-4-13-centos gitcode]$ git reset --hard HEAD^
HEAD is now at 1ed7c16 add first file
[sxk@VM-4-13-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ 

九、删除文件

使用rm 命令只是把文件从工作区中删除了,但是暂存区和版本库中并没有改变,可以使用git rm filename和git commit -m "message"命令,将文件从暂存区和版本库中也删除

[sxk@VM-4-13-centos gitcode]$ touch test
[sxk@VM-4-13-centos gitcode]$ git add test
[sxk@VM-4-13-centos gitcode]$ git commit -m "del test"
[master e045872] del test
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test
[sxk@VM-4-13-centos gitcode]$ git rm test
rm 'test'
[sxk@VM-4-13-centos gitcode]$ ll
total 4
-rw-rw-r-- 1 sxk sxk 13 Mar  4 20:38 ReadMe
[sxk@VM-4-13-centos gitcode]$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	deleted:    test
#
[sxk@VM-4-13-centos gitcode]$ git commit -m "delete test"
[master 00bb8a2] delete test
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 test
[sxk@VM-4-13-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[sxk@VM-4-13-centos gitcode]$ 

十、分支管理

在版本回退⾥,你已经知道,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即master分⽀。

再来理解⼀下HEAD,HEAD 严格来说不是指向提交,⽽是指向master,master才是指向提交的,所以,HEAD 指向的就是当前分⽀。

每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓,⽽
HEAD只要⼀直指向master分⽀即可指向当前分⽀

(1) 创建分支

通过 git branch可以查看本地所有分支

[sxk@VM-4-13-centos gitcode]$ git branch
* master

通过 git branch CreateName可以创建新的分支

[sxk@VM-4-13-centos gitcode]$ git branch
  CreateName
* master

(2) 切换分支

如何切换到新建的分支下进行开发呢? 使用 git checkout CreateName可以完成切换

[sxk@VM-4-13-centos gitcode]$ git checkout CreateName 
Switched to branch 'CreateName'
// 在不同分支中对ReadMe进行修改。
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
------------------------------------------------------------------------------------
// 将文件提交到本地仓库
[sxk@VM-4-13-centos gitcode]$ git add ReadMe
[sxk@VM-4-13-centos gitcode]$ git commit -m "md ReadMe"
[CreateName fa00f51] md ReadMe
 1 file changed, 4 insertions(+)
------------------------------------------------------------------------------------
// 查看文件状态并将分支切换到master
[sxk@VM-4-13-centos gitcode]$ git status
# On branch CreateName
nothing to commit, working directory clean
[sxk@VM-4-13-centos gitcode]$ git branch
* CreateName
  master
[sxk@VM-4-13-centos gitcode]$ git checkout master
Switched to branch 'master'
------------------------------------------------------------------------------------   
// 文件在master分支下的内容
[sxk@VM-4-13-centos gitcode]$ git branch
  CreateName
* master
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
------------------------------------------------------------------------------------ 
// 文件在CreateName分支下的内容
[sxk@VM-4-13-centos gitcode]$ git checkout CreateName
Switched to branch 'CreateName'
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!

为什么会出现这个现象呢?我们来看看CreateName分⽀和master分⽀指向,发现两者指向的提交是不⼀样的 。

[sxk@VM-4-13-centos gitcode]$ cat .git/refs/heads/CreateName 
fa00f518c0c2baffdd74cde515761de343dcff3d
[sxk@VM-4-13-centos gitcode]$ cat .git/refs/heads/master 
00bb8a2258f62a5afd79c77cf25549fb7a2fa6aa
[sxk@VM-4-13-centos gitcode]$ 


 

(3) 合并分支

为了在master主分⽀上能看到新的提交,就需要将 CreateName 分⽀合并到 master 分⽀ 。

将分支切换到master分支,并执行 git merge CreateName,就可以将分支合并到master中,然后在查看master中ReadMe的内容,可以发现,内容已经和CreateName分支中的ReadMe内容一样。

[sxk@VM-4-13-centos gitcode]$ git checkout master
Switched to branch 'master'
[sxk@VM-4-13-centos gitcode]$ git merge CreateName 
Updating 00bb8a2..fa00f51
Fast-forward
 ReadMe | 4 ++++
 1 file changed, 4 insertions(+)
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!

Fast-forward代表“快进模式”,也就是直接把master指向CreateName的当前提交,所以合并速度⾮常快。当然,也不是每次合并都能Fast-forward。

(4) 删除分支

合并完成后,CreateName分⽀对于我们来说就没⽤了,那么CreateName分⽀就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀。

通过 git branch -d CreateName来删除分支

[sxk@VM-4-13-centos gitcode]$ git checkout CreateName 
Switched to branch 'CreateName'
[sxk@VM-4-13-centos gitcode]$ git branch -d CreateName 
error: Cannot delete the branch 'CreateName' which you are currently on.
[sxk@VM-4-13-centos gitcode]$ git checkout master 
Switched to branch 'master'
[sxk@VM-4-13-centos gitcode]$ git branch -d CreateName 
Deleted branch CreateName (was fa00f51).
[sxk@VM-4-13-centos gitcode]$ 

(5) 合并冲突

在实际合并当中,可能会遇到代码冲突的问题。

# 1.创建新的分支dev1,并切换到分支dev1中把ReadMe文件进行修改,然后commit到本地仓库
[sxk@VM-4-13-centos gitcode]$ git branch dev1
[sxk@VM-4-13-centos gitcode]$ git checkout dev1 
Switched to branch 'dev1'
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
dev1 modify
[sxk@VM-4-13-centos gitcode]$ git add .
[sxk@VM-4-13-centos gitcode]$ git status
# On branch dev1
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   ReadMe
#
[sxk@VM-4-13-centos gitcode]$ git commit -m "modify ReadMe: dev1"
[dev1 b472615] modify ReadMe: dev1
 1 file changed, 1 insertion(+)

# 2. 切换到分支master中,修改ReadMe的内容,并commit到本地仓库中
    
[sxk@VM-4-13-centos gitcode]$ git checkout master 
Switched to branch 'master'
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
master modify
[sxk@VM-4-13-centos gitcode]$ git add .
[sxk@VM-4-13-centos gitcode]$ git commit -m "modify ReadMe: master"
[master 05bf5ab] modify ReadMe: master
 1 file changed, 1 insertion(+)
[sxk@VM-4-13-centos gitcode]$ git branch
  dev1
* master

# 3. 合并dev1分支到master中,发现会出现冲突问题,并且ReadMe文件中的内容也会出现一些其他内容

[sxk@VM-4-13-centos gitcode]$ git merge dev1
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
<<<<<<< HEAD
master modify
=======
dev1 modify
>>>>>>> dev1
[sxk@VM-4-13-centos gitcode]$ 

此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘
记)

[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
master modify
[sxk@VM-4-13-centos gitcode]$ git add .
[sxk@VM-4-13-centos gitcode]$ git commit -m "merge master"
[master 17985b9] merge master
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
master modify
[sxk@VM-4-13-centos gitcode]$ 

最后,不要忘记dev1分⽀使⽤完毕后就可以删除了

十一、分支管理策略

在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提交到底是merge进来的还是正常提交的 。

Git ⽀持我们强制禁⽤ Fast forward 模式,那么就会在 merge 时⽣成⼀个新的 commit ,这样,从分⽀历史上就可以看出分⽀信息。下⾯我们实战⼀下 --no-ff ⽅式的 git merge 。⾸先,创建新的分⽀ dev2 ,并切换⾄新的分⽀。所以在合并分⽀时,加上 --no-ff 参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾经做过合并,⽽ fast forward 合并就看不出来曾经做过合并。
创建一个新的分支,然后修改ReadMe中的内容,add,commit之后,切换分支到master,合并分支的时候使用

git merge --no-ff -m "merge dev" dev命令 -m ""是用来记录信息的。

[sxk@VM-4-13-centos gitcode]$ git merge --no-ff -m "merge dev" dev
Already up-to-date.
[sxk@VM-4-13-centos gitcode]$ cat ReadMe 
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
HELLO WORLD!
master modify
我是dev
[sxk@VM-4-13-centos gitcode]$ git log --graph --abbrev-commit 
*   commit cd08c07
|\  Merge: 17985b9 16286a2
| | Author: user <email>
| | Date:   Tue Mar 5 19:29:50 2024 +0800
| | 
| |     A
| |     A
| |     Merge branch 'dev'

(1) master分支

在实际开发中,master分支应该是非常稳定的,也就是仅仅用来发布新版本,平时不能在上面干活,干活都是在dev分支上,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的同学在做项目的时候,每个人都有自己的分支,时不时的往dev分支上合并就可以了。

(2) bug分支

假如我们现在正在dev2分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有bug,需要解决。在Git中,每个bug都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀
删除。可现在dev2的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?

git 提供了 git stash命令,可以将当前工作区信息进行存藏,被存藏的内容可以恢复出来。

[sxk@VM-4-13-centos gitcode]$ git checkout -b dev3
Switched to a new branch 'dev3'
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ git stash
Saved working directory and index state WIP on dev3: cd08c07 A A Merge branch 'dev'
HEAD is now at cd08c07 A

现在就可以区修bug了

[sxk@VM-4-13-centos gitcode]$ git checkout -b fix_bug
Switched to a new branch 'fix_bug'
[sxk@VM-4-13-centos gitcode]$ git checkout master 
Switched to branch 'master'
[sxk@VM-4-13-centos gitcode]$ git merge -m "" fix_bug 
Already up-to-date.
[sxk@VM-4-13-centos gitcode]$ git branch -d fix_bug 
Deleted branch fix_bug (was cd08c07).

在bug修复完成之后,切换到master分支,完成合并,将bug分支删除。

切回dev3分支,通过 git stash list可以看到刚才存藏的工作现场。

[sxk@VM-4-13-centos gitcode]$ git stash list
stash@{0}: WIP on dev3: cd08c07 A A Merge branch 'dev'

使用 git stash pop命令可以在恢复工作区的同时把stash给删除了。

[sxk@VM-4-13-centos gitcode]$ git checkout dev3 
Switched to branch 'dev3'
[sxk@VM-4-13-centos gitcode]$ git stash list
stash@{0}: WIP on dev3: cd08c07 A A Merge branch 'dev'
[sxk@VM-4-13-centos gitcode]$ git stash pop
# On branch dev3
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   ReadMe
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (a13b34d28bdb8d5374b115c2f1dc817ac040fc9b)
[sxk@VM-4-13-centos gitcode]$ 


再次查看的时候,就没有现场可以恢复了。
[sxk@VM-4-13-centos gitcode]$ git stash list
[sxk@VM-4-13-centos gitcode]$ 

另外,恢复现场也可以采⽤ git stash apply 恢复,但是恢复后,stash内容并不删除,你需要⽤ git stash drop 来删除;你可以多次stash,恢复的时候,先⽤ git stash list 查看,然后恢复指定的stash,⽤命令git stash apply stash@{0}


注意一个细节,我们让dev3进行的存藏,然后去修复master的bug,在解决bug之后,将bug分支和master分支进行了合并,但是,dev3中的master内容并不是解决完bug之后的master内容,在dev3中是看不到修复bug的相关代码的。

我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合并即可,但这样其实是有⼀定⻛险的。是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到 master 上。此时的状态为:

解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态为
 

(3) 删除临时分支

在开发的过程中,会有新功能要添加进来。添加一个新功能的时候,会先新建一个分支,在这个分支上面开发,完成后在合并,最后删除这个分支。

如果这个在这个分支上开发了一半,突然就不需要继续开发了,这个分支就要销毁了,留着没啥用了。这个时候,传统的 git branch -d命令删除分支的方法是不行的。

把小d换成D就可以强制删除了。

[sxk@VM-4-13-centos gitcode]$ git checkout -b dev4
M	ReadMe
Switched to a new branch 'dev4'
[sxk@VM-4-13-centos gitcode]$ vim ReadMe 
[sxk@VM-4-13-centos gitcode]$ git add .
[sxk@VM-4-13-centos gitcode]$ git commit -m "dev4"
[dev4 d7b27ca] dev4
 1 file changed, 2 insertions(+)
[sxk@VM-4-13-centos gitcode]$ git checkout master 
Switched to branch 'master'
[sxk@VM-4-13-centos gitcode]$ git branch -d dev4
error: The branch 'dev4' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev4'.
[sxk@VM-4-13-centos gitcode]$ git branch -D dev4
Deleted branch dev4 (was d7b27ca).

十二、远程操作

前面所说的所有内容,都是在本地,也就是我们自己的计算机上,但是我们的git其实是分布式版本控制系统。同一个git仓库,可以分部到不同的机器上。我们可以将Git仓库托管到github或者gitee上,就可以免费获得git远程仓库。github是国外的网站,速度可能会比较慢。

(1) 新建远程仓库

点 New repository可以创建仓库。

这里我选的是public

这样就可以简单的创建一个远程仓库了。


如果你写了一个项目并且公开了,那么别人在阅读你的代码的时候发现问题了,这个时候别人就可以在lssues中提出问题。


在实际的开发中,并不会直接让代码和master分支进行合并,而是会PR(Pull Requests)拉去一个请求,来帮助自己和别人协作编写代码,然后由管理员同意了,才可以进行merge。

(2) 克隆远程仓库

a. 通过HTTPS克隆

克隆/下载远端仓库到本地,需要使⽤ git clone 命令,后⾯跟上我们的远端仓库的链接

[sxk@VM-4-13-centos storage]$ git clone https://github.com/HaiFanNeon/remote-github.git
Cloning into 'remote-github'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
[sxk@VM-4-13-centos storage]$ ls
gitcode  remote-github
[sxk@VM-4-13-centos storage]$ 

如果你是第一次clone的话,需要输入你github或者gitee的用户和密码。

[sxk@VM-4-13-centos remote-github]$ ls -al
total 16
drwxrwxr-x 3 sxk sxk 4096 Mar  6 18:52 .
drwxrwxr-x 4 sxk sxk 4096 Mar  6 18:51 ..
drwxrwxr-x 8 sxk sxk 4096 Mar  6 18:52 .git
-rw-rw-r-- 1 sxk sxk   30 Mar  6 18:52 README.md

这个仓库里面有创建远程仓库时候选择的 add a README file选项自动创建的README文件。

b. 通过SSH克隆

SSH协议是采用的公钥加密和解密的过程,所以我们需要先添加一个public key,将本地服务器上的public key添加到github中。

[sxk@VM-4-13-centos storage]$ git clone git@github.com:HaiFanNeon/remote-github.git
Cloning into 'remote-github'...
The authenticity of host 'github.com' can't be established.
Are you sure you want to continue connecting (yes/no)? y
Please type 'yes' or 'no': yes
Warning: Permanently added 'github.com' (ECDSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
[sxk@VM-4-13-centos storage]$ 

在没有配置public key的情况下强行clone就会出现报错。


第⼀步:创建SSH Key。在⽤⼾主⽬录下,看看有没有.ssh⽬录,如果有,再看看这个⽬录下有没有
id_rsa 和 id_rsa.pub 这两个⽂件,如果已经有了,可直接跳到下⼀步。如果没有,需要创建
SSH Key:

[sxk@VM-4-13-centos .ssh]$ ssh-keygen -t rsa -C "email" // 这里的邮箱要跟你的github或者gitee中的邮箱相对应
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sxk/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/sxk/.ssh/id_rsa.
Your public key has been saved in /home/sxk/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:+6hLrOOna4IrASg/tkF8Jd4jlfpUIDU7awZMxCbla3M haifan0312@163.com
The key's randomart image is:
+---[RSA 2048]----+    |
+----[SHA256]-----+

把id_rsa.pub中的密钥拷贝到github或者gitee中

[sxk@VM-4-13-centos storage]$ git clone git@github.com:HaiFanNeon/remote-github.git
Cloning into 'remote-github'...
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.
[sxk@VM-4-13-centos storage]$ 

当我们在使用ssh进行clone的时候就可以完成了。


如果有多个⼈协作开发,GitHub/Gitee允许添加多个公钥,只要把每个⼈的电脑上的Key都添加到GitHub/Gitee,就可以在每台电脑上往GitHub/Gitee上提交推送了 。

(3) 向远程仓库推送

本地已经 clone 成功远程仓库后,我们便可以向仓库中提交内容(git push命令)

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

sxk@VM-4-13-centos storage]$ 先进入到remote目录下面^C
[sxk@VM-4-13-centos storage]$ cd remote-github/
[sxk@VM-4-13-centos remote-github]$ ls
README.md
[sxk@VM-4-13-centos remote-github]$ touch hello_world.cc
[sxk@VM-4-13-centos remote-github]$ vim hello_world.cc 
[sxk@VM-4-13-centos remote-github]$ 写了一个helloworld的代码^C
[sxk@VM-4-13-centos remote-github]$ 现在将这个代码推送到远程仓库^C
[sxk@VM-4-13-centos remote-github]$ git config -l
user.name=name
user.email=email
name和email要和github/gitee中的name和email对应
[sxk@VM-4-13-centos remote-github]$  git add .
[sxk@VM-4-13-centos remote-github]$ git commit -m "create hello_world.cc"
[main 3914558] create hello_world.cc
 1 file changed, 7 insertions(+)
 create mode 100644 hello_world.cc
[sxk@VM-4-13-centos remote-github]$ git push origin(是往远程推送的) main(推送的是本地的main分支):main(推送到远程分支main中,如果远程分支和本地分支一样,可以省略远程分支 不写)^C
[sxk@VM-4-13-centos remote-github]$ git push origin main 
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 372 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: To git@github.com:HaiFanNeon/remote-github.git
   9bdd187..3914558  main -> main
[sxk@VM-4-13-centos remote-github]$ 

这就推送成功了。

(4) 拉取远程仓库

我在github上对代码进行了修改,但是本地仓库中的这个代码还是以前的。远程仓库领先本地仓库一个版本,为了使本地仓库处于最新的版本,需要拉去远端代码,并合并到本地。git 提供了 git pull命令,该命令用于从远程获取代码并合并本地的版本。

git pull <远程主机名> <远程分⽀名>:<本地分⽀名>
如果远程分⽀是与当前分⽀合并,则冒号后⾯的部分可以省略。
git pull <远程主机名> <远程分⽀名>

[sxk@VM-4-13-centos remote-github]$ git pull origin main
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:HaiFanNeon/remote-github
 * branch            main       -> FETCH_HEAD
Updating 3914558..a192e7e
Fast-forward
 hello_world.cc | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
[sxk@VM-4-13-centos remote-github]$ cat hello_world.cc 
#include <iostream>

int main()
{
    for (int i = 0; i < 10; i++)
    {
        std::cout << "hello github" << std::endl;
    }
    
    return 0;
}
[sxk@VM-4-13-centos remote-github]$ 

拉取成功。

十三、配置git

(1) .gitignore忽略特殊文件

在我们创建仓库的时候,有一个添加.gitignore(.git ignore)选项,

当工作目录下面文件非常多的时候,要add,一般会使用add .,但是因为文件非常多,不想要的文件也会add,如何让git只添加我们需要的文件?

在Git⼯作区的根⽬录下创建⼀个特殊的 .gitignore ⽂件,然后把要忽略的⽂件名填进去,Git就会⾃动忽略这些⽂件了 。

如果当时没有选择这个选择,在⼯作区创建⼀个也是可以的。⽆论哪种⽅式,最终都可以得到⼀个完
整的 .gitignore ⽂件,例如我们想忽略以 .py 结尾所有⽂件,
.gitignore 的内容如下

[sxk@VM-4-13-centos remote-github]$ touch .gitignore
[sxk@VM-4-13-centos remote-github]$ vim .gitignore 
[sxk@VM-4-13-centos remote-github]$ cat .gitignore 
*.so
[sxk@VM-4-13-centos remote-github]$ git add .
[sxk@VM-4-13-centos remote-github]$ git status
# On branch main
# Your branch is ahead of 'origin/main' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   .gitignore
#
[sxk@VM-4-13-centos remote-github]$ 

可以看到,我新增了两个文件,一个.gitignore一个a.so文件,但是add之后,查看文件状态,会显示只有.gitignore是新增文件。我们commit和push一下,到远端查看。


只有gitignore文件推送到了远端。


把指定⽂件排除在外的写法就是 ! +⽂件名,所以,只需把例外⽂件添加进去即可。

例如
.* // 排除所有.开头的隐藏文件
!.gitignore // 不排除.gitignore文件

(2) 给命令配置别名

在我们使⽤Git期间,有些命令敲的时候着实让⼈头疼(太⻓了。。),幸运的是,git⽀持对命令进⾏简化!
举个例⼦,将 git status 简化为 git st ,对应的命令为:

git config --global alias.st status

--global 参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有⽤。如果不加,那只
针对当前的仓库起作⽤ 。

十四、标签管理

(1) 理解标签

标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项⽬发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样的标签来标识。
这有什么⽤呢?相较于难以记住的 commit id , tag 很好的解决这个问题,因为 tag ⼀定要给⼀
个让⼈容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使⽤标签就能很快定位
到。

(2) 创建标签

  1. 切换到需要打标签的分支上
  2. git tag [name] 可以打一个新标签
    [sxk@VM-4-13-centos remote-github]$ git tag v1.0
  3. git tag查看所有标签

默认标签是打在最新提交的 commit 上的。那如何在指定的commit上打标签呢?⽅法是找到历史提
交的commit id,然后打上就可以了,⽰例如下

[sxk@VM-4-13-centos remote-github]$ git log --pretty=oneline 
c00bceacd1760b6663b28876670757297b41c302 要忽略的文件
a192e7e29a531e6f5bbd43a6d8bd9f55c8289602 Update hello_world.cc
3914558f6f6884059ad67fff5aefa46062880701 create hello_world.cc
9bdd187d73e77502f164372852d1f54b07b7f775 Initial commit
[sxk@VM-4-13-centos remote-github]$ git log --pretty=oneline --abbrev-commit 
c00bcea 要忽略的文件
a192e7e Update hello_world.cc
3914558 create hello_world.cc
9bdd187 Initial commit
[sxk@VM-4-13-centos remote-github]$ git tag v9.99 a192e7e
[sxk@VM-4-13-centos remote-github]$ git tag
v1.0
v9.99

注意,标签不是按时间顺序列出,⽽是按字⺟排序的。可以⽤ git show [tagname] 查看标签信息。

[sxk@VM-4-13-centos remote-github]$ git show v1.0
commit c00bceacd1760b6663b28876670757297b41c302
Author: HaiFanNeon <haifan0312@163.com>
Date:   Wed Mar 6 19:43:28 2024 +0800

    要忽略的文件

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..140f8cf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.so

Git还提供可以创建带有说明的标签,⽤-a指定标签名,-m指定说明⽂字,格式为

git tag -a [name] -m "XXX" [commit_id]

[sxk@VM-4-13-centos remote-github]$ git show v99.9
tag v99.9
Date:   Wed Mar 6 20:00:54 2024 +0800

important tag:XXX

commit c00bceacd1760b6663b28876670757297b41c302
Date:   Wed Mar 6 19:43:28 2024 +0800

    要忽略的文件

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..140f8cf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.so

(3) 操作标签

如果标签打错了,也可以删除 。使用git tag -d tagname

[sxk@VM-4-13-centos remote-github]$ git tag -d v1.0
Deleted tag 'v1.0' (was c00bcea)
[sxk@VM-4-13-centos remote-github]$ git show v1.0
fatal: ambiguous argument 'v1.0': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
[sxk@VM-4-13-centos remote-github]$ 

因为创建的标签都只存储在本地,不会⾃动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使⽤命令 git push origin <tagname>

[sxk@VM-4-13-centos remote-github]$ git push origin v99.9
Counting objects: 1, done.
Writing objects: 100% (1/1), 169 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
remote: To git@github.com:HaiFanNeon/remote-github.git
 * [new tag]         v99.9 -> v99.9
[sxk@VM-4-13-centos remote-github]$ 


将所有标签推送到远端 git push origin --tags

[sxk@VM-4-13-centos remote-github]$ git push origin --tags 
Counting objects: 1, done.
Writing objects: 100% (1/1), 168 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
remote: To git@github.com:HaiFanNeon/remote-github.git
 * [new tag]         v9.9 -> v9.9
 * [new tag]         v9.99 -> v9.99
[sxk@VM-4-13-centos remote-github]$ 


如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除。

[sxk@VM-4-13-centos remote-github]$ git tag -d v9.9
Deleted tag 'v9.9' (was d441e7e)
[sxk@VM-4-13-centos remote-github]$ git push origin :v9.9
remote: To git@github.com:HaiFanNeon/remote-github.git
 - [deleted]         v9.9
[sxk@VM-4-13-centos remote-github]$ 



 

十五、多人协作

(1) 多人协作

目标:远程main分支下的helloworld.cc文件新增代码"aaa"、“bbb”;

实现:由开发者1新增“aaa”, 由开发者2新增“bbb”

条件:在一个分支下协作完成

在github中新建了一个dev分支,将dev分支拉取到本地仓库中

[sxk@VM-4-13-centos remote-github]$ git pull
From github.com:HaiFanNeon/remote-github
 * [new branch]      dev        -> origin/dev
Already up-to-date.
[sxk@VM-4-13-centos remote-github]$ git branch
* main
[sxk@VM-4-13-centos remote-github]$ git branch -r
  origin/HEAD -> origin/main
  origin/dev
  origin/main

用户1已经完成对helloworld文件的修改

[sxk@VM-4-13-centos remote-github]$ vim hello_world.cc 
[sxk@VM-4-13-centos remote-github]$ cat hello_world.cc 
#include <iostream>

int main()
{
    for (int i = 0; i < 10; i++)
    {
        std::cout << "hello github" << std::endl;
    }
    std::cout << "aaa" << std::endl; 
    return 0;
}
[sxk@VM-4-13-centos remote-github]$ 

通过add,commit,push将代码提交到远端。


此时用户2对helloworld文件进行修改。修改之后add,commit,push

hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

会出现错误,因为用户1修改之后内容已经改变,用户2需要先将远端拉取到本地,解决冲突,然后在push。


其实在实际开发中,遇到了这种冲突的问题是非常烦的,在解决冲突的时候,可能会把好的代码给删了,从而出现问题,所以在协作开发的时候,一般不会在同一个分支中开发。

在不同分支下协作完成,各自让某一个功能私有一个分支。

在本地创建的分⽀也可以通过推送的⽅式发送到远端 。

[sxk@VM-4-13-centos remote-github]$ git checkout -b featuer-1
Switched to a new branch 'featuer-1'
[sxk@VM-4-13-centos remote-github]$ vim fucntion1
[sxk@VM-4-13-centos remote-github]$ cat fucntion1 
aaaaaa
[sxk@VM-4-13-centos remote-github]$ git add fucntion1
[sxk@VM-4-13-centos remote-github]$ git commit -m "add fucntion1"
[featuer-1 29ce283] add fucntion1
 1 file changed, 1 insertion(+)
 create mode 100644 fucntion1
[sxk@VM-4-13-centos remote-github]$ git push origin featuer-1 
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 267 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: 
remote: Create a pull request for 'featuer-1' on GitHub by visiting:
remote:      https://github.com/HaiFanNeon/remote-github/pull/new/featuer-1
remote: 
remote: To git@github.com:HaiFanNeon/remote-github.git
 * [new branch]      featuer-1 -> featuer-1
[sxk@VM-4-13-centos remote-github]$ 


我在我的windows里面下载了个git,然后用windows端来模拟合作人员,合作人员创建了feature-2分支并提交到远端。

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (main)
$ git checkout -b feature-2
Switched to a new branch 'feature-2'

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (feature-2)
$ vim feature2

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (feature-2)
$ cat feature2
bbbbbb

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (feature-2)
$ git add .
warning: LF will be replaced by CRLF in feature2.
The file will have its original line endings in your working directory

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (feature-2)
$ git commit -m "add feature2"
[feature-2 0579275] add feature2
 1 file changed, 1 insertion(+)
 create mode 100644 feature2

Lenovo@DESKTOP-5A1B7J0 MINGW64 ~/Desktop/杂件/remote-github (feature-2)
$ git push origin feature-2
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Delta compression using up to 16 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 853 bytes | 853.00 KiB/s, done.
Total 9 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (4/4), completed with 2 local objects.
remote:
remote: Create a pull request for 'feature-2' on GitHub by visiting:
remote:      https://github.com/HaiFanNeon/remote-github/pull/new/feature-2
remote:
To https://github.com/HaiFanNeon/remote-github.git
 * [new branch]      feature-2 -> feature-2

在本地,你看不⻅他新建的⽂档,他看不⻅你新建的⽂档。并且推送各⾃的分⽀时,并没有任何冲突,你俩互不影响,⽤起来很舒服!


正常情况下,你俩就可以在⾃⼰的分⽀