Git之旅(15):远程仓库(二)

  • A+
所属分类:Git  运维技术

  

博主会将与Git有关的知识点总结到"通俗易懂Git入门系列"文章中,如果你对Git不是特别了解,请按照顺序阅读"Git系列",以便站在前文的基础上理解新的知识点。

 

前文中,我们初步的认识了远程仓库,并且了解了一些相关的基本操作,这篇文章我们继续聊。

 

我们已经知道,当我们需要多人协作时,可以利用远程仓库交换代码,如果你创建的远程仓库是私有仓库,则只有仓库的成员才能对仓库中的代码进行操作,那么,我们就从"为项目添加成员"这个话题开始吧。

 

我们先来看看为仓库添加成员的具体操作步骤,仍然使用前文中创建的github私有仓库为例,现在我有两个github账号,两个账号分别是zsythink和zhushuangyin,我用这两个账号模拟仓库的管理员和项目成员,zsythink是仓库的创建者,也就是默认的管理员,zhushuangyin是另一个测试账号,此账号充当项目成员的角色,当然,zsythink也是项目成员之一,只是权限是最高的。

 

登录zsythink账户,打开上次创建的github仓库,如下图位置

Git之旅(15):远程仓库(二)   

进入项目后,如下图,

第1步:点击Settings菜单

第2步:点击Manager access菜单

第3步:点击 invite a collaborator 按钮即可邀请成员

从下图可以看出,当前仓库还没有任何成员

Git之旅(15):远程仓库(二)

点击上图的邀请成员按钮后,会提示你搜索对应成员的github账号,输入成员的github账号进行搜索,会出现对应的搜索列表,如下图所示,此处输入zhushuangyin,点击对应的账号,会出现一个绿色的按钮,提示添加对应账号到当前的仓库中,点击对应的绿色按钮添加账号即可。

Git之旅(15):远程仓库(二)

 

完成上述操作后,页面会自动跳转到 Settings菜单--Manager access菜单中,会看到如下图所示的状态

Git之旅(15):远程仓库(二)

可以看到,我们已经邀请了zhushaungyin成为项目的成员,当前的状态是等待zhushuangyin的响应,也就是说,仓库管理员已经向zhushuangyin账户对应的用户发送了邀请,但是zhushuangyin还没有同意邀请。

 

现在,我们将角色转换为zhushuangyin用户,zhushuangyin用户的注册邮箱会收到一封邀请邮件,也就是刚才zsythink用户发送的邀请请求,邮件内容如下:

Git之旅(15):远程仓库(二)

可以看到,邮件的大致内容就是zsythink用户邀请你成为zsythink/test仓库的成员,你可以选择接受或者拒绝,我们点击邮件中的绿色按钮查看邀约,邀约内容如下图

Git之旅(15):远程仓库(二)

点击上图的接受邀约的按钮,即可成为zsythink/test项目中的一员。

 

此时,我们再把视角切换回zsythink,再次回到 Settings菜单--Manager access菜单中,如下图所示,可以看到zhushuangyin用户已经变成了仓库的成员。

如果你想要的邀请更多的成员,只要再次点击下图中的"Invite a collaborator"按钮,然后重复上述步骤即可。

Git之旅(15):远程仓库(二)

 

目前,zsythink用户和zhushuangyin用户均可对项目中的代码进行操作了。

 

当然,zhushuangyin用户也需要将自己的公钥配置到自己的github账户中,具体的操作前文已经描述过了,此处不再赘述。为了方便操作,我启动了一台Linux虚拟机,并将root用户的公钥放在了zhushuangyin账户的github账户中,也就是说,目前我在windows中的操作代表zsythink用户,在linux中的操作zhushuangyin用户,以便模拟出多人进行操作时的场景。

 

我们还是以实际的场景为例,以便更好的将命令融入到实际的应用中。

 

场景一

场景描述:zhushuangyin用户需要基于master分支开发一个新模块,zhushaungyin用户在本地开发完成,并且测试没有问题以后,需要将最新的代码上传到远程仓库中,以便zsythink用户能够获取到最新的、包含新模块的代码。

 

我们一起来看一下具体的操作步骤。

 

步骤1

由于需要基于master分支开发新模块,所以zhushaungyin用户需要获取到最新的master分支的代码,通常的做法是从远程仓库中拉取远程master分支的代码到本地,以便将本地的master分支的代码更新到最新(这个方法我们稍后再说),由于我们刚刚才将zhushunagyin用户添加为仓库的成员,所以zhushuangyin用户可以直接通过clone命令获取到最新的仓库代码,现在,我们就站在zhushuangyin的视角上进行操作。

操作如上,zhushuangyin先克隆了仓库,然后进入仓库目录,使用"git branch -avv"命令查看了所有的分支,可以看到,当前处于master分支中,除了master分支,还有很多其他分支,比如m1分支以及new分支,前文中说过,

以remotes/origin开头的分支代表了origin远程仓库中的分支,这些分支实际存放在你的本地仓库中,但是这些分支代表了远程仓库中的分支,你可以把这些分支理解成远程分支在本地的大使,本地通过大使与远程分支进行实际的交互,大使很多时候也需要做一些中转的工作,先不用纠结这些,随着使用的加深,你会有自己的理解,如果我们现在检出到m1分支,本地的m1分支会自动将自己的上游分支设置为origin/m1,也就是说,如果此时检出到m1分支,本地的m1分支和远程的m1分支中的内容是一样的。

 

步骤2

我们已经通过克隆操作,获取到了远程仓库中的最新的代码,现在我们要做的就是,基于master分支,创建新的分支,因为之前说过,zhushuangyin用户需要基于master分支开发新的模块,为了不影响现有的稳定代码,我们通常会创建一个新的分支来完成新的开发工作,所以,zhushuangyin需要基于master分支创建新的分支,当然,如果需要基于m1分支开发新模块,你也可以先检出到m1分支,然后基于m1分支创建新分支,此处我们还是按照场景中的描述来操作,我们现在就处于master分支中,可以直接创建新分支,命令如下:

创建新分支后,我们再创建一些文件,来模拟新的开发工作

如上述操作所示,我们创建了一些文件,模拟新的开发工作,然后在本地的testmodule1分支中创建了新的提交

现在,我们就可以将本地的testmodule1分支推送到远程仓库了,这样做一是可以在远程仓库中有一份代码的备份,二是能够让其他用户通过远程仓库获取到最新的包含新模块的代码,当然,在实际的工作中,开发一个模块不可能这么容易,推送到远程仓库也不代表开发工作完成了,我们可以持续开发,持续的推送,以便实现开发和交付代码的目的,那么现在我们就执行以下推送命令,如下

当前我们处于testmodule1分支,执行上述命令后,本地的testmodule1分支会被推送到远程仓库中,并且本地的testmodule1分支的上游分支会设置为origin远程仓库中testmodule1分支。

再次回到github页面回到远程仓库,即可看到对应的新分支。

 

步骤3

刚才的第1步操作和第2步操作都是在zhushuangyin用户的视角下完成的,现在我们把角色切换到zsythink用户,zsythink用户现在需要获取到zhushuangyin用户创建的新分支,以便获取到最新的、包含新模块的代码,对于zsythink用户来说,远程仓库的大多数代码已经存在于本地上了,只不过这些本地的代码并不是最新的代码,zsythink用户现在需要做的就是获取最新代码到本地,以便查看或者操作,那么具体需要怎样操作呢?命令如下

注:目前的视角是zsythink用户,即所有操作在windows中进行。

首先,查看一下当前仓库下的分支,如下

可以看到,当前处于m1分支中,当前仓库中还没有testmodule1分支,因为我们还没有从远程仓库拉取最新的代码,现在,我们执行如下命令获取一下远程仓库的最新的代码

如上所示,我们执行"git fetch"命令,"git fetch"命令表示获取远程仓库中的最新代码。

仔细观察上述反馈信息,可以发现,执行"git fetch"命令后,有一个新分支被获取到了,这个新分支的名字就是testmodule1, 这个分支其实就是远程origin仓库中的testmodule1分支。

执行上述命令后,我们再次查看当前仓库的所有分支,如下:

如上所示,我们已经可以看到"remotes/origin/testmodule1"分支了,也就是说,远程仓库中的testmodule1分支的"代表"已经到达本地了,再换句话说就是,真正的存在于github中的"testmodule1"分支已经同步到了本地仓库中的 "remotes/origin/testmodule1"分支中,我们随时可以在本地检出testmodule1分支,以便在本地仓库中进行操作或者查看,我们现在就检出吧,命令如下:

如上所示,在本地仓库中检出testmodule1分支后,即可看到对应的目录,正是zhushuangyin用户创建的目录和文件,细心如你肯定已经发现了,由于我们刚刚获取到了最新的代码,而且检出testmodule1分支后还没有创建任何新提交到本地的testmodule1分支中,所以本地的"testmodule1"分支和代表远程分支的"remotes/origin/testmodule1"分支的哈希码是相同的,都是1422130

 

说了这么多,其实我们只用了一个新命令,这个命令就是"git fetch"命令,其他的命令在前文中都已经解释过,只有"git fetch"命令是这篇文章中新出现的命令,这个命令在上述场景中的作用就是拉取了最新的远程代码到本次仓库中,但是由于远程仓库中只有testmodule1分支是新内容,所以我们从"git fetch"命令的返回信息中只能看到testmodule1分支的更新信息,如果有其他用户更新了其他分支并推送到了远程仓库中,那么我们执行"git fetch"命令后,也能看到所有更新的分支的信息。

 

上述场景其实非常简单,我们通过这个简单的场景,学到了一个基础的命令,这个命令就是"git fetch",通过它我们可以把远程仓库的最新代码同步到本地中,如果说的更加详细一点,就是将真正存在于远程服务器中的分支中的新内容同步到本地的"代表"分支中,以便用户再通过"代表"分支进行进一步的操作。如果你没有明白,不用纠结,继续向下看。

 
 

   

场景二

场景描述:场景二是建立在场景一的基础上的,zhushuangyin用户更新了testmodule1分支以及其他一些分支中的代码,zsythink用户现在想要在自己的本地仓库中看到最新的代码该怎么办呢?注意,此场景中只有zhushuangyin用户更新了代码,zsythink没有做任何操作,即使在本地仓库中,也没有进行任何操作,说明此注意事项只是为了让大家不要考虑太多,以免我们自己把自己绕进去。

 

其实仔细想想,场景二和场景一不是一样的吗?都是一个用户产生新内容,另一个用户获取新内容,没错,两个场景本质上是一样的,只不过我们可以通过不同的命令,去实现我们的目的,先不用多说,来看看具体的命令吧。

 

步骤1

zhushuangyin用户操作如下

如上述命令所示,zhushaungyin用户在本地更新了testmodule1分支中的tmfile1文件,然后创建了提交,提交的哈希码为1d4ce3c,然后zhushuangyin用户将最新的提交1d4ce3c推送到了远程仓库中。

现在,zhushuangyin用户来修改一下其他分支中的代码,也推送到远程仓库中,命令如下:

如上所示,zhushaungyin用户修改了m1分支中的testfile1文件,本地创建提交后,将更新推送到了远程仓库中。

目前,我们模拟zhushuangyin用户的操作已经完成了。

 

步骤2

现在我们将角色转换成zsythink用户,zsythink用户的操作如下。

zsythink现在需要获取到远程仓库中的最新的代码,于是zsythink用户先执行了"git fetch"命令,如下

可以看到,fetch后有两个分支被更新了,一个testmodule1 分支,一个m1分支,分支更新后,我们能够直接看到更新的内容吗,我们一起来试试看

什么情况?zhushuangyin用户明明在"testmodule1/tmfile1"文件中加入了一行文本"2",这边更新后为什么没有看到呢?别着急,我们先来执行"git branch -avv"命令,就会发现一些端倪,执行如下:

从上述命令可以看出,本地的testmodule1分支的当前提交ID为1422130,而代表远程分支的"remotes/origin/testmodule1"分支的提交ID为1d4ce3c,而1d4ce3c正是zhushaungyin用户推送到远程仓库中的提交,看到此处你肯定已经明白了,"git fetch"命令只会将真正的远程分支中的更新同步到本地的"代表"分支中,并不会将更新一并同步到真正的"纯"本地分支中,这样描述非常不专业,但是方便理解,我觉得你肯定明白我要表达的意思了吧,那么我们怎样才能把代表分支中的更新同步到本地工作区中的分支中呢?其实很简单,我们只需要执行一下合并操作就行了,命令如下:

命令如上,当前我们就处于testmodule1分支中,当我们执行"git merge origin/testmodule1"命令后,相当于将 "remotes/origin/testmodule1"分支中的内容合并到了"testmodule1"分支中,所以,对应的更新也一并进入到了"testmodule1"分支中。而且,从上述提示信息可以看出,这次合并操作使用了Fast-forward模式进行了合并,所以没有提示我们输入注释信息,因为没有创建新的提交,所以并不用填写注释,如果你忘记了什么是Fast-forward模式,请回顾前文。

 

你可能会问,为什么场景一中就没有执行merge操作,而是fetch后直接checkout就可以呢?那是因为,在场景一中还从来没有检出过testmodule1分支,所以fetch后的检出操作就是第一次检出操作,检出后的本地分支自然和"remotes/origin/testmodule1"分支是一样的,所以不用再次执行merge操作,而在场景二中,之前就已经检出过testmodule1分支,所以fetch以后,检出过的testmodule1分支与fetch后的"remotes/origin/testmodule1"分支是不一样的(因为远程仓库有更新,所以不一样,如果远程仓库没有更新,即使fetch后也是一样的),所以需要在fetch后执行merge操作,以便更新同步到之前检出过的testmodule1分支中。

 

同样的道理,由于刚才fetch时,还显示了m1分支的更新,我们现在切换回m1分支,再来熟悉一遍操作。

可以看到,当我们检出到m1分支后,git的提示信息中显示,你的分支比 'origin/m1' 分支落后1个提交,也就是说,本地检出的m1分支比远程仓库的m1分支落后一个提交,git之所以知道本地的m1分支比远程仓库的m1落后一个提交,就是因为fetch命令已经将远程的信息同步到了"remotes/origin/testmodule1"分支中,所以,git可以知道本地的分支是落后的,而且,从上述提示信息可以看出,当前的情况下,可以使用fast-forwarded模式进行合并,因为zsythink用户并没有对本地的m1分支创建新提交,只有远程分支中存在新的提交,这种情况下可以满足ff模式的条件,所以可以使用ff模式进行合并。

此刻,执行merge命令即可,操作如下:

其实,上述fetch+merge的操作步骤可以通过一条命令完成,这条命令就是"git pull"命令,也就是说,"git pull"命令会完成"git fetch"命令和"git merge"命令两条命令的工作,为了实际演示"git pull"命令,我们重新来模拟一遍上述场景,即A用户更新,B用户不进行操作,只在A用户更新完的情况下拉取代码到本地,操作如下:

由于当前处于zsythink用户下,我们就用zsythink用户来进行更新操作吧,zsythink用户操作如下

如上述操作所示,zsythink用户分别在m1分支和testmodule1分支中创建了新提交,并且使用"git push --all"命令一次性将所有分支的更新推送到了远程仓库中(注:我的windows和linux中安装的git都是2.x版本的git,所以一次性推送所有满足条件的分支需要加上--all选项)

 

上述操作完成后,我们将视角切换到zhushuangyin用户,来执行一下"pull"命令,以便测试此命令的拉取效果,在执行pull命令之前,我们先来看一下当前仓库的状态,如下:

如上述命令所示,当前我们处于m1分支中,查看testfile1文件的内容,只有两行,当前状态下m1分支和"remotes/origin/m1"分支的哈希码都是08e67c2,现在,我们来执行pull命令,在执行命令之前,先确定你已经处于m1分支中,由于我们当前就处于m1分支,所以可以直接执行如下命令:

如上所示,当执行"git pull origin m1"命令后,更新直接同步到了testfile1 文件中,再次执行"git branch -avv"命令查看分支信息,可以发现,m1分支和"remotes/origin/m1"分支的哈希码都变成了c94bdfe ,效果很明显,pull操作一次性的完成了fetch操作和merge操作的工作,"git pull origin m1"命令表示拉取origin远程仓库中的m1分支到当前分支,由于我们当前就处于m1分支,所以,执行"git pull origin m1"命令就相当于直接将本地的m1的分支更新到最新。

同理,我们可以用同样的方法对testmodule1分支执行pull操作,先checkout到testmodule1分支,然后执行pull命令:操作如下

没错,当你想要pull某个分支时,一定要先切换到对应的分支,因为"git pull"命令的默认动作就是pull指定的远程分支到当前分支,搞明白这一点,再来看其他"pull"命令就方便理解了,我们来看看如下命令是什么意思:

我们来猜猜上述命令是什么意思···

上述命令的意思是,将远程的Abr分支pull到本地的Abr分支,同时,将远程的Abr分支pull到本地的当前所在分支,如果我们当前就处于Abr分支,那么上述命令的作用就是将远程Abr分支的最新更新拉取到本地Abr分支,如果我们当前处于非Abr分支,那么上述命令就会将远程Abr分支更新到本地Abr分支的同时,也将远程Abr分支pull到本地分支上,由于pull命令本身就有merge的操作,所以当合并的分支名不同时,出现冲突的概率会比较大,我们先不考虑冲突的情况,后文中自然会遇到,当前文章我们刻意的避免了冲突情况的发生,以便从简单的场景理解这些命令的本质用法。

 

我们再来猜猜如下命令是什么意思···

没错,这次我们什么选项都没有加,那么执行上述命令的作用是什么呢?

上述命令的作用就是,pull当前分支的同名上游分支,并且将其他分支的同名上游分支的更新fetch到本地,这样说不容易理解,我们举个例子,比如,当前仓库有A、B、C三个分支,这3个分支都已经checkout到本地的仓库当中了,假设当前我们处于本地的A分支中,那么,当我们执行"git pull"命令时,会有几种情况

 

情况1:当我们处于A分支,A分支的同名上游分支没有更新,但是B分支或者C分支的同名上游分支有更新,执行"git pull"命令,你会看到git对B分支或者C分支执行了fetch操作,但是只是fetch,没有对应的自动merge操作,当然,如果B分支和C分支的同名上游分支都有更新,就都会fetch。

 

情况2:当我们处于A分支,A分支的同名上游分支有更新,B分支或者C分支的同名上游分支也有更新,执行"git pull"命令,你会看到git对A分支执行了pull操作(即fetch+merge),对B分支或C分支执行了fetch操作,当然,如果B分支和C分支的同名上游分支都有更新,就都会fetch。

 

总结一下就是,当本地分支与上游分支同名时,"git pull"命令会对当前分支执行pull操作,对其他分支执行fetch操作,具体的差异主要取决于对应的远程分支有没有更新。

具体的测试此处就不再赘述了,快动手试试吧。

 

 

小结

我们来总结一下这边文章中提到的命令的用法

此命令表示当本地分支与上游分支同名时,push所有分支的更新到对应的远程分支。

 

此命令表示获取远程仓库的更新到本地,但是不会更新本地分支中的代码。

 

此命令表示将remote仓库的A分支pull到本地当前所在分支,如果你想要pull到本地的A分支,需要先checkout到本地A分支中。

 

此命令表示将remote仓库的A分支pull到本地的B分支,在成功的将远程A分支pull到本地B分支后(如果远程A到本地B的pull操作失败了,后面的操作不会执行),再将远程A分支pull到本地的当前所在的分支。

 

此命令表示当本地分支与上游分支同名时,对当前分支执行pull操作,对其他分支执行fetch操作,具体的差异主要取决于对应的远程分支有没有更新。

 

好了,这边文章就先总结到这里,希望能够对你有所帮助。

 

weinxin
我的微信公众号
关注"实用运维笔记"微信公众号,当博客中有新文章时,可第一时间得知哦~
朱双印

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:6   其中:访客  4   博主  2

    • avatar 猜猜 0

      哈哈, 居然收到了你的blog, 猜猜我是谁

      • avatar bbcking5 0

        gitlab中的cicd会讲到吗,期待新文章!嘿嘿😁

        • avatar 27808080785 1

          您终于更新了 我以为你转行了呐

          • avatar tony 1

            你终于更新了,大神,感谢大神。我是tony,我是总监 :mrgreen:

              • avatar 朱双印 Admin

                @tony 总监你在哪里,我要找你免费造型~hhhhh~