4. 远程仓库拉取和推送
本小节我们来学习如何使用远程仓库进行协作开发。我们将学习如下三个常用与远程操作的命令。
git fetchgit pullgit pushgit pull 然后再推送。下面我们来解释一下上述命令的应用场景。
上一小节我们已经将 my_project 最新的两次提交都推送到了码云的远程仓库中。现在本地仓库和远程仓库的内容如下:
HEAD
|
.--------.
| master |
`--------`
|
+-------+ +-------+
|8cb34d1| <-- |5dcccb0|
+-------+ +-------+
第一次提交 第二次提交
它们都有两个提交对象,并且提交对象的ID(哈希值)也完全一致。
现在假设你的合作伙伴小张完了一次新的功能,并提交到远程仓库中。远程仓库的内容编程如下状态:
HEAD
|
.--------.
| master |
`--------`
|
+-------+ +-------+ +-------+
|8cb34d1| <-- |5dcccb0| <-- |1111111|
+-------+ +-------+ +-------+
第一次提交 第二次提交 小张的提交
而你本地的 master分支依旧没有变化。
此时我们可以使用 git fetch 或 git pull 将远程仓库中小张的修改也同步到我的本地仓库中,那这两个命令有什么不同呢?不同之处在于 git fetch 只是将远程仓库的分支下载到本地仓库,形成一个 origin/master 的远程分支,但本地的 master 分支不会有任何变化。而 git pull 先做 git fetch 的工作,然后将 远程分支 orgin/master 合并但本地分支 master 中,此时的本地分支和远程分支一模一样。
git fetch 命令
作用: 从远程仓库下载所有的提交对象到本地,但不合并到本地当前分支。
命令格式如下:
git fetch [选项] [远程仓库名] [远程分支名]
说明:
- 远程仓库名如果省略不写,默认是
origin。 - 远程分支名如果省略不写,默认是
master。 - 如果远程仓库名和远程分支名都省略,则默认抓取
origin的所有分支. 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 [选项] [远程仓库名] [远程分支名[:本地分支名]]
说明:
- 远程仓库名如果省略不写,默认是
origin。 - 远程分支名如果省略不写,默认是当前本地分支对应的分支名。
- 本地分支名如果省略不写,默认是当前本地分支。
- 如果远程仓库名和本地分支名都省略,则默认获取
origin的当前分支对应的远程分支。 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 [选项] [远程仓库名] [本地分支名][:[远程分支名]]
说明:
- 远程仓库名如果不写,默认是
origin。 - 本地分支名如果不写,默认是
master。 - 远程分支名默认是本地分支名,也可是手动指定。
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 命令完成推送。
实验:
在码云上创建远程仓库,然后克隆到本地,在本地编写代码并提交,最后将本地仓库的各个版本提交到码云上的远程仓库。在码云上查看你的提交。