LV01-Git-05-远程仓库-02-远程分支
本文主要是GitHub的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
点击查看本文参考资料
参考方向 | 参考原文 |
Git 官网 | https://git-scm.com/ |
Git 官方文档 | https://git-scm.com/doc |
Pro Git Book | https://git-scm.com/book/zh/v2 |
Git 快速使用指南 | https://training.github.com/downloads/zh_CN/github-git-cheat-sheet/ |
Visual Git Cheat Sheet | https://ndpsoftware.com/git-cheatsheet.html#loc=index |
我们上一节简单了解可一下GitHub以及一些相关命令,我们这部分就来深入了解一下这些命令怎么用。
一、远程分支
1. 远程分支说明
远程引用是对远程仓库的引用(指针),包括分支、标签等等。 我们可以通过 git ls-remote <remote>
来显式地获得远程引用的完整列表, 或者通过 git remote show <remote>
获得远程分支的更多信息。 然而,一个更常见的做法是利用远程跟踪分支。
远程跟踪分支是远程分支状态的引用。它们是我们无法移动的本地引用。一旦我们进行了网络通信, Git 就会为我们移动它们以精确反映远程仓库的状态。请将它们看做书签, 这样可以提醒我们该分支在远程仓库中的位置就是我们最后一次连接到它们的位置。
它们以 <remote>/<branch>
的形式命名。 例如,如果我们想要看你最后一次与远程仓库 origin
通信时 master
分支的状态,我们可以查看 origin/master
分支。 我们与同事合作解决一个问题并且他们推送了一个 iss53
分支,我们可能有自己的本地 iss53
分支, 然而在服务器上的分支会以 origin/iss53
来表示。
2. 远程分支实例
让我们来看一个例子。 假设我们的网络里有一个在 git.ourcompany.com
的 Git 服务器。 如果我们从这里克隆,Git 的 clone
命令会为我们自动将其命名为 origin
,拉取它的所有数据, 创建一个指向它的 master
分支的指针,并且在本地将其命名为 origin/master
。 Git 也会给我们一个与 origin 的 master
分支在指向同一个地方的本地 master
分支,这样我们就有工作的基础。
“origin” 并无特殊含义
远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。 同时 “master” 是当我们运行
git init
时默认的起始分支名字,原因仅仅是它的广泛使用, “origin” 是当我们运行git clone
时默认的远程仓库名字。 如果我们运行git clone -o booyah
,那么我们默认的远程分支名字将会是booyah/master
。
图一-1 克隆之后的服务器与本地仓库
如果我们在本地的 master
分支做了一些工作,在同一段时间内有其他人推送提交到 git.ourcompany.com
并且更新了它的 master
分支,这就是说我们们和其他人的提交历史已走向不同的方向。 即便这样,只要我们保持不与 origin
服务器连接(并拉取数据),我们的 origin/master
指针就不会移动。
图一-2 本地与远程的工作可以分叉
如果要与给定的远程仓库同步数据,运行 git fetch <remote>
命令(在本例中为 git fetch origin
)。 这个命令查找 origin
是哪一个服务器(在本例中,它是 git.ourcompany.com
), 从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master
指针到更新之后的位置。
图一-3 git fetch 更新我们的远程跟踪分支
为了演示有多个远程仓库与远程分支的情况,假定我们有另一个内部 Git 服务器,仅服务于我们的某个敏捷开发团队。 这个服务器位于 git.team1.ourcompany.com
。 我们可以运行 git remote add
命令添加一个新的远程仓库引用到当前的项目。 将这个远程仓库命名为 teamone
,将其作为完整 URL 的缩写。
图一-4 远程跟踪分支 teamone/master
二、创建远程仓库
其实在GitHub上创建的仓库有两种状态,一种是单纯的创建一个空仓库。另一种是创建的时候直接创建一些必要的文件,并进行一次提交。
1. 空的仓库
1.1 仓库说明
需要注意的是这种仓库灵活性比较大,由于是空的,所以们可以直接将此仓库clone到本地使用,这样的话,clone下来的仓库直接与远程仓库建立好了连接,可以直接使用。或者我们也可以自己在本地初始化一个文件夹,然后将这个本地仓库与远程仓库建立连接,然后就可以开始呢使用了。
1.2 创建空仓库
我们先创建一个空的远程仓库作为测试使用
按照上边填写信息,然后点击右下角的创建,我们会得到一个空的仓库,然后会弹出以下界面,在界面中会给出我们相关命令来提示如何操作仓库:
2. 非空仓库
2.1 仓库说明
这种仓库在创建的时候已经添加了readme文件或者其他的文件,并产生了一次提交,这种的一般是要clone到本地使用的,当然,也可以在本地初始化仓库,然后建立与远程仓库的连接,只不过可能会产生一些冲突,但是解决一下应该也问题不大。
2.2 创建非空仓库
我们其实也可以创建非空仓库,比如直接添加readme文件还有.gitignore忽略文件,以及license文件等,来看一下:
这个直接创建一个初始化的仓库,好像必须要在这里勾线ADD a README file
,然后我们点击创建,会看到以下界面:
会发现直接就是仓库源码界面了,而且仓库直接进行了一次提交,班喊一个README.md文件。
3. 测试说明
这里只是演示一下两种仓库的创立方式,后边为了学习更多的操作,我们选择使用空仓库来进行演示说明。
三、克隆仓库
接下来我们将仓库下载到本地,看一下情况。想要进行仓库的克隆,需要先让我们的电脑跟GitHub进行正常连接,我们是通过SSH连接的,在前边Git配置的时候我们其实已经配置过了,这里就不用管这一步了。
1. git clone命令详细说明
这个我们还是看文档吧:Git - git-clone Documentation (git-scm.com),文档中说的特别详细。
1 | git clone [--template=<template-directory>] |
2. 基本clone命令
2.1 命令说明
我们想要将仓库下载到本地的话,可以用下边的命令:
1 | 克隆相关操作 |
- repository_url :仓库的地址,这个怎么看?对于创建的空仓库,在提示界面会有,对于直接初始化的仓库,我们可以直接在源码界面找到,这里会有两种地址,一种是https的,一种是ssh地址,一般我是用的ssh地址,两者是有区别的,但是忘记了,不过简单验证一下就知道了,用ssh地址好像是更方便一些。如下图:
- another-repository-name :就是我们克隆到本地的仓库的名字是可以与远程仓库的名字不同的,这里就是clone到本地之后的仓库的名字。
2.2 使用实例
我们这里以前边创建的空仓库为例进行演示sumumm/git-test (github.com)。
2.2.1 HTTPS地址
- 查看HTTPS地址
- clone仓库
1 | git clone https://github.com/sumumm/git-test.git http_addr_git_test |
- 查看文件夹内容:
可以发现,这是一个空仓库,并且是有.git目录的。
2.2.2 SSH地址
- 查看SSH地址
- clone仓库
1 | git clone git@github.com:sumumm/git-test.git ssh_addr_git_test |
- 查看文件夹内容:
可以发现,这是一个空仓库,并且是有.git目录的。
3. 克隆指定版本
那有的时候我们想要clone某个仓库指定的版本,该怎么操作?貌似不太支持啊,我看官方说明文档里也没得,那暂时就只有一种办法喽:
(1)克隆整个仓库下来;
(2)查看提交记录,获取要跳转的指定版本的commit提交记录的ID;
(3)版本回滚。
4. 克隆指定分支
有的时候我们想要clone指定分支的话,怎么办?
4.1 命令说明
一般来讲,我们不加任何参数的实行git clone
,这样将会下载到master分支或者叫main分支,或者就是自己定义的默认的分支。我们可以加上-b
参数克隆指定分支:
1 | git clone -b <branch_name> <repository_url> # clone仓库 |
4.2 使用实例
我们还是以hexo的仓库为例(hexojs/hexo: A fast, simple & powerful blog framework, powered by Node.js. (github.com))我们先看一下都有哪些分支:
然后执行以下命令:
1 | git clone -b 4.2.1 git@github.com:hexojs/hexo.git |
然后我们来看一下分支名:
可以看到这里的分支为4.2.1啦。
5. depth参数
我们经常会用 git clone来下载项目,但遇到大项目的时候,clone 就很慢,比如我要学习的uboot的有一个分支nxp-imx/uboot-imx at nxp/imx_v2016.03_4.1.15_2.0.0_ga (github.com):
在clone的时候就很慢很慢很慢。原因是历史提交的commits太多了,我们能不能只下载其中的一个?当然可以啦,就是通过depth参数控制:
1 | git clone git@github.com:nxp-imx/uboot-imx.git -b nxp/imx_v2016.03_4.1.15_2.0.0_ga --depth 1 |
就会发现下载的很快很快,并且只有一次提交:
那这样代码还是全的么?当然,代码是最新的完整代码。那为啥下载的内容少了呢?少了哪一部分呢?就是历史 commit。
git 中文件是通过 object 存储不同数据的:
- blob 对象存储文件内容
- tree 对象存储文件路径
- commit 对象存储 commit 信息,关联多个 tree
然后 HEAD、branch、tag 等是指向具体 commit 的指针,可以在 .git/refs 下看到。所以说,每个版本的代码都是从 commit 对象作为入口关联起来的。指定了 depth 1 的时候,就是只保留了最新的入口,历史入口就没下载了。
这样自然快很多,代码也是完整的。但这么好的事情也是有代价的,它有一些后遗症。
(1)最容易想到的就是切不到历史 commit,不能使用git reset命令去切换到其他提交记录。
(2)git pull 的时候,也下载不了历史 commit 的代码。git 团队自然也想到了这点,于是提供了一个 unshallow 的选项,加上 –unshallow 再 pull 的时候也会同时拉取历史 commit(默认没开这个是为了性能)。
我们完全可以用 depth 1 下载的项目来开发,正常的 pull、push 都没问题,因为都是基于最新 commit 创建的更新的 commit。当你有一天需要历史 commit 的时候再 pull –unshallow 也不迟。
(3)换不了其他 branch。切不到别的分支是因为 fetch 配置导致的,配置成 +refs/heads/**:refs/remotes/origin/**
也就可以了,也就是拉取远程所有分支代码到本地。这样再 fetch 和 pull 就会拉取所有分支的新 commit,也可以正常的切分支。
总的来说–depth 1 在下载大项目的时候,或者 build 时下载代码的时候,都很有意义。它提高下载速度导致的俩后遗症也都可以解决。
四、本地与远程仓库的联系?
1. 概述
1.1 情况说明
上边我们学习了如何从GitHub克隆仓库,这样我们可以直接得到一个初始化过的仓库,那么,倘若我们本地有一个仓库,我们已经做了很多的提交了,但是它与远程仓库没有任何关系,我们该如何做才能将本地仓库与远程的仓库联系起来?
1.2 命令汇总
这里的详细命令我们可以参考Git - git-remote Documentation (git-scm.com):
1 | git remote [-v | --verbose] |
上边这么多命令,如何使用呢?其实我们创建空仓库的时候就已经告诉我们了:
接下来就来详细学习一下吧。
2. 本地仓库准备
2.1 仓库说明
为了演示一些情况,我们在这里创建一个本地仓库,这个仓库有以下特点:
(1)含有两个分支,分别为master和dev分支。
(2)master分支最开始做两次修改和提交,分别为C0、C1。
(3)master完成C1提交的时候,我们创建dev分支。
(4)我们在master分支在进行一次C2提交。
(5)切换到dev分支,然后进行一次C3提交。
其中每次提交只要有修改即可,我们的这个仓库包含read.md文件和test.txt文件。
2.2 本地仓库创建
- (1)初始化仓库,在master分支进行C0提交
1 | mkdir remote-branch |
- (2)在master分支进行C1提交,并创建dev分支
1 | git commit -a -m "feat:C1提交" |
- (3)在master分支进行C2提交
1 | git commit -a -m "feat:C2提交" |
- (4)切换到dev分支,并进行dev分支的C3提交
1 | git checkout dev |
2.3 两个分支情况
2.3.1 master分支
master分支的文件内容及提交记录如下:
2.3.2 dev分支
dev分支的文件内容及提交记录如下:
3. 添加本地仓库与远程仓库连接
3.1 命令说明
想要让本地仓库与远程仓库建立连接,我们可以使用下边的命令:
1 | git remote add <remote_name> <URL> |
- remote_name :表示远程分支在本地的名字,我们一般命名为origin。
- URL :表示远程仓库的链接,我一般是使用的SSH链接,HTTPS的也可以。
3.2 使用实例
我们在刚才的仓库的master分支执行下边的命令:
1 | git remote add origin git@github.com:sumumm/git-test.git |
会发现什么输出都没有,怎么看有事没有建立成功?我们后边再说。
4. 查看远程引用的信息
4.1 命令说明
我们刚才是建立了本地仓库与远程仓库的连接,但是我们如何获取这些信息呢?
1 | git remote show <remote_name> |
4.2 使用实例
我们接下来看一下这三条命令显示的信息有何不同:
- (1)
git remote show <remote_name>
1 | git remote show origin |
- (2)
git remote -v
1 | git remote -v |
- (3)
git remote
1 | git remote |
4.3 多个remote名?
有个想法,remote_name可以有多个吗?它们都指向同一个git远程仓库地址,我们来尝试一下:
1 | git remote add aaa git@github.com:sumumm/git-test.git |
可以看到是可以的,但是这样做暂时似乎没发现有什么意义。
5. 移除与远程仓库的连接
我们上边建立了那么多的多余的remote名,怎么移除?
5.1 命令说明
我们可以通过以下命令移除本地仓库与远程仓库的关联,就相当于删除了本地的remote_name:
1 | git remote remove <remote_name> # 删除本地仓库与远程仓库关联 |
5.2 使用实例
我们执行以下命令:
1 | git remote remove aaa |
会发现前边创建的aaa,bbb等远程连接的名就被删除了,当我们删除最后一个与远程仓库的连接的时候,就意味着我们本地仓库断开了与远程仓库的连接,本地也便无法再跟踪远程仓库了。
五、推送到远程仓库
上边我们已经可以建立与远程仓库的连接了,那我们怎么吧本地的仓库推送到远程仓库?
1. 概述
我们可以在这里看到相关的命令说明:Git - git-push Documentation (git-scm.com)
1 | git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>] |
其实在创建空仓库的时候GitHub也告诉了我们最基础的git push
命令。
2. 推送到远程仓库
2.1 命令说明
我们来看一下基础的命令:
1 | git push -u <remote_name> <branch_name> # 将本地仓库文件上传到远程仓库分支 |
- remote_name :远程仓库在本地的别名,我上边命名为了origin。
- branch_name :要推送的本地仓库的分支名。
2.2 使用实例
我们来将刚才本地的master分支和dev分支都推送到远程仓库:
1 | git push -u origin master |
然后我们再来看一下GitHub远程仓库(sumumm/git-test (github.com))的情况:
若是看每个分支的历史记录的话,会发现,它们的提交与本地一模一样,这里就不贴图了。
3. 一个问题
有这样一种情况,就是,远程分支比本地的提交更新的时候怎么办?或者说,本地提交与远程完全不一样怎么办?这两种情况其实都是一样的结果,我们可以尝试一下,我们刚才已经成功将master分支和dev分支推送到GitHub上的空仓库了,我们现在来修改本地仓库,我们在master分支做操作,我们重新修改master分支的C3提交,我们这里为了方便,近仅仅修改提交记录,也能达到一样的效果:
然后我们再来推送试一下:
1 | git push -u origin master |
发现它报错啦,这种情况怎么处理?我们后边再说。
4. 强制推送
上边我们分析了一些问题,就是推送失败的情况,其实很多时候都会这样,我们该怎么办?
4.1 命令说明
我们可以加上-f(--force)
参数:
1 | git push --force -u <remote_name> <branch_name> # 将本地仓库文件上传到远程仓库分支 |
这个命令会强制推送本地的所有提交记录到远程,就像给远程仓库的提交记录清空,然后重新推送了一样。
4.2 使用实例
我们加上--force
参数再试一下:
1 | git push --force -u origin master |
会发现强制推送成功,这个时候再看GitHub远程仓库的话没回发现master分支的提交记录与本地完全一样啦。
5. 删除远程分支
额,在手册上看到的,但从来没遇到过使用的情况,这里也学习一下吧。
5.1 命令说明
假设我们已经通过远程分支做完所有的工作了——也就是说我们和我们的协作者已经完成了一个特性, 并且将其合并到了远程仓库的 master
分支(或任何其他稳定代码分支)。 可以运行带有 --delete
选项的 git push
命令来删除一个远程分支。 我们可以通过以下命令在本地删除远程仓库的某一分支:
1 | git push origin --delete <remote_branch_name> |
基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。
5.2 使用实例
我们在刚才的仓库的基础上删除dev分支:
1 | git push origin --delete dev |
我们来看一下远程仓库:
发现我们的远程仓库中的dev分支消失了,那完全消失了吗?其实没有,如果我们没有从我们的本地仓库删除这个分支,并且我们有推送到 GitHub 的权限,那我们可以通过再次推送它而在 Github 上恢复它。
六、从远程仓库拉取代码
1. 概述
拉取就是将远程仓库的更改同步到本地仓库。
1.1 命令汇总
我们可以在这里看到相关的命令说明:Git - git-pull Documentation (git-scm.com)
1 | git pull [<options>] [<repository> [<refspec>...]] |
1.2 仓库准备
我们再克隆一份测试仓库:
1 | git clone git@github.com:sumumm/git-test.git git-pull-test |
然后我们就得到了一份与远程仓库一模一样的本地仓库,我们进入刚的仓库在master分支做一次提交,修改完后如下所示:
我们将该动推送到远程仓库:
1 | git push -u origin master |
我们来看一下远程仓库是否已经有了更新:
2. 更新本地仓库
2.1 命令说明
我们执行以下命令可以更新本地仓库:
1 | git pull <remote_name> <远程分支名> # 从远程仓库更新本地仓库版本,远程分支与本地当前分支合并 |
这个时候会将远程分支强行合并到本地当前所处的分支,此时可能会有冲突出现,解决后提交即可。
2.2 使用实例
我们回到最开始的测试仓库remote-branch,为了演示冲突,我们将远程仓库合并到本地的dev分支。我们查看当前仓库dev分支的提交:
然后我们执行以下命令,拉取master分支:
1 | git pull origin master |
发现,出现了报错,我们看一下文件:
原来是发生了冲突,我们解决一下冲突,然后提交一次,再查看提交记录:
现在我们切换到master分支,拉取一下master分支看看:
七、跟踪分支
1. 概述
从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull
,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。
当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master
的 master
分支。 然而,如果我们愿意的话可以设置其他的跟踪分支,或是一个在其他远程仓库上的跟踪分支,又或者不跟踪 master
分支。
2. 切换分支
2.1 命令说明
其实我们clone仓库的时候,会自动创建跟踪分支,我们通过git checkout
命令就可以在本地创建与远程仓库一模一样的分支,并且建立跟踪关系
1 | git checkout -b <local_branch_name> <remote_name>/<remote_branch_name> |
2.2 使用实例
我们来看一下,这里以hexo框架(hexojs/hexo: A fast, simple & powerful blog framework, powered by Node.js. (github.com))为例。我们将其克隆到本地,并查看克隆后的分支情况:
1 | git clone git@github.com:hexojs/hexo.git |
会发现只有一条分支,我们知道hexo框架是有很多分支的:
我们以这里的4.2.1分支为例,我们直接切换:
1 | git checkout -b 4.2.1 origin/4.2.1 |
3. 查看设置的跟踪分支
3.1 命令说明
如果想要查看设置的所有跟踪分支,可以使用 git branch
的 -vv
选项。 这会将所有的本地分支列出来并且包含更多的信息,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有。
1 | git branch -vv |
3.2 使用实例
我们直接在刚才的hexo本地仓库试一下:
1 | git branch -vv |