本章将详细介绍如何使用git push和git pull,以及远程仓库的一些知识。

远程仓库的用法

git clone

从技术上来讲,git clone命令在真实的环境下的作用是在本地创建一个远程仓库的拷贝。常用用法有: git clone [url] ,git clone [url] --branch [branch]等。

克隆远程分支时,我们的本地仓库里面会出现一个名为"origin/main"的分支(主要的远程仓库默认命名为"origin"),这种类型的分支叫作远程分支。切换到远程分支时,自动进入分离HEAD状态(也就是"origin/main"并不会进行更新),因为git不能直接在这些远程分支上进行更改,我们必须在别的地方完成你的工作,(更新了远程分支之后)再用远程分享成果。

git fetch

git远程仓库相当的操作实际可以归纳为两点:

  1. 向远程仓库传输数据
  2. 从远程仓库获取数据

git fetch用来从远程仓库获取数据。当我们从远程仓库获取数据时, 远程分支也会更新以反映最新的远程仓库。

下面是一个使用git fetch的实例。图中有一个远程仓库,它有两个本地仓库没有的提交。使用git fetch后,C2和C3被下载到了仓库,同时远程分支o/main也被更新,反映到了这一变化。

变化前变化后
git_tutorial_4_1git_tutorial_4_2

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

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

git fetch通常通过互联网(使用http://或git://协议)与远程仓库通信。

git fetch并不会改变你本地仓库的状态。它不会更新你的main分支,也不会修改你磁盘上的文件。我们可以将git fetch的理解为单纯的下载操作。

git pull

当远程分支中有新的提交时,我们可以像合并本地分支那样来合并远程分支。实际上,由于先抓取更新再合并到本地分支这个流程很常用,我们可以使用git pull来完成这两个操作。git pull也可以理解为是git fetchgit merge的缩写。下图产生的变化可以通过git pullgit fetchgit merge生成。

变化前变化后
git_tutorial_4_3git_tutorial_4_4

git push

git push负责将本地的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦git push完成, 其他人就可以从这个远程仓库下载新的提交成果(注:git push不带任何参数时的行为与git的一个名为push.default的配置有关。它的默认值取决于你正使用的git的版本)。

下图展示了使用git push后的变化。远程仓库接收了C2,远程仓库的main分支指向了C2,本地文件的远程分支(o/main)也同样进行了更新,即所有的分支都完成了同步。

变化前变化后
git_tutorial_4_5git_tutorial_4_6

处理偏移的提交

假如我们克隆了一个仓库,此时的提交是C1,当我们研发了新的功能准备提交时(记为C3),远程仓库的提交已经变成C2了,此时我们使用git push的时候就不能直接将C3直接提交到远程仓库中,因为远程仓库最新的提交是C2,而我们的提交C3是基于之前版本的C1实现的。我们需要先合并远程最新的代码,然后才能分享。比如下面的图,我们使用git push时,最新提交的C3基于远程分支中的C1,而远程仓库中该分支已经更新到C2了,所以git会拒绝推送请求。

git_tutorial_4_7

解决方法

使用git rebase

最直接的方法是通过git rebase调整工作。

下图是采用了git fetch; git rebase o/main; git push的变化: 使用git fetch会更新本地仓库中的远程分支,然后用 rebase 将我们的工作移动到最新的提交记录下,最后再用git push推送到远程仓库。

git_tutorial_4_8

使用git merge

使用git merge也可以进行解决。

下图是采用了git fetch; git merge o/main; git push的变化: 使用git fetch更新了本地仓库中的远程分支,然后合并了新变更到我们的本地分支(为了包含远程仓库的变更),最后用git push把工作推送到远程仓库。

git_tutorial_4_9

使用git pull

上面提到过git pullgit fetchgit merge的简写,git pull --rebasegit fetchgit rebase的简写。也就是说,使用git pull或者git pull --rebase就跟上面的结果是一样的。

远程服务器被拒绝

如果出现远程服务器被拒绝的情况,很可能是main被锁定了,需要一些Pull Request流程来合并修改。如果直接提交(commit)到本地main,然后试图推送(push)修改,你将会收到这样类似的信息: ![远程服务器拒绝] main -> main (TF402455: 不允许推送(push)这个分支; 你必须使用pull request来更新这个分支.)

出现这种情况的原因可能是远程服务器拒绝直接推送(push)提交到main,因为策略配置要求pull requests来提交更新。

应该按照流程,新建一个分支,推送(push)这个分支并申请pull request。如果忘记并直接提交给了main,就会出现远程服务器被拒绝的情况。

解决方法就是新建一个分支推送到远程服务器,然后reset你的main分支和远程服务器保持一致, 否则下次使用git pull并且他人的提交和你冲突的时候就会有问题。