Git 沙盒模拟实战(远程篇)

Git 沙盒模拟实战(远程篇)

>---基础篇html

远程仓库

远程仓库并不复杂, 在现在的云计算盛行的世界很容易把远程仓库想象成一个富有魔力的东西, 但实际上它们只是你的仓库在另个一台计算机上的拷贝。你能够经过因特网与这台计算机通讯 —— 也就是增长或是获取提交记录git

话虽如此, 远程仓库却有一系列强大的特性github

  • 首先也是最重要的的点, 远程仓库是一个强大的备份。本地仓库也有恢复文件到指定版本的能力, 但全部的信息都是保存在本地的。有了远程仓库之后,即便丢失了本地全部数据, 你仍能够经过远程仓库拿回你丢失的数据。
  • 还有就是, 远程让代码社交化了! 既然你的项目被托管到别的地方了, 你的朋友能够更容易地为你的项目作贡献(或者拉取最新的变动)

如今用网站来对远程仓库进行可视化操做变得愈加流行了(像 Github ), 但远程仓库永远是这些工具的顶梁柱, 所以理解其概念很是的重要!shell


使用clone命令将远程仓库中的项目克隆到本地。ide

$ git clone [remoteName]

remoteName : 远程仓库的地址(名称)工具

Git Fetch

Git 远程仓库至关的操做实际能够概括为两点:向远程仓库传输数据以及从远程仓库获取数据。既然咱们能与远程仓库同步,那么就能够分享任何能被 Git 管理的更新(所以能够分享代码、文件、想法、情书等等)。学习

本节课咱们将学习如何从远程仓库获取数据 —— 命令如其名,它就是 git fetch测试

你会看到当咱们从远程仓库获取数据时, 远程分支也会更新以反映最新的远程仓库。在上一了咱们已经说起过这一点了。fetch

image-20210119114118304

虚线为远程仓库,实线为本地仓库。网站

$ git fetch

image-20210119114211342

git fetch 作了些什么

git fetch 完成了仅有的可是很重要的两步:

  • 从远程仓库下载本地仓库中缺失的提交记录
  • 更新远程分支指针(如 o/master)

git fetch 实际上将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态。

若是你还记得上一节课程中咱们说过的,远程分支反映了远程仓库在你最后一次与它通讯时的状态,git fetch 就是你与远程仓库通讯的方式了!但愿我说的够明白了,你已经了解 git fetch 与远程分支之间的关系了吧。

git fetch 一般经过互联网(使用 http://git:// 协议) 与远程仓库通讯。

git fetch 不会作的事

git fetch不会改变你本地仓库的状态。它不会更新你的 master 分支,也不会修改你磁盘上的文件。

理解这一点很重要,由于许多开发人员误觉得执行了 git fetch 之后,他们本地仓库就与远程仓库同步了。它可能已经将进行这一操做所需的全部数据都下载了下来,可是并无修改你本地的文件。咱们在后面的课程中将会讲解能完成该操做的命令。

因此, 你能够将 git fetch 的理解为单纯的下载操做。

Git Pull

既然咱们已经知道了如何用 git fetch 获取远程的数据, 如今咱们学习如何将这些变化更新到咱们的工做当中。

其实有不少方法的 —— 当远程分支中有新的提交时,你能够像合并本地分支那样来合并远程分支。也就是说就是你能够执行如下命令:

  • git cherry-pick o/master
  • git rebase o/master
  • git merge o/master
  • 等等

实际上,因为先抓取更新再合并到本地分支这个流程很经常使用,所以 Git 提供了一个专门的命令来完成这两个操做。它就是咱们要讲的 git pull

image-20210120104624095

$ git pull

image-20210120104640123

git pull 就是 git fetchgit merge <just-fetched-branch> 的缩写!

模拟团队合做

这里有一件棘手的事 —— 为了接下来的课程, 咱们须要先教你如何制造远程仓库的变动。

这意味着,咱们须要“伪装”你的同事、朋友、合做伙伴更新了远程仓库,有多是某个特定的分支,或是几个提交记录。

为了作到这点,咱们引入一个自造命令 git fakeTeamwork!它的名称已经说明了一切,先看演示..

image-20210120104701712

$ git clone

local branch "master" set to track remote branch "o/master"

$ git commit -m "c2"

$ git commit -m "c3"

$ git push

$ git checkout c1

$ git commit -m "c4"

警告!如今是分离 HEAD 状态

$ git checkout master

$ git merge c4

image-20210120104712094

Git Push

OK,咱们已经学过了如何从远程仓库获取更新并合并到本地的分支当中。这很是棒……可是我如何与你们分享个人成果呢?

嗯,上传本身分享内容与下载他人的分享恰好相反,那与 git pull 相反的命令是什么呢?git push

git push 负责将你的变动上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦 git push 完成, 你的朋友们就能够从这个远程仓库下载你分享的成果了!

你能够将 git push 想象成发布你成果的命令。它有许多应用技巧,稍后咱们会了解到,可是我们仍是先从基础的开始吧……

注意 —— git push 不带任何参数时的行为与 Git 的一个名为 push.default 的配置有关。它的默认值取决于你正使用的 Git 的版本,可是在教程中咱们使用的是 upstream。 这没什么太大的影响,可是在你的项目中进行推送以前,最好检查一下这个配置。

image-20210120104724490

$ git push

过去了, 远程仓库接收了 C2,远程仓库中的 master 分支也被更新到指向 C2 了,咱们的远程分支 (``o/master`) 也一样被更新了。全部的分支都同步了!

image-20210120104748698

冲突处理

image-20210120104759464

git push 失败是由于你最新提交的 C3 基于远程分支中的 C1。而远程仓库中该分支已经更新到 C2 了,因此 Git 拒绝了你的推送请求。

$ git fakeTeamwork

$ git fetch

$ git commit -m "c3"

$ git rebase c2

$ git push

image-20210120104831530

git fetch 更新了本地仓库中的远程分支,而后用 rebase 将咱们的工做移动到最新的提交记录下,最后再用 git push 推送到远程仓库。

origin 和它的周边

合并特性分支

既然你应该很熟悉 fetch、``pullpush` 了,如今咱们要经过一个新的工做流来测试你的这些技能。

在大型项目中开发人员一般会在(从 master 上分出来的)特性分支上工做,工做完成后只作一次集成。这跟前面课程的描述很相像(把 side 分支推送到远程仓库),不过本节咱们会深刻一些.

可是有些开发人员只在 master 上作 pushpull —— 这样的话 master 老是最新的,始终与远程分支 (o/master) 保持一致。

对于接下来这个工做流,咱们集成了两个步骤:

  • 将特性分支集成到 master
  • 推送并更新远程分支

image-20210120104841787

$ git pull -rebase

$ git push

执行了两个命令:

  • 将咱们的工做 rebase 到远程分支的最新提交记录
  • 向远程仓库推送咱们的工做

image-20210120104850824

fetch远程仓库的更新到本地仓库,进行rebase合并,最后push到远程仓库中。

image-20210120104910537

$ git fetch

$ git rebase o/master side1

$ git rebase side1 side2

$ git rebase side2 side3

$ git rebase side3 master

$ git push

image-20210120104953469

为何不用 merge 呢?

为了 push 新变动到远程仓库,你要作的就是包含远程仓库中最新变动。意思就是只要你的本地分支包含了远程分支(如 o/master)中的最新变动就能够了,至于具体是用 rebase 仍是 merge,并无限制。

那么既然没有规定限制,为什么前面几节都在着重于 rebase 呢?为何在操做远程分支时不喜欢用 merge 呢?

在开发社区里,有许多关于 mergerebase 的讨论。如下是关于 rebase 的优缺点:

优势:

  • Rebase 使你的提交树变得很干净, 全部的提交都在一条线上

缺点:

  • Rebase 修改了提交树的历史

好比, 提交 C1 能够被 rebaseC3 以后。这看起来 C1 中的工做是在 C3 以后进行的,但其实是在 C3 以前。

一些开发人员喜欢保留提交历史,所以更偏心 merge。而其余人(好比我本身)可能更喜欢干净的提交树,因而偏心 rebase。仁者见仁,智者见智。

image-20210120105007891

$ git fetch

$ git checkout side1

$ git merge o/master

$ git merge side2

$ git merge side3

$ git checkout master

$ git merge side1

$ git push

image-20210120105017867

远程跟踪分支

在前几节课程中有件事儿挺神奇的,Git 好像知道 mastero/master 是相关的。固然这些分支的名字是类似的,可能会让你以为是依此将远程分支 master 和本地的 master 分支进行了关联。这种关联在如下两种状况下能够清楚地获得展现:

  • pull 操做时, 提交记录会被先下载到 o/master 上,以后再合并到本地的 master 分支。隐含的合并目标由这个关联肯定的。
  • push 操做时, 咱们把工做从 master 推到远程仓库中的 master 分支(同时会更新远程分支 o/master) 。这个推送的目的地也是由这种关联肯定的!

远程跟踪

直接了当地讲,mastero/master 的关联关系就是由分支的“remote tracking”属性决定的。master 被设定为跟踪 o/master —— 这意味着为 master 分支指定了推送的目的地以及拉取后合并的目标。

你可能想知道 master 分支上这个属性是怎么被设定的,你并无用任何命令指定过这个属性呀!好吧, 当你克隆仓库的时候, Git 就自动帮你把这个属性设置好了。

当你克隆时, Git 会为远程仓库中的每一个分支在本地仓库中建立一个远程分支(好比 o/master)。而后再建立一个跟踪远程仓库中活动分支的本地分支,默认状况下这个本地分支会被命名为 master

克隆完成后,你会获得一个本地分支(若是没有这个本地分支的话,你的目录就是“空白”的),可是能够查看远程仓库中全部的分支(若是你好奇心很强的话)。这样作对于本地仓库和远程仓库来讲,都是最佳选择。

这也解释了为何会在克隆的时候会看到下面的输出:

local branch "master" set to track remote branch "o/master"

我能本身指定这个属性吗?

固然能够啦!你可让任意分支跟踪 o/master, 而后该分支会像 master 分支同样获得隐含的 push 目的地以及 merge 的目标。 这意味着你能够在分支 totallyNotMaster 上执行 git push,将工做推送到远程仓库的 master 分支上。

有两种方法设置这个属性,第一种就是经过远程分支检出一个新的分支,执行:

git checkout -b totallyNotMaster o/master

就能够建立一个名为 totallyNotMaster 的分支,它跟踪远程分支 o/master


检出 master 分支的状况下将工做推送到的远程仓库中的 master 分支上。

image-20210120105052237

$ git branch side

$ git checkout side

$ git commit -m "c3"

$ git fetch

$ git rebase c2 side

$ git push

Git Push 的参数

很好! 既然你知道了远程跟踪分支,咱们能够开始揭开 git pushfetchpull 的神秘面纱了。咱们会逐个介绍这几个命令,它们在理念上是很是类似的。

首先来看 git push。在远程跟踪课程中,你已经学到了 Git 是经过当前检出分支的属性来肯定远程仓库以及要 push 的目的地的。这是未指定参数时的行为,咱们能够为 push 指定参数,语法是:

git push <remote> <place>

<place> 参数是什么意思呢?咱们稍后会深刻其中的细节, 先看看例子, 这个命令是:

git push origin master

把这个命令翻译过来就是:

切到本地仓库中的“master”分支,获取全部的提交,再到远程仓库“origin”中找到“master”分支,将远程仓库中没有的提交记录都添加上去,搞定以后告诉我。

咱们经过place参数来告诉 Git 提交记录来自于 master, 要推送到远程仓库中的 master。它实际就是要同步的两个仓库的位置。

须要注意的是,由于咱们经过指定参数告诉了 Git 全部它须要的信息, 因此它就忽略了咱们所检出的分支的属性!

image-20210120105126285

$ git push origin master

$ git push origin foo

image-20210120105134365

place 参数详解

还记得以前课程说的吧,当为 git push 指定 place 参数为 master 时,咱们同时指定了提交记录的来源和去向。

你可能想问 —— 若是来源和去向分支的名称不一样呢?好比你想把本地的 foo 分支推送到远程仓库中的 bar 分支。

哎,很遗憾 Git 作不到…… 开个玩笑,别当真!固然是能够的啦 😃 Git 拥有超强的灵活性(有点过于灵活了)

接下来我们看看是怎么作的……

要同时为源和目的地指定 <place> 的话,只须要用冒号 : 将两者连起来就能够了:

git push origin <source>:<destination>

这个参数实际的值是个 refspecrefspec 是一个自造的词,意思是 Git 能识别的位置(好比分支 foo 或者 HEAD~1

一旦你指定了独立的来源和目的地,就能够组织出言简意赅的远程操做命令了,让咱们看看演示!

image-20210120105142621

$ git push origin foo^:master

image-20210120105152060

若是你要推送到的目的分支不存在会怎么样呢?没问题!Git 会在远程仓库中根据你提供的名称帮你建立这个分支!

image-20210120105201822

$ git push origin master^:foo

$ git push origin foo:master

image-20210120105210579

Git fetch 的参数

咱们刚学习了 git push 的参数,很酷的 <place> 参数,还有用冒号分隔的 refspecs<source>:<destination>)。 这些参数能够用于 git fetch 吗?

你猜中了!git fetch 的参数和 git push 极其类似。他们的概念是相同的,只是方向相反罢了(由于如今你是下载,而非上传)

让咱们逐个讨论下这些概念……

place 参数

若是你像以下命令这样为 git fetch 设置 place 的话:

$ git fetch origin foo

Git 会到远程仓库的 foo 分支上,而后获取全部本地不存在的提交,放到本地的 o/foo 上。

来看个例子(仍是前面的例子,只是命令不一样了)

咱们只下载了远程仓库中 foo 分支中的最新提交记录,并更新了 o/foo

你可能会好奇 —— 为什么 Git 会将新提交放到 o/foo 而不是放到我本地的 foo 分支呢?以前不是说这样的 place 参数就是同时应用于本地和远程的位置吗?

好吧, 本例中 Git 作了一些特殊处理,由于你可能在 foo 分支上的工做还未完成,你也不想弄乱它。还记得在 git fetch 课程里咱们讲到的吗 —— 它不会更新你的本地的非远程分支, 只是下载提交记录(这样, 你就能够对远程分支进行检查或者合并了)。

“若是咱们指定 <source>:<destination> 会发生什么呢?”

若是你以为直接更新本地分支很爽,那你就用冒号分隔的 refspec 吧。不过,你不能在当前检出的分支上干这个事,可是其它分支是能够的。

这里有一点是须要注意的 —— source 如今指的是远程仓库中的位置,而 <destination> 才是要放置提交的本地仓库的位置。它与 git push 恰好相反,这是能够讲的通的,由于咱们在往相反的方向传送数据。

理论上虽然行的通,但开发人员不多这么作。我在这里介绍它主要是为了从概念上说明 fetchpush 的类似性,只是方向相反罢了。


使用 fetch 时, 你必须指定source destination。 注意一下目标窗口, 由于提交对象的 ID 可能会变哦!

image-20210120105218686

$ git fetch origin master^1:foo

$ git fetch origin foo:master

$ git checkout foo

$ git merge master

image-20210120105227744

会让人挨揍的 source

Git 有两种关于 source 的用法是比较诡异的,即你能够在 git pushgit fetch 时不指定任何 source,方法就是仅保留冒号和 destination 部分,source 部分留空。

  • git push origin :side

    若是 pushsource 到远程仓库会如何呢?它会删除远程仓库中的分支!慎重使用,删除别人的远程分支可能会挨揍。

  • git fetch origin :bugFix

    若是 fetchsource 到本地,会在本地建立一个新分支。

Git pull 参数

既然你已经掌握关于 git fetchgit push 参数的方方面面了,关于 git pull 几乎没有什么能够讲的了 😃

由于 git pull 到头来就是 fetch 后跟 merge 的缩写。你能够理解为用一样的参数执行 git fetch,而后再 merge你所抓取到的提交记录。

还能够和其它更复杂的参数一块儿使用, 来看一些例子:

如下命令在 Git 中是等效的:

git pull origin foo 至关于:

$ git fetch origin foo
$ git merge o/foo

还有...

git pull origin bar~1:bugFix 至关于:

$ git fetch origin bar~1:bugFix
$ git merge bugFix

看到了? git pull 实际上就是 fetch + merge 的缩写, git pull 惟一关注的是提交最终合并到哪里(也就是为 git fetch 所提供的 destination 参数)。

经过指定 master 咱们更新了 o/master。而后将 o/master merge 到咱们的检出位置,不管咱们当前检出的位置(checkout的位置、HEAD所在位置)是哪。


须要下载一些提交,而后建立一些新分支,再合并这些分支到其它分支, 但这用不了几个命令。

image-20210120105251136

$ git pull origin bar:foo

$ git pull origin master:side

image-20210119160554842

内容来源:码云 --- Learn Git Branching(远程篇)

相关文章
相关标签/搜索