文章目录
1 🍑环境准备🍑
在
centos
平台上,我们可以使用
git
命令来查看是否安装了git:
[grm@iZ2vcf5z5ky8svdkf00zfzZ home]$ git
bash: git: command not found
如果显示了上面结果,那就说明没有安装git,此时我们可以使用以下命令安装:
sudo yum -y install git
使用
git --version
命令可以查看 Git 安装的版本。
2 🍑git 的基本操作🍑
2.1 🍎创建 git 本地仓库🍎
要提前说的是,仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂件进⾏版本控制,就必须先创建⼀个仓库出来。创建⼀个 Git 本地仓库对应的命令为
git init
,注意命令要在⽂件⽬录下执⾏。
比如下面我们创建了一个gitcode的目录,并且在里面执行
git init
命令:
查看该目录:
我们发现,当前⽬录下多了⼀个
.git
的隐藏目录,
.git
目录是 Git 来跟踪管理仓库的,记住不要⼿动修改这个⽬录⾥⾯的东西,不然改乱了,就把 Git 仓库给破坏了。
我们先查看
.git
目录下的所有文件,这里只是简单看一下,后面我们会对每一个部分做出解释:
2.2 🍎配置 git🍎
当安装 Git 后⾸先要做的事情是设置你的 用户名称 和 e-mail 地址,配置命令为:
git config [--global] user.name "Your Name"git config [--global] user.email "[email protected]"# 把 Your Name 改成你的昵称# 把 [email protected] 改成邮箱的格式,只要格式正确即可
其中
--global
是⼀个可选项。如果使⽤了该选项,表⽰这台机器上所有的 Git 仓库都会使⽤这个配置。如果你希望在不同仓库中使⽤不同的 name 或 e-mail ,可以不要
--global
选项,但要注意的是,执⾏命令时必须要在仓库⾥。查看配置命令为:
git config -l
删除对应的配置命令为:
git config [--global] --unset user.name
git config [--global] --unset user.email
2.3 🍎认识工作区、暂存区、版本库🍎
- 工作区:是在电脑上你要写代码或⽂件的⽬录。
- 暂存区:英⽂叫 stage 或 index。⼀般存放在
.git
⽬录下的 index ⽂件(.git/index)中,我们把暂存区有时也叫作索引(index)。 - 版本库:⼜名仓库,英⽂名 repository 。⼯作区有⼀个隐藏⽬录
.git
,它不算⼯作区,⽽是 git 的版本库。这个版本库⾥⾯的所有⽂件都可以被 Git 管理起来,每个⽂件的修改、删除,git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
下⾯这个图展⽰了⼯作区、暂存区和版本库之间的关系:
图中左侧为⼯作区,右侧为版本库。Git 的版本库⾥存了很多东西,其中最重要的就是暂存区。
- 在创建 Git 版本库时,Git 会为我们⾃动创建⼀个唯⼀的 master 分⽀,以及指向 master 的⼀个指针叫
HEAD
; - 当对⼯作区修改(或新增)的⽂件执⾏
git add
命令时,暂存区⽬录树的⽂件索引会被更新; - 当执⾏提交操作
git commit
时,master 分⽀会做相应的更新,可以简单理解为暂存区的⽬录树才会被真正写到版本库中.
由上述描述我们便能得知:通过新建或粘贴进⽬录的⽂件,并不能称之为向仓库中新增⽂件,⽽只是在⼯作区新增了⽂件。必须要通过使⽤
git add
和
git commit
命令才能将⽂件添加到仓库中进⾏管理。
2.4 🍎git add 和 git commit 的基本使用🍎
我们在与
.git
目录同级目录下创建一个文件Upload,使⽤
git add
命令可以将⽂件添加到暂存区:
- 添加⼀个或多个⽂件到暂存区: git add [file1] [file2] …
- 添加指定⽬录到暂存区,包括⼦⽬录: git add [dir]
- 添加当前⽬录下的所有⽂件改动到暂存区: git add .
注意:不仅仅可以添加文件,目录也是OK的。
此时我们就在暂存区中添加了一个Upload文件。
再使⽤
git commit
命令将暂存区内容添加到本地仓库中:
- 提交暂存区全部内容到本地仓库中: git commit -m “message”
- 提交暂存区的指定⽂件到仓库区: git commit [file1] [file2] … -m “message”
注意
git commit
后⾯的
-m
选项,后面要跟上描述本次提交的 message,由用户⾃⼰完成,这部分内容绝对不能省略,并要好好描述,是⽤来记录你的提交细节,比如我们修改了一个什么Bug,添加了一些功能等。
此时我们可以使用
git log
命令来查看提交的日志消息:
最开始Upload文件中是没有数据的,此时我们在Upload文件添加一行数据并保存,然后使用
git add
和
git commit
命令:
此时我们可以看见,git是能够告诉用户增加了数据还是删减了数据。
我们还可以多次
add
不同的⽂件,⽽只
commit
⼀次便可以提交所有⽂件,是因为需要提交的⽂件是通通被
add
到暂存区中,然后⼀次性
commit
暂存区中的所有修改。
查看日志信息时有时候可能输出的消息太多,不便于观察,可以加上
--pretty=oneline
选项:
需要说明的是,我们看到的⼀⼤串类似20bd……08的是每次提交的 commit id (版本号),Git 的 commit id 不是1,2,3……递增的数字,⽽是⼀个 SHA1 计算出来的⼀个⾮常⼤的数字,⽤⼗六进制表⽰。
此时我们查看.log目录下的文件,会发现多出了一些东西:
- 1️⃣
index
就是我们的暂存区,add
后的内容都是添加到这⾥的; - 2️⃣
HEAD
就是我们的默认指向 master 分⽀的指针;
默认的 master 分⽀又是什么鬼呢?
打印的 20bd60bc38abd76737b112fc87e5cf7f3cdc6f08 是什么东西呢?保存的就是当前最新的 commit id。
- 3️⃣objects 为 Git 的对象库,⾥⾯包含了创建的各种版本库对象及内容。当执⾏
git add
命令时,暂存区的⽬录树被更新,同时⼯作区修改(或新增)的⽂件内容被写⼊到对象库中的⼀个新的对象中,就位于.git/objects
⽬录下,让我们来看看这些对象有何⽤处: 查找 object 时要将 commit id 分成2部分,其前2位是⽂件夹名称,后38位是⽂件名称。 找到这个⽂件之后,⼀般不能直接看到⾥⾯是什么,该类⽂件是经过 sha (安全哈希算法)加密过的⽂件,不过我们可以使⽤git cat-file
命令来查看版本库对象的内容:
总结⼀下,在本地的 git 仓库中,有⼏个⽂件或者⽬录很特殊:
- index: 暂存区, git add 后会更新该内容。
- HEAD: 默认指向 master 分⽀的⼀个指针。
- refs/heads/master: ⽂件⾥保存当前 master 分⽀的最新 commit id 。
- objects: 包含了创建的各种版本库对象及内容,可以简单理解为放了 git 维护的所有修改。
2.5 🍎修改文件🍎
Git ⽐其他版本控制系统设计得优秀,因为 Git 跟踪并管理的是修改,⽽⾮⽂件。
什么是修改?⽐如你新增了⼀⾏,这就是⼀个修改,删除了⼀⾏,也是⼀个修改,更改了某些字符,也是⼀个修改,删了⼀些⼜加了⼀些,也是⼀个修改,甚⾄创建⼀个新⽂件,也算⼀个修改。
此时修改下Upload文件中的数据:
但是过了一段时间后我们忘记了怎么办?此时可以使用
git status
命令⽤于查看在你上次提交之后是否有对⽂件进⾏再次修改:
上⾯的结果告诉我们,Upload 被修改过了,但还没有完成添加与提交。
⽬前,我们只知道⽂件被修改了,如果能知道具体哪些地⽅被修改了,就更好了。此时可以使用
git diff
命令显⽰暂存区和⼯作区⽂件的差异,也可以使⽤
git diff HEAD -- [file]
命令来查看版本库和⼯作区⽂件的区别。
当
add
之后:
就看不见最后一行
no changes added to commit (use "git add" and/or "git commit -a")
2.6 🍎版本回退🍎
之前我们也提到过,Git 能够管理⽂件的历史版本,这也是版本控制器重要的能⼒。如果有⼀天你发现之前的⼯作做的出现了很⼤的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了。
执⾏
git reset
命令⽤于回退版本,可以指定退回某⼀次提交的版本。要解释⼀下“回退”本质是要将版本库中的内容进⾏回退,⼯作区或暂存区是否回退由命令参数决定。
git reset 命令语法格式为:
git reset [--soft | --mixed | --hard][HEAD]
--mixed
为默认选项,使⽤时可以不⽤带该参数。该参数将暂存区的内容退回为指定提交版本内容,⼯作区⽂件保持不变。--soft
参数对于⼯作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。--hard
参数将暂存区与⼯作区与版本库都退回到指定版本。切记⼯作区有未提交的代码时不要⽤这个命令,因为⼯作区会回滚,你没有提交的代码就再也找不回了,所以使⽤该参数前⼀定要慎重。HEAD
说明: 可直接写成 commit id,表⽰指定退回的版本:- HEAD 表⽰当前版本- HEAD^ 上⼀个版本- HEAD^^ 上上⼀个版本也可以使⽤~
数字表⽰:- HEAD0 表⽰当前版本- HEAD1 上⼀个版本- HEAD~2 上上⼀个版本
我们先来做一下准备工作,首先提交3个版本的内容,然后使用
git log
命令进行查看:
现在,如果我们在提交完 version3 后, 发现 version 3 编写错误,想回退到 version1,重新基于version 1 开始编写。由于我们在这⾥希望的是将⼯作区的内容也回退到 version 2 版本,所以需要⽤到
--hard
参数,⽰例如下:
但现在如果我后悔了,想再回到 version 3 怎么办?我们可以继续使⽤
git reset
命令,回退到 version 3 版本,但我们必须要拿到 version 3 的 commit id 去指定回退的版本。我们可以查看之前的id来进行回退:
那假如我们在终端上已经找不到之前敲的命令了应该咋办呢?我们可以使用
git reflog
命令补救⼀下,该命令⽤来记录本地的每⼀次命令。
大家注意到了没前面这一行数据没,我们还可以使用前面这一行数据id对应的版本来进行回退,比如现在我想要回退到版本2,此时我们可以这样回退:
Git 的版本回退速度⾮常快,因为 Git 在内部有个指向当前分⽀(此处是master)的HEAD 指针, refs/heads/master ⽂件⾥保存当前 master 分⽀的最新 commit id 。当我们在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储⼀个特定的version。
2.7 🍎撤销修改🍎
如果我们在我们的⼯作区写了很⻓时间代码,越写越写不下去,觉得⾃⼰写的实在是垃圾,想恢复到上⼀个版本。
情况⼀:对于⼯作区的代码,还没有 add
大家想到的最简便的方法是直接删除修改的代码就行了,但是问题是万一我们修改量很大,记不住了怎么办?所以我们可以使用Git 提供的⽅式,
git checkout -- [file]
命令让⼯作区的⽂件回到最近⼀次 add 或 commit 时的状态。 要注意该命令中的
--
很重要,切记不要省略,⼀旦省略,该命令就变为其他意思了,后⾯我们再说。
我们简单验证一下:
情况⼆:已经 add ,但没有 commit
add 后还是保存到了暂存区中,怎么撤销呢?
让我们来回忆⼀下学过的
git reset
回退命令,该命令如果使⽤
--mixed
参数,可以将暂存区的内容退回为指定的版本内容,但⼯作区⽂件保持不变。那我们就可以回退下暂存区的内容了!
此时⽤
git status
查看⼀下,发现暂存区是⼲净的,⼯作区有修改:
情况三:已经 add ,并且也 commit 了
我们可以
git reset --hard HEAD^
回退到上⼀个版本!不过,这是有条件的,就是你还没有把⾃⼰的本地版本库推送到远程。
2.8 🍎删除文件🍎
首先准备好一个测试文件file1,向里面写入数据并且add和commit:
此时我们能够直接使用
rm
删除文件吗?我们可以试试,删除完毕后我们使用
git status
命令进行查看:
从上面我们可以看出我们只是删除了文件,但是现在版本库中仍然存在。假如误删了我们可以使用
git checkout
命令补救:
那假如我们想要将⽂件从暂存区和⼯作区中删除呢?我们可以使用
git rm
命令,然后将删除的结果使用
commit
进行提交即可:
3 🍑分⽀管理🍑
3.1 🍎理解分支🍎
在版本回退⾥,你已经知道,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即 master 分⽀。
再来理解⼀下HEAD,HEAD 严格来说不是指向提交,⽽是指向master,master才是指向提交的,所以,HEAD 指向的就是当前工作分⽀。
每次提交,master分⽀都会向前移动⼀步,这样随着你不断提交,master分⽀的线也越来越⻓,⽽HEAD只要⼀直指向master分⽀即可指向当前分⽀。
3.2 🍎创建分⽀🍎
Git ⽀持我们查看或创建其他分⽀,在这⾥我们来创建第⼀个⾃⼰的分⽀ dev ,对应的命令为
git branch
。
我们可以先使用git branch 查看当前所有分支:
其中有
*
的表示当前的工作分支。下面我们再创建一个
dev
分支:
此时我们查看.git的目录结构时会发现多出了一个dev分支:
发现⽬前 dev 和 master 指向同⼀个修改。
3.3 🍎切换分支🍎
使⽤
git checkout
命令即可完成切换,⽰例如下:
我们发现 HEAD 已经指向了 dev,就表⽰我们已经成功的切换到了 dev 上。
接下来,在 dev 分⽀下修改 Upload ⽂件,新增⼀⾏内容,并进⾏⼀次提交操作:
此时我们切回到master,查看工作区中的内容:
我们此时发现居然这里面没有我们刚才在dev中修改的数据,赶紧再切回 dev 看看:
发现此时数据又有了,为什么会出现这个现象呢?我们来看看 dev 分⽀和 master 分⽀指向,发现两者指向的提交是不⼀样的:
看到这⾥就能明⽩了,因为我们是在dev分⽀上提交的,⽽master分⽀此刻的提交点并没有变,此时的状态如图如下所⽰:
此时dev是最新提交的,而master则是上一次提交的。当切换到 master 分⽀之时,HEAD 就指向了 master,当然看不到最新提交了。
3.4 🍎合并分⽀🍎
为了在 master 主分⽀上能看到新的提交,就需要将
dev
分⽀合并到
master
分⽀,⽰例如下:
我们先切换到master分支,然后进行合并:
此时我们就在master下看见了最新提交:
我们在合并时会出现Fast-forward,Fast-forward 代表“快进模式”,也就是直接把master指向dev的当前提交:
3.5 🍎删除分⽀🍎
合并完成后, dev 分⽀对于我们来说就没⽤了, 那么dev分⽀就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀,如:
也就是自己不能够删除自己。另外要注意
git branch -d
命令适用于已经合并了的分支进行删除,对于没有进行合并的分支后面我们会讲解删除方式。
此时的状态如图如下所⽰:
因为创建、合并和删除分⽀⾮常快,所以Git⿎励你使⽤分⽀完成某个任务,合并后再删掉分⽀,这和直接在master分⽀上⼯作效果是⼀样的,但过程更安全。
我们使用下面命令来查看提交日志不难发现:
此时我们使用
Fast-forward
模式是无法区分是合并提交的?还是只在master上提交?
3.6 🍎合并冲突🍎
可是,在实际分⽀合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。
为了演⽰这问题,创建⼀个新的分⽀ dev1 ,并切换⾄⽬标分⽀,我们可以使⽤
git checkout -b dev1
⼀步完成创建并切换的动作,⽰例如下:
先看看原始文件中的数据:
在 dev1 分⽀下修改 Upload ⽂件,更改⽂件内容如下,并进⾏⼀次提交,如:
切换⾄ master 分⽀,观察 Upload ⽂件内容:
我们发现,切回来之后,⽂件内容由变成了⽼的版本,这种现象很正常,我们现在也完全能理解。
此时在 master 分⽀上,我们对 Upload ⽂件再进⾏⼀次修改,并进⾏提交:
现在, master 分⽀和 dev1 分⽀各⾃都分别有新的提交,变成了这样:
)
这种情况下,Git 只能试图把各⾃的修改合并起来,但这种合并就可能会有冲突,如下所⽰:
此时我们打开Upload文件:
此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果:
到这⾥冲突就解决完成,此时的状态变成了:
此时我们查看提交日志时发现:
这个跟我们画的图几乎是一摸一样的。也就是说使用这种非
Fast-forward
模式是可以区分是合并修改还是只是master修改的,更加方便追责哈哈。
最后,不要忘记 dev1 分⽀使⽤完毕后就可以删除了:
3.7 🍎分⽀管理策略🍎
通常合并分⽀时,如果可能,Git 会采⽤
Fast forward
模式。还记得如果我们采⽤ Fast forward 模式之后,形成的合并结果是什么呢?
在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提交到底是 merge 进来的还是正常提交的?
但在合并冲突部分,我们也看到通过解决冲突问题,会再进⾏⼀次新的提交。那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。
Git ⽀持我们强制禁⽤
Fast forward
模式,那么就会在 merge 时⽣成⼀个新的 commit ,这样从分⽀历史上就可以看出分⽀信息。
下⾯我们实战⼀下
--no-ff
⽅式的 git merge 。⾸先,创建新的分⽀ dev2 ,并切换⾄新的分⽀:
切回 master 分⽀,开始合并:
请注意
--no-ff
参数,表⽰
禁⽤ Fast forward
模式。禁⽤ Fast forward 模式后合并会创建⼀个新的 commit ,所以加上
-m
参数,把描述写进去(ps:不管是使用ff模式还是非ff模式,在多个分支下进行修改时都有可能会出现冲突,需要用户自己手动处理冲突)。
合并后,查看分⽀历史:
所以在合并分⽀时,加上
--no-ff
参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾经做过合并,⽽
fast forward
合并就看不出来曾经做过合并。
4 🍑分⽀策略🍑
在实际开发中,我们应该按照⼏个基本原则进⾏分⽀管理:
⾸先,master分⽀应该是⾮常稳定的,也就是仅⽤来发布新版本,平时不能在上⾯⼲活。
那在哪⼲活呢?⼲活都在dev分⽀上,也就是说,dev分⽀是不稳定的,到某个时候,⽐如1.0版本发布时,再把dev分⽀合并到master上,在master分⽀发布1.0版本;你和你的⼩伙伴们每个⼈都在dev分⽀上⼲活,每个⼈都有⾃⼰的分⽀,时不时地往dev分⽀上合并就可以了。
所以,团队合作的分⽀看起来就像这样:
4.1 🍎bug 分⽀🍎
假如我们现在正在 dev2 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有 bug,需要解决。在Git中,每个 bug 都可以通过⼀个新的临时分⽀来修复,修复后再合并分⽀,然后将临时分⽀删除。
可现在 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?例如:
Git 提供了
git stash
命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时间恢复出来。
⽤ git status 查看⼯作区,就是⼲净的(除⾮有没有被 Git 管理的⽂件),因此可以放⼼地创建分⽀来修复bug。
储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复 bug,所以需要切回 master 分⽀,再新建临时分⽀来修复 bug,⽰例如下:
修复完成后,切换到 master 分⽀,并完成合并,最后删除 solve_bug 分⽀:
⾄此,bug 的修复⼯作已经做完了,我们还要继续回到 dev2 分⽀进⾏开发。切换回 dev2 分⽀:
⼯作区是⼲净的,刚才的⼯作现场存到哪去了?⽤
git stash list
命令看看:
⼯作现场还在,Git 把 stash 内容存在某个地⽅了,但是需要恢复⼀下,如何恢复现场呢?我们可以使⽤
git stash pop
命令,恢复的同时会把 stash 也删了,⽰例如下:
再次查看的时候,我们已经发现已经没有现场可以恢复了:
另外,恢复现场也可以采⽤
git stash apply
恢复,但是恢复后,stash内容并不删除,你需要⽤
git stash drop
来删除;你可以多次stash,恢复的时候,先⽤ git stash list 查看,然后恢复指定的stash,⽤命令
git stash apply stash@{0}
恢复完代码之后我们便可以继续完成开发,开发完成后便可以进⾏提交,例如:
但我们注意到了,修复 bug 的内容,并没有在 dev2 上显⽰。此时的状态图为:
Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以我们在 dev2 中当然看不⻅修复 bug 的相关代码。
我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合并即可,但这样其实是有⼀定⻛险的。
是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到 master 上。
此时的状态为:
解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并dev2 ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。
4.2 🍎删除临时分⽀🍎
软件开发中,总有⽆穷⽆尽的新的功能要不断添加进来。
添加⼀个新功能时,你肯定不希望因为⼀些实验性质的代码,把主分⽀搞乱了,所以,每添加⼀个新功能,最好新建⼀个分⽀,我们可以将其称之为 feature 分⽀,在上⾯开发,完成后,合并,最后,删除该 feature 分⽀。
可是,如果我们今天正在某个 feature 分⽀上开发了⼀半,被产品经理突然叫停,说是要停⽌新功能的开发。虽然⽩⼲了,但是这个 feature 分⽀还是必须就地销毁,留着⽆⽤了。这时使⽤传统的
git branch -d
命令删除分⽀的⽅法是不⾏的。演⽰如下:
然后我们切换到master分支进行删除:
使用这种方式是失败的,我们需要使用
-D
选项:
5 🍑远程操作🍑
5.1 🍎理解分布式版本控制系统🍎
我们⽬前所说的所有内容(⼯作区,暂存区,版本库等等),都是在本地!也就是在你的笔记本或者计算机上。⽽我们的 Git 其实是分布式版本控制系统!什么意思呢?
可以简单理解为,我们每个⼈的电脑上都是⼀个完整的版本库,这样你⼯作的时候,就不需要联⽹了,因为版本库就在你⾃⼰的电脑上。既然每个⼈电脑上都有⼀个完整的版本库,那多个⼈如何协作呢?⽐⽅说你在⾃⼰电脑上改了⽂件A,你的同事也在他的电脑上改了⽂件A,这时,你们俩之间只需把各⾃的修改推送给对⽅,就可以互相看到对⽅的修改了。
分布式版本控制系统的安全性要⾼很多,因为每个⼈电脑⾥都有完整的版本库,某⼀个⼈的电脑坏掉了不要紧,随便从其他⼈那⾥复制⼀个就可以了。
在实际使⽤分布式版本控制系统的时候,其实很少在两⼈之间的电脑上推送版本库的修改,因为可能你们俩不在⼀个局域⽹内,两台电脑互相访问不了。也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有⼀台充当“中央服务器”的电脑,但这个服务器的作⽤仅仅是⽤来⽅便“交换”⼤家的修改,没有它⼤家也⼀样⼲活,只是交换修改不⽅便⽽已。有了这个“中央服务器”的电脑,这样就不怕本地出现什么故障了(⽐如运⽓差,硬盘坏了,上⾯的所有东西全部丢失,包括git的所有内容)
5.2 🍎新建远程仓库🍎
从创建好的远程仓库中我们便能看到,之前在本地学习过的分⽀,也存在于远程仓库中并被管理起来了。刚创建的仓库有且只有⼀个默认的master分⽀
5.3 🍎克隆远程仓库🍎
克隆/下载远端仓库到本地,需要使⽤
git clone
命令,后⾯跟上我们的远端仓库的链接,远端仓库的链接可以从仓库中找到:选择“克隆/下载”获取远程仓库链接:
SSH 协议和 HTTPS 协议是 Git 最常使⽤的两种数据传输协议。SSH 协议使⽤了公钥加密和公钥登陆机制,体现了其实⽤性和安全性,使⽤此协议需要将我们的公钥放上服务器,由 Git 服务器进⾏管理。使⽤ HTTPS ⽅式时,没有要求,可以直接克隆下来。
5.3.1 🍋使⽤ HTTPS ⽅式🍋
我们进入到仓库里面看看:
5.3.1 🍋使⽤ SSH ⽅式🍋
我们重新创建一个仓库:
此时我们直接克隆会直接报错:
使⽤ SSH ⽅式克隆仓库,由于我们没有添加公钥到远端库中,服务器拒绝了我们的 clone 链接。需要我们设置⼀下:
- 1️⃣第⼀步:创建SSH Key。在⽤⼾主⽬录下,看看有没有.ssh⽬录,如果有,再看看这个⽬录下有没有id_rsa 和 id_rsa.pub 这两个⽂件,如果已经有了,可直接跳到下⼀步。如果没有,需要创建SSH Key: 顺利的话,可以在⽤⼾主⽬录⾥找到 .ssh ⽬录,⾥⾯有 id_rsa 和 id_rsa.pub 两个⽂件,这两个就是SSH Key的秘钥对, id_rsa 是私钥,不能泄露出去, id_rsa.pub 是公钥,可以放⼼地告诉任何⼈.
- 2️⃣第⼆步:添加⾃⼰的公钥到远端仓库。 我们将公钥进行复制,然后在远程仓库里面添加公钥: 输入密码验证成功后即可: 此时我们进行克隆就成功了: 如果有多个⼈协作开发,GitHub/Gitee 允许添加多个公钥,只要把每个⼈的电脑上的Key 都添加到 GitHub/Gitee,就可以在每台电脑上往 GitHub/Gitee 上提交推送了。
当我们从远程仓库克隆后,实际上 Git 会⾃动把本地的 master 分⽀和远程的 master 分⽀对应起来,并且,远程仓库的默认名称是
origin
。在本地我们可以使⽤
git remote
命令,来查看远程库的信息,如:
上⾯显⽰了可以抓取和推送的origin的地址。
5.4 🍎向远程仓库推送🍎
本地已经 clone 成功远程仓库后,我们便可以向仓库中提交内容,例如新增⼀个 test.txt文件:
先配置好用户名和邮箱:
注意你这里的用户名要跟gitup/gitee用户名保持一致。然后进行add和commit即可。
到这⾥我们已经将内容提交⾄本地仓库中,如何将本地仓库的内容推送⾄远程仓库呢,需要使⽤
git push
命令,
该命令⽤于将本地的分⽀版本上传到远程并合并,命令格式如下:
git push <远程主机名><本地分⽀名>:<远程分⽀名># 如果本地分⽀名与远程分⽀名相同,则可以省略冒号:git push <远程主机名><本地分⽀名>
此时我们要将本地的 master 分⽀推送到 origin 主机的 master 分⽀,则可以:
此时我们在远端仓库进行查看:
5.5 🍎拉取远程仓库🍎
为了方便演示,我直接将远端仓库的内容进行修改(不建议大家这么做):
此时,远程仓库是要领先于本地仓库⼀个版本,为了使本地仓库保持最新的版本,我们需要拉取下远端代码,并合并到本地。Git 提供了
git pull
命令,该命令⽤于从远程获取代码并合并本地的版本。格式如下:
git pull <远程主机名><远程分⽀名>:<本地分⽀名>23 # 如果远程分⽀是与当前分⽀合并,则冒号后⾯的部分可以省略。
4 git pull <远程主机名><远程分⽀名>
我们发现,拉取成功了!
5.6 🍎配置 Git🍎
5.6.1 🍋忽略特殊⽂件🍋
在⽇常开发中,我们有些⽂件不想或者不应该提交到远端,⽐如保存了数据库密码的配置⽂件,那怎么让 Git 知道呢?在 Git ⼯作区的根⽬录下创建⼀个特殊的
.gitignore
⽂件,然后把要忽略的⽂件名填进去,Git 就会⾃动忽略这些⽂件了。不需要从头写 .gitignore ⽂件,gitee 在创建仓库时就可以为我们⽣成,不过需要我们主动勾选⼀下.
由于在创建时我添加了C++的一些常用忽略文件。所以打开
.gitignore
效果就是这样:
此时我们是无法将忽略文件提交到暂存区的。
但有些时候,你就是想添加⼀个⽂件到 Git,但由于这个⽂件被 .gitignore 忽略了,根本添加不了,那么可以⽤
-f
强制添加:
gitadd -f [filename]
或者你发现,可能是 .gitignore 写得有问题,需要找出来到底哪个规则写错了,⽐如说 a.so ⽂件是要被添加的,可以⽤
git check-ignore
命令检查。此时Git 会告诉我们, .gitignore 的哪一⾏规则忽略了该⽂件,于是我们就可以知道应该修订哪个规则。
还有些情况我们不想要某个文件被忽略,在
.gitignore
规则外的写法就是
! +⽂件名
,所以,只需把例外⽂件添加进去即可。
# 不排除.gitignore
!.gitignore
5.6.2 🍋给命令配置别名🍋
在我们使⽤ Git 期间,有些命令敲的时候着实让⼈头疼(太⻓了。。),幸运的是,git⽀持对命令进⾏简化!
举个例⼦,将 git status 简化为 git st ,对应的命令为:
git config --global alias.st status
--global
参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有⽤。如果不加,那只针对当前的仓库起作⽤。
5.7 🍎标签管理🍎
标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项⽬发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样的标签来标识⾥程碑的意义。
这有什么⽤呢?相较于难以记住的 commit id , tag 很好的解决这个问题,因为 tag ⼀定要给⼀个让⼈容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使⽤标签就能很快定位到。
在Git中打标签⾮常简单,⾸先,切换到需要打标签的分⽀上:
然后,敲命令
git tag [name]
就可以打⼀个新标签,可以⽤命令
git tag
查看所有标签:
默认标签是打在最新提交的
commit
上的。那如何在指定的commit上打标签呢?⽅法是找到历史提交的commit id,然后打上就可以了,⽰例如下:
注意,标签不是按时间顺序列出,⽽是按字⺟排序的。
可以⽤
git show [tagname]
查看标签信息。
Git 还提供可以创建带有说明的标签,⽤
-a
指定标签名,
-m
指定说明⽂字,格式为:
git tag -a <tagname> -m "XXX"[commit_id]
如果标签打错了,也可以删除,使用
git tag -d [name]
命令即可。
因为创建的标签都只存储在本地,不会⾃动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使⽤命令
git push origin <tagname>
此时在远端就能够看见推送过来的标签:
当然,如果你本地有很多标签,也可以⼀次性的全部推送到远端:
git push origin --tags
如果标签已经推送到远程,要删除远程标签就⿇烦⼀点,先从本地删除使用
git tag -d
命令,然后,从远程删除。删除命令也是push,但是格式如下:
git push origin :refs/tags/v1.0
6 🍑多⼈协作🍑
6.1 🍎场景一🍎
为了方便演示,分别在 linux 和 windows 上针对于同项⽬进⾏协作开发(使用linux 和 windows 来模拟不同成员的协作)。
⽬前,我们的仓库中只有⼀个 master 主分⽀,但在实际的项⽬开发中,在任何情况下其实都是不允许直接在 master 分⽀上修改代码的,这是为了保证主分⽀的稳定。所以在开发新功能时,常常会新建其他分⽀,供开发时进⾏迭代使⽤。
那么接下来,就让我们在 gitee 上新建 dev 远程分⽀供我们使⽤:
创建成功的远程分⽀是可以通过 Git 拉取到本地来,以实现完成本地开发⼯作。
在Linux下:
我们首先将远程仓库中的分支给拉取下来:
然后使用
git branch -r
命令查看远程分⽀:
拉取后便可以看到远程的 dev 分⽀,接着切换到 dev 分⽀供我们进⾏本地开发。要说明的是,我们切换到的是本地的 dev 分⽀,根据⽰例中的操作,会将本地分⽀和远程分⽀的进⾏关系链接。
在Windows下:
我们首先将远程仓库中的分支给拉取下来:
然后进行查看:
后面我们就可以在dev上进行开发了。将Windowsxp和Linux中工作分支都切换到dev。
现在Linux上进行推送:
上面操作都是之前已经讲过了的,这里就不再多说了。此时我们观察远端仓库:
然后我们切换到Windows中:
我们找到对应的目录使用记事本打开文件进行修改:
我们发现此时打开是没有在Linux中增加的数据,这是符合预期的,因为我们拉取的代码本来就是在开始的版本。
然后进行推送:
发现此时推送会出现冲突,解决办法也很简单,Git已经提⽰我们,先⽤
git pull
把最新的提交从 origin/dev 抓下来,然后,在本地进⾏合并,并解决冲突,再推送。操作如下:
此时我们打开记事本,进行修改:
修改后成了这样:
然后进行重新推送:
此时已经推送成功,我们在远端下观察:
最后不要忘记,虽然我们是在分⽀上进⾏多⼈协作开发,但最终的⽬的是要将开发后的代码合并到master上去,让我们的项⽬运⾏最新的代码。接下来我们就需要做这件事情了。
我们可以使用远端的方式来进行合并,但这里我们使用命令的方式来进行合并帮助大家理解:
首先我们要切换⾄ master分⽀, pull ⼀下,保证本地的master是最新内容, 合并前这么做是⼀个好习惯:
然后 切换⾄ dev 分⽀, 合并 master 分⽀,这么做是因为如果有冲突,可以在dev分⽀上进⾏处理,⽽不是在master上解决冲突,这么做是⼀个好习惯。
最后切换⾄ master 分⽀,合并 dev 分⽀,并将mastet推送至远端:
然后在远端下观察,master已经是最新代码了:
dev 分⽀对于我们来说就没⽤了, 那么 dev 分⽀就可以被删除掉。我们可以直接在远程仓库中将dev分⽀删除掉:
删除后只剩master了:
然后在本地我们也可以手动删除dev分支了。这里就不再演示了,之前讲解过。
总结⼀下,在同⼀分⽀下进⾏多⼈协作的⼯作模式通常是这样:
- ⾸先,可以试图⽤ git push origin branch-name 推送⾃⼰的修改;
- 如果推送失败,则因为远程分⽀⽐你的本地更新,需要先⽤ git pull 试图合并;
- 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再⽤git push origin branch-name推送就能成功;
- 功能开发完毕,将分⽀ merge 进 master,最后删除分⽀。
6.2 🍎场景二🍎
场景一的情况在日常开发中应该时很少见的,一般来说场景二更为常见些。
如果有多需求需要多⼈同时进⾏开发,是不会在⼀个分⽀上进⾏多⼈开发,⽽是⼀个需求或⼀个功能点就要创建⼀个 feature 分⽀。
现在同时有两个需求需要你和你的⼩伙伴进⾏开发,那么你们俩便可以各⾃创建⼀个分⽀来完成⾃⼰的⼯作。在上个部分我们已经了解了可以从码云上直接创建远程分⽀,其实在本地创建的分⽀也可以通过推送的⽅式发送到远端。在这个部分我们就来⽤⼀下这种⽅式。
在场景一下我们是在远端创建了新分支然后拉取到本地的,现在我们换一种方式,在本地建立新的分支来推送到远端。
在Linux下:
首先新增本地分⽀ feature-1 并切换:
然后新增需求内容,创建function1⽂件,并将 feature-1 分⽀推送到远端:
在Windows下也是进行相同的操作:
此时在远端下观察:
正常情况下,你俩就可以在⾃⼰的分⽀上进⾏专业的开发了!
但天有不测⻛云,你的⼩伙伴突然⽣病了,但需求还没开发完,需要你帮他继续开发,于是他便把feature-2 分⽀名告诉你了。这时你就需要在⾃⼰的机器上切换到 feature-2 分⽀帮忙继续开发,要做的操作如下:
首先必须先拉取远端仓库内容:
然后切换到feature-2分⽀上,可以和远程的feature-2分⽀关联起来,否则将来只使⽤
git push
推送内容会失败:
git checkout -b feature-2 origin/feature-2
查看远程状态,推送成功了:
这时,你的⼩伙伴已经修养的差不多,可以继续进⾏⾃⼰的开发⼯作,那么他⾸先要获取到你帮他开发的内容,然后接着你的代码继续开发。或者你已经帮他开发完了,那他也需要在⾃⼰的电脑上看看你帮他写的代码:
首先拉取最新代码:
但是我们查看文件内容时发现并没有成功:
pull ⽆效的原因是⼩伙伴没有指定本地 feature-2 分⽀与远程 origin/feature-2 分⽀的链接,根据提⽰,设置feature-2和origin/feature-2的链接即可:
此时发现拉取成功:
⽬前,⼩伙伴的本地代码和远端保持严格⼀致。你和你的⼩伙伴可以继续在不同的分⽀下进⾏协同开发了。
各⾃功能开发完毕后,不要忘记我们需要将代码合并到master中才算真正意义上的开发完毕。
由于你的⼩伙伴率先开发完毕,于是开始
merge
:
首先切换至master,pull一下,保证本地master是最新的内容:
然后切换至featrue-2分支,拉取最新代码,然后合并master:
切换至master分支,合并featrue-2:
最后将master分支推向远端:
此时远程仓库的状态:
当你的⼩伙伴将其代码 merge 到 master 后,这是你也开发完成了,也需要进⾏ merge 到master 操作,于是你:
首先切换⾄ master分⽀, pull ⼀下,保证本地的master是最新内容,合并前这么做是⼀个好习惯:
然后切换⾄ feature-1 分⽀, 合并 master 分⽀,这么做是因为如果有冲突,可以在feature-1分⽀上进⾏处理,⽽不是在在master上解决冲突,这么做也是⼀个好习惯:
要注意的点:由于feature-1分⽀已经merge进来了新内容,为了保证远程分⽀最新,所以最好push⼀下;要 push 的另⼀个原因是因为在实际的开发中,master的merge操作⼀般不是由我们⾃⼰在本地进其他⼈员或某些平台merge时,操作的肯定是远程分⽀,所以就要保证远程分⽀的最新;如果 merge 出现冲突,不要忘记需要commit才可以push。
切换⾄ master 分⽀,合并 feature-1 分⽀:
最后将 master 分⽀推送⾄远端:
此时远程仓库的状态:
此时, feature-1 和 feature-2 分⽀对于我们来说就没⽤了, 那么我们可以直接在远程仓库中将分⽀删除掉。
。
但是远程分⽀删除后,本地
git branch -a
依然能看到:
当前我们已经删除了远程的⼏个分⽀,使⽤
git branch -a
命令可以查看所有本地分⽀和远程分⽀,但发现很多在远程仓库已经删除的分⽀在本地依然可以看到。
使⽤命令
git remote show origin
,可以查看remote地址,远程分⽀,还有本地分⽀与之相对应关系等信息。
此时我们可以看到那些远程仓库已经不存在的分⽀,根据提⽰,使⽤
git remote prune origin
命令:
这样就删除了那些远程仓库不存在的分⽀。对于本地仓库的删除,之前的课程已经学过了,⼤家可以⾃⾏操作。
版权归原作者 Fox! 所有, 如有侵权,请联系我们删除。