目录
1、git clone
你可能注意到的第一个事就是在我们的本地仓库多了一个名为
o/master
的分支, 这种类型的分支就叫远程分支。由于远程分支的特性导致其拥有一些特殊属性。远程分支反映了远程仓库(在你上次和它通信时)的状态。这会有助于你理解本地的工作与公共工作的差别 —— 这是你与别人分享工作成果前至关重要的一步.
远程分支有一个特别的属性,在你检出时自动进入分离 HEAD 状态。Git 这么做是出于不能直接在这些分支上进行操作的原因, 你必须在别的地方完成你的工作, (更新了远程分支之后)再用远程分享你的工作成果。
为什么有
o/
?你可能想问这些远程分支的前面的
o/
是什么意思呢?好吧, 远程分支有一个命名规范 —— 它们的格式是:
<remote name>/<branch name>
因此,如果你看到一个名为
o/master
的分支,那么这个分支就叫master
,远程仓库的名称就是o
。大多数的开发人员会将它们主要的远程仓库命名为
origin
,并不是o
。这是因为当你用git clone
某个仓库时,Git 已经帮你把远程仓库的名称设置为origin
了不过
origin
对于我们的 UI 来说太长了,因此不得不使用简写o
:) 但是要记住, 当你使用真正的 Git 时, 你的远程仓库默认为origin
!
2、git fetch
Git 远程仓库相当的操作实际可以归纳为两点:向远程仓库传输数据以及从远程仓库获取数据。既然我们能与远程仓库同步,那么就可以分享任何能被 Git 管理的更新(因此可以分享代码、文件、想法、情书等等)。
本节课我们将学习如何从远程仓库获取数据 —— 命令如其名,它就是
git fetch
。你会看到当我们从远程仓库获取数据时, 远程分支也会更新以反映最新的远程仓库。
git fetch 做了些什么
git fetch
完成了仅有的但是很重要的两步:
- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针(如
o/master
)
git fetch
实际上将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态。如果你还记得上一节课程中我们说过的,远程分支反映了远程仓库在你最后一次与它通信时的状态,
git fetch
就是你与远程仓库通信的方式了!希望我说的够明白了,你已经了解git fetch
与远程分支之间的关系了吧。
git fetch
通常通过互联网(使用http://
或git://
协议) 与远程仓库通信。
git fetch 不会做的事
git fetch
并不会改变你本地仓库的状态。它不会更新你的master
分支,也不会修改你磁盘上的文件。理解这一点很重要,因为许多开发人员误以为执行了
git fetch
以后,他们本地仓库就与远程仓库同步了。它可能已经将进行这一操作所需的所有数据都下载了下来,但是并没有修改你本地的文件。我们在后面的课程中将会讲解能完成该操作的命令 :D所以, 你可以将
git fetch
的理解为单纯的下载操作。
3、git pull
git pull
就是 git fetch 和 git merge 的缩写!
既然我们已经知道了如何用
git fetch
获取远程的数据, 现在我们学习如何将这些变化更新到我们的工作当中。其实有很多方法的 —— 当远程分支中有新的提交时,你可以像合并本地分支那样来合并远程分支。也就是说就是你可以执行以下命令:
git cherry-pick o/master
git rebase o/master
git merge o/master
- 等等
实际上,由于先抓取更新再合并到本地分支这个流程很常用,因此 Git 提供了一个专门的命令来完成这两个操作。它就是我们要讲的
git pull
。
4、模拟团队合作
引入一个自造命令 git fakeTeamwork,来
模拟团队合作。
5、git push
OK,我们已经学过了如何从远程仓库获取更新并合并到本地的分支当中。这非常棒……但是我如何与大家分享我的成果呢?
嗯,上传自己分享内容与下载他人的分享刚好相反,那与
git pull
相反的命令是什么呢?git push
!
git push
负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦git push
完成, 你的朋友们就可以从这个远程仓库下载你分享的成果了!你可以将
git push
想象成发布你成果的命令。它有许多应用技巧,稍后我们会了解到,但是咱们还是先从基础的开始吧……注意 ——
git push
不带任何参数时的行为与 Git 的一个名为push.default
的配置有关。它的默认值取决于你正使用的 Git 的版本,但是在教程中我们使用的是upstream
。 这没什么太大的影响,但是在你的项目中进行推送之前,最好检查一下这个配置。
6、偏离的工作
设你周一克隆了一个仓库,然后开始研发某个新功能。到周五时,你新功能开发测试完毕,可以发布了。但是 —— 天啊!你的同事这周写了一堆代码,还改了许多你的功能中使用的 API,这些变动会导致你新开发的功能变得不可用。但是他们已经将那些提交推送到远程仓库了,因此你的工作就变成了基于项目旧版的代码,与远程仓库最新的代码不匹配了。
这种情况下,
git push
就不知道该如何操作了。如果你执行git push
,Git 应该让远程仓库回到星期一那天的状态吗?还是直接在新代码的基础上添加你的代码,亦或由于你的提交已经过时而直接忽略你的提交?因为这情况(历史偏离)有许多的不确定性,Git 是不会允许你
push
变更的。实际上它会强制你先合并远程最新的代码,然后才能分享你的工作。
通过rebase调整工作。
还有其它的方法可以在远程仓库变更了以后更新我的工作吗? 当然有,我们还可以使用
merge
尽管
git merge
不会移动你的工作(它会创建新的合并提交),但是它会告诉 Git 你已经合并了远程仓库的所有变更。这是因为远程分支现在是你本地分支的祖先,也就是说你的提交已经包含了远程分支的所有变化。
前面已经介绍过
git pull
就是 fetch 和 merge 的简写,类似的git pull --rebase
就是 fetch 和 rebase 的简写!
7、远程服务器拒绝!(Remote Rejected)
如果你是在一个大的合作团队中工作, 很可能是master被锁定了, 需要一些Pull Request流程来合并修改。如果你直接提交(commit)到本地master, 然后试图推送(push)修改, 你将会收到这样类似的信息:
! [远程服务器拒绝] master -> master (TF402455: 不允许推送(push)这个分支; 你必须使用pull request来更新这个分支.)
为什么会被拒绝?
远程服务器拒绝直接推送(push)提交到master, 因为策略配置要求 pull requests 来提交更新.
你应该按照流程,新建一个分支, 推送(push)这个分支并申请pull request,但是你忘记并直接提交给了master.现在你卡住并且无法推送你的更新.
解决办法
新建一个分支feature, 推送到远程服务器. 然后reset你的master分支和远程服务器保持一致, 否则下次你pull并且他人的提交和你冲突的时候就会有问题.
目标:
目前:
解决:
8、合并特性分支
在大型项目中开发人员通常会在(从
master
上分出来的)特性分支上工作,工作完成后只做一次集成。这跟前面课程的描述很相像(把 side 分支推送到远程仓库),不过本节我们会深入一些.但是有些开发人员只在 master 上做 push、pull —— 这样的话 master 总是最新的,始终与远程分支 (o/master) 保持一致。
对于接下来这个工作流,我们集成了两个步骤:
- 将特性分支集成到
master
上- 推送并更新远程分支
目标:
目前:
解决方案: