4. 远程仓库拉取和推送

本小节我们来学习如何使用远程仓库进行协作开发。我们将学习如下三个常用与远程操作的命令。

命令
说明
git fetch
从远程仓库下载所有的提交对象到本地,但不合并到本地当前分支。
git pull
从远程仓库下载所有的提交对象到本地,然后自动合并到本地当前分支。
git push
将本地提交上传到远程仓库并更新远程分支。如果此时远程有修改,则需要先拉取git pull 然后再推送。

下面我们来解释一下上述命令的应用场景。

上一小节我们已经将 my_project 最新的两次提交都推送到了码云的远程仓库中。现在本地仓库和远程仓库的内容如下:

                 HEAD
                  |
              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
第一次提交      第二次提交

它们都有两个提交对象,并且提交对象的ID(哈希值)也完全一致。

现在假设你的合作伙伴小张完了一次新的功能,并提交到远程仓库中。远程仓库的内容编程如下状态:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+     +-------+     +-------+
第一次提交      第二次提交      小张的提交

而你本地的 master分支依旧没有变化。

此时我们可以使用 git fetchgit pull 将远程仓库中小张的修改也同步到我的本地仓库中,那这两个命令有什么不同呢?不同之处在于 git fetch 只是将远程仓库的分支下载到本地仓库,形成一个 origin/master 的远程分支,但本地的 master 分支不会有任何变化。而 git pull 先做 git fetch 的工作,然后将 远程分支 orgin/master 合并但本地分支 master 中,此时的本地分支和远程分支一模一样。

git fetch 命令

作用: 从远程仓库下载所有的提交对象到本地,但不合并到本地当前分支。

命令格式如下:

git fetch [选项] [远程仓库名] [远程分支名]

说明:

git fetch 常用选项

选项
说明
--all
获取所有远程的所有分支。
--prune-p
获取并删除本地已不存在的远程分支引用。
-v
获取并显示详细信息
--force
强制更新所有分支
--tags
获取所有标签

示例:

在上述远程仓库 已经有个了提交对象 1111111 的情况下使用 git fetch 获取后的结果。

本地的远程分支 origin/master 分支是这样:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+     +-------+     +-------+
第一次提交      第二次提交      小张的提交

本地的 master 分支是这样:

                 HEAD
                  |
              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
第一次提交      第二次提交

可见本地的 master 分支并没有变化。此时如果我们在本地仓库产生新的提交就会在 master 分支后创建提交对象。这样会导致本地分支和远程分支不一致的情况。

git pull 命令

作用:从远程仓库下载所有的提交对象到本地,然后自动合并到本地当前分支。

命令格式如下:

git pull [选项] [远程仓库名] [远程分支名[:本地分支名]]

说明:

git pull 常用选项

选项
说明
--rebase
拉取所有远程的所有分支,并使用变基的方式合并到当前分支。
--all
拉取所有远程的所有分支。
--no-commit
拉取但不自动提交合并。需要手动提交。
-v
显示详细信息

示例:

在上述远程仓库 已经有个了提交对象 1111111 的情况下使用 git pull 获取后的结果。

本地的远程分支 origin/master 分支是这样:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+     +-------+     +-------+
第一次提交      第二次提交      小张的提交

本地的 master 分支会和本地的远程 origin/master 分支合并,即:将 1111111 这个提交对象合并到 5dcccb0 这个对象之后。最终结果同远程分支一致。如下图所示:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+     +-------+     +-------+
第一次提交      第二次提交      小张的提交

现在如果你完成了某个工作,再次本地提交则会在 1111111 提交对象后创建你的提交对象。

git pull 注意事项:

假设小张在远程仓库进行了提交,而你在本地仓库进行了提交。结果如下:

远程仓库的内容:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+     +-------+     +-------+
第一次提交      第二次提交      小张的提交

你的本地仓库的内容:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |2222222|
+-------+     +-------+     +-------+
第一次提交      第二次提交       你的提交

这样在使用 git pull 可能就会出现合并失败的情况。因此带提交到远程仓库使用的分支时,最好先使用 git pull 将远程仓库的变化合并到本地。然后再进行提交。还有一个好办法就是在本地仓库建立其它的分支进行提交。在需要时在合并到远程仓库协作开发的分支中。

关于分支的管理我们后面会讲。

git push 命令

作用: 将本地分支推送到远程分支,让远程仓库的一个或多个分支与本地分支同步。

命令格式如下:

git push [选项] [远程仓库名] [本地分支名][:[远程分支名]]

说明:

git push 常用选项

选项
说明
--all
推送所有分支
-u
建立本地分支与远程分支的追踪关系,只需要首次设置。
--force
强制推送(谨慎使用)
--delete 分支名
删除远程分支
--tags
推送所有标签

现在假设远程分支是这样:

                 HEAD
                  |
              .--------.
              | master |
              `--------`
                  |
+-------+     +-------+
|8cb34d1| <-- |5dcccb0|
+-------+     +-------+
第一次提交      第二次提交

而我的本地分支经过了一次提交,内容是如下这样:

                               HEAD
                                |
                            .--------.
                            | master |
                            `--------`
                                |
+-------+     +-------+     +-------+
|8cb34d1| <-- |5dcccb0| <-- |2222222|
+-------+     +-------+     +-------+
第一次提交      第二次提交       你的提交

现在要让远程仓库和本地仓库同步,我可以使用 git push 命令远程仓库变成本地仓库的样子。

需要注意的是,默认情况下 git push 并不会向远程仓库推送标签,如果你需要推送所有的标签可以添加 --tags 选项。如果你只是向远程仓库推送某一个标签,你可以使用 git push origin <标签名> 的方式推送。这样远程仓库就存在标签并可以被其它使用者拉取到本地仓库,如推送:v0.2这个标签,你可以使用命令 git push origin v0.2 命令完成推送。

实验:

在码云上创建远程仓库,然后克隆到本地,在本地编写代码并提交,最后将本地仓库的各个版本提交到码云上的远程仓库。在码云上查看你的提交。